Frames | No Frames |
1: /** 2: * ======================================== 3: * JFreeReport : a free Java report library 4: * ======================================== 5: * 6: * Project Info: http://reporting.pentaho.org/ 7: * 8: * (C) Copyright 2000-2007, by Object Refinery Limited, Pentaho Corporation and Contributors. 9: * 10: * This library is free software; you can redistribute it and/or modify it under the terms 11: * of the GNU Lesser General Public License as published by the Free Software Foundation; 12: * either version 2.1 of the License, or (at your option) any later version. 13: * 14: * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 15: * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 16: * See the GNU Lesser General Public License for more details. 17: * 18: * You should have received a copy of the GNU Lesser General Public License along with this 19: * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, 20: * Boston, MA 02111-1307, USA. 21: * 22: * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 23: * in the United States and other countries.] 24: * 25: * ------------ 26: * $Id: JFreeReportBoot.java 3525 2007-10-16 11:43:48Z tmorgner $ 27: * ------------ 28: * (C) Copyright 2000-2005, by Object Refinery Limited. 29: * (C) Copyright 2005-2007, by Pentaho Corporation. 30: */ 31: package org.jfree.report; 32: 33: import java.util.Enumeration; 34: 35: import org.jfree.base.AbstractBoot; 36: import org.jfree.base.BaseBoot; 37: import org.jfree.base.BootableProjectInfo; 38: import org.jfree.base.config.HierarchicalConfiguration; 39: import org.jfree.base.config.ModifiableConfiguration; 40: import org.jfree.base.config.PropertyFileConfiguration; 41: import org.jfree.base.config.SystemPropertyConfiguration; 42: import org.jfree.base.log.DefaultLog; 43: import org.jfree.base.modules.PackageManager; 44: import org.jfree.report.util.CSVTokenizer; 45: import org.jfree.util.Configuration; 46: import org.jfree.util.Log; 47: 48: /** 49: * An utility class to safely boot and initialize the JFreeReport library. This class 50: * should be called before using the JFreeReport classes, to make sure that all subsystems 51: * are initialized correctly and in the correct order. 52: * <p/> 53: * Application developers should make sure, that the booting is done, before JFreeReport 54: * objects are used. Although the boot process will be started automaticly if needed, this 55: * automated start may no longer guarantee the module initialization order. 56: * <p/> 57: * Additional modules can be specified by defining the system property 58: * <code>"org.jfree.report.boot.Modules"</code>. The property expects a comma-separated 59: * list of {@link org.jfree.base.modules.Module} implementations. 60: * <p/> 61: * Booting should be done by aquirering a new boot instance using {@link 62: * JFreeReportBoot#getInstance()} and then starting the boot process with {@link 63: * JFreeReportBoot#start()}. 64: * 65: * @author Thomas Morgner 66: */ 67: public class JFreeReportBoot extends AbstractBoot 68: { 69: /** 70: * A wrappper around the user supplied global configuration. 71: */ 72: private static class UserConfigWrapper extends HierarchicalConfiguration 73: { 74: /** The wrapped configuration. */ 75: private Configuration wrappedConfiguration; 76: 77: /** 78: * Default constructor. 79: */ 80: private UserConfigWrapper () 81: { 82: this (null); 83: } 84: 85: private UserConfigWrapper (final Configuration config) 86: { 87: this.wrappedConfiguration = config; 88: } 89: /** 90: * Sets a new configuration. This configuration will be inserted into the 91: * report configuration hierarchy. Set this property to null to disable 92: * the user defined configuration. 93: * 94: * @param wrappedConfiguration the wrapped configuration. 95: */ 96: public void setWrappedConfiguration (final Configuration wrappedConfiguration) 97: { 98: this.wrappedConfiguration = wrappedConfiguration; 99: } 100: 101: /** 102: * Returns the user supplied global configuration, if exists. 103: * 104: * @return the user configuration. 105: */ 106: public Configuration getWrappedConfiguration () 107: { 108: return wrappedConfiguration; 109: } 110: 111: /** 112: * Returns the configuration property with the specified key. 113: * 114: * @param key the property key. 115: * @return the property value. 116: */ 117: public String getConfigProperty (final String key) 118: { 119: if (wrappedConfiguration == null) 120: { 121: return getParentConfig().getConfigProperty(key); 122: } 123: 124: final String retval = wrappedConfiguration.getConfigProperty(key); 125: if (retval != null) 126: { 127: return retval; 128: } 129: return getParentConfig().getConfigProperty(key); 130: } 131: 132: /** 133: * Returns the configuration property with the specified key 134: * (or the specified default value if there is no such property). 135: * <p/> 136: * If the property is not defined in this configuration, the code 137: * will lookup the property in the parent configuration. 138: * 139: * @param key the property key. 140: * @param defaultValue the default value. 141: * @return the property value. 142: */ 143: public String getConfigProperty (final String key, final String defaultValue) 144: { 145: if (wrappedConfiguration == null) 146: { 147: return getParentConfig().getConfigProperty(key, defaultValue); 148: } 149: 150: final String retval = wrappedConfiguration.getConfigProperty(key, null); 151: if (retval != null) 152: { 153: return retval; 154: } 155: return getParentConfig().getConfigProperty(key, defaultValue); 156: } 157: 158: /** 159: * Sets a configuration property. 160: * 161: * @param key the property key. 162: * @param value the property value. 163: */ 164: public void setConfigProperty (final String key, final String value) 165: { 166: if (wrappedConfiguration instanceof ModifiableConfiguration) 167: { 168: final ModifiableConfiguration modConfiguration = 169: (ModifiableConfiguration) wrappedConfiguration; 170: modConfiguration.setConfigProperty(key, value); 171: } 172: } 173: 174: /** 175: * Returns all defined configuration properties for the report. The enumeration 176: * contains all keys of the changed properties, properties set from files or 177: * the system properties are not included. 178: * 179: * @return all defined configuration properties for the report. 180: */ 181: public Enumeration getConfigProperties () 182: { 183: if (wrappedConfiguration instanceof ModifiableConfiguration) 184: { 185: final ModifiableConfiguration modConfiguration = 186: (ModifiableConfiguration) wrappedConfiguration; 187: return modConfiguration.getConfigProperties(); 188: } 189: return super.getConfigProperties(); 190: } 191: } 192: 193: /** 194: * The singleton instance of the Boot class. 195: */ 196: private static JFreeReportBoot instance; 197: /** 198: * The project info contains all meta data about the project. 199: */ 200: private BootableProjectInfo projectInfo; 201: 202: /** 203: * Holds a possibly empty reference to a user-supplied Configuration 204: * implementation. 205: */ 206: private static transient UserConfigWrapper configWrapper = 207: new UserConfigWrapper(); 208: 209: /** 210: * Creates a new instance. 211: */ 212: private JFreeReportBoot () 213: { 214: projectInfo = JFreeReportInfo.getInstance(); 215: } 216: 217: /** 218: * Returns the singleton instance of the boot utility class. 219: * 220: * @return the boot instance. 221: */ 222: public static synchronized JFreeReportBoot getInstance () 223: { 224: if (instance == null) 225: { 226: // make sure that I am able to debug the package manager .. 227: DefaultLog.installDefaultLog(); 228: instance = new JFreeReportBoot(); 229: 230: final HierarchicalConfiguration hc = (HierarchicalConfiguration) BaseBoot.getConfiguration(); 231: hc.insertConfiguration(new UserConfigWrapper(instance.getGlobalConfig())); 232: } 233: return instance; 234: } 235: 236: /** 237: * Returns the current global configuration as modifiable instance. This 238: * is exactly the same as casting the global configuration into a 239: * ModifableConfiguration instance. 240: * <p/> 241: * This is a convinience function, as all programmers are lazy. 242: * 243: * @return the global config as modifiable configuration. 244: */ 245: public ModifiableConfiguration getEditableConfig() 246: { 247: return (ModifiableConfiguration) getGlobalConfig(); 248: } 249: 250: /** 251: * Returns the project info. 252: * 253: * @return The project info. 254: */ 255: protected BootableProjectInfo getProjectInfo () 256: { 257: return projectInfo; 258: } 259: 260: /** 261: * Loads the configuration. This will be called exactly once. 262: * 263: * @return The configuration. 264: */ 265: protected Configuration loadConfiguration () 266: { 267: final HierarchicalConfiguration globalConfig = new HierarchicalConfiguration(); 268: 269: final PropertyFileConfiguration rootProperty = new PropertyFileConfiguration(); 270: rootProperty.load("/org/jfree/report/jfreereport.properties"); 271: rootProperty.load("/org/jfree/report/ext/jfreereport-ext.properties"); 272: globalConfig.insertConfiguration(rootProperty); 273: globalConfig.insertConfiguration(JFreeReportBoot.getInstance().getPackageManager() 274: .getPackageConfiguration()); 275: 276: final PropertyFileConfiguration baseProperty = new PropertyFileConfiguration(); 277: baseProperty.load("/jfreereport.properties"); 278: globalConfig.insertConfiguration(baseProperty); 279: 280: globalConfig.insertConfiguration(configWrapper); 281: 282: final SystemPropertyConfiguration systemConfig = new SystemPropertyConfiguration(); 283: globalConfig.insertConfiguration(systemConfig); 284: return globalConfig; 285: } 286: 287: /** 288: * Performs the actual boot process. 289: */ 290: protected void performBoot () 291: { 292: // Inject JFreeReport's configuration into jcommon. 293: // make sure logging is re-initialized after we injected our configuration. 294: Log.getInstance().init(); 295: 296: if (isStrictFP() == false) 297: { 298: Log.warn("The used VM seems to use a non-strict floating point arithmetics"); 299: Log.warn("Layouts computed with this Java Virtual Maschine may be invalid."); 300: Log.warn("JFreeReport and the library 'iText' depend on the strict floating point rules"); 301: Log.warn("of Java1.1 as implemented by the Sun Virtual Maschines."); 302: Log.warn("If you are using the BEA JRockit VM, start the Java VM with the option"); 303: Log.warn("'-Xstrictfp' to restore the default behaviour."); 304: } 305: 306: final PackageManager mgr = getPackageManager(); 307: 308: mgr.addModule(JFreeReportCoreModule.class.getName()); 309: mgr.load("org.jfree.report.modules."); 310: mgr.load("org.jfree.report.ext.modules."); 311: mgr.load("org.jfree.report.userdefined.modules."); 312: 313: bootAdditionalModules(); 314: mgr.initializeModules(); 315: } 316: 317: /** 318: * Boots modules, which have been spcified in the "org.jfree.report.boot.Modules" 319: * configuration parameter. 320: */ 321: private void bootAdditionalModules () 322: { 323: try 324: { 325: final String bootModules = 326: getGlobalConfig().getConfigProperty 327: ("org.jfree.report.boot.Modules"); 328: if (bootModules != null) 329: { 330: final CSVTokenizer csvToken = new CSVTokenizer(bootModules, ","); 331: while (csvToken.hasMoreTokens()) 332: { 333: final String token = csvToken.nextToken(); 334: getPackageManager().load(token); 335: } 336: } 337: } 338: catch (SecurityException se) 339: { 340: Log.info("Security settings forbid to check the system properties for extension modules."); 341: } 342: catch (Exception se) 343: { 344: Log.error 345: ("An error occured while checking the system properties for extension modules.", se); 346: } 347: } 348: 349: 350: /** 351: * This method returns true on non-strict floating point systems. 352: * <p/> 353: * Since Java 1.2 Virtual Maschines may implement the floating point arithmetics in a 354: * more performant way, which does not put the old strict constraints on the floating 355: * point types <code>float</code> and <code>double</code>. 356: * <p/> 357: * As iText and this library requires strict (in the sense of Java1.1) floating point 358: * operations, we have to test for that feature here. 359: * <p/> 360: * The only known VM that seems to implement that feature is the JRockit VM. The strict 361: * mode can be restored on that VM by adding the "-Xstrictfp" VM parameter. 362: * 363: * @return true, if the VM uses strict floating points by default, false otherwise. 364: */ 365: private static boolean isStrictFP () 366: { 367: final double d = 8e+307; 368: final double result1 = 4.0 * d * 0.5; 369: final double result2 = 2.0 * d; 370: return (result1 != result2 && (result1 == Double.POSITIVE_INFINITY)); 371: } 372: 373: 374: /** 375: * Returns the user supplied global configuration. 376: * 377: * @return the user configuration, if any. 378: */ 379: public static Configuration getUserConfig () 380: { 381: return configWrapper.getWrappedConfiguration(); 382: } 383: 384: /** 385: * Defines the global user configuration. 386: * 387: * @param config the user configuration. 388: */ 389: public static void setUserConfig (final Configuration config) 390: { 391: configWrapper.setWrappedConfiguration(config); 392: } 393: 394: }