001    package org.apache.commons.digester3.substitution;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one
005     * or more contributor license agreements.  See the NOTICE file
006     * distributed with this work for additional information
007     * regarding copyright ownership.  The ASF licenses this file
008     * to you under the Apache License, Version 2.0 (the
009     * "License"); you may not use this file except in compliance
010     * with the License.  You may obtain a copy of the License at
011     *
012     *   http://www.apache.org/licenses/LICENSE-2.0
013     *
014     * Unless required by applicable law or agreed to in writing,
015     * software distributed under the License is distributed on an
016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017     * KIND, either express or implied.  See the License for the
018     * specific language governing permissions and limitations
019     * under the License.
020     */
021    
022    import java.util.Map;
023    import java.util.ArrayList;
024    
025    /**
026     * <p>
027     * Expands variable references from multiple sources.
028     * </p>
029     * 
030     * @since 1.6
031     */
032    public class MultiVariableExpander
033        implements VariableExpander
034    {
035    
036        private int nEntries = 0;
037    
038        private final ArrayList<String> markers = new ArrayList<String>( 2 );
039    
040        private final ArrayList<Map<String, Object>> sources = new ArrayList<Map<String, Object>>( 2 );
041    
042        /**
043         * Add a new variables source, identified by the input marker
044         *
045         * @param marker The input variables marker
046         * @param source The variables source
047         */
048        public void addSource( String marker, Map<String, Object> source )
049        {
050            ++nEntries;
051            markers.add( marker );
052            sources.add( source );
053        }
054    
055        /**
056         * {@inheritDoc}
057         */
058        public String expand( String param )
059        {
060            for ( int i = 0; i < nEntries; ++i )
061            {
062                param = expand( param, markers.get( i ), sources.get( i ) );
063            }
064            return param;
065        }
066    
067        /**
068         * Replace any occurrences within the string of the form "marker{key}" with the value from source[key].
069         * <p>
070         * Commonly, the variable marker is "$", in which case variables are indicated by ${key} in the string.
071         * <p>
072         * Returns the string after performing all substitutions.
073         * <p>
074         * If no substitutions were made, the input string object is returned (not a copy).
075         *
076         * @param str The input string containing placeholders
077         * @param marker The input variables marker
078         * @param source The variables source
079         * @return The input string where variables have been expanded by replacing values found in source
080         */
081        public String expand( String str, String marker, Map<String, Object> source )
082        {
083            String startMark = marker + "{";
084            int markLen = startMark.length();
085    
086            int index = 0;
087            for ( ;; )
088            {
089                index = str.indexOf( startMark, index );
090                if ( index == -1 )
091                {
092                    return str;
093                }
094    
095                int startIndex = index + markLen;
096                if ( startIndex > str.length() )
097                {
098                    throw new IllegalArgumentException( "var expression starts at end of string" );
099                }
100    
101                int endIndex = str.indexOf( "}", index + markLen );
102                if ( endIndex == -1 )
103                {
104                    throw new IllegalArgumentException( "var expression starts but does not end" );
105                }
106    
107                String key = str.substring( index + markLen, endIndex );
108                Object value = source.get( key );
109                if ( value == null )
110                {
111                    throw new IllegalArgumentException( "parameter [" + key + "] is not defined." );
112                }
113                String varValue = value.toString();
114    
115                str = str.substring( 0, index ) + varValue + str.substring( endIndex + 1 );
116                index += varValue.length();
117            }
118        }
119    
120    }