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