Source for org.jfree.report.JFreeReportBoot

   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: }