1 /*
2 * Copyright (C) The Spice Group. All rights reserved.
3 *
4 * This software is published under the terms of the Spice
5 * Software License version 1.1, a copy of which has been included
6 * with this distribution in the LICENSE.txt file.
7 */
8 package org.codehaus.spice.configkit;
9
10 import java.util.Iterator;
11 import java.util.Map;
12 import java.util.Properties;
13 import org.w3c.dom.Attr;
14 import org.w3c.dom.Element;
15 import org.w3c.dom.NamedNodeMap;
16 import org.w3c.dom.Node;
17 import org.w3c.dom.NodeList;
18 import org.w3c.dom.Text;
19
20 /***
21 * This is a utility class designed for expanding propertys in configuration
22 * files. Propertys are stored in Map objects and any section that begins with
23 * "${" and ends with "}" will have inner name replaced with property value from
24 * map.
25 *
26 * @author Peter Donald
27 * @version $Revision: 1.1 $ $Date: 2003/12/03 03:19:28 $
28 */
29 public final class PropertyExpander
30 {
31 /***
32 * Flag indicating that undefined propertys should be not be replaced. ie
33 * "${myUnresolvedProperty}"
34 */
35 public static final int LEAVE_UNDEFINED = 1;
36
37 /***
38 * Flag indicating that undefined propertys should cause an exception to be
39 * thrown.
40 */
41 public static final int EXCEPT_ON_UNDEFINED = 2;
42
43 /***
44 * Flag indicating that undefined propertys should be replaced with a empty
45 * string "".
46 */
47 public static final int EMPTY_ON_UNDEFINED = 3;
48
49 /***
50 * The flag for behaviour when undefined property is encountered. Must be
51 * one of the *_UNDEFINED propertys.
52 */
53 private final int m_onUndefined;
54
55 /***
56 * Create property expander with EXCEPT_ON_UNDEFINED policy for undefined
57 * propertys.
58 */
59 public PropertyExpander()
60 {
61 this( EXCEPT_ON_UNDEFINED );
62 }
63
64 /***
65 * Create property expander with specified policy for undefined propertys.
66 *
67 * @param onUndefined the flag indicating behaviour when undefined property
68 * is encountered. Must be one of the *_UNDEFINED constants.
69 */
70 public PropertyExpander( final int onUndefined )
71 {
72 m_onUndefined = onUndefined;
73 }
74
75 /***
76 * Expand all propertys in the input Properties object.
77 *
78 * @param input the Properties object to resolve
79 * @param data the data that holds property values
80 * @throws Exception if an error occurs
81 */
82 public Properties expandValues( final Properties input, final Map data )
83 throws Exception
84 {
85 final Properties result = new Properties();
86 final Iterator iterator = input.keySet().iterator();
87 while( iterator.hasNext() )
88 {
89 final String key = (String)iterator.next();
90 final String value = input.getProperty( key );
91 final String newKey = expandValues( key, data );
92 final String newValue = expandValues( value, data );
93 result.setProperty( newKey, newValue );
94 }
95 return result;
96 }
97
98 /***
99 * Expand all propertys in the input XML attributes and text contents.
100 *
101 * @param input the DOM element to resolve
102 * @param data the data that holds property values
103 * @throws Exception if an error occurs
104 */
105 public void expandValues( final Element input, final Map data )
106 throws Exception
107 {
108 final NamedNodeMap attributes = input.getAttributes();
109 final int attributeCount = attributes.getLength();
110 for( int i = 0; i < attributeCount; i++ )
111 {
112 final Attr attr = (Attr)attributes.item( i );
113 final String value = attr.getValue();
114 final String newValue = expandValues( value, data );
115 attr.setValue( newValue );
116 }
117 final NodeList nodes = input.getChildNodes();
118 final int childCount = nodes.getLength();
119 for( int i = 0; i < childCount; i++ )
120 {
121 final Node node = nodes.item( i );
122 if( node instanceof Element )
123 {
124 expandValues( (Element)node, data );
125 }
126 else if( node instanceof Text )
127 {
128 final Text text = (Text)node;
129 final String content = text.getData();
130 final String newContent = expandValues( content, data );
131 text.setData( newContent );
132 }
133 }
134 }
135
136 /***
137 * Expand all propertys in input string.
138 *
139 * @param input the string to resolve
140 * @param data the data that holds property values
141 * @return the resolved string
142 * @throws Exception if an error occurs
143 */
144 public String expandValues( final String input, final Map data )
145 throws Exception
146 {
147 int start = findBeginning( input, 0 );
148 if( -1 == start )
149 {
150 return input;
151 }
152
153 int end = findEnding( input, start );
154
155 final int length = input.length();
156 if( 0 == start && end == ( length - 1 ) )
157 {
158 return getValue( input.substring( start + 2, end ),
159 data );
160 }
161
162 final StringBuffer sb = new StringBuffer( length * 2 );
163 int lastPlace = 0;
164
165 while( true )
166 {
167 final String value =
168 getValue( input.substring( start + 2, end ), data );
169
170 sb.append( input.substring( lastPlace, start ) );
171 sb.append( value );
172
173 lastPlace = end + 1;
174
175 start = findBeginning( input, lastPlace );
176 if( -1 == start )
177 {
178 break;
179 }
180
181 end = findEnding( input, start );
182 }
183
184 sb.append( input.substring( lastPlace, length ) );
185
186 return sb.toString();
187 }
188
189 /***
190 * Helper method to find the start of a input definition.
191 *
192 * @param input the input string
193 * @param index the current index into input
194 * @return the index of start of property definition
195 */
196 private int findBeginning( final String input, final int index )
197 {
198 return input.indexOf( "${", index );
199 }
200
201 /***
202 * Helper method to find the end of a property definition.
203 *
204 * @param input the input string
205 * @param index the current index into input
206 * @return the index of end of property definition
207 * @throws Exception if unable to locate end of property
208 */
209 private int findEnding( final String input, final int index )
210 throws Exception
211 {
212 final int end = input.indexOf( '}', index );
213 if( -1 == end )
214 {
215 final String message = "Malformed input with mismatched }'s";
216 throw new Exception( message );
217 }
218
219 return end;
220 }
221
222 /***
223 * Return value from data map. If null is retrieved from data map then
224 * behave as defined by {@link #m_onUndefined} flag.
225 *
226 * @param key the key of value in data
227 * @param data the data map
228 * @return the stringized value of value in map
229 * @throws Exception if an error occurs
230 */
231 private String getValue( final String key, final Map data )
232 throws Exception
233 {
234 final Object value = data.get( key );
235 if( null == value )
236 {
237 if( LEAVE_UNDEFINED == m_onUndefined )
238 {
239 return "${" + key + "}";
240 }
241 else if( EMPTY_ON_UNDEFINED == m_onUndefined )
242 {
243 return "";
244 }
245 else// if( EXCEPT_ON_UNDEFINED == m_onUndefined )
246 {
247 final String message = "Unable to find " +
248 key +
249 " to expand during property resolution.";
250 throw new Exception( message );
251 }
252 }
253
254 return String.valueOf( value );
255 }
256 }
This page was automatically generated by Maven