2
* Licensed to the Apache Software Foundation (ASF) under one or more
3
* contributor license agreements. See the NOTICE file distributed with
4
* this work for additional information regarding copyright ownership.
5
* The ASF licenses this file to You under the Apache License, Version 2.0
6
* (the "License"); you may not use this file except in compliance with
7
* the License. You may obtain a copy of the License at
9
* http://www.apache.org/licenses/LICENSE-2.0
11
* Unless required by applicable law or agreed to in writing, software
12
* distributed under the License is distributed on an "AS IS" BASIS,
13
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
* See the License for the specific language governing permissions and
15
* limitations under the License.
17
package org.apache.commons.configuration.interpol;
19
import java.util.HashMap;
23
import org.apache.commons.lang.text.StrLookup;
27
* A class that handles interpolation (variable substitution) for configuration
31
* Each instance of <code>AbstractConfiguration</code> is associated with an
32
* object of this class. All interpolation tasks are delegated to this object.
35
* <code>ConfigurationInterpolator</code> works together with the
36
* <code>StrSubstitutor</code> class from <a
37
* href="http://commons.apache.org/lang">Commons Lang</a>. By extending
38
* <code>StrLookup</code> it is able to provide values for variables that
39
* appear in expressions.
42
* The basic idea of this class is that it can maintain a set of primitive
43
* <code>StrLookup</code> objects, each of which is identified by a special
44
* prefix. The variables to be processed have the form
45
* <code>${prefix:name}</code>. <code>ConfigurationInterpolator</code> will
46
* extract the prefix and determine, which primitive lookup object is registered
47
* for it. Then the name of the variable is passed to this object to obtain the
48
* actual value. It is also possible to define a default lookup object, which
49
* will be used for variables that do not have a prefix or that cannot be
50
* resolved by their associated lookup object.
53
* When a new instance of this class is created it is initialized with a default
54
* set of primitive lookup objects. This set can be customized using the static
55
* methods <code>registerGlobalLookup()</code> and
56
* <code>deregisterGlobalLookup()</code>. Per default it contains the
57
* following standard lookup objects:
63
* <th>Lookup object</th>
66
* <td valign="top">sys</td>
67
* <td>With this prefix a lookup object is associated that is able to resolve
68
* system properties.</td>
71
* <td valign="top">const</td>
72
* <td>The <code>const</code> prefix indicates that a variable is to be
73
* interpreted as a constant member field of a class (i.e. a field with the
74
* <b>static final</b> modifiers). The name of the variable must be of the form
75
* <code><full qualified class name>.<field name></code>, e.g.
76
* <code>org.apache.commons.configuration.interpol.ConfigurationInterpolator.PREFIX_CONSTANTS
82
* After an instance has been created the current set of lookup objects can be
83
* modified using the <code>registerLookup()</code> and
84
* <code>deregisterLookup()</code> methods. The default lookup object (that is
85
* invoked for variables without a prefix) can be set with the
86
* <code>setDefaultLookup()</code> method. (If a
87
* <code>ConfigurationInterpolator</code> instance is created by a
88
* configuration object, this lookup points to the configuration itself, so that
89
* variables are resolved using the configuration's properties. This ensures
90
* backward compatibility to earlier version of Commons Configuration.)
93
* Implementation node: Instances of this class are not thread-safe related to
94
* modifications of their current set of registered lookup objects. It is
95
* intended that each instance is associated with a single
96
* <code>Configuration</code> object and used for its interpolation tasks.
99
* @version $Id: ConfigurationInterpolator.java 833923 2009-11-08 20:53:52Z oheger $
102
* href="http://commons.apache.org/configuration/team-list.html">Commons
103
* Configuration team</a>
105
public class ConfigurationInterpolator extends StrLookup
108
* Constant for the prefix of the standard lookup object for resolving
111
public static final String PREFIX_SYSPROPERTIES = "sys";
114
* Constant for the prefix of the standard lookup object for resolving
117
public static final String PREFIX_CONSTANTS = "const";
120
* Constant for the prefix of the standard lookup object for resolving
121
* environment properties.
124
public static final String PREFIX_ENVIRONMENT = "env";
126
/** Constant for the prefix separator. */
127
private static final char PREFIX_SEPARATOR = ':';
129
/** A map with the globally registered lookup objects. */
130
private static Map globalLookups;
132
/** A map with the locally registered lookup objects. */
133
private Map localLookups;
135
/** Stores the default lookup object. */
136
private StrLookup defaultLookup;
138
/** Stores a parent interpolator objects if the interpolator is nested hierarchically. */
139
private ConfigurationInterpolator parentInterpolator;
142
* Creates a new instance of <code>ConfigurationInterpolator</code>.
144
public ConfigurationInterpolator()
146
synchronized (globalLookups)
148
localLookups = new HashMap(globalLookups);
153
* Registers the given lookup object for the specified prefix globally. This
154
* means that all instances that are created later will use this lookup
155
* object for this prefix. If for this prefix a lookup object is already
156
* registered, the new lookup object will replace the old one. Note that the
157
* lookup objects registered here will be shared between multiple clients.
158
* So they should be thread-safe.
160
* @param prefix the variable prefix (must not be <b>null</b>)
161
* @param lookup the lookup object to be used for this prefix (must not be
164
public static void registerGlobalLookup(String prefix, StrLookup lookup)
168
throw new IllegalArgumentException(
169
"Prefix for lookup object must not be null!");
173
throw new IllegalArgumentException(
174
"Lookup object must not be null!");
176
synchronized (globalLookups)
178
globalLookups.put(prefix, lookup);
183
* Deregisters the global lookup object for the specified prefix. This means
184
* that this lookup object won't be available for later created instances
185
* any more. For already existing instances this operation does not have any
188
* @param prefix the variable prefix
189
* @return a flag whether for this prefix a lookup object had been
192
public static boolean deregisterGlobalLookup(String prefix)
194
synchronized (globalLookups)
196
return globalLookups.remove(prefix) != null;
201
* Registers the given lookup object for the specified prefix at this
202
* instance. From now on this lookup object will be used for variables that
203
* have the specified prefix.
205
* @param prefix the variable prefix (must not be <b>null</b>)
206
* @param lookup the lookup object to be used for this prefix (must not be
209
public void registerLookup(String prefix, StrLookup lookup)
213
throw new IllegalArgumentException(
214
"Prefix for lookup object must not be null!");
218
throw new IllegalArgumentException(
219
"Lookup object must not be null!");
221
localLookups.put(prefix, lookup);
225
* Deregisters the lookup object for the specified prefix at this instance.
226
* It will be removed from this instance.
228
* @param prefix the variable prefix
229
* @return a flag whether for this prefix a lookup object had been
232
public boolean deregisterLookup(String prefix)
234
return localLookups.remove(prefix) != null;
238
* Returns a set with the prefixes, for which lookup objects are registered
239
* at this instance. This means that variables with these prefixes can be
242
* @return a set with the registered variable prefixes
244
public Set prefixSet()
246
return localLookups.keySet();
250
* Returns the default lookup object.
252
* @return the default lookup object
254
public StrLookup getDefaultLookup()
256
return defaultLookup;
260
* Sets the default lookup object. This lookup object will be used for all
261
* variables without a special prefix. If it is set to <b>null</b>, such
262
* variables won't be processed.
264
* @param defaultLookup the new default lookup object
266
public void setDefaultLookup(StrLookup defaultLookup)
268
this.defaultLookup = defaultLookup;
272
* Resolves the specified variable. This implementation will try to extract
273
* a variable prefix from the given variable name (the first colon (':') is
274
* used as prefix separator). It then passes the name of the variable with
275
* the prefix stripped to the lookup object registered for this prefix. If
276
* no prefix can be found or if the associated lookup object cannot resolve
277
* this variable, the default lookup object will be used.
279
* @param var the name of the variable whose value is to be looked up
280
* @return the value of this variable or <b>null</b> if it cannot be
283
public String lookup(String var)
290
int prefixPos = var.indexOf(PREFIX_SEPARATOR);
293
String prefix = var.substring(0, prefixPos);
294
String name = var.substring(prefixPos + 1);
295
String value = fetchLookupForPrefix(prefix).lookup(name);
296
if (value == null && getParentInterpolator() != null)
298
value = getParentInterpolator().fetchLookupForPrefix(prefix).lookup(name);
305
String value = fetchNoPrefixLookup().lookup(var);
306
if (value == null && getParentInterpolator() != null)
308
value = getParentInterpolator().fetchNoPrefixLookup().lookup(var);
314
* Returns the lookup object to be used for variables without a prefix. This
315
* implementation will check whether a default lookup object was set. If
316
* this is the case, it will be returned. Otherwise a <b>null</b> lookup
317
* object will be returned (never <code>null</code>).
319
* @return the lookup object to be used for variables without a prefix
321
protected StrLookup fetchNoPrefixLookup()
323
return (getDefaultLookup() != null) ? getDefaultLookup() : StrLookup.noneLookup();
327
* Obtains the lookup object for the specified prefix. This method is called
328
* by the <code>lookup()</code> method. This implementation will check
329
* whether a lookup object is registered for the given prefix. If not, a
330
* <b>null</b> lookup object will be returned (never <code>null</code>).
332
* @param prefix the prefix
333
* @return the lookup object to be used for this prefix
335
protected StrLookup fetchLookupForPrefix(String prefix)
337
StrLookup lookup = (StrLookup) localLookups.get(prefix);
340
lookup = StrLookup.noneLookup();
346
* Registers the local lookup instances for the given interpolator.
348
* @param interpolator the instance receiving the local lookups
351
public void registerLocalLookups(ConfigurationInterpolator interpolator)
353
interpolator.localLookups.putAll(localLookups);
357
* Sets the parent interpolator. This object is used if the interpolation is nested
358
* hierarchically and the current interpolation object cannot resolve a variable.
360
* @param parentInterpolator the parent interpolator object or <code>null</code>
363
public void setParentInterpolator(ConfigurationInterpolator parentInterpolator)
365
this.parentInterpolator = parentInterpolator;
369
* Requests the parent interpolator. This object is used if the interpolation is nested
370
* hierarchically and the current interpolation
372
* @return the parent interpolator or <code>null</code>
375
public ConfigurationInterpolator getParentInterpolator()
377
return this.parentInterpolator;
380
// static initializer, sets up the map with the standard lookups
383
globalLookups = new HashMap();
384
globalLookups.put(PREFIX_SYSPROPERTIES, StrLookup.systemPropertiesLookup());
385
globalLookups.put(PREFIX_CONSTANTS, new ConstantLookup());
386
globalLookups.put(PREFIX_ENVIRONMENT, new EnvironmentLookup());