1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.fulcrum.yaafi.framework.util;
20
21 import java.util.Map;
22
23 import org.apache.avalon.framework.configuration.Configuration;
24 import org.apache.avalon.framework.configuration.ConfigurationException;
25 import org.apache.avalon.framework.configuration.DefaultConfiguration;
26 import org.apache.avalon.framework.logger.Logger;
27
28 /**
29 * Helper class to expand the value and all attributes.
30 *
31 * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a>
32 */
33 public class ConfigurationUtil
34 {
35 /**
36 * Expand place holders found in values or attrbute values with the
37 * content of the given variables. The implementation assumes that
38 * the given configuration can be cast to a DefaultConfiguration
39 * otherwise we can't use any setters.
40 *
41 * @param logger the logger to write diagnostic messages
42 * @param defaultConfiguration the configuration
43 * @param vars the map holding the variables
44 * @throws ConfigurationException parsing the configuration failed
45 */
46 public static void expand(Logger logger, DefaultConfiguration defaultConfiguration, Map<?, ?> vars) throws ConfigurationException
47 {
48 if( vars == null || vars.size() == 0)
49 {
50 return;
51 }
52
53 // update the value of the configuration element
54
55 if(defaultConfiguration.getValue(null) != null)
56 {
57 String oldValue = defaultConfiguration.getValue();
58 String newValue = ConfigurationUtil.expand(oldValue, vars);
59 defaultConfiguration.setValue(newValue);
60
61 if(oldValue.equals(newValue) == false)
62 {
63 logger.debug("Changed element <"
64 + defaultConfiguration.getName()
65 + "> from '"
66 + oldValue
67 + "' ==> '"
68 + newValue
69 + "'"
70 );
71 }
72 }
73
74 // update all attributes
75
76 String attributeName = null;
77 String[] attributeNames = defaultConfiguration.getAttributeNames();
78
79 for(int i=0; i<attributeNames.length; i++)
80 {
81 attributeName = attributeNames[i];
82 String oldAttributeValue = defaultConfiguration.getAttribute(attributeName);
83 String newAttributeValue = ConfigurationUtil.expand(oldAttributeValue, vars);
84 defaultConfiguration.setAttribute(attributeName, newAttributeValue);
85
86 if(oldAttributeValue.equals(newAttributeValue) == false)
87 {
88 logger.debug("Changed attribute '"
89 + defaultConfiguration.getName() + "@" + attributeName
90 + "' from '"
91 + oldAttributeValue
92 + "' ==> '"
93 + newAttributeValue
94 + "'"
95 );
96 }
97 }
98
99 // and now recurse through all children (children are in general a lot of work)
100
101 Configuration[] children = defaultConfiguration.getChildren();
102
103 for(int i=0; i<children.length; i++)
104 {
105 ConfigurationUtil.expand(logger, ((DefaultConfiguration) children[i]), vars);
106 }
107 }
108
109 /**
110 * Perform a series of substitutions. The substitutions
111 * are performed by replacing ${variable} in the target
112 * string with the value of provided by the key "variable"
113 * in the provided hashtable.
114 *
115 * The unexpanded ${variable} is always written to
116 * the string buffer.
117 *
118 * @param argStr target string
119 * @param vars name/value pairs used for substitution
120 * @return String target string with replacements.
121 */
122 private static String expand(String argStr, Map<?, ?> vars)
123 {
124 // ignore failures
125 boolean isLenient = true;
126
127 StringBuilder argBuf = new StringBuilder();
128 int argStrLength = argStr.length();
129
130 for (int cIdx = 0 ; cIdx < argStrLength;)
131 {
132 char ch = argStr.charAt(cIdx);
133 char del = ' ';
134
135 switch (ch)
136 {
137 case '$':
138 StringBuilder nameBuf = new StringBuilder();
139 del = argStr.charAt(cIdx+1);
140 if( del == '{')
141 {
142 cIdx++;
143
144 for (++cIdx ; cIdx < argStr.length(); ++cIdx)
145 {
146 ch = argStr.charAt(cIdx);
147 if (ch != '}')
148 nameBuf.append(ch);
149 else
150 break;
151 }
152
153 if (nameBuf.length() > 0)
154 {
155 Object value = vars.get(nameBuf.toString());
156
157 if (value != null)
158 {
159 argBuf.append(value.toString());
160 }
161 else
162 {
163 if (!isLenient)
164 {
165 throw new RuntimeException("No value found for : " + nameBuf );
166 }
167 else
168 {
169 argBuf.append("${").append(nameBuf).append("}");
170 }
171 }
172
173 del = argStr.charAt(cIdx);
174
175 if( del != '}')
176 {
177 throw new RuntimeException("Delimineter not found for : " + nameBuf );
178 }
179 }
180
181 cIdx++;
182 }
183 else
184 {
185 argBuf.append(ch);
186 ++cIdx;
187 }
188
189 break;
190
191 default:
192 argBuf.append(ch);
193 ++cIdx;
194 break;
195 }
196 }
197
198 return argBuf.toString();
199 }
200 }