001 /** 002 * ======================================== 003 * JFreeReport : a free Java report library 004 * ======================================== 005 * 006 * Project Info: http://reporting.pentaho.org/ 007 * 008 * (C) Copyright 2000-2007, by Object Refinery Limited, Pentaho Corporation and Contributors. 009 * 010 * This library is free software; you can redistribute it and/or modify it under the terms 011 * of the GNU Lesser General Public License as published by the Free Software Foundation; 012 * either version 2.1 of the License, or (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 015 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 016 * See the GNU Lesser General Public License for more details. 017 * 018 * You should have received a copy of the GNU Lesser General Public License along with this 019 * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, 020 * Boston, MA 02111-1307, USA. 021 * 022 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 023 * in the United States and other countries.] 024 * 025 * ------------ 026 * $Id: JFreeReportBoot.java 3525 2007-10-16 11:43:48Z tmorgner $ 027 * ------------ 028 * (C) Copyright 2000-2005, by Object Refinery Limited. 029 * (C) Copyright 2005-2007, by Pentaho Corporation. 030 */ 031 package org.jfree.report; 032 033 import java.util.Enumeration; 034 035 import org.jfree.base.AbstractBoot; 036 import org.jfree.base.BaseBoot; 037 import org.jfree.base.BootableProjectInfo; 038 import org.jfree.base.config.HierarchicalConfiguration; 039 import org.jfree.base.config.ModifiableConfiguration; 040 import org.jfree.base.config.PropertyFileConfiguration; 041 import org.jfree.base.config.SystemPropertyConfiguration; 042 import org.jfree.base.log.DefaultLog; 043 import org.jfree.base.modules.PackageManager; 044 import org.jfree.report.util.CSVTokenizer; 045 import org.jfree.util.Configuration; 046 import org.jfree.util.Log; 047 048 /** 049 * An utility class to safely boot and initialize the JFreeReport library. This class 050 * should be called before using the JFreeReport classes, to make sure that all subsystems 051 * are initialized correctly and in the correct order. 052 * <p/> 053 * Application developers should make sure, that the booting is done, before JFreeReport 054 * objects are used. Although the boot process will be started automaticly if needed, this 055 * automated start may no longer guarantee the module initialization order. 056 * <p/> 057 * Additional modules can be specified by defining the system property 058 * <code>"org.jfree.report.boot.Modules"</code>. The property expects a comma-separated 059 * list of {@link org.jfree.base.modules.Module} implementations. 060 * <p/> 061 * Booting should be done by aquirering a new boot instance using {@link 062 * JFreeReportBoot#getInstance()} and then starting the boot process with {@link 063 * JFreeReportBoot#start()}. 064 * 065 * @author Thomas Morgner 066 */ 067 public class JFreeReportBoot extends AbstractBoot 068 { 069 /** 070 * A wrappper around the user supplied global configuration. 071 */ 072 private static class UserConfigWrapper extends HierarchicalConfiguration 073 { 074 /** The wrapped configuration. */ 075 private Configuration wrappedConfiguration; 076 077 /** 078 * Default constructor. 079 */ 080 private UserConfigWrapper () 081 { 082 this (null); 083 } 084 085 private UserConfigWrapper (final Configuration config) 086 { 087 this.wrappedConfiguration = config; 088 } 089 /** 090 * Sets a new configuration. This configuration will be inserted into the 091 * report configuration hierarchy. Set this property to null to disable 092 * the user defined configuration. 093 * 094 * @param wrappedConfiguration the wrapped configuration. 095 */ 096 public void setWrappedConfiguration (final Configuration wrappedConfiguration) 097 { 098 this.wrappedConfiguration = wrappedConfiguration; 099 } 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 }