1 /*
2 * Copyright 2007 Ralf Joachim
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * $Id: Configuration.java 6907 2007-03-28 21:24:52Z rjoachim $
17 */
18 package org.castor.core.util;
19
20 import java.io.File;
21 import java.io.FileInputStream;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.net.URL;
25 import java.text.MessageFormat;
26 import java.util.ArrayList;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Properties;
31
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34
35 /**
36 * Abstract base class to hold Castor configuration properties.
37 *
38 * @version $Id: Configuration.java,v 1.8 2006/03/08 17:25:52 jens Exp $
39 * @author <a href="mailto:ralf DOT joachim AT syscon DOT eu">Ralf Joachim</a>
40 * @since 1.1.3
41 */
42 public abstract class AbstractProperties {
43
44 /**
45 * Name of the system property that can be used to specify the location
46 * of user properties.
47 */
48 private static final String USER_PROPERTIES_SYSTEM_PROPERTY =
49 "org.castor.user.properties.location";
50
51 /**
52 * The <a href="http://jakarta.apache.org/commons/logging/">Jakarta Commons
53 * Logging</a> instance used for all logging.
54 */
55 private static final Log LOG = LogFactory.getLog(AbstractProperties.class);
56
57 /**
58 * {@link ClassLoader} to be used for all classes of Castor and its required
59 * libraries.
60 */
61 private final ClassLoader _applicationClassLoader;
62
63 /**
64 * {@link ClassLoader} to be used for all domain objects that are
65 * marshalled/unmarshalled or loaded from the database.
66 */
67 private final ClassLoader _domainClassLoader;
68
69 /**
70 * Parent properties.
71 */
72 private final AbstractProperties _parent;
73
74 private final Map _map = new HashMap();
75
76 /**
77 * Default constructor. Application and domain class loaders will be initialized to the one
78 * used to load the concrete properties class. No parent properties will be set.
79 */
80 protected AbstractProperties() {
81 this(null, null);
82 }
83
84 /**
85 * Construct properties that uses the specified class loaders. No parent properties will be set.
86 *
87 * @param app Classloader to be used for all classes of Castor and its required libraries.
88 * @param domain Classloader to be used for all domain objects.
89 */
90 protected AbstractProperties(final ClassLoader app, final ClassLoader domain) {
91 _applicationClassLoader = (app != null) ? app : getClass().getClassLoader();
92 _domainClassLoader = (domain != null) ? domain : getClass().getClassLoader();
93
94 _parent = null;
95 }
96
97 /**
98 * Construct properties with given parent. Application and domain class loaders will be
99 * initialized to the ones of the parent.
100 *
101 * @param parent Parent properties.
102 */
103 protected AbstractProperties(final AbstractProperties parent) {
104 _applicationClassLoader = parent.getApplicationClassLoader();
105 _domainClassLoader = parent.getDomainClassLoader();
106
107 _parent = parent;
108 }
109
110 /**
111 * Get classloader to be used for all classes of Castor and its required libraries.
112 *
113 * @return Classloader to be used for all classes of Castor and its required libraries.
114 */
115 public final ClassLoader getApplicationClassLoader() {
116 return _applicationClassLoader;
117 }
118
119 /**
120 * Get classloader to be used for all domain objects that are marshalled/unmarshalled or
121 * loaded from the database.
122 *
123 * @return Classloader to be used for all domain objects.
124 */
125 public final ClassLoader getDomainClassLoader() {
126 return _domainClassLoader;
127 }
128
129 /**
130 * Load module properties from default locations.
131 * <br/>
132 * First it loads default properties contained in Castor JAR. This gets overwritten
133 * by a properties found on Java library directory. If no properties could be found
134 * until that point a PropertiesException will be thrown.
135 *
136 * @param path Path to the default properties to load.
137 * @param filename Name of the properties file.
138 */
139 protected void loadDefaultProperties(final String path, final String filename) {
140 Properties properties = new Properties();
141
142 // Get default properties from the Castor JAR.
143 boolean inCastorJar = loadFromClassPath(properties, path + filename);
144
145 // Get overriding properties from the Java library directory, ignore if not
146 // found. If found merge existing properties.
147 boolean inJavaLibDir = loadFromJavaHome(properties, filename);
148
149 // Couldn't find properties in Castor jar nor Java library directory.
150 if (!inCastorJar && !inJavaLibDir) {
151 throw new PropertiesException("Failed to load properties: " + filename);
152 }
153
154 _map.putAll(properties);
155 }
156
157 /**
158 * Load common user properties from classpath root and current working directory.
159 * <br/>
160 * First it loads default properties contained in Castor JAR. This gets overwritten
161 * by properties found on Java library directory. If no properties could be found
162 * until that point a PropertiesException will be thrown. At last overriding
163 * properties are loaded from root of classpath or, if that could not be found, from
164 * local working directory.
165 *
166 * @param filename Name of the properties file.
167 */
168 protected void loadUserProperties(final String filename) {
169 Properties properties = new Properties();
170
171 // Get common properties from the classpath root, ignore if not found.
172 boolean userPropertiesLoaded = loadFromClassPath(properties, "/" + filename);
173
174 // If not found on classpath root, either it doesn't exist, or "." is not part of
175 // the classpath, try looking at local working directory.
176 if (!userPropertiesLoaded) {
177 userPropertiesLoaded = loadFromWorkingDirectory(properties, filename);
178 }
179
180 if (!userPropertiesLoaded) {
181 String property = System.getProperty(USER_PROPERTIES_SYSTEM_PROPERTY);
182 if (property != null && property.length() > 0) {
183 File file = new File(property);
184 if (file.exists()) {
185 LOG.info("Loading custom Castor properties from " + file.getAbsolutePath());
186 userPropertiesLoaded = loadFromFile(properties, file);
187 } else {
188 LOG.warn(file.getAbsolutePath() + " is not a valid file.");
189 }
190 }
191 }
192
193 _map.putAll(properties);
194 }
195
196 /**
197 * Load properties with given filename from classpath and merge them into the given properties.
198 *
199 * @param properties Properties to merge the loaded ones into.
200 * @param filename Name of the properties file to load from classpath.
201 * @return <code>true</code> if properties could be loaded, <code>false</code> otherwise.
202 */
203 private boolean loadFromClassPath(final Properties properties, final String filename) {
204 InputStream classPathStream = null;
205 try {
206 URL url = getClass().getResource(filename);
207 if (url != null) {
208 classPathStream = url.openStream();
209 properties.load(classPathStream);
210
211 if (LOG.isDebugEnabled()) {
212 LOG.debug("Properties loaded from classpath: " + filename);
213 }
214
215 return true;
216 }
217 return false;
218 } catch (Exception ex) {
219 LOG.warn("Failed to load properties from classpath: " + filename, ex);
220 return false;
221 } finally {
222 if (classPathStream != null) {
223 try {
224 classPathStream.close();
225 } catch (IOException e) {
226 LOG.warn("Failed to close properties from classpath: " + filename);
227 }
228 }
229 }
230 }
231
232 /**
233 * Load properties with given filename from Java library directory and merge them into
234 * the given properties.
235 *
236 * @param properties Properties to merge the loaded ones into.
237 * @param filename Name of the properties file to load from Java library directory.
238 * @return <code>true</code> if properties could be loaded, <code>false</code> otherwise.
239 */
240 private boolean loadFromJavaHome(final Properties properties, final String filename) {
241 try {
242 String javaHome = System.getProperty("java.home");
243 if (javaHome == null) { return false; }
244 return loadFromFile(properties, new File(new File(javaHome, "lib"), filename));
245 } catch (SecurityException ex) {
246 LOG.warn("Security policy prevented access to system property 'java.home'.", ex);
247 return false;
248 }
249 }
250
251 /**
252 * Load properties with given filename from local working directory and merge them into
253 * the given properties.
254 *
255 * @param properties Properties to merge the loaded ones into.
256 * @param filename Name of the properties file to load from local working directory.
257 * @return <code>true</code> if properties could be loaded, <code>false</code> otherwise.
258 */
259 private boolean loadFromWorkingDirectory(final Properties properties, final String filename) {
260 return loadFromFile(properties, new File(filename));
261 }
262
263 /**
264 * Load properties with given file and merge them into the given properties.
265 *
266 * @param properties Properties to merge the loaded ones into.
267 * @param file Properties file to load.
268 * @return <code>true</code> if properties could be loaded, <code>false</code> otherwise.
269 */
270 private boolean loadFromFile(final Properties properties, final File file) {
271 InputStream fileStream = null;
272 try {
273 if (file.exists() && file.canRead()) {
274 fileStream = new FileInputStream(file);
275 properties.load(fileStream);
276
277 if (LOG.isDebugEnabled()) {
278 LOG.debug("Properties file loaded: " + file);
279 }
280
281 return true;
282 }
283 return false;
284 } catch (SecurityException ex) {
285 LOG.warn("Security policy prevented access to properties file: " + file, ex);
286 return false;
287 } catch (Exception ex) {
288 LOG.warn("Failed to load properties file: " + file, ex);
289 return false;
290 } finally {
291 if (fileStream != null) {
292 try {
293 fileStream.close();
294 } catch (IOException e) {
295 LOG.warn("Failed to close properties file: " + file);
296 }
297 }
298 }
299 }
300
301 /**
302 * Put given value associated with given key into the properties map of this properties. If
303 * the properties previously associated the key to another value the previous value will be
304 * returned. If a mapping for the key previously exist in the parent properties only, the
305 * method returns <code>null</code> and not the value of the parent. This allows to distingush
306 * if the mapping existed in this properties or one of its parents.
307 * <br/>
308 * Putting a value in this properties does not change the value of its parent but the
309 * parents value isn't visible any more as it gets overwritten by this properties one.
310 * While this allows to redefine the value of a property it isn't allowed to undefine it.
311 * Therefore a <code>NullPointerException</code> will be thrown if the given value is
312 * <code>null</code>.
313 *
314 * @param key Key of the property to put into properties.
315 * @param value Value to put into properties associated with the given key..
316 * @return Object in this properties that previously has been associated with the given key.
317 */
318 public final synchronized Object put(final String key, final Object value) {
319 if (value == null) { throw new NullPointerException(); }
320 return _map.put(key, value);
321 }
322
323 /**
324 * Remove any value previously associated with the given key from this properties. The value
325 * previously associated with the key in this properties will be returned. If a mapping
326 * for the key existed in the parent properties only, the method returns <code>null</code>
327 * and not the value of the parent. This allows to distingush if the mapping existed in this
328 * properties or one of its parents.
329 * <br/>
330 * Removing the value from this properties does not mean that consecutive gets return
331 * <code>null</code> as one of the parents may still contain a mapping for the key that
332 * was hidden by the mapping in this properties.
333 *
334 * @param key Key of the property to remove from properties.
335 * @return Object in this properties that previously has been associated with the given key.
336 */
337 public final synchronized Object remove(final String key) {
338 return _map.remove(key);
339 }
340
341 /**
342 * Searches for the property with the specified key in this property map. If the key is not
343 * found in this property map, the parent property map, and its parents, recursively, are then
344 * checked.
345 * <br/>
346 * If the key maps to any object value, it will be returned as is. If the property is not found,
347 * <code>null</code> will be returned.
348 *
349 * @param key Key of the property to get from properties.
350 * @return Object in this property map with the specified key value.
351 */
352 protected synchronized Object get(final String key) {
353 Object value = _map.get(key);
354 if ((value == null) && (_parent != null)) {
355 value = _parent.get(key);
356 }
357 return value;
358 }
359
360 /**
361 * Searches for the property with the specified key in this property map. If the key is not
362 * found in this property map, the parent property map, and its parents, recursively, are then
363 * checked.
364 * <br/>
365 * If the key maps to a boolean value, it will be returned as is. For string values that are
366 * equal, ignore case, to 'true' or 'false', the respective boolean value will be returned. If
367 * the property is not found, <code>null</code> will be returned. For all other types and
368 * string values a PropertiesException will be thrown. This behaviour is intended for those
369 * usecases that need distinguish between values that are missconfigured or not specified at
370 * all.
371 *
372 * @param key Property key.
373 * @return Boolean value in this property map with the specified key value.
374 */
375 public final Boolean getBoolean(final String key) {
376 Object objectValue = get(key);
377
378 if (objectValue == null) {
379 return null;
380 } else if (objectValue instanceof Boolean) {
381 return (Boolean) objectValue;
382 } else if (objectValue instanceof String) {
383 String stringValue = (String) objectValue;
384 if ("true".equalsIgnoreCase(stringValue)) {
385 return Boolean.TRUE;
386 } else if ("false".equalsIgnoreCase(stringValue)) {
387 return Boolean.FALSE;
388 }
389 }
390
391 Object[] args = new Object[] {key, objectValue};
392 String msg = "Properties value can not be converted to boolean: {0}={1}";
393 throw new PropertiesException(MessageFormat.format(msg, args));
394 }
395
396 /**
397 * Searches for the property with the specified key in this property map. If the key is not
398 * found in this property map, the parent property map, and its parents, recursively, are then
399 * checked.
400 * <br/>
401 * If the key maps to a boolean value, it will be returned as is. For string values that are
402 * equal, ignore case, to 'true' or 'false', the respective boolean value will be returned. In
403 * all other cases the given default value will be returned.
404 *
405 * @param key Property key.
406 * @param defaultValue Default value.
407 * @return Boolean value in this property map with the specified key value.
408 */
409 public final boolean getBoolean(final String key, final boolean defaultValue) {
410 Object objectValue = get(key);
411
412 if (objectValue instanceof Boolean) {
413 return ((Boolean) objectValue).booleanValue();
414 } else if (objectValue instanceof String) {
415 String stringValue = (String) objectValue;
416 if ("true".equalsIgnoreCase(stringValue)) {
417 return true;
418 } else if ("false".equalsIgnoreCase(stringValue)) {
419 return false;
420 }
421 }
422
423 return defaultValue;
424 }
425
426 /**
427 * Searches for the property with the specified key in this property map. If the key is not
428 * found in this property map, the parent property map, and its parents, recursively, are then
429 * checked.
430 * <br/>
431 * If the key maps to a integer value, it will be returned as is. For string values that can
432 * be interpreted as signed decimal integer, the respective integer value will be returned. If
433 * the property is not found, <code>null</code> will be returned. For all other types and
434 * string values a PropertiesException will be thrown. This behaviour is intended for those
435 * usecases that need distinguish between values that are missconfigured or not specified at
436 * all.
437 *
438 * @param key Property key.
439 * @return Integer value in this property map with the specified key value.
440 */
441 public final Integer getInteger(final String key) {
442 Object objectValue = get(key);
443
444 if (objectValue == null) {
445 return null;
446 } else if (objectValue instanceof Integer) {
447 return (Integer) objectValue;
448 } else if (objectValue instanceof String) {
449 try {
450 return Integer.valueOf((String) objectValue);
451 } catch (NumberFormatException ex) {
452 Object[] args = new Object[] {key, objectValue};
453 String msg = "Properties value can not be converted to int: {0}={1}";
454 throw new PropertiesException(MessageFormat.format(msg, args), ex);
455 }
456 }
457
458 Object[] args = new Object[] {key, objectValue};
459 String msg = "Properties value can not be converted to int: {0}={1}";
460 throw new PropertiesException(MessageFormat.format(msg, args));
461 }
462
463 /**
464 * Searches for the property with the specified key in this property map. If the key is not
465 * found in this property map, the parent property map, and its parents, recursively, are then
466 * checked.
467 * <br/>
468 * If the key maps to a integer value, it will be returned as is. For string values that can
469 * be interpreted as signed decimal integer, the respective integer value will be returned. In
470 * all other cases the given default value will be returned.
471 *
472 * @param key Property key.
473 * @param defaultValue Default value.
474 * @return Integer value in this property map with the specified key value.
475 */
476 public final int getInteger(final String key, final int defaultValue) {
477 Object objectValue = get(key);
478
479 if (objectValue instanceof Integer) {
480 return ((Integer) objectValue).intValue();
481 } else if (objectValue instanceof String) {
482 String stringValue = (String) objectValue;
483 try {
484 return Integer.parseInt(stringValue);
485 } catch (NumberFormatException ex) {
486 return defaultValue;
487 }
488 }
489
490 return defaultValue;
491 }
492
493 /**
494 * Searches for the property with the specified key in this property map. If the key is not
495 * found in this property map, the parent property map, and its parents, recursively, are then
496 * checked.
497 * <br/>
498 * If the key maps to a string value, it will be returned as is. If the property is not found,
499 * <code>null</code> will be returned. For all other types a PropertiesException will be
500 * thrown.
501 *
502 * @param key Property key.
503 * @return String value in this property map with the specified key value.
504 */
505 public final String getString(final String key) {
506 Object objectValue = get(key);
507
508 if (objectValue == null) {
509 return null;
510 } else if (objectValue instanceof String) {
511 return (String) objectValue;
512 }
513
514 Object[] args = new Object[] {key, objectValue};
515 String msg = "Properties value is not a string: {0}={1}";
516 throw new PropertiesException(MessageFormat.format(msg, args));
517 }
518
519 /**
520 * Searches for the property with the specified key in this property map. If the key is not
521 * found in this property map, the parent property map, and its parents, recursively, are then
522 * checked.
523 * <br/>
524 * If the key maps to a string value that is not empty, it will be returned as is. In all other
525 * cases the given default value will be returned.
526 *
527 * @param key Property key.
528 * @param defaultValue Default value.
529 * @return String value in this property map with the specified key value.
530 */
531 public final String getString(final String key, final String defaultValue) {
532 Object objectValue = get(key);
533
534 if ((objectValue instanceof String) && !"".equals(objectValue)) {
535 return (String) objectValue;
536 }
537
538 return defaultValue;
539 }
540
541 /**
542 * Searches for the property with the specified key in this property map. If the key is not
543 * found in this property map, the parent property map, and its parents, recursively, are then
544 * checked.
545 * <br/>
546 * If the key maps to a string array, it will be returned as is. A simple string will be
547 * converted into a string array by splitting it into substrings at every occurence of ','
548 * character. If the property is not found, <code>null</code> will be returned. For all other
549 * types a PropertiesException will be thrown.
550 *
551 * @param key Property key.
552 * @return String array in this property map with the specified key value.
553 */
554 public final String[] getStringArray(final String key) {
555 Object objectValue = get(key);
556
557 if (objectValue == null) {
558 return null;
559 } else if (objectValue instanceof String[]) {
560 return (String[]) objectValue;
561 } else if (objectValue instanceof String) {
562 return ((String) objectValue).split(",");
563 }
564
565 Object[] args = new Object[] {key, objectValue};
566 String msg = "Properties value is not a String[]: {0}={1}";
567 throw new PropertiesException(MessageFormat.format(msg, args));
568 }
569
570 /**
571 * Searches for the property with the specified key in this property map. If the key is not
572 * found in this property map, the parent property map, and its parents, recursively, are then
573 * checked.
574 * <br/>
575 * If the key maps to a class, it will be returned as is. A simple string will be interpreted
576 * as class name of which the class will be loaded with the given class loader. If the property
577 * is not found, <code>null</code> will be returned. For all other types and if loading of the
578 * class fails a PropertiesException will be thrown.
579 *
580 * @param key Property key.
581 * @param loader Class loader to load classes with.
582 * @return Class in this property map with the specified key value.
583 */
584 public final Class getClass(final String key, final ClassLoader loader) {
585 Object objectValue = get(key);
586
587 if (objectValue == null) {
588 return null;
589 } else if (objectValue instanceof Class) {
590 return (Class) objectValue;
591 } else if (objectValue instanceof String) {
592 String classname = (String) objectValue;
593 try {
594 return loader.loadClass(classname);
595 } catch (ClassNotFoundException ex) {
596 Object[] args = new Object[] {key, classname};
597 String msg = "Could not find class of properties value: {0}={1}";
598 throw new PropertiesException(MessageFormat.format(msg, args), ex);
599 }
600 }
601
602 Object[] args = new Object[] {key, objectValue};
603 String msg = "Properties value is not a Class: {0}={1}";
604 throw new PropertiesException(MessageFormat.format(msg, args));
605 }
606
607 /**
608 * Searches for the property with the specified key in this property map. If the key is not
609 * found in this property map, the parent property map, and its parents, recursively, are then
610 * checked.
611 * <br/>
612 * If the key maps to a class array, it will be returned as is. A simple string will be
613 * splitted it into substrings at every occurence of ',' character. Each of these substrings
614 * will interpreted as class name of which the class will be loaded with the given class
615 * loader. If the property is not found, <code>null</code> will be returned. For all other
616 * types and if loading of one of the classes fails a PropertiesException will be thrown.
617 *
618 * @param key Property key.
619 * @param loader Class loader to load classes with.
620 * @return Class array in this property map with the specified key value.
621 */
622 public final Class[] getClassArray(final String key, final ClassLoader loader) {
623 Object objectValue = get(key);
624
625 if (objectValue == null) {
626 return null;
627 } else if (objectValue instanceof Class[]) {
628 return (Class[]) objectValue;
629 } else if (objectValue instanceof String) {
630 String[] classnames = ((String) objectValue).split(",");
631 Class[] classes = new Class[classnames.length];
632 for (int i = 0; i < classnames.length; i++) {
633 try {
634 classes[i] = loader.loadClass(classnames[i]);
635 } catch (ClassNotFoundException ex) {
636 Object[] args = new Object[] {key, new Integer(i), classnames[i]};
637 String msg = "Could not find class of properties value: {0}[{1}]={2}";
638 throw new PropertiesException(MessageFormat.format(msg, args), ex);
639 }
640 }
641 return classes;
642 }
643
644 Object[] args = new Object[] {key, objectValue};
645 String msg = "Properties value is not a Class[]: {0}={1}";
646 throw new PropertiesException(MessageFormat.format(msg, args));
647 }
648
649 /**
650 * Searches for the property with the specified key in this property map. If the key is not
651 * found in this property map, the parent property map, and its parents, recursively, are then
652 * checked.
653 * <br/>
654 * If the key maps to any object value, it will be returned as is. If the property is not found,
655 * <code>null</code> will be returned.
656 *
657 * @param key Property key.
658 * @return Object in this property map with the specified key value.
659 */
660 public final Object getObject(final String key) {
661 return get(key);
662 }
663
664 /**
665 * Searches for the property with the specified key in this property map. If the key is not
666 * found in this property map, the parent property map, and its parents, recursively, are then
667 * checked.
668 * <br/>
669 * If the key maps to a object array, it will be returned as is. A simple string will be
670 * splitted it into substrings at every occurence of ',' character. Each of these substrings
671 * will interpreted as class name of which the class will be loaded with the given class
672 * loader and instantiated using its default constructor. If the property is not found,
673 * <code>null</code> will be returned. For all other types and if loading or instantiation of
674 * one of the classes fails a PropertiesException will be thrown.
675 *
676 * @param key Property key.
677 * @param loader Class loader to load classes with.
678 * @return Class array in this property map with the specified key value.
679 */
680 public final Object[] getObjectArray(final String key, final ClassLoader loader) {
681 Object objectValue = get(key);
682
683 if (objectValue == null) {
684 return null;
685 } else if (objectValue instanceof Object[]) {
686 return (Object[]) objectValue;
687 } else if (objectValue instanceof String) {
688 List objects = new ArrayList();
689 String[] classnames = ((String) objectValue).split(",");
690 for (int i = 0; i < classnames.length; i++) {
691 String classname = classnames[i];
692 try {
693 if ((classname != null) && !"".equals(classname.trim())) {
694 classname = classname.trim();
695 objects.add(loader.loadClass(classname).newInstance());
696 }
697 } catch (ClassNotFoundException ex) {
698 Object[] args = new Object[] {key, new Integer(i), classname};
699 String msg = "Could not find configured class: {0}[{1}]={2}";
700 throw new PropertiesException(MessageFormat.format(msg, args), ex);
701 } catch (IllegalAccessException ex) {
702 Object[] args = new Object[] {key, new Integer(i), classname};
703 String msg = "Could not instantiate configured class: {0}[{1}]={2}";
704 throw new PropertiesException(MessageFormat.format(msg, args), ex);
705 } catch (InstantiationException ex) {
706 Object[] args = new Object[] {key, new Integer(i), classname};
707 String msg = "Could not instantiate configured class: {0}[{1}]={2}";
708 throw new PropertiesException(MessageFormat.format(msg, args), ex);
709 } catch (ExceptionInInitializerError ex) {
710 Object[] args = new Object[] {key, new Integer(i), classname};
711 String msg = "Could not instantiate configured class: {0}[{1}]={2}";
712 throw new PropertiesException(MessageFormat.format(msg, args), ex);
713 } catch (SecurityException ex) {
714 Object[] args = new Object[] {key, new Integer(i), classname};
715 String msg = "Could not instantiate configured class: {0}[{1}]={2}";
716 throw new PropertiesException(MessageFormat.format(msg, args), ex);
717 }
718 }
719 return objects.toArray();
720 }
721
722 Object[] args = new Object[] {key, objectValue};
723 String msg = "Properties value is not an Object[]: {0}={1}";
724 throw new PropertiesException(MessageFormat.format(msg, args));
725 }
726
727 }