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 }