001package org.jconfig; 002 003import java.io.*; 004import java.util.*; 005 006import org.jconfig.event.*; 007/** 008 * The ConfigurationManager is the do-it-all-in-one utility. The 009 * ConfigurationManager allows you to store properties inside an XML file or a 010 * properties file. The properties can be retrieved later for use in your 011 * applications. <P/> 012 * 013 * Typical usage: <P/> 014 * 015 * <CODE> 016 * // <BR /> 017 * // first we get an existing property from the category "general" 018 * <BR /> 019 * //<BR /> 020 * String debug_file = cfgmgr.getProperty("debug_file");<BR /> 021 * System.out.println("The debug_file is:" + debug_file);<BR /> 022 * //<BR /> 023 * // now we try to get a non-existing property from the category 024 * "general"<BR /> 025 * //<BR /> 026 * String neProp = cfgmgr.getProperty("hello","my 027 * default");<BR /> 028 * System.out.println("The value is:" + neProp );<BR /> 029 * //<BR /> 030 * // last step is we get a property from the category "JDBC"<BR /> 031 * //<BR /> 032 * String driver = cfgmgr.getProperty("DRIVER","","JDBC"); 033 * <BR /> 034 * System.out.println("The driver is:" + driver);<BR /> 035 * </CODE> 036 * 037 *@author Andreas Mecky andreas.mecky@xcom.de 038 *@author Terry Dye terry.dye@xcom.de 039 *@created 27. Januar 2002 040 *@version $Id: ConfigurationManager.java,v 1.16 2002/08/06 15:08:59 041 * Andreas.Mecky Exp $ 042 */ 043public class ConfigurationManager implements FileListener { 044 045 // separator for category and property for HashMap 046 private final static char C_SEP = 127; 047 // prefix for category names 048 private final static char C_PFIX = 64; 049 // all instances of the ConfigurationManager 050 private static HashMap configurationManagers = null; 051 // the parameters for one instance 052 private HashMap parameter; 053 // all categories for one instance 054 private Vector categories; 055 // flag if we should validate an XML input 056 private boolean validate = false; 057 // the name of the instance 058 private String name; 059 // file watcher 060 private FileWatcher watcher; 061 // the config file 062 private File configFile; 063 064 065 /** 066 * Constructor for the ConfigurationManager object 067 * 068 *@param name Description of the Parameter 069 */ 070 private ConfigurationManager(String name) { 071 parameter = new HashMap(); 072 categories = new Vector(); 073 addCategory("general"); 074 this.name = name; 075 } 076 077 078 /** 079 * This method returns the value for a particular key. The category is 080 * "general". 081 * 082 *@param key the name of the property 083 *@return the value as String or null 084 */ 085 public String getProperty(String key) { 086 return getProperty(key, null, null); 087 } 088 089 090 /** 091 * This method returns the value for a particular key. If this key does not 092 * exist then the method returns the defaultValue. The category is 093 * "general". 094 * 095 *@param key the name of the property 096 *@param defaultValue the value that will be returned if the property 097 * cannot be found 098 *@return the value as String or the defaultValue 099 */ 100 public String getProperty(String key, String defaultValue) { 101 return getProperty(key, defaultValue, null); 102 } 103 104 105 /** 106 * This method returns the value for a particular key in the certain 107 * category. If this key does not exist then the method returns the 108 * defaultValue 109 * 110 *@param key the name of the property 111 *@param defaultValue the value that will be returned if the property 112 * cannot be found 113 *@param category the name of the category 114 *@return the value as String or the defaultValue 115 */ 116 public String getProperty(String key, String defaultValue, String category) { 117 if (key == null) { 118 return defaultValue; 119 } 120 String mykey; 121 String generalKey = C_PFIX + "general" + C_SEP + key; 122 if (category != null) { 123 mykey = C_PFIX + category + C_SEP + key; 124 } else { 125 mykey = generalKey; 126 } 127 if (parameter.containsKey((String) mykey)) { 128 return (String) parameter.get((String) mykey); 129 } else if (parameter.containsKey((String) generalKey)) { 130 return (String) parameter.get((String) generalKey); 131 } else { 132 return defaultValue; 133 } 134 } 135 136 137 /** 138 * This method returns the default instance of the ConfigurationManager. If 139 * no instance is found it will create a new instance and will try to load 140 * the config.xml. This file must be in the classpath. 141 * 142 *@return 143 */ 144 public static ConfigurationManager getInstance() { 145 return getInstance("default", true); 146 } 147 148 149 /** 150 * This method returns an instance of the ConfigurationManager with the 151 * given name<BR /> 152 * If no instance is found it will create a new instance and will try to 153 * load the config.xml. This file must be in the classpath. 154 * 155 *@param instanceName 156 *@return 157 */ 158 public static ConfigurationManager getInstance(String instanceName) { 159 return getInstance(instanceName, true); 160 } 161 162 163 /** 164 * This method returns an instance of the ConfigurationManager with this 165 * name. If there is no instance then it will create a new one. If the 166 * autoLoad flag is set to true then it will try to load the config.xml. In 167 * order to use the ConfigurationManager do the following: <BR /> 168 * private ConfigurationManager<BR /> 169 * cfgmgr = ConfigurationManager.getInstance("myConfiguration",true); 170 * 171 *@param instanceName 172 *@param autoLoad if true then the method wil try to load the 173 * config.xml if it can find it in the classpath 174 *@return an instance of the ConfigurationManager 175 */ 176 public static ConfigurationManager getInstance(String instanceName, boolean autoLoad) { 177 if (configurationManagers == null) { 178 configurationManagers = new HashMap(); 179 } 180 if (configurationManagers.containsKey(instanceName)) { 181 return (ConfigurationManager) configurationManagers.get(instanceName); 182 } 183 ConfigurationManager cfgmgr = new ConfigurationManager(instanceName); 184 InputStream is = null; 185 try { 186 /* 187 * get a default config.xml, means no need to call method 188 * load ( filename ) 189 */ 190 if (autoLoad) { 191 ClassLoader cl = cfgmgr.getClass().getClassLoader(); 192 is = cl.getResourceAsStream("config.xml"); 193 if (is != null) { 194 cfgmgr.load(is); 195 cfgmgr.setAutoReload(true); 196 } 197 /* 198 * we now try register the watchers 199 */ 200 java.net.URL url = cl.getResource("config.xml"); 201 if (url != null) { 202 File file = new File(url.getFile()); 203 cfgmgr.configFile = file; 204 cfgmgr.setWatcher(new FileWatcher(file)); 205 cfgmgr.watcher = cfgmgr.getWatcher(); 206 cfgmgr.watcher.addFileListener(cfgmgr); 207 cfgmgr.watcher.start(); 208 } 209 } 210 configurationManagers.put(instanceName, cfgmgr); 211 } catch (Exception e) { 212 e.printStackTrace(); 213 return null; 214 } 215 return cfgmgr; 216 } 217 218 219 /** 220 * This method returns an Enumeration of all categories. The names are 221 * stored as Strings inside the Enumeration. 222 * 223 *@return an enumeratiuon containing all names of all categories 224 *@deprecated use getAllCategoryNames instead 225 */ 226 public Enumeration getCategoryNames() { 227 return categories.elements(); 228 } 229 230 231 /** 232 * This method returns an <code>String</code> array of the names of all 233 * categories. 234 * 235 *@return an <code>String</code> containing all names of all categories 236 */ 237 public String[] getAllCategoryNames() { 238 return (String[]) categories.toArray(new String[0]); 239 } 240 241 242 /** 243 * This method will return a Hashtable that contains all properties for the 244 * category "general". The properties are stored as key and value both as 245 * strings. 246 * 247 *@return a Hashtable that contains all properties for the category 248 * "general" 249 */ 250 public Hashtable getProperties() { 251 return getProperties(null); 252 } 253 254 255 /** 256 * This method will return a Hashtable that contains all properties for the 257 * selected category. The properties are stored as key and value both as 258 * strings. 259 * 260 *@param category the name of the category 261 *@return a Hashtable that contains all properties for this 262 * category 263 */ 264 public Hashtable getProperties(String category) { 265 Hashtable retValues = new Hashtable(); 266 // if no category was passed to us then we take "general" 267 if (category == null) { 268 category = C_PFIX + "general"; 269 } else { 270 category = C_PFIX + category; 271 } 272 String currentKey = null; 273 // get all the keys from our Hashtable 274 Iterator it = parameter.keySet().iterator(); 275 while (it.hasNext()) { 276 currentKey = (String) it.next(); 277 // let's see if the category name is inside the key-string 278 if (currentKey.indexOf(category + C_SEP) != -1) { 279 // now extract the category name from the key and 280 // store the name and the value 281 String name = currentKey.substring(currentKey.indexOf(C_SEP) + 1); 282 String value = (String) parameter.get((String) currentKey); 283 retValues.put(name, value); 284 } 285 } 286 return retValues; 287 } 288 289 290 /** 291 * This method will set the value for a specific property in the category 292 * "general". If this property does not exist then it will be created 293 * 294 *@param name the name of the property 295 *@param value the value for this property 296 */ 297 public void setProperty(String name, String value) { 298 setProperty(name, value, null); 299 } 300 301 302 /** 303 * This method will set the value for a specific property in the selected 304 * category. If this property does not exist then it will be created. If 305 * the category does not exist it will be created. 306 * 307 *@param name the name of the property 308 *@param value the value for this property 309 *@param category the name of the category 310 */ 311 public void setProperty(String name, String value, String category) { 312 // we use the default one if it is not specified 313 String tmpCategory = null; 314 if (category == null) { 315 tmpCategory = C_PFIX + "general"; 316 } else { 317 tmpCategory = C_PFIX + category; 318 } 319 // it is safe to use addCategory since it will check 320 // if this category already exists and return quitely 321 addCategory(category); 322 // now we save the property 323 String mykey = tmpCategory + C_SEP + name; 324 parameter.put(mykey, value); 325 } 326 327 328 /** 329 * This method removes the property with the given name from the category 330 * general. It calls <code>removeProperty(name,"general")</code>. 331 * 332 *@param name the name of the property that will be removed 333 */ 334 public void removeProperty(String name) { 335 if (name != null) { 336 removeProperty(name, "general"); 337 } 338 } 339 340 341 /** 342 * This method will remove a property with the given name from the specific 343 * category. 344 * 345 *@param name the name of the property 346 *@param category the name of the category 347 */ 348 public void removeProperty(String name, String category) { 349 if (name != null && category != null) { 350 String mykey = C_PFIX + category + C_SEP + name; 351 if( parameter.get(mykey) != null ) { 352 parameter.remove(mykey); 353 } 354 } 355 } 356 357 358 /** 359 * Adds a feature to the Category attribute of the ConfigurationManager 360 * object 361 * 362 *@param category The feature to be added to the Category attribute 363 */ 364 public void addCategory(String category) { 365 if (categories.indexOf(category) == -1) { 366 categories.add(category); 367 } 368 } 369 370 371 /** 372 * This method removes the specific category. 373 * 374 *@param category the name of the category that will be removed 375 */ 376 public void removeCategory(String category) { 377 String tmpCategory = C_PFIX + category; 378 if (categories.indexOf(tmpCategory) != -1) { 379 String[] propertyNames = getAllPropertyNamesFromCategory(category); 380 for (int i = 0; i < propertyNames.length; i++) { 381 removeProperty(propertyNames[i], category); 382 } 383 categories.remove(tmpCategory); 384 } 385 } 386 387 /** 388 * Gets all property names for a given category. If the category 389 * is <code>null</code> then the category is "general". 390 * 391 *@param category the name of the category 392 *@return a string array with the names 393 */ 394 public String[] getAllPropertyNamesFromCategory(String category) { 395 Hashtable allProps = getProperties(category); 396 Set myKeys = allProps.keySet(); 397 return (String[]) myKeys.toArray(new String[0]); 398 } 399 400 401 /** 402 * This method will save the current categories and their properties to a 403 * file 404 * 405 *@param file the file that will be generated 406 *@exception ConfigurationManagerException Description of the Exception 407 */ 408 public void store(File file) throws ConfigurationManagerException { 409 ConfigurationFileHandler cph = new ConfigurationFileHandler(); 410 HashMap props = new HashMap(); 411 for (int i = 0; i < categories.size(); i++) { 412 String currentCategory = (String) categories.get(i); 413 Hashtable myProperties = getProperties(currentCategory); 414 props.put(currentCategory, myProperties); 415 } 416 HashMap params = new HashMap(); 417 params.put("File", file); 418 params.put("Data", props); 419 cph.initialize(params); 420 cph.store(); 421 } 422 423 424 /** 425 * This method will store all categories and properties to a 426 * Java-properties file. All properties will be in the category "general". 427 * It will override an existing configuration. 428 * 429 *@param file the file 430 *@throws ConfigurationManagerException if the file cannot be processed 431 */ 432 public void loadProperties(File file) throws ConfigurationManagerException { 433 ConfigurationPropertiesHandler cph = new ConfigurationPropertiesHandler(); 434 HashMap params = new HashMap(); 435 params.put("File", file); 436 cph.initialize(params); 437 cph.load(); 438 categories = cph.getCategories(); 439 parameter = cph.getProperties(); 440 } 441 442 443 /** 444 * This method will generate a Java-properties file. All categories will be 445 * saved as comments and only the properties are written to the file. The 446 * output is category.property=value 447 * 448 *@param file the file 449 *@throws ConfigurationManagerException if the file cannot be processed 450 */ 451 public void storeProperties(File file) throws ConfigurationManagerException { 452 ConfigurationPropertiesHandler cph = new ConfigurationPropertiesHandler(); 453 HashMap props = new HashMap(); 454 for (int i = 0; i < categories.size(); i++) { 455 String currentCategory = (String) categories.get(i); 456 Hashtable myProperties = getProperties(currentCategory); 457 props.put(currentCategory, myProperties); 458 } 459 HashMap params = new HashMap(); 460 params.put("File", file); 461 params.put("Data", props); 462 // flag to show that only a single category will be saved 463 params.put("Type", "Multi"); 464 cph.initialize(params); 465 cph.store(); 466 } 467 468 469 /** 470 * This method will write a Java-properties file and fill in the properties 471 * for the particular category. The category will be saved as comment and 472 * only the properties are written to the file. The output is 473 * property=value. The category is not included in the property name. 474 * 475 *@param file the file 476 *@param category Description of the Parameter 477 *@throws ConfigurationManagerException if the file cannot be processed 478 */ 479 public void storeProperties(File file, String category) throws ConfigurationManagerException { 480 ConfigurationPropertiesHandler cph = new ConfigurationPropertiesHandler(); 481 HashMap params = new HashMap(); 482 params.put("File", file); 483 params.put("Properties", getProperties(category)); 484 params.put("Category", category); 485 // flag to show that only a single category will be saved 486 params.put("Type", "Single"); 487 cph.initialize(params); 488 cph.store(); 489 } 490 491 492 /** 493 * This method reads the configuration from an URL. It must be a XML file. 494 * 495 *@param theURL the URL 496 *@throws ConfigurationManagerException if an error occurs 497 */ 498 public synchronized void load(String theURL) throws ConfigurationManagerException { 499 HashMap params = new HashMap(); 500 params.put("URL", theURL); 501 load(params); 502 } 503 504 505 /** 506 * This method will read an <code>InputStream</code>.<BR /> 507 * 508 * 509 *@param is the <code>InputStream</code> 510 *@throws ConfigurationManagerException if an error occurs 511 */ 512 public synchronized void load(InputStream is) throws ConfigurationManagerException { 513 HashMap params = new HashMap(); 514 params.put("InputStream", is); 515 load(params); 516 } 517 518 519 /** 520 * This method reads a XML file. 521 * 522 *@param file the file that will be read 523 *@throws ConfigurationManagerException if the file cannot be read 524 */ 525 public synchronized void load(File file) throws ConfigurationManagerException { 526 HashMap params = new HashMap(); 527 params.put("File", file); 528 529 configFile = file; 530 load(params); 531 } 532 533 534 /** 535 * Description of the Method 536 * 537 *@param params Description of the Parameter 538 *@exception ConfigurationManagerException Description of the Exception 539 */ 540 private void load(HashMap params) throws ConfigurationManagerException { 541 ConfigurationFileHandler cfh = new ConfigurationFileHandler(); 542 cfh.initialize(params); 543 cfh.load(); 544 cfh.setValidation(validate); 545 categories = cfh.getCategories(); 546 parameter = cfh.getProperties(); 547 reloadWatcher(); 548 } 549 550 551 /** 552 * Description of the Method 553 */ 554 private void reloadWatcher() { 555 // how do I get the File information that was loaded? 556 } 557 558 559 /** 560 * This method creates a string representation of this configuration. It 561 * can be used for debugging. 562 * 563 *@return the configuration as <code>String</code> 564 */ 565 public String toString() { 566 StringBuffer sb = new StringBuffer(); 567 sb.append("Configuration\n"); 568 sb.append("Name:" + name + "\n"); 569 for (int i = 0; i < categories.size(); i++) { 570 String currentCategory = (String) categories.get(i); 571 sb.append(" Category:" + currentCategory + "\n"); 572 Hashtable myProperties = getProperties(currentCategory); 573 Enumeration lprops = myProperties.keys(); 574 // here we walk through the properties 575 while (lprops.hasMoreElements()) { 576 String currentKey = (String) lprops.nextElement(); 577 sb.append(" " + currentKey + "=" + (String) myProperties.get(currentKey) + "\n"); 578 } 579 } 580 return sb.toString(); 581 } 582 583 584 /** 585 * This method, once implemented, will be called when the File object 586 * itself changes. 587 * 588 *@param evt Description of the Parameter 589 */ 590 public void fileChanged(FileListenerEvent evt) { 591 try { 592 load(evt.getFile()); 593 } catch (Exception e) { 594 e.printStackTrace(); 595 } 596 } 597 598 599 /** 600 * Sets the validation attribute of the ConfigurationManager object 601 * 602 *@param validate The new validation value 603 */ 604 public void setValidation(boolean validate) { 605 this.validate = validate; 606 } 607 608 609 /** 610 * Sets the reloadIntervall attribute of the ConfigurationManager object 611 * 612 *@param seconds The new reloadIntervall value 613 */ 614 public void setReloadIntervall(int seconds) { 615 if (getWatcher() != null) { 616 getWatcher().setInterval(seconds); 617 } 618 } 619 620 621 /** 622 * Sets the reload flag. If it is set to true then jConfig will watch the 623 * correspondig resource for this configuration and reload it if it has 624 * changed. 625 * 626 *@param reload The new autoReload value 627 */ 628 public void setAutoReload(boolean reload) { 629 if (reload) { 630 if (getWatcher() != null) { 631 getWatcher().start(); 632 } else { 633 if (configFile != null) { 634 setWatcher(new FileWatcher(configFile)); 635 getWatcher().addFileListener(this); 636 getWatcher().start(); 637 } 638 } 639 } else { 640 if (getWatcher() != null) { 641 getWatcher().stopWatching(); 642 } 643 } 644 } 645 646 647 /** 648 * Getter for property FileWatcher 649 * 650 *@return The FileWatcher 651 */ 652 public FileWatcher getWatcher() { 653 return watcher; 654 } 655 656 657 /** 658 * Setter for FileWatcher . 659 * 660 *@param watcher New value of property watcher. 661 */ 662 public void setWatcher(org.jconfig.FileWatcher watcher) { 663 this.watcher = watcher; 664 } 665 666 667 /** 668 * Getter for property Configuration Name. 669 * 670 *@return Configuration Name. 671 */ 672 public java.lang.String getConfigurationName() { 673 return name; 674 } 675 676 677 /** 678 * Adds a FileListener to the current configuration 679 * 680 *@param fileListener The FileListener 681 */ 682 public void addFileListener(FileListener fileListener) { 683 getWatcher().addFileListener(fileListener); 684 } 685 686 /** 687 * Getter for the File Object of the configuration file used. 688 * 689 * @return The File object 690 */ 691 public File getConfigFile() { 692 return configFile; 693 } 694}