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 }