1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.germinus.easyconf;
17
18 import java.math.BigDecimal;
19 import java.math.BigInteger;
20 import java.util.*;
21
22 import org.apache.commons.beanutils.DynaBean;
23 import org.apache.commons.configuration.beanutils.ConfigurationDynaBean;
24 import org.apache.commons.configuration.CompositeConfiguration;
25 import org.apache.commons.configuration.Configuration;
26 import org.apache.commons.configuration.ConfigurationConverter;
27 import org.apache.commons.configuration.DataConfiguration;
28 import org.apache.commons.configuration.MapConfiguration;
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31
32 /***
33 * Part of a component configuration which contains its properties.
34 *
35 * The properties can be accessed by type and automatic conversion will be
36 * performed. The supported types are: BigDecimal, BigInteger, Boolean, Byte,
37 * Double, Float, Integer, List, Long, Short, String and StringArray
38 *
39 * It is based on the <code>Configuration</code> interface from Jakarta
40 * Commons Configuration but it is given a different name which makes more sense
41 * inside EasyConf.
42 *
43 * The boolean flag throwExceptionOnMissing controls the behaviour of this class
44 * when a property that does not exist is queried. If set to true (the default)
45 * a <tt>NoSuchElementException</tt> will be thrown if the given key does not
46 * exist and no default was provided. If set to false, <tt>null</tt> will be
47 * returned except for the method getList() which will return an empty
48 * unmodifyiable list.
49 *
50 * @author Jorge Ferrer
51 * @version $Revision: 1.22 $
52 *
53 */
54 public class ComponentProperties {
55
56 public static final String NULL_STRING = null;
57
58 private static final List EMPTY_LIST = Collections
59 .unmodifiableList(new ArrayList());
60
61 private static final Log log = LogFactory.getLog(ComponentProperties.class);
62
63 AggregatedProperties properties;
64
65 ComponentProperties(AggregatedProperties conf) {
66 this.properties = conf;
67 setThrowExceptionOnMissing(false);
68 }
69
70
71
72 /***
73 * Returns a decorator of the configuration that implements the Map
74 * interface. Note that any changes made to this decorator will be made to
75 * the original configuration and viceversa.
76 *
77 * @return a <code>java.util.Map</code> instance
78 */
79 public Map toMap() {
80 return ConfigurationConverter.getMap(properties);
81 }
82
83 /***
84 * Returns a decorator of the configuration that can be used as a DynaBean.
85 * Note that any changes made to this decorator will be made to the original
86 * configuration and viceversa.
87 *
88 * @return a <code>DynaBean</code> instance
89 */
90 public DynaBean toDynaBean() {
91 return new ConfigurationDynaBean(properties);
92 }
93
94 /***
95 * Returns a decorator of the configuration of type
96 * <tt>org.apache.commons.configuration.Configuration</tt> Note that any
97 * changes made to this decorator will be made to the original configuration
98 * and viceversa.
99 *
100 * @return a <code>Configuration</code> instance
101 */
102 public Configuration toConfiguration() {
103 return properties;
104 }
105
106 /***
107 * Returns a decorator of the configuration of type
108 * <tt>org.apache.commons.configuration.DataConfiguration</tt>. This
109 * decorator has many extra methods for retrieving typed properties such as
110 * color, URL, locale, Calendar and lists and array of any of these types.
111 *
112 * Note that any changes made to this decorator will be made to the original
113 * configuration and viceversa.
114 *
115 * @return a <code>DataConfiguration</code> instance
116 */
117 public DataConfiguration toDataConfiguration() {
118 return new DataConfiguration(properties);
119 }
120
121 /***
122 * Returns a <b>copy </b> of the configuration into a
123 * <tt>java.util.Properties</tt> class. Multivalued properties will be
124 * converted to comma-separated strings. Any changes made to the
125 * configuration will <b>not </b>be available to the Properties and
126 * viceversa.
127 *
128 * @return a <code>Properties</code> instance
129 */
130 public java.util.Properties getProperties() {
131 return ConfigurationConverter.getProperties(properties);
132 }
133
134 public Object getProperty(String key) {
135 return properties.getProperty(key);
136 }
137
138
139
140 public boolean containsKey(String key) {
141 return properties.containsKey(key);
142 }
143
144 public boolean equals(Object obj) {
145 return properties.equals(obj);
146 }
147
148 public Iterator getKeys() {
149 return properties.getKeys();
150 }
151
152 public Iterator getKeys(String prefix) {
153 return properties.getKeys(prefix);
154 }
155
156 public int hashCode() {
157 return properties.hashCode();
158 }
159
160 public boolean isEmpty() {
161 return properties.isEmpty();
162 }
163
164 public void setProperty(String key, Object value) {
165 properties.setProperty(key, value);
166 }
167
168 public Configuration subset(String prefix) {
169 return properties.subset(prefix);
170 }
171
172 public String toString() {
173 return properties.toString();
174 }
175
176
177
178 public BigDecimal getBigDecimal(String key) {
179 return properties.getBigDecimal(key);
180 }
181
182 public BigDecimal getBigDecimal(String key, BigDecimal defaultValue) {
183 return properties.getBigDecimal(key, defaultValue);
184 }
185
186 public BigDecimal getBigDecimal(String key, Filter filter) {
187 BigDecimal value = getBigDecimal(key, filter, null);
188 validateValue(key, value);
189 return value;
190 }
191
192 public BigDecimal getBigDecimal(String key, Filter filter,
193 BigDecimal defaultValue) {
194 return (BigDecimal) getPropertyWithFilter(key, filter,
195 BigDecimal.class, defaultValue);
196 }
197
198
199
200 public BigInteger getBigInteger(String key) {
201 return properties.getBigInteger(key);
202 }
203
204 public BigInteger getBigInteger(String key, BigInteger defaultValue) {
205 return properties.getBigInteger(key, defaultValue);
206 }
207
208 public BigInteger getBigInteger(String key, Filter filter) {
209 BigInteger value = getBigInteger(key, filter, null);
210 validateValue(key, value);
211 return value;
212 }
213
214 public BigInteger getBigInteger(String key, Filter filter,
215 BigInteger defaultValue) {
216 return (BigInteger) getPropertyWithFilter(key, filter,
217 BigInteger.class, defaultValue);
218 }
219
220
221
222 public boolean getBoolean(String key) {
223 return properties.getBoolean(key);
224 }
225
226 public boolean getBoolean(String key, boolean defaultValue) {
227 return properties.getBoolean(key, defaultValue);
228 }
229
230 public Boolean getBoolean(String key, Boolean defaultValue)
231 throws NoClassDefFoundError {
232 return properties.getBoolean(key, defaultValue);
233 }
234
235 public boolean getBoolean(String key, Filter filter) {
236 Boolean value = getBoolean(key, filter, null);
237 validateValue(key, value);
238 return value.booleanValue();
239 }
240
241 public Boolean getBoolean(String key, Filter filter, Boolean defaultValue)
242 throws NoClassDefFoundError {
243 return (Boolean) getPropertyWithFilter(key, filter, Boolean.class,
244 defaultValue);
245 }
246
247 public boolean getBoolean(String key, Filter filter, boolean defaultValue) {
248 return getBoolean(key, filter, new Boolean(defaultValue))
249 .booleanValue();
250 }
251
252
253
254 public byte getByte(String key) {
255 return properties.getByte(key);
256 }
257
258 public byte getByte(String key, byte defaultValue) {
259 return properties.getByte(key, defaultValue);
260 }
261
262 public Byte getByte(String key, Byte defaultValue) {
263 return properties.getByte(key, defaultValue);
264 }
265
266 public byte getByte(String key, Filter filter) {
267 Byte value = getByte(key, filter, null);
268 validateValue(key, value);
269 return value.byteValue();
270 }
271
272 public Byte getByte(String key, Filter filter, Byte defaultValue) {
273 return (Byte) getPropertyWithFilter(key, filter, Byte.class,
274 defaultValue);
275 }
276
277 public byte getByte(String key, Filter filter, byte defaultValue) {
278 return getByte(key, filter, new Byte(defaultValue)).byteValue();
279 }
280
281
282
283 public double getDouble(String key) {
284 return properties.getDouble(key);
285 }
286
287 public double getDouble(String key, double defaultValue) {
288 return properties.getDouble(key, defaultValue);
289 }
290
291 public Double getDouble(String key, Double defaultValue) {
292 return properties.getDouble(key, defaultValue);
293 }
294
295 public double getDouble(String key, Filter filter) {
296 Double value = getDouble(key, filter, null);
297 validateValue(key, value);
298 return value.doubleValue();
299 }
300
301 public Double getDouble(String key, Filter filter, Double defaultValue) {
302 return (Double) getPropertyWithFilter(key, filter, Double.class,
303 defaultValue);
304 }
305
306 public double getDouble(String key, Filter filter, double defaultValue) {
307 return getDouble(key, filter, new Double(defaultValue)).doubleValue();
308 }
309
310
311
312 /***
313 * Get the <code>Class</code> representation of the class name specified
314 * in the given property
315 *
316 * @throws ClassNotFoundException
317 * if the specified class is not found
318 */
319 public Class getClass(String key) throws ClassNotFoundException {
320 String className = getString(key);
321 return ClasspathUtil.locateClass(className);
322 }
323
324 /***
325 * Get the <code>Class</code> representation of the class name specified
326 * in the given property. Or the <code>defaultValue</code> if no value has
327 * been given to the property.
328 *
329 * @throws ClassNotFoundException
330 * if a class has been configured but it is not found
331 */
332 public Class getClass(String key, Class defaultValue)
333 throws ClassNotFoundException {
334 String defaultStringValue = null;
335 String className = getString(key, defaultStringValue);
336 if (className == defaultStringValue) {
337 return defaultValue;
338 }
339 return ClasspathUtil.locateClass(className);
340 }
341
342 /***
343 * Similar to the previous methods but complementing the property key with
344 * the given filter
345 */
346 public Class getClass(String key, Filter filter)
347 throws ClassNotFoundException {
348 String className = getString(key, filter);
349 return ClasspathUtil.locateClass(className);
350 }
351
352 /***
353 * Equivalent to the previous method but giving a default value which will
354 * be used if no value has been specified in the configurations file
355 */
356 public Class getClass(String key, Filter filter, Class defaultValue)
357 throws ClassNotFoundException {
358 String defaultStringValue = null;
359 String className = getString(key, filter, null);
360 if (className == defaultStringValue) {
361 return defaultValue;
362 }
363 return ClasspathUtil.locateClass(className);
364 }
365
366
367
368 /***
369 * Get an array of <code>Class</code> objects for the class names
370 * specified in the given property
371 *
372 * @throws ClassNotFoundException
373 * if the any of the configured classes is not found
374 */
375 public Class[] getClassArray(String key) throws ClassNotFoundException {
376 String[] classNames = getStringArray(key);
377 return ClasspathUtil.locateClasses(classNames);
378 }
379
380 /***
381 * Get an array of <code>Class</code> objects for the class names
382 * specified in the given property. Or the <code>defaultValue</code> if no
383 * value has been given to the property.
384 *
385 * @throws ClassNotFoundException
386 * if the any of the configured classes is not found
387 */
388 public Class[] getClassArray(String key, Class[] defaultValue)
389 throws ClassNotFoundException {
390 String[] defaultStringArrayValue = null;
391 String[] classNames = getStringArray(key, defaultStringArrayValue);
392 if (classNames == defaultStringArrayValue) {
393 return defaultValue;
394 }
395 return ClasspathUtil.locateClasses(classNames);
396 }
397
398 /***
399 * Similar to the previous methods but complementing the property key with
400 * the given filter
401 */
402 public Class[] getClassArray(String key, Filter filter)
403 throws ClassNotFoundException {
404 String[] classNames = getStringArray(key, filter);
405 return ClasspathUtil.locateClasses(classNames);
406 }
407
408 /***
409 * Equivalent to the previous method but giving a default value which will
410 * be used if no value has been specified in the configurations file
411 */
412 public Class[] getClassArray(String key, Filter filter, Class[] defaultValue)
413 throws ClassNotFoundException {
414 String[] defaultStringArrayValue = null;
415 String[] classNames = getStringArray(key, filter,
416 defaultStringArrayValue);
417 if (classNames == defaultStringArrayValue) {
418 return defaultValue;
419 }
420 return ClasspathUtil.locateClasses(classNames);
421 }
422
423
424
425 public float getFloat(String key) {
426 return properties.getFloat(key);
427 }
428
429 public float getFloat(String key, float defaultValue) {
430 return properties.getFloat(key, defaultValue);
431 }
432
433 public Float getFloat(String key, Float defaultValue) {
434 return properties.getFloat(key, defaultValue);
435 }
436
437 public float getFloat(String key, Filter filter) {
438 Float value = getFloat(key, filter, null);
439 validateValue(key, value);
440 return value.floatValue();
441 }
442
443 public Float getFloat(String key, Filter filter, Float defaultValue) {
444 return (Float) getPropertyWithFilter(key, filter, Float.class,
445 defaultValue);
446 }
447
448 public float getFloat(String key, Filter filter, float defaultValue) {
449 return getFloat(key, filter, new Float(defaultValue)).floatValue();
450 }
451
452
453
454 public int getInt(String key) {
455 return properties.getInt(key);
456 }
457
458 public int getInt(String key, int defaultValue) {
459 return properties.getInt(key, defaultValue);
460 }
461
462 public Integer getInteger(String key, Integer defaultValue) {
463 return properties.getInteger(key, defaultValue);
464 }
465
466 public int getInt(String key, Filter filter) {
467 Integer value = getInteger(key, filter, null);
468 validateValue(key, value);
469 return value.intValue();
470 }
471
472 public Integer getInteger(String key, Filter filter, Integer defaultValue) {
473 return (Integer) getPropertyWithFilter(key, filter, Integer.class,
474 defaultValue);
475 }
476
477 public int getInt(String key, Filter filter, int defaultValue) {
478 return getInteger(key, filter, new Integer(defaultValue)).intValue();
479 }
480
481
482
483 public List getList(String key) {
484 return properties.getList(key);
485 }
486
487 public List getList(String key, List defaultValue) {
488 return properties.getList(key, defaultValue);
489 }
490
491 public List getList(String key, Filter filter) {
492 List value = (List) getPropertyWithFilter(key, filter, List.class, null);
493 validateValue(key, value);
494 if (value == null) {
495 value = EMPTY_LIST;
496 }
497 return value;
498 }
499
500 public List getList(String key, Filter filter, List defaultValue) {
501 return (List) getPropertyWithFilter(key, filter, List.class,
502 defaultValue);
503 }
504
505
506
507 public long getLong(String key) {
508 return properties.getLong(key);
509 }
510
511 public Long getLong(String key, Long defaultValue) {
512 return properties.getLong(key, defaultValue);
513 }
514
515 public long getLong(String key, long defaultValue) {
516 return properties.getLong(key, defaultValue);
517 }
518
519 public long getLong(String key, Filter filter) {
520 Long value = getLong(key, filter, null);
521 validateValue(key, value);
522 return value.longValue();
523 }
524
525 public Long getLong(String key, Filter filter, Long defaultValue) {
526 return (Long) getPropertyWithFilter(key, filter, Long.class,
527 defaultValue);
528 }
529
530 public long getLong(String key, Filter filter, long defaultValue) {
531 return getLong(key, filter, new Long(defaultValue)).longValue();
532 }
533
534
535
536 public short getShort(String key) {
537 return properties.getShort(key);
538 }
539
540 public Short getShort(String key, Short defaultValue) {
541 return properties.getShort(key, defaultValue);
542 }
543
544 public short getShort(String key, short defaultValue) {
545 return properties.getShort(key, defaultValue);
546 }
547
548 public short getShort(String key, Filter filter) {
549 Short value = getShort(key, filter, null);
550 validateValue(key, value);
551 return value.shortValue();
552 }
553
554 public Short getShort(String key, Filter filter, Short defaultValue) {
555 return (Short) getPropertyWithFilter(key, filter, Short.class,
556 defaultValue);
557 }
558
559 public short getShort(String key, Filter filter, short defaultValue) {
560 return getShort(key, filter, new Short(defaultValue)).shortValue();
561 }
562
563
564
565 /***
566 * Get the String value of the given key. If it contains a list of values,
567 * they will be serialized to a comma-separated format (use getList or
568 * getStringArray if you want separated list items)
569 */
570 public String getString(String key) {
571 Object value = properties.getProperty(key);
572 String result;
573 if (value instanceof List) {
574 result = listToString((List) value);
575 } else {
576 result = properties.getString(key);
577 }
578 return result;
579
580 }
581
582 public String getString(String key, String defaultValue) {
583 return properties.getString(key, defaultValue);
584 }
585
586 public String getString(String key, Filter filter) {
587 String value = getString(key, filter, null);
588 validateValue(key, value);
589 return value;
590 }
591
592 public String getString(String key, Filter filter, String defaultValue) {
593 return (String) getPropertyWithFilter(key, filter, String.class,
594 defaultValue);
595 }
596
597
598
599 public String[] getStringArray(String key) {
600 return properties.getStringArray(key);
601 }
602
603 public String[] getStringArray(String key, Filter filter) {
604 List value = getList(key, filter);
605 return (String[]) value.toArray(new String[0]);
606 }
607
608 public String[] getStringArray(String key, Filter filter,
609 String[] defaultValue) {
610 List defaultList = null;
611 if (defaultValue != null) {
612 defaultList = Arrays.asList(defaultValue);
613 }
614 List value = getList(key, filter, defaultList);
615 if (value == null) {
616 return null;
617 } else {
618 return (String[]) value.toArray(new String[0]);
619 }
620 }
621
622 public String[] getStringArray(String key, String[] defaultValue) {
623 List defaultList = null;
624 if (defaultValue != null) {
625 defaultList = Arrays.asList(defaultValue);
626 }
627 List value = getList(key, defaultList);
628 if (value == null) {
629 return null;
630 } else {
631 return (String[]) value.toArray(new String[0]);
632 }
633 }
634
635
636
637 public boolean hasBaseConfiguration() {
638 return properties.hasBaseConfiguration();
639 }
640
641 /***
642 * Get a list of the sources which have been loaded for this component
643 */
644 public List getLoadedSources() {
645 return properties.loadedSources();
646 }
647
648 /***
649 * Set the flag throwExceptionOnMissing. See the class documentation for
650 * more details.
651 */
652 public void setThrowExceptionOnMissing(boolean throwExceptionOnMissing) {
653 properties.setThrowExceptionOnMissing(throwExceptionOnMissing);
654 }
655
656 public boolean isThrowExceptionOnMissing() {
657 return properties.isThrowExceptionOnMissing();
658 }
659
660 /***
661 * Returned the configured delay period for this component or null if
662 * reloading is not being performed
663 */
664 public Long getDelayPeriod() {
665 Long nullLong = null;
666 return getLong(Conventions.RELOAD_DELAY_PROPERTY, nullLong);
667 }
668
669 public String getComponentName() {
670 return properties.getComponentName();
671 }
672
673
674
675 protected Object getPropertyWithFilter(String key, Filter filter,
676 Class theClass, Object defaultValue) {
677 CompositeConfiguration filteredConf = properties;
678 Object value = null;
679 for (int i = filter.numOfSelectors(); (i >= 0) && (value == null); i--) {
680 MapConfiguration varsConf = null;
681 if (filter.hasVariables()) {
682 varsConf = new MapConfiguration(filter.getVariables());
683 filteredConf = new CompositeConfiguration();
684 filteredConf.addConfiguration(properties);
685 filteredConf.addConfiguration(varsConf);
686 }
687 value = getTypedPropertyWithDefault(
688 key + filter.getFilterSuffix(i), theClass, filteredConf,
689 null);
690 if (varsConf != null) {
691 properties.removeConfiguration(varsConf);
692 }
693 log.debug("Value for " + key + filter.getFilterSuffix(i) + "="
694 + value);
695 }
696 if (value == null) {
697 value = defaultValue;
698 }
699 return value;
700 }
701
702 protected static Object getTypedPropertyWithDefault(
703 String key,
704 Class theClass,
705 Configuration properties,
706 Object defaultValue) {
707 if (theClass.equals(Float.class)) {
708 return properties.getFloat(key, (Float) defaultValue);
709
710 } else if (theClass.equals(Integer.class)) {
711 return properties.getInteger(key, (Integer) defaultValue);
712
713 } else if (theClass.equals(String.class)) {
714 return properties.getString(key, (String) defaultValue);
715
716 } else if (theClass.equals(Double.class)) {
717 return properties.getDouble(key, (Double) defaultValue);
718
719 } else if (theClass.equals(Long.class)) {
720 return properties.getLong(key, (Long) defaultValue);
721
722 } else if (theClass.equals(Boolean.class)) {
723 return properties.getBoolean(key, (Boolean) defaultValue);
724
725 } else if (theClass.equals(List.class)) {
726 return properties.getList(key, (List) defaultValue);
727
728 } else if (theClass.equals(BigInteger.class)) {
729 return properties.getBigInteger(key, (BigInteger) defaultValue);
730
731 } else if (theClass.equals(BigDecimal.class)) {
732 return properties.getBigDecimal(key, (BigDecimal) defaultValue);
733
734 } else if (theClass.equals(Byte.class)) {
735 return properties.getByte(key, (Byte) defaultValue);
736
737 } else if (theClass.equals(Short.class)) {
738 return properties.getShort(key, (Short) defaultValue);
739 }
740 throw new IllegalArgumentException("Class " + theClass + " is not"
741 + "supported for properties");
742 }
743
744 protected void validateValue(String key, Object value) {
745 if ((value == null) && isThrowExceptionOnMissing()) {
746 throw new NoSuchElementException("Property with key=" + key
747 + " was not found");
748 }
749 }
750
751 protected String listToString(List list) {
752 StringBuffer property = new StringBuffer();
753 Iterator it = list.iterator();
754 while (it.hasNext()) {
755 property.append(String.valueOf(it.next()));
756 if (it.hasNext()) {
757 property.append(",");
758 }
759 }
760 return property.toString();
761 }
762 }
763