001: /* ========================================================================
002: * JCommon : a free general purpose class library for the Java(tm) platform
003: * ========================================================================
004: *
005: * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
006: *
007: * Project Info: http://www.jfree.org/jcommon/index.html
008: *
009: * This library is free software; you can redistribute it and/or modify it
010: * under the terms of the GNU Lesser General Public License as published by
011: * the Free Software Foundation; either version 2.1 of the License, or
012: * (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful, but
015: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017: * License for more details.
018: *
019: * You should have received a copy of the GNU Lesser General Public
020: * License along with this library; if not, write to the Free Software
021: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
022: * USA.
023: *
024: * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025: * in the United States and other countries.]
026: *
027: * -----------------
028: * AbstractBoot.java
029: * -----------------
030: * (C)opyright 2004, 2005, by Thomas Morgner and Contributors.
031: *
032: * Original Author: Thomas Morgner;
033: * Contributor(s): David Gilbert (for Object Refinery Limited);
034: *
035: * $Id: AbstractBoot.java,v 1.19 2006/12/11 12:02:27 taqua Exp $
036: *
037: * Changes
038: * -------
039: * 07-Jun-2004 : Added source headers (DG);
040: * 18-Aug-2005 : Added casts to suppress compiler warnings, as suggested in
041: * patch 1260622 (DG);
042: *
043: */
044:
045: package org.jfree.base;
046:
047: import java.io.IOException;
048: import java.io.InputStream;
049: import java.lang.reflect.Method;
050: import java.net.URL;
051: import java.util.ArrayList;
052: import java.util.Enumeration;
053:
054: import org.jfree.base.config.HierarchicalConfiguration;
055: import org.jfree.base.config.PropertyFileConfiguration;
056: import org.jfree.base.config.SystemPropertyConfiguration;
057: import org.jfree.base.modules.PackageManager;
058: import org.jfree.base.modules.SubSystem;
059: import org.jfree.util.Configuration;
060: import org.jfree.util.ExtendedConfiguration;
061: import org.jfree.util.ExtendedConfigurationWrapper;
062: import org.jfree.util.Log;
063: import org.jfree.util.ObjectUtilities;
064:
065: /**
066: * The common base for all Boot classes.
067: * <p>
068: * This initializes the subsystem and all dependent subsystems.
069: * Implementors of this class have to provide a public static
070: * getInstance() method which returns a singleton instance of the
071: * booter implementation.
072: * <p>
073: * Further creation of Boot object should be prevented using
074: * protected or private constructors in that class, or proper
075: * initialzation cannot be guaranteed.
076: *
077: * @author Thomas Morgner
078: */
079: public abstract class AbstractBoot implements SubSystem {
080:
081: /** The configuration wrapper around the plain configuration. */
082: private ExtendedConfigurationWrapper extWrapper;
083:
084: /** A packageManager instance of the package manager. */
085: private PackageManager packageManager;
086:
087: /** Global configuration. */
088: private Configuration globalConfig;
089:
090: /** A flag indicating whether the booting is currenly in progress. */
091: private boolean bootInProgress;
092:
093: /** A flag indicating whether the booting is complete. */
094: private boolean bootDone;
095:
096: /**
097: * Default constructor.
098: */
099: protected AbstractBoot() {
100: }
101:
102: /**
103: * Returns the packageManager instance of the package manager.
104: *
105: * @return The package manager.
106: */
107: public synchronized PackageManager getPackageManager() {
108: if (this .packageManager == null) {
109: this .packageManager = PackageManager.createInstance(this );
110: }
111: return this .packageManager;
112: }
113:
114: /**
115: * Returns the global configuration.
116: *
117: * @return The global configuration.
118: */
119: public synchronized Configuration getGlobalConfig() {
120: if (this .globalConfig == null) {
121: this .globalConfig = loadConfiguration();
122: }
123: return this .globalConfig;
124: }
125:
126: /**
127: * Checks, whether the booting is in progress.
128: *
129: * @return true, if the booting is in progress, false otherwise.
130: */
131: public final synchronized boolean isBootInProgress() {
132: return this .bootInProgress;
133: }
134:
135: /**
136: * Checks, whether the booting is complete.
137: *
138: * @return true, if the booting is complete, false otherwise.
139: */
140: public final synchronized boolean isBootDone() {
141: return this .bootDone;
142: }
143:
144: /**
145: * Loads the configuration. This will be called exactly once.
146: *
147: * @return The configuration.
148: */
149: protected abstract Configuration loadConfiguration();
150:
151: /**
152: * Starts the boot process.
153: */
154: public final void start() {
155:
156: synchronized (this ) {
157: if (isBootDone()) {
158: return;
159: }
160: while (isBootInProgress()) {
161: try {
162: wait();
163: } catch (InterruptedException e) {
164: // ignore ..
165: }
166: }
167: if (isBootDone()) {
168: return;
169: }
170: this .bootInProgress = true;
171: }
172:
173: // boot dependent libraries ...
174: final BootableProjectInfo info = getProjectInfo();
175: if (info != null) {
176: final BootableProjectInfo[] childs = info.getDependencies();
177: for (int i = 0; i < childs.length; i++) {
178: final AbstractBoot boot = loadBooter(childs[i]
179: .getBootClass());
180: if (boot != null) {
181: // but we're waiting until the booting is complete ...
182: synchronized (boot) {
183: boot.start();
184: while (boot.isBootDone() == false) {
185: try {
186: boot.wait();
187: } catch (InterruptedException e) {
188: // ignore it ..
189: }
190: }
191: }
192: }
193: }
194: }
195:
196: performBoot();
197: if (info != null) {
198: Log.info(info.getName() + " " + info.getVersion()
199: + " started.");
200: } else {
201: Log.info(getClass() + " started.");
202: }
203:
204: synchronized (this ) {
205: this .bootInProgress = false;
206: this .bootDone = true;
207: notifyAll();
208: }
209: }
210:
211: /**
212: * Performs the boot.
213: */
214: protected abstract void performBoot();
215:
216: /**
217: * Returns the project info.
218: *
219: * @return The project info.
220: */
221: protected abstract BootableProjectInfo getProjectInfo();
222:
223: /**
224: * Loads the specified booter implementation.
225: *
226: * @param classname the class name.
227: *
228: * @return The boot class.
229: */
230: protected AbstractBoot loadBooter(final String classname) {
231: if (classname == null) {
232: return null;
233: }
234: try {
235: final Class c = ObjectUtilities.getClassLoader(getClass())
236: .loadClass(classname);
237: final Method m = c.getMethod("getInstance", (Class[]) null);
238: return (AbstractBoot) m.invoke(null, (Object[]) null);
239: } catch (Exception e) {
240: Log.info("Unable to boot dependent class: " + classname);
241: return null;
242: }
243: }
244:
245: /**
246: * Creates a default configuration setup, which loads its settings from
247: * the static configuration (defaults provided by the developers of the
248: * library) and the user configuration (settings provided by the deployer).
249: * The deployer's settings override the developer's settings.
250: *
251: * If the parameter <code>addSysProps</code> is set to true, the system
252: * properties will be added as third configuration layer. The system
253: * properties configuration allows to override all other settings.
254: *
255: * @param staticConfig the resource name of the developers configuration
256: * @param userConfig the resource name of the deployers configuration
257: * @param addSysProps a flag defining whether to include the system
258: * properties into the configuration.
259: * @return the configured Configuration instance.
260: */
261: protected Configuration createDefaultHierarchicalConfiguration(
262: final String staticConfig, final String userConfig,
263: final boolean addSysProps) {
264: final HierarchicalConfiguration globalConfig = new HierarchicalConfiguration();
265:
266: if (staticConfig != null) {
267: final PropertyFileConfiguration rootProperty = new PropertyFileConfiguration();
268: rootProperty.load(staticConfig);
269: globalConfig.insertConfiguration(rootProperty);
270: globalConfig.insertConfiguration(getPackageManager()
271: .getPackageConfiguration());
272: }
273: if (userConfig != null) {
274: String userConfigStripped;
275: if (userConfig.startsWith("/")) {
276: userConfigStripped = userConfig.substring(1);
277: } else {
278: userConfigStripped = userConfig;
279: }
280: try {
281: final Enumeration userConfigs = ObjectUtilities
282: .getClassLoader(getClass()).getResources(
283: userConfigStripped);
284: final ArrayList configs = new ArrayList();
285: while (userConfigs.hasMoreElements()) {
286: final URL url = (URL) userConfigs.nextElement();
287: try {
288: final PropertyFileConfiguration baseProperty = new PropertyFileConfiguration();
289: final InputStream in = url.openStream();
290: baseProperty.load(in);
291: in.close();
292: configs.add(baseProperty);
293: } catch (IOException ioe) {
294: Log.warn(
295: "Failed to load the user configuration at "
296: + url, ioe);
297: }
298: }
299:
300: for (int i = configs.size() - 1; i >= 0; i--) {
301: final PropertyFileConfiguration baseProperty = (PropertyFileConfiguration) configs
302: .get(i);
303: globalConfig.insertConfiguration(baseProperty);
304: }
305: } catch (IOException e) {
306: Log
307: .warn(
308: "Failed to lookup the user configurations.",
309: e);
310: }
311: }
312: final SystemPropertyConfiguration systemConfig = new SystemPropertyConfiguration();
313: globalConfig.insertConfiguration(systemConfig);
314: return globalConfig;
315: }
316:
317: /**
318: * Returns the global configuration as extended configuration.
319: *
320: * @return the extended configuration.
321: */
322: public synchronized ExtendedConfiguration getExtendedConfig() {
323: if (extWrapper == null) {
324: extWrapper = new ExtendedConfigurationWrapper(
325: getGlobalConfig());
326: }
327: return extWrapper;
328: }
329: }
|