001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.commons.configuration;
019:
020: import java.util.Iterator;
021:
022: import org.apache.commons.collections.Transformer;
023: import org.apache.commons.collections.iterators.TransformIterator;
024:
025: /**
026: * <p>A subset of another configuration. The new Configuration object contains
027: * every key from the parent Configuration that starts with prefix. The prefix
028: * is removed from the keys in the subset.</p>
029: * <p>It is usually not necessary to use this class directly. Instead the
030: * <code>{@link Configuration#subset(String)}</code> method should be used,
031: * which will return a correctly initialized instance.</p>
032: *
033: * @author Emmanuel Bourg
034: * @version $Revision: 501987 $, $Date: 2007-01-31 21:57:04 +0100 (Mi, 31 Jan 2007) $
035: */
036: public class SubsetConfiguration extends AbstractConfiguration {
037: /** The parent configuration. */
038: protected Configuration parent;
039:
040: /** The prefix used to select the properties. */
041: protected String prefix;
042:
043: /** The prefix delimiter */
044: protected String delimiter;
045:
046: /**
047: * Create a subset of the specified configuration
048: *
049: * @param parent The parent configuration
050: * @param prefix The prefix used to select the properties
051: */
052: public SubsetConfiguration(Configuration parent, String prefix) {
053: this .parent = parent;
054: this .prefix = prefix;
055: }
056:
057: /**
058: * Create a subset of the specified configuration
059: *
060: * @param parent The parent configuration
061: * @param prefix The prefix used to select the properties
062: * @param delimiter The prefix delimiter
063: */
064: public SubsetConfiguration(Configuration parent, String prefix,
065: String delimiter) {
066: this .parent = parent;
067: this .prefix = prefix;
068: this .delimiter = delimiter;
069: }
070:
071: /**
072: * Return the key in the parent configuration associated to the specified
073: * key in this subset.
074: *
075: * @param key The key in the subset.
076: * @return the key as to be used by the parent
077: */
078: protected String getParentKey(String key) {
079: if ("".equals(key) || key == null) {
080: return prefix;
081: } else {
082: return delimiter == null ? prefix + key : prefix
083: + delimiter + key;
084: }
085: }
086:
087: /**
088: * Return the key in the subset configuration associated to the specified
089: * key in the parent configuration.
090: *
091: * @param key The key in the parent configuration.
092: * @return the key in the context of this subset configuration
093: */
094: protected String getChildKey(String key) {
095: if (!key.startsWith(prefix)) {
096: throw new IllegalArgumentException("The parent key '" + key
097: + "' is not in the subset.");
098: } else {
099: String modifiedKey = null;
100: if (key.length() == prefix.length()) {
101: modifiedKey = "";
102: } else {
103: int i = prefix.length()
104: + (delimiter != null ? delimiter.length() : 0);
105: modifiedKey = key.substring(i);
106: }
107:
108: return modifiedKey;
109: }
110: }
111:
112: /**
113: * Return the parent configuation for this subset.
114: *
115: * @return the parent configuration
116: */
117: public Configuration getParent() {
118: return parent;
119: }
120:
121: /**
122: * Return the prefix used to select the properties in the parent configuration.
123: *
124: * @return the prefix used by this subset
125: */
126: public String getPrefix() {
127: return prefix;
128: }
129:
130: /**
131: * Set the prefix used to select the properties in the parent configuration.
132: *
133: * @param prefix the prefix
134: */
135: public void setPrefix(String prefix) {
136: this .prefix = prefix;
137: }
138:
139: /**
140: * {@inheritDoc}
141: */
142: public Configuration subset(String prefix) {
143: return parent.subset(getParentKey(prefix));
144: }
145:
146: /**
147: * {@inheritDoc}
148: */
149: public boolean isEmpty() {
150: return !getKeys().hasNext();
151: }
152:
153: /**
154: * {@inheritDoc}
155: */
156: public boolean containsKey(String key) {
157: return parent.containsKey(getParentKey(key));
158: }
159:
160: /**
161: * {@inheritDoc}
162: */
163: public void addPropertyDirect(String key, Object value) {
164: parent.addProperty(getParentKey(key), value);
165: }
166:
167: /**
168: * {@inheritDoc}
169: */
170: public void setProperty(String key, Object value) {
171: parent.setProperty(getParentKey(key), value);
172: }
173:
174: /**
175: * {@inheritDoc}
176: */
177: public void clearProperty(String key) {
178: parent.clearProperty(getParentKey(key));
179: }
180:
181: /**
182: * {@inheritDoc}
183: */
184: public Object getProperty(String key) {
185: return parent.getProperty(getParentKey(key));
186: }
187:
188: /**
189: * {@inheritDoc}
190: */
191: public Iterator getKeys(String prefix) {
192: return new TransformIterator(parent
193: .getKeys(getParentKey(prefix)), new Transformer() {
194: public Object transform(Object obj) {
195: return getChildKey((String) obj);
196: }
197: });
198: }
199:
200: /**
201: * {@inheritDoc}
202: */
203: public Iterator getKeys() {
204: return new TransformIterator(parent.getKeys(prefix),
205: new Transformer() {
206: public Object transform(Object obj) {
207: return getChildKey((String) obj);
208: }
209: });
210: }
211:
212: /**
213: * {@inheritDoc}
214: */
215: protected Object interpolate(Object base) {
216: if (delimiter == null && "".equals(prefix)) {
217: return super .interpolate(base);
218: } else {
219: SubsetConfiguration config = new SubsetConfiguration(
220: parent, "");
221: return config.interpolate(base);
222: }
223: }
224:
225: /**
226: * {@inheritDoc}
227: */
228: protected String interpolate(String base) {
229: return super .interpolate(base);
230: }
231:
232: /**
233: * {@inheritDoc}
234: *
235: * Change the behaviour of the parent configuration if it supports this feature.
236: */
237: public void setThrowExceptionOnMissing(
238: boolean throwExceptionOnMissing) {
239: if (parent instanceof AbstractConfiguration) {
240: ((AbstractConfiguration) parent)
241: .setThrowExceptionOnMissing(throwExceptionOnMissing);
242: } else {
243: super .setThrowExceptionOnMissing(throwExceptionOnMissing);
244: }
245: }
246:
247: /**
248: * {@inheritDoc}
249: *
250: * The subset inherits this feature from its parent if it supports this feature.
251: */
252: public boolean isThrowExceptionOnMissing() {
253: if (parent instanceof AbstractConfiguration) {
254: return ((AbstractConfiguration) parent)
255: .isThrowExceptionOnMissing();
256: } else {
257: return super .isThrowExceptionOnMissing();
258: }
259: }
260:
261: /**
262: * Returns the list delimiter. This property will be fetched from the parent
263: * configuration if supported.
264: *
265: * @return the list delimiter
266: * @since 1.4
267: */
268: public char getListDelimiter() {
269: return (parent instanceof AbstractConfiguration) ? ((AbstractConfiguration) parent)
270: .getListDelimiter()
271: : super .getListDelimiter();
272: }
273:
274: /**
275: * Sets the list delimiter. If the parent configuration supports this
276: * feature, the delimiter will be set at the parent.
277: *
278: * @param delim the new list delimiter
279: * @since 1.4
280: */
281: public void setListDelimiter(char delim) {
282: if (parent instanceof AbstractConfiguration) {
283: ((AbstractConfiguration) parent).setListDelimiter(delim);
284: } else {
285: super .setListDelimiter(delim);
286: }
287: }
288:
289: /**
290: * Returns a flag whether string properties should be checked for list
291: * delimiter characters. This implementation ensures that this flag is kept
292: * in sync with the parent configuration if this object supports this
293: * feature.
294: *
295: * @return the delimiter parsing disabled flag
296: * @since 1.4
297: */
298: public boolean isDelimiterParsingDisabled() {
299: return (parent instanceof AbstractConfiguration) ? ((AbstractConfiguration) parent)
300: .isDelimiterParsingDisabled()
301: : super .isDelimiterParsingDisabled();
302: }
303:
304: /**
305: * Sets a flag whether list parsing is disabled. This implementation will
306: * also set the flag at the parent configuration if this object supports
307: * this feature.
308: *
309: * @param delimiterParsingDisabled the delimiter parsing disabled flag
310: * @since 1.4
311: */
312: public void setDelimiterParsingDisabled(
313: boolean delimiterParsingDisabled) {
314: if (parent instanceof AbstractConfiguration) {
315: ((AbstractConfiguration) parent)
316: .setDelimiterParsingDisabled(delimiterParsingDisabled);
317: } else {
318: super.setDelimiterParsingDisabled(delimiterParsingDisabled);
319: }
320: }
321: }
|