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,v 1.15 2007/04/01 18:49:23 taqua Exp $ 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 implements Configuration 074 { 075 /** The wrapped configuration. */ 076 private Configuration wrappedConfiguration; 077 078 /** 079 * Default constructor. 080 */ 081 public UserConfigWrapper () 082 { 083 this (null); 084 } 085 086 public UserConfigWrapper (Configuration config) 087 { 088 this.wrappedConfiguration = config; 089 } 090 /** 091 * Sets a new configuration. This configuration will be inserted into the 092 * report configuration hierarchy. Set this property to null to disable 093 * the user defined configuration. 094 * 095 * @param wrappedConfiguration the wrapped configuration. 096 */ 097 public void setWrappedConfiguration (final Configuration wrappedConfiguration) 098 { 099 this.wrappedConfiguration = wrappedConfiguration; 100 } 101 102 /** 103 * Returns the user supplied global configuration, if exists. 104 * 105 * @return the user configuration. 106 */ 107 public Configuration getWrappedConfiguration () 108 { 109 return wrappedConfiguration; 110 } 111 112 /** 113 * Returns the configuration property with the specified key. 114 * 115 * @param key the property key. 116 * @return the property value. 117 */ 118 public String getConfigProperty (final String key) 119 { 120 if (wrappedConfiguration == null) 121 { 122 return getParentConfig().getConfigProperty(key); 123 } 124 125 final String retval = wrappedConfiguration.getConfigProperty(key); 126 if (retval != null) 127 { 128 return retval; 129 } 130 return getParentConfig().getConfigProperty(key); 131 } 132 133 /** 134 * Returns the configuration property with the specified key 135 * (or the specified default value if there is no such property). 136 * <p/> 137 * If the property is not defined in this configuration, the code 138 * will lookup the property in the parent configuration. 139 * 140 * @param key the property key. 141 * @param defaultValue the default value. 142 * @return the property value. 143 */ 144 public String getConfigProperty (final String key, final String defaultValue) 145 { 146 if (wrappedConfiguration == null) 147 { 148 return getParentConfig().getConfigProperty(key, defaultValue); 149 } 150 151 final String retval = wrappedConfiguration.getConfigProperty(key, null); 152 if (retval != null) 153 { 154 return retval; 155 } 156 return getParentConfig().getConfigProperty(key, defaultValue); 157 } 158 159 /** 160 * Sets a configuration property. 161 * 162 * @param key the property key. 163 * @param value the property value. 164 */ 165 public void setConfigProperty (final String key, final String value) 166 { 167 if (wrappedConfiguration instanceof ModifiableConfiguration) 168 { 169 final ModifiableConfiguration modConfiguration = 170 (ModifiableConfiguration) wrappedConfiguration; 171 modConfiguration.setConfigProperty(key, value); 172 } 173 } 174 175 /** 176 * Returns all defined configuration properties for the report. The enumeration 177 * contains all keys of the changed properties, properties set from files or 178 * the system properties are not included. 179 * 180 * @return all defined configuration properties for the report. 181 */ 182 public Enumeration getConfigProperties () 183 { 184 if (wrappedConfiguration instanceof ModifiableConfiguration) 185 { 186 final ModifiableConfiguration modConfiguration = 187 (ModifiableConfiguration) wrappedConfiguration; 188 return modConfiguration.getConfigProperties(); 189 } 190 return super.getConfigProperties(); 191 } 192 } 193 194 /** 195 * The singleton instance of the Boot class. 196 */ 197 private static JFreeReportBoot instance; 198 /** 199 * The project info contains all meta data about the project. 200 */ 201 private BootableProjectInfo projectInfo; 202 203 /** 204 * Holds a possibly empty reference to a user-supplied Configuration 205 * implementation. 206 */ 207 private static transient UserConfigWrapper configWrapper = 208 new UserConfigWrapper(); 209 210 /** 211 * Creates a new instance. 212 */ 213 private JFreeReportBoot () 214 { 215 projectInfo = JFreeReportInfo.getInstance(); 216 } 217 218 /** 219 * Returns the singleton instance of the boot utility class. 220 * 221 * @return the boot instance. 222 */ 223 public static synchronized JFreeReportBoot getInstance () 224 { 225 if (instance == null) 226 { 227 // make sure that I am able to debug the package manager .. 228 DefaultLog.installDefaultLog(); 229 instance = new JFreeReportBoot(); 230 231 HierarchicalConfiguration hc = (HierarchicalConfiguration) BaseBoot.getConfiguration(); 232 hc.insertConfiguration(new UserConfigWrapper(instance.getGlobalConfig())); 233 } 234 return instance; 235 } 236 237 /** 238 * Returns the current global configuration as modifiable instance. This 239 * is exactly the same as casting the global configuration into a 240 * ModifableConfiguration instance. 241 * <p/> 242 * This is a convinience function, as all programmers are lazy. 243 * 244 * @return the global config as modifiable configuration. 245 */ 246 public ModifiableConfiguration getEditableConfig() 247 { 248 return (ModifiableConfiguration) getGlobalConfig(); 249 } 250 251 /** 252 * Returns the project info. 253 * 254 * @return The project info. 255 */ 256 protected BootableProjectInfo getProjectInfo () 257 { 258 return projectInfo; 259 } 260 261 /** 262 * Loads the configuration. This will be called exactly once. 263 * 264 * @return The configuration. 265 */ 266 protected Configuration loadConfiguration () 267 { 268 HierarchicalConfiguration globalConfig = new HierarchicalConfiguration(); 269 270 final PropertyFileConfiguration rootProperty = new PropertyFileConfiguration(); 271 rootProperty.load("/org/jfree/report/jfreereport.properties"); 272 rootProperty.load("/org/jfree/report/ext/jfreereport-ext.properties"); 273 globalConfig.insertConfiguration(rootProperty); 274 globalConfig.insertConfiguration(JFreeReportBoot.getInstance().getPackageManager() 275 .getPackageConfiguration()); 276 277 final PropertyFileConfiguration baseProperty = new PropertyFileConfiguration(); 278 baseProperty.load("/jfreereport.properties"); 279 globalConfig.insertConfiguration(baseProperty); 280 281 globalConfig.insertConfiguration(configWrapper); 282 283 final SystemPropertyConfiguration systemConfig = new SystemPropertyConfiguration(); 284 globalConfig.insertConfiguration(systemConfig); 285 return globalConfig; 286 } 287 288 /** 289 * Performs the actual boot process. 290 */ 291 protected void performBoot () 292 { 293 // Inject JFreeReport's configuration into jcommon. 294 // make sure logging is re-initialized after we injected our configuration. 295 Log.getInstance().init(); 296 297 if (isStrictFP() == false) 298 { 299 Log.warn("The used VM seems to use a non-strict floating point arithmetics"); 300 Log.warn("Layouts computed with this Java Virtual Maschine may be invalid."); 301 Log.warn("JFreeReport and the library 'iText' depend on the strict floating point rules"); 302 Log.warn("of Java1.1 as implemented by the Sun Virtual Maschines."); 303 Log.warn("If you are using the BEA JRockit VM, start the Java VM with the option"); 304 Log.warn("'-Xstrictfp' to restore the default behaviour."); 305 } 306 307 final PackageManager mgr = getPackageManager(); 308 309 mgr.addModule(JFreeReportCoreModule.class.getName()); 310 mgr.load("org.jfree.report.modules."); 311 mgr.load("org.jfree.report.ext.modules."); 312 mgr.load("org.jfree.report.userdefined.modules."); 313 314 bootAdditionalModules(); 315 mgr.initializeModules(); 316 } 317 318 /** 319 * Boots modules, which have been spcified in the "org.jfree.report.boot.Modules" 320 * configuration parameter. 321 */ 322 private void bootAdditionalModules () 323 { 324 try 325 { 326 final String bootModules = 327 getGlobalConfig().getConfigProperty 328 ("org.jfree.report.boot.Modules"); 329 if (bootModules != null) 330 { 331 final CSVTokenizer csvToken = new CSVTokenizer(bootModules, ","); 332 while (csvToken.hasMoreTokens()) 333 { 334 final String token = csvToken.nextToken(); 335 getPackageManager().load(token); 336 } 337 } 338 } 339 catch (SecurityException se) 340 { 341 Log.info("Security settings forbid to check the system properties for extension modules."); 342 } 343 catch (Exception se) 344 { 345 Log.error 346 ("An error occured while checking the system properties for extension modules.", se); 347 } 348 } 349 350 351 /** 352 * This method returns true on non-strict floating point systems. 353 * <p/> 354 * Since Java 1.2 Virtual Maschines may implement the floating point arithmetics in a 355 * more performant way, which does not put the old strict constraints on the floating 356 * point types <code>float</code> and <code>double</code>. 357 * <p/> 358 * As iText and this library requires strict (in the sense of Java1.1) floating point 359 * operations, we have to test for that feature here. 360 * <p/> 361 * The only known VM that seems to implement that feature is the JRockit VM. The strict 362 * mode can be restored on that VM by adding the "-Xstrictfp" VM parameter. 363 * 364 * @return true, if the VM uses strict floating points by default, false otherwise. 365 */ 366 private static boolean isStrictFP () 367 { 368 final double d = 8e+307; 369 final double result1 = 4.0 * d * 0.5; 370 final double result2 = 2.0 * d; 371 return (result1 != result2 && (result1 == Double.POSITIVE_INFINITY)); 372 } 373 374 375 /** 376 * Returns the user supplied global configuration. 377 * 378 * @return the user configuration, if any. 379 */ 380 public static Configuration getUserConfig () 381 { 382 return configWrapper.getWrappedConfiguration(); 383 } 384 385 /** 386 * Defines the global user configuration. 387 * 388 * @param config the user configuration. 389 */ 390 public static void setUserConfig (final Configuration config) 391 { 392 configWrapper.setWrappedConfiguration(config); 393 } 394 395 }