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