001 /*
002 *
003 * $Revision: 15619 $ $Date: 2009-07-25 08:28:03 +0200 (Sat, 25 Jul 2009) $
004 *
005 * This file is part of *** M y C o R e ***
006 * See http://www.mycore.de/ for details.
007 *
008 * This program is free software; you can use it, redistribute it
009 * and / or modify it under the terms of the GNU General Public License
010 * (GPL) as published by the Free Software Foundation; either version 2
011 * of the License or (at your option) any later version.
012 *
013 * This program is distributed in the hope that it will be useful, but
014 * WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program, in a file called gpl.txt or license.txt.
020 * If not, write to the Free Software Foundation Inc.,
021 * 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
022 */
023
024 package org.mycore.common;
025
026 import java.io.File;
027 import java.io.FileInputStream;
028 import java.io.FileNotFoundException;
029 import java.io.FileOutputStream;
030 import java.io.IOException;
031 import java.io.InputStream;
032 import java.io.OutputStream;
033 import java.io.PrintStream;
034 import java.io.PrintWriter;
035 import java.lang.reflect.Method;
036 import java.util.Enumeration;
037 import java.util.Hashtable;
038 import java.util.Properties;
039 import java.util.StringTokenizer;
040
041 import org.apache.log4j.Logger;
042 import org.apache.log4j.PropertyConfigurator;
043
044 import org.mycore.services.plugins.FilterPluginInstantiationException;
045
046 /**
047 * Provides methods to manage and read all configuration properties from the
048 * MyCoRe configuration files. The class is implemented using the singleton
049 * pattern. Using this class is very easy, here is an example:
050 *
051 * <PRE>
052 * // Get a configuration property as a String:
053 * String driver = MCRConfiguration.instance().getString( "MCR.JDBC.Driver" );
054 * // Get a configuration property as an int, use 500 as default if not set:
055 * int max = MCRConfiguration.instance().getInt( "MCR.Cache.Size", 500 );
056 * </PRE>
057 *
058 * As you see, the class provides methods to get configuration properties as
059 * different data types and allows you to specify defaults. All MyCoRe
060 * configuration properties should start with "<CODE>MCR.</CODE>" When
061 * <CODE>instance()</CODE> is called the first time, the file <B><CODE>
062 * mycore.properties</CODE> </B> is read. It can be located somewhere in the
063 * <CODE>CLASSPATH</CODE>, even in a jar or zip file. The properties file may
064 * have a property called <B><CODE>MCR.Configuration.Include</CODE> </B> that
065 * contains a comma-separated list of other configuration files to read
066 * subsequently. The class also reads any Java <B>system properties</B> that
067 * start with "<CODE>MCR.</CODE>" and that are set when the application
068 * starts. System properties will override properties read from the
069 * configuration files. Furthermore, the name of the main configuration file can
070 * be altered by specifying the system property <B><CODE>
071 * MCR.Configuration.File</CODE> </B>. Here is an example:
072 *
073 * <PRE>
074 * java -DMCR.Configuration.File=some_other.properties -DMCR.foo=bar MyCoReSample
075 * </PRE>
076 *
077 * Property values may include the values of other properties, recursively, by
078 * referencing the other property. Example:
079 *
080 * <PRE>
081 * MCR.Foo1=FooValue
082 * MCR.Foo2=Some %MCR.Foo1% more information
083 * </PRE>
084 *
085 * The class also provides methods for <B>listing or saving </B> all properties
086 * to an <CODE>OutputStream</CODE> and for <B>reloading </B> all configuration
087 * properties at runtime. This allows servlets that run a long time to re-read
088 * the configuration files when client code tells them to do so, for example.
089 * Using the <CODE>set</CODE> methods allows client code to set new
090 * configuration properties or overwrite existing ones with new values. Finally,
091 * applications could also <B>subclass <CODE>MCRConfiguration</CODE> </B> to
092 * change or add behavior and use an instance of the subclass instead of this
093 * class. This is transparent for client code, they would still use <CODE>
094 * MCRConfiguration.instance()</CODE> to get the subclass instance. To use a
095 * subclass instead of <CODE>MCRConfiguration</CODE> itself, specify the
096 * system property <CODE>MCR.Configuration.Class</CODE>, e. g.
097 *
098 * <PRE>
099 * java -DMCR.Configuration.Class=MCRConfigurationSubclass MyCoReSample
100 * </PRE>
101 *
102 * @see #loadFromFile
103 * @see #reload
104 * @see #list(PrintStream)
105 * @see #store
106 *
107 * @author Frank Lützenkirchen
108 * @version $Revision: 15619 $ $Date: 2009-07-25 08:28:03 +0200 (Sat, 25 Jul 2009) $
109 */
110 public class MCRConfiguration {
111 /**
112 * The single instance of this class that will be used at runtime
113 */
114 protected static MCRConfiguration singleton;
115
116 private static Hashtable instanceHolder;
117
118 static File lastModifiedFile;
119
120 /**
121 * Returns the single instance of this class that can be used to read and
122 * manage the configuration properties.
123 *
124 * @return the single instance of <CODE>MCRConfiguration</CODE> to be used
125 */
126 public static synchronized MCRConfiguration instance() {
127 if (singleton == null) {
128 createSingleton();
129 }
130
131 return singleton;
132 }
133
134 /**
135 * Instantiates the singleton by calling the protected constructor. If the
136 * system property <CODE>MCR.Configuration.Class</CODE> is set when the
137 * system starts, the class specified in that property will be instantiated
138 * instead. This allows for subclassing <CODE>MCRConfiguration</CODE> to
139 * change behaviour and use the subclass instead of <CODE>MCRConfiguration
140 * </CODE>.
141 */
142 protected static void createSingleton() {
143 String name = System.getProperty("MCR.Configuration.Class");
144
145 if (name != null) {
146 try {
147 singleton = (MCRConfiguration) (Class.forName(name).newInstance());
148 } catch (Exception exc) {
149 throw new MCRConfigurationException("Could not create MCR.Configuration.Class singleton \"" + name + "\"", exc);
150 }
151 } else {
152 singleton = new MCRConfiguration();
153 }
154 singleton.systemModified();
155 }
156
157 /**
158 * returns the last point in time when the MyCoRe system was last modified.
159 *
160 * This method can help you to validate caches not under your controll, e.g.
161 * client caches.
162 *
163 * @see System#currentTimeMillis()
164 */
165 public final long getSystemLastModified() {
166 return lastModifiedFile.lastModified();
167 }
168
169 /**
170 * signalize that the system state has changed.
171 *
172 * Call this method when ever you changed the persistency layer.
173 *
174 */
175 public final void systemModified() {
176 lastModifiedFile.setLastModified(System.currentTimeMillis());
177 }
178
179 /**
180 * The properties instance that stores the values that have been read from
181 * every configuration file
182 */
183 protected Properties properties;
184
185 /**
186 * List of deprecated properties with their new name
187 */
188 protected Properties depr;
189
190 /**
191 * Protected constructor to create the singleton instance
192 */
193 protected MCRConfiguration() {
194 properties = new Properties();
195 depr = new Properties();
196 reload(true);
197 final String dataDirKey = "MCR.datadir";
198 if (properties.containsKey(dataDirKey)) {
199 lastModifiedFile = new File(getString(dataDirKey), ".systemTime");
200 } else {
201 try {
202 lastModifiedFile = File.createTempFile("MyCoRe", ".systemTime");
203 } catch (IOException e) {
204 throw new MCRException("Could not create temporary file, please set property MCR.datadir");
205 }
206 }
207 if (!lastModifiedFile.exists()) {
208 try {
209 FileOutputStream fout = new FileOutputStream(lastModifiedFile);
210 fout.write(new byte[0]);
211 } catch (Exception e) {
212 throw new MCRException("Error while creating file: " + lastModifiedFile, e);
213 }
214
215 }
216 }
217
218 /**
219 * Reloads all properties from the configuration files. If the system
220 * property <CODE>MCR.Configuration.File</CODE> is set, the file specified
221 * in this property will be used as main configuration file, otherwise the
222 * default file <CODE>mycore.properties</CODE> will be read. If the
223 * parameter <CODE>clear</CODE> is <CODE>true</CODE>, all properties
224 * currently set will be deleted first, otherwise the properties read from
225 * the configuration files will be added to the properties currently set and
226 * they will overwrite existing properties with the same name.
227 *
228 * @param clear
229 * if true, properties currently set will be deleted first
230 * @throws MCRConfigurationException
231 * if the config files can not be loaded
232 */
233 public void reload(boolean clear) {
234 if (clear) {
235 properties.clear();
236 depr.clear();
237 }
238
239 String fn = System.getProperty("MCR.Configuration.File", "mycore.properties");
240 loadFromFile(fn);
241
242 Enumeration names = System.getProperties().propertyNames();
243 while (names.hasMoreElements()) {
244 String name = (String) (names.nextElement());
245 if (name.startsWith("MCR.")) {
246 String value = System.getProperty(name);
247 if (value != null) {
248 set(name, value);
249 }
250 }
251 }
252
253 substituteReferences();
254 substituteDeprecatedProperties();
255
256 if (clear) {
257 configureLogging();
258 }
259 }
260
261 /**
262 * Substitute any %reference% in any property value with the value of the
263 * referenced property, recursively.
264 */
265 private void substituteReferences() {
266 boolean found;
267 do {
268 found = false;
269 Enumeration keys = properties.keys();
270 while (keys.hasMoreElements()) {
271 String key = (String) (keys.nextElement());
272 String value = properties.getProperty(key, "");
273 int pos1 = value.indexOf("%");
274 if (pos1 >= 0) {
275 int pos2 = value.indexOf("%", pos1 + 1);
276 if (pos2 == -1)
277 continue;
278
279 String ref = value.substring(pos1 + 1, pos2);
280 String refValue = properties.getProperty(ref, null);
281 if (refValue == null)
282 continue;
283
284 found = true;
285 value = value.substring(0, pos1) + refValue + value.substring(pos2 + 1);
286 properties.setProperty(key, value);
287 }
288 }
289 } while (found);
290 }
291
292 /**
293 * Loads file deprecated.properties that can be used to rename old properties.
294 * The file contains a list of renamed properties: OldPropertyName=NewPropertyName.
295 * The old property is automatically replaced with the new name, so that
296 * existing mycore.properties files must not be migrated immediately. Users get a
297 * warning when their configuration still contains deprecated properties.
298 */
299 private void substituteDeprecatedProperties() {
300 InputStream in = this.getClass().getResourceAsStream("/deprecated.properties");
301 if (in == null)
302 return;
303 try {
304 depr.load(in);
305 in.close();
306 } catch (Exception exc) {
307 throw new MCRConfigurationException("Could not load configuration file deprecated.properties", exc);
308 }
309
310 Enumeration names = depr.keys();
311 while (names.hasMoreElements()) {
312 String deprecatedName = (String) (names.nextElement());
313 if (properties.containsKey(deprecatedName)) {
314 String newName = depr.getProperty(deprecatedName);
315 String msg = "DEPRECATED: User should rename property " + deprecatedName + " to " + newName;
316 Logger.getLogger(this.getClass()).warn(msg);
317 if (!properties.containsKey(newName))
318 properties.put(newName, properties.get(deprecatedName));
319 }
320 }
321 }
322
323 /**
324 * Loads configuration properties from a specified properties file and adds
325 * them to the properties currently set. This method scans the <CODE>
326 * CLASSPATH</CODE> for the properties file, it may be a plain file, but
327 * may also be located in a zip or jar file. If the properties file contains
328 * a property called <CODE>MCR.Configuration.Include</CODE>, the files
329 * specified in that property will also be read. Multiple include files have
330 * to be separated by spaces or colons.
331 *
332 * @param filename
333 * the properties file to be loaded
334 * @throws MCRConfigurationException
335 * if the file can not be loaded
336 */
337 private void loadFromFile(String filename) {
338 File mycoreProperties = new File(filename);
339 InputStream in;
340 if (mycoreProperties.canRead()) {
341 try {
342 in = new FileInputStream(mycoreProperties);
343 } catch (FileNotFoundException e) {
344 // should never happend, because we verified it allready with canRead() above
345 String msg = "Could not find configuration file " + filename;
346 throw new MCRConfigurationException(msg, e);
347 }
348 } else {
349 in = this.getClass().getResourceAsStream("/" + filename);
350 }
351 if (in == null) {
352 String msg = "Could not find configuration file " + filename + " in CLASSPATH";
353 throw new MCRConfigurationException(msg);
354 }
355
356 try {
357 properties.load(in);
358 in.close();
359 } catch (Exception exc) {
360 throw new MCRConfigurationException("Could not load configuration file " + filename, exc);
361 }
362
363 String include = getString("MCR.Configuration.Include", null);
364
365 if (include != null) {
366 StringTokenizer st = new StringTokenizer(include, ", ");
367 set("MCR.Configuration.Include", null);
368
369 while (st.hasMoreTokens())
370 loadFromFile(st.nextToken());
371 }
372 }
373
374 /**
375 * Returns all the properties
376 *
377 * @return the list of properties
378 */
379 public Properties getProperties() {
380 return properties;
381 }
382
383 /**
384 * Returns all the properties beginning with the specified string
385 *
386 * @param startsWith
387 * the string all the returned properties start with
388 * @return the list of properties
389 */
390 public Properties getProperties(String startsWith) {
391 Properties properties = new Properties();
392
393 Enumeration names = this.properties.propertyNames();
394
395 while (names.hasMoreElements()) {
396 String name = (String) (names.nextElement());
397
398 if (name.startsWith(startsWith)) {
399 String value = this.properties.getProperty(name);
400 properties.setProperty(name, value);
401 }
402 }
403
404 return properties;
405 }
406
407 /**
408 * Configures Log4J based on the log4j properties
409 */
410 public synchronized void configureLogging() {
411 Properties prop = new Properties();
412 Enumeration names = this.properties.propertyNames();
413 boolean reconfigure = false;
414 java.util.List<String> warn = new java.util.ArrayList<String>();
415
416 while (names.hasMoreElements()) {
417 String name = (String) (names.nextElement());
418 if (!name.contains("log4j"))
419 continue;
420 String value = this.properties.getProperty(name);
421 if (name.startsWith("MCR.log4j")) {
422 warn.add(name);
423 name = name.substring(4);
424 }
425 if (name.startsWith("log4j")) {
426 prop.setProperty(name, value);
427 reconfigure = true;
428 }
429 }
430
431 if (reconfigure) {
432 System.out.println("MCRConfiguration reconfiguring Log4J logging...");
433 org.apache.log4j.LogManager.resetConfiguration();
434 PropertyConfigurator.configure(prop);
435 for (String name : warn) {
436 Logger logger = Logger.getLogger(this.getClass());
437 logger.warn("DEPRECATED: User should rename property " + name + " to " + name.substring(4));
438 }
439 }
440 }
441
442 /**
443 * Returns a new instance of the class specified in the configuration
444 * property with the given name.
445 *
446 * @param name
447 * the non-null and non-empty name of the configuration property
448 * @return the value of the configuration property as a String, or null
449 * @throws MCRConfigurationException
450 * if the property is not set or the class can not be loaded or
451 * instantiated
452 */
453 public Object getInstanceOf(String name, String defaultname) throws MCRConfigurationException {
454 String classname = getString(name, defaultname);
455 if (classname == null) {
456 throw new MCRConfigurationException("Configuration property missing: " + name);
457 }
458
459 Logger.getLogger(this.getClass()).debug("Loading Class: " + classname);
460
461 Class cl;
462 try {
463 cl = Class.forName(classname);
464 } catch (Exception ex) {
465 throw new MCRConfigurationException("Could not load class " + classname, ex);
466 }
467
468 Object o = null;
469
470 try {
471 try {
472 o = cl.newInstance();
473 } catch (Exception e) {
474 if (e instanceof FilterPluginInstantiationException)
475 Logger.getLogger(this.getClass()).info(e.toString());
476 // check for singleton
477 Method[] querymethods = cl.getMethods();
478
479 for (int i = 0; i < querymethods.length; i++) {
480 if (querymethods[i].getName().toLowerCase().equals("instance")
481 || querymethods[i].getName().toLowerCase().equals("getinstance")) {
482 Object[] ob = new Object[0];
483 o = querymethods[i].invoke(cl, ob);
484
485 break;
486 }
487 }
488 }
489 } catch (Throwable t) {
490 String msg = "Could not instantiate class " + classname;
491
492 if (t instanceof ExceptionInInitializerError) {
493 Throwable t2 = ((ExceptionInInitializerError) t).getException();
494
495 if (t2 instanceof Exception) {
496 throw new MCRConfigurationException(msg, (Exception) t2);
497 }
498
499 throw new MCRConfigurationException(msg + ": " + t2.getClass().getName() + " - " + t2.getMessage());
500 } else if (t instanceof Exception) {
501 t.printStackTrace();
502 throw new MCRConfigurationException(msg, (Exception) t);
503 } else {
504 msg += (" because of: " + t.getMessage());
505 msg += ("\n" + MCRException.getStackTraceAsString(t));
506 throw new MCRConfigurationException(msg);
507 }
508 }
509
510 return o;
511 }
512
513 /**
514 * Returns a new instance of the class specified in the configuration
515 * property with the given name.
516 *
517 * @param name
518 * the non-null and non-empty name of the configuration property
519 * @return the value of the configuration property as a String, or null
520 * @throws MCRConfigurationException
521 * if the property is not set or the class can not be loaded or
522 * instantiated
523 */
524 public Object getInstanceOf(String name) throws MCRConfigurationException {
525 return getInstanceOf(name, null);
526 }
527
528 /**
529 * Returns a instance of the class specified in the configuration property
530 * with the given name. If the class was prevously instantiated by this
531 * method this instance is returned.
532 *
533 * @param name
534 * the non-null and non-empty name of the configuration property
535 * @return the instance of the class named by the value of the configuration
536 * propertyl
537 * @throws MCRConfigurationException
538 * if the property is not set or the class can not be loaded or
539 * instantiated
540 */
541 public Object getSingleInstanceOf(String name, String defaultname) throws MCRConfigurationException {
542 if (instanceHolder == null) {
543 instanceHolder = new Hashtable(); // initialize the hashtable if it's not yet
544 } else if (instanceHolder.containsKey(name)) {
545 return instanceHolder.get(name); // we have an instance allready, return it
546 }
547
548 Object inst = getInstanceOf(name, defaultname); // we need a new instance, get it
549 instanceHolder.put(name, inst); // save the instance in the hashtable
550
551 return inst;
552 }
553
554 /**
555 * Returns a instance of the class specified in the configuration property
556 * with the given name. If the class was prevously instantiated by this
557 * method this instance is returned.
558 *
559 * @param name
560 * non-null and non-empty name of the configuration property
561 * @return the instance of the class named by the value of the configuration
562 * propertyl
563 * @throws MCRConfigurationException
564 * if the property is not set or the class can not be loaded or
565 * instantiated
566 */
567 public Object getSingleInstanceOf(String name) {
568 return getSingleInstanceOf(name, null);
569 }
570
571 /**
572 * Returns the configuration property with the specified name as a String.
573 *
574 * @param name
575 * the non-null and non-empty name of the configuration property
576 * @return the value of the configuration property as a String
577 * @throws MCRConfigurationException
578 * if the property with this name is not set
579 */
580 public String getString(String name) {
581 String value = getString(name, null);
582
583 if (value == null) {
584 throw new MCRConfigurationException("Configuration property " + name + " is not set");
585 }
586
587 return value.trim();
588 }
589
590 /**
591 * Returns the configuration property with the specified name as a String,
592 * or returns a given default value if the property is not set.
593 *
594 * @param name
595 * the non-null and non-empty name of the configuration property
596 * @param defaultValue
597 * the value to return if the configuration property is not set
598 * @return the value of the configuration property as a String
599 */
600 public String getString(String name, String defaultValue) {
601 if (depr.containsKey(name)) {
602 String msg = "DEPRECATED: Developer should rename property " + name + " to " + depr.getProperty(name);
603 Logger.getLogger(this.getClass()).warn(msg);
604 }
605
606 String value = properties.getProperty(name);
607 if ((value == null) && depr.containsKey(name))
608 value = properties.getProperty(depr.getProperty(name));
609
610 return (value == null ? defaultValue : value.trim());
611 }
612
613 /**
614 * Returns the configuration property with the specified name as an <CODE>
615 * int</CODE> value.
616 *
617 * @param name
618 * the non-null and non-empty name of the configuration property
619 * @return the value of the configuration property as an <CODE>int</CODE>
620 * value
621 * @throws NumberFormatException
622 * if the configuration property is not an <CODE>int</CODE>
623 * value
624 * @throws MCRConfigurationException
625 * if the property with this name is not set
626 */
627 public int getInt(String name) throws NumberFormatException {
628 return Integer.parseInt(getString(name));
629 }
630
631 /**
632 * Returns the configuration property with the specified name as an <CODE>
633 * int</CODE> value, or returns a given default value if the property is
634 * not set.
635 *
636 * @param name
637 * the non-null and non-empty name of the configuration property
638 * /** Returns the configuration property with the specified name
639 * as an <CODE>int</CODE> value, or returns a given default
640 * value if the property is not set.
641 * @param defaultValue
642 * the value to return if the configuration property is not set
643 * @return the value of the specified property as an <CODE>int</CODE>
644 * value
645 * @throws NumberFormatException
646 * if the configuration property is set but is not an <CODE>int
647 * </CODE> value
648 */
649 public int getInt(String name, int defaultValue) throws NumberFormatException {
650 String value = getString(name, null);
651
652 return ((value == null) ? defaultValue : Integer.parseInt(value));
653 }
654
655 /**
656 * Returns the configuration property with the specified name as a <CODE>
657 * long</CODE> value.
658 *
659 * @param name
660 * the non-null and non-empty name of the configuration property
661 * @return the value of the configuration property as a <CODE>long</CODE>
662 * value
663 * @throws NumberFormatException
664 * if the configuration property is not a <CODE>long</CODE>
665 * value
666 * @throws MCRConfigurationException
667 * if the property with this name is not set
668 */
669 public long getLong(String name) throws NumberFormatException {
670 return Long.parseLong(getString(name));
671 }
672
673 /**
674 * Returns the configuration property with the specified name as a <CODE>
675 * long</CODE> value, or returns a given default value if the property is
676 * not set.
677 *
678 * @return the value of the specified property as a <CODE>long</CODE>
679 * value
680 * @param name
681 * the non-null and non-empty name of the configuration property
682 * @param defaultValue
683 * the value to return if the configuration property is not set
684 * @throws NumberFormatException
685 * if the configuration property is set but is not a <CODE>long
686 * </CODE> value
687 */
688 public long getLong(String name, long defaultValue) throws NumberFormatException {
689 String value = getString(name, null);
690
691 return ((value == null) ? defaultValue : Long.parseLong(value));
692 }
693
694 /**
695 * Returns the configuration property with the specified name as a <CODE>
696 * float</CODE> value.
697 *
698 * @param name
699 * the non-null and non-empty name of the configuration property
700 * @return the value of the configuration property as a <CODE>float</CODE>
701 * value
702 * @throws NumberFormatException
703 * if the configuration property is not a <CODE>float</CODE>
704 * value
705 * @throws MCRConfigurationException
706 * if the property with this name is not set
707 */
708 public float getFloat(String name) throws NumberFormatException {
709 return Float.parseFloat(getString(name));
710 }
711
712 /**
713 * Returns the configuration property with the specified name as a <CODE>
714 * float</CODE> value, or returns a given default value if the property is
715 * not set.
716 *
717 * @return the value of the specified property as a <CODE>float</CODE>
718 * value
719 * @param name
720 * the non-null and non-empty name of the configuration property
721 * @param defaultValue
722 * the value to return if the configuration property is not set
723 * @throws NumberFormatException
724 * if the configuration property is set but is not a <CODE>
725 * float</CODE> value
726 */
727 public float getFloat(String name, float defaultValue) throws NumberFormatException {
728 String value = getString(name, null);
729
730 return ((value == null) ? defaultValue : Float.parseFloat(value));
731 }
732
733 /**
734 * Returns the configuration property with the specified name as a <CODE>
735 * double</CODE> value.
736 *
737 * @param name
738 * the non-null and non-empty name of the configuration property
739 * @return the value of the configuration property as a <CODE>double
740 * </CODE> value
741 * @throws NumberFormatException
742 * if the configuration property is not a <CODE>double</CODE>
743 * value
744 * @throws MCRConfigurationException
745 * if the property with this name is not set
746 */
747 public double getDouble(String name) throws NumberFormatException {
748 return Double.parseDouble(getString(name));
749 }
750
751 /**
752 * Returns the configuration property with the specified name as a <CODE>
753 * double</CODE> value, or returns a given default value if the property is
754 * not set.
755 *
756 * @return the value of the specified property as a <CODE>double</CODE>
757 * value
758 * @param name
759 * the non-null and non-empty name of the configuration property
760 * @param defaultValue
761 * the value to return if the configuration property is not set
762 * @throws NumberFormatException
763 * if the configuration property is set but is not a <CODE>
764 * double</CODE> value
765 */
766 public double getDouble(String name, double defaultValue) throws NumberFormatException {
767 String value = getString(name, null);
768
769 return ((value == null) ? defaultValue : Double.parseDouble(value));
770 }
771
772 /**
773 * Returns the configuration property with the specified name as a <CODE>
774 * boolean</CODE> value.
775 *
776 * @param name
777 * the non-null and non-empty name of the configuration property
778 * @return <CODE>true</CODE>, if and only if the specified property has
779 * the value <CODE>true</CODE>
780 * @throws MCRConfigurationException
781 * if the property with this name is not set
782 */
783 public boolean getBoolean(String name) {
784 String value = getString(name);
785
786 return "true".equals(value.trim());
787 }
788
789 /**
790 * Returns the configuration property with the specified name as a <CODE>
791 * boolean</CODE> value, or returns a given default value if the property
792 * is not set. If the property is set and its value is not <CODE>true
793 * </CODE>, then <code>false</code> is returned.
794 *
795 * @return the value of the specified property as a <CODE>boolean</CODE>
796 * value
797 * @param name
798 * the non-null and non-empty name of the configuration property
799 * @param defaultValue
800 * the value to return if the configuration property is not set
801 */
802 public boolean getBoolean(String name, boolean defaultValue) {
803 String value = getString(name, null);
804
805 return ((value == null) ? defaultValue : "true".equals(value.trim()));
806 }
807
808 /**
809 * Sets the configuration property with the specified name to a new <CODE>
810 * String</CODE> value. If the parameter <CODE>value</CODE> is <CODE>
811 * null</CODE>, the property will be deleted.
812 *
813 * @param name
814 * the non-null and non-empty name of the configuration property
815 * @param value
816 * the new value of the configuration property, possibly <CODE>
817 * null</CODE>
818 */
819 public void set(String name, String value) {
820 if (value == null) {
821 properties.remove(name);
822 } else {
823 properties.setProperty(name, value);
824 }
825 }
826
827 /**
828 * Sets the configuration property with the specified name to a new <CODE>
829 * int</CODE> value.
830 *
831 * @param name
832 * the non-null and non-empty name of the configuration property
833 * @param value
834 * the new value of the configuration property
835 */
836 public void set(String name, int value) {
837 set(name, String.valueOf(value));
838 }
839
840 /**
841 * Sets the configuration property with the specified name to a new <CODE>
842 * long</CODE> value.
843 *
844 * @param name
845 * the non-null and non-empty name of the configuration property
846 * @param value
847 * the new value of the configuration property
848 */
849 public void set(String name, long value) {
850 set(name, String.valueOf(value));
851 }
852
853 /**
854 * Sets the configuration property with the specified name to a new <CODE>
855 * float</CODE> value.
856 *
857 * @param name
858 * the non-null and non-empty name of the configuration property
859 * @param value
860 * the new value of the configuration property
861 */
862 public void set(String name, float value) {
863 set(name, String.valueOf(value));
864 }
865
866 /**
867 * Sets the configuration property with the specified name to a new <CODE>
868 * double</CODE> value.
869 *
870 * @param name
871 * the non-null and non-empty name of the configuration property
872 * @param value
873 * the new value of the configuration property
874 */
875 public void set(String name, double value) {
876 set(name, String.valueOf(value));
877 }
878
879 /**
880 * Sets the configuration property with the specified name to a new <CODE>
881 * boolean</CODE> value.
882 *
883 * @param name
884 * the non-null and non-empty name of the configuration property
885 * @param value
886 * the new value of the configuration property
887 */
888 public void set(String name, boolean value) {
889 set(name, String.valueOf(value));
890 }
891
892 /**
893 * Lists all configuration properties currently set to a PrintStream. Useful
894 * for debugging, e. g. by calling
895 *
896 * <P>
897 * <CODE>MCRConfiguration.instance().list( System.out );</CODE>
898 * </P>
899 *
900 * @see java.util.Properties#list( PrintStream )
901 *
902 * @param out
903 * the PrintStream to list the configuration properties on
904 */
905 public void list(PrintStream out) {
906 properties.list(out);
907 }
908
909 /**
910 * Lists all configuration properties currently set to a PrintWriter. Useful
911 * for debugging.
912 *
913 * @see java.util.Properties#list( PrintWriter )
914 *
915 * @param out
916 * the PrintWriter to list the configuration properties on
917 */
918 public void list(PrintWriter out) {
919 properties.list(out);
920 }
921
922 /**
923 * Stores all configuration properties currently set to an OutputStream.
924 *
925 * @see java.util.Properties#store
926 *
927 * @param out
928 * the OutputStream to write the configuration properties to
929 * @param header
930 * the header to prepend before writing the list of properties
931 * @throws IOException
932 * if writing to the OutputStream throws an <CODE>IOException
933 * </CODE>
934 */
935 public void store(OutputStream out, String header) throws IOException {
936 properties.store(out, header);
937 }
938
939 /**
940 * Returns a String containing the configuration properties currently set.
941 * Useful for debugging, e. g. by calling
942 *
943 * <P>
944 * <CODE>System.out.println( MCRConfiguration.instance() );</CODE>
945 * </P>
946 *
947 * @return a String containing the configuration properties currently set
948 */
949 public String toString() {
950 return properties.toString();
951 }
952 }