001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     * 
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     * 
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */ 
017    package org.apache.commons.betwixt.strategy;
018    
019    import org.apache.commons.betwixt.XMLUtils;
020    
021    /**
022     * <code>NameMapper</code> implementation that processes a name by replacing or stripping
023     * illegal characters before passing result down the chain.
024     * 
025     * @author Robert Burrell Donkin
026     * @since 0.5
027     */
028    public class BadCharacterReplacingNMapper implements NameMapper {
029        /** Next mapper in chain, possibly null */
030        private NameMapper chainedMapper;
031        /** Replacement character, possibly null */
032        private Character replacement = null;
033        
034        /**
035          * Constructs a replacing mapper which delegates to given mapper.
036          * @param chainedMapper next link in processing chain, possibly null
037          */
038        public BadCharacterReplacingNMapper(NameMapper chainedMapper) {
039            this.chainedMapper = chainedMapper;
040        }   
041    
042        /**
043          * Gets the character that should be used to replace bad characters
044          * if null then bad characters will be deleted.
045          * @return the replacement Character possibly null
046          */
047        public Character getReplacement() {
048            return replacement;
049        }
050        
051        /**
052          * Sets the character that should be used to replace bad characters.
053          * @param replacement the Charcter to be used for replacement if not null.
054          * Otherwise, indicates that illegal characters should be deleted.
055          */
056        public void setReplacement( Character replacement ) {
057            this.replacement = replacement;
058        } 
059    
060        /**
061         * This implementation processes characters which are not allowed in xml
062         * element names and then returns the result from the next link in the chain.
063         * This processing consists of deleting them if no replacement character
064         * has been set. 
065         * Otherwise, the character will be replaced.
066         *  
067         * @param typeName the string to convert 
068         * @return the processed input
069         */
070        public String mapTypeToElementName(String typeName) {
071            
072            StringBuffer buffer = new StringBuffer( typeName );
073            for (int i=0, size = buffer.length(); i< size; i++) {
074                char nextChar = buffer.charAt( i );
075                boolean bad = false;
076                if ( i==0 ) {
077                    bad = !XMLUtils.isNameStartChar( nextChar );
078                } else {
079                    bad = !XMLUtils.isNameChar( nextChar );
080                }
081                    
082                if (bad) {
083                    if ( replacement != null ) {
084                        buffer.setCharAt( i, replacement.charValue() );
085                    } else {
086                        // delete
087                        buffer.deleteCharAt( i );
088                        i--;
089                        size--;
090                    }
091                }
092            }
093            
094            if ( buffer.length() == 0 ) {
095                throw new IllegalArgumentException(
096    "Element name contains no legal characters and no replacements have been set.");
097            }
098            
099            typeName = buffer.toString();
100            
101            if ( chainedMapper == null ) {
102                return typeName;
103            }
104            return chainedMapper.mapTypeToElementName( typeName );
105        }
106    }