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.21 2008/09/10 09:22:57 mungady 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 }
164 catch (InterruptedException e) {
165 // ignore ..
166 }
167 }
168 if (isBootDone()) {
169 return;
170 }
171 this.bootInProgress = true;
172 }
173
174 // boot dependent libraries ...
175 final BootableProjectInfo info = getProjectInfo();
176 if (info != null) {
177 final BootableProjectInfo[] childs = info.getDependencies();
178 for (int i = 0; i < childs.length; i++) {
179 final AbstractBoot boot = loadBooter(childs[i].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 }
188 catch (InterruptedException e) {
189 // ignore it ..
190 }
191 }
192 }
193 }
194 }
195 }
196
197 performBoot();
198 if (info != null)
199 {
200 Log.info (info.getName() + " " + info.getVersion() + " started.");
201 }
202 else
203 {
204 Log.info (getClass() + " started.");
205 }
206
207 synchronized (this) {
208 this.bootInProgress = false;
209 this.bootDone = true;
210 notifyAll();
211 }
212 }
213
214 /**
215 * Performs the boot.
216 */
217 protected abstract void performBoot();
218
219 /**
220 * Returns the project info.
221 *
222 * @return The project info.
223 */
224 protected abstract BootableProjectInfo getProjectInfo();
225
226 /**
227 * Loads the specified booter implementation.
228 *
229 * @param classname the class name.
230 *
231 * @return The boot class.
232 */
233 protected AbstractBoot loadBooter(final String classname) {
234 if (classname == null) {
235 return null;
236 }
237 try {
238 final Class c = ObjectUtilities.getClassLoader(
239 getClass()).loadClass(classname);
240 final Method m = c.getMethod("getInstance", (Class[]) null);
241 return (AbstractBoot) m.invoke(null, (Object[]) null);
242 }
243 catch (Exception e) {
244 Log.info ("Unable to boot dependent class: " + classname);
245 return null;
246 }
247 }
248
249 /**
250 * Creates a default configuration setup, which loads its settings from
251 * the static configuration (defaults provided by the developers of the
252 * library) and the user configuration (settings provided by the deployer).
253 * The deployer's settings override the developer's settings.
254 *
255 * If the parameter <code>addSysProps</code> is set to true, the system
256 * properties will be added as third configuration layer. The system
257 * properties configuration allows to override all other settings.
258 *
259 * @param staticConfig the resource name of the developers configuration
260 * @param userConfig the resource name of the deployers configuration
261 * @param addSysProps a flag defining whether to include the system
262 * properties into the configuration.
263 * @return the configured Configuration instance.
264 */
265 protected Configuration createDefaultHierarchicalConfiguration
266 (final String staticConfig, final String userConfig,
267 final boolean addSysProps)
268 {
269 return createDefaultHierarchicalConfiguration
270 (staticConfig, userConfig, addSysProps, PropertyFileConfiguration.class);
271 }
272
273 /**
274 * Creates a default hierarchical configuration.
275 *
276 * @param staticConfig the static configuration.
277 * @param userConfig the user configuration.
278 * @param addSysProps additional system properties.
279 * @param source the source.
280 *
281 * @return The configuration.
282 */
283 protected Configuration createDefaultHierarchicalConfiguration
284 (final String staticConfig, final String userConfig,
285 final boolean addSysProps, final Class source)
286 {
287 final HierarchicalConfiguration globalConfig
288 = new HierarchicalConfiguration();
289
290 if (staticConfig != null) {
291 final PropertyFileConfiguration rootProperty
292 = new PropertyFileConfiguration();
293 rootProperty.load(staticConfig, getClass());
294 globalConfig.insertConfiguration(rootProperty);
295 globalConfig.insertConfiguration(
296 getPackageManager().getPackageConfiguration());
297 }
298 if (userConfig != null) {
299 String userConfigStripped;
300 if (userConfig.startsWith("/")) {
301 userConfigStripped = userConfig.substring(1);
302 }
303 else {
304 userConfigStripped = userConfig;
305 }
306 try {
307 final Enumeration userConfigs = ObjectUtilities.getClassLoader
308 (getClass()).getResources(userConfigStripped);
309 final ArrayList configs = new ArrayList();
310 while (userConfigs.hasMoreElements()) {
311 final URL url = (URL) userConfigs.nextElement();
312 try {
313 final PropertyFileConfiguration baseProperty =
314 new PropertyFileConfiguration();
315 final InputStream in = url.openStream();
316 baseProperty.load(in);
317 in.close();
318 configs.add(baseProperty);
319 }
320 catch(IOException ioe) {
321 Log.warn ("Failed to load the user configuration at " + url, ioe);
322 }
323 }
324
325 for (int i = configs.size() - 1; i >= 0; i--) {
326 final PropertyFileConfiguration baseProperty =
327 (PropertyFileConfiguration) configs.get(i);
328 globalConfig.insertConfiguration(baseProperty);
329 }
330 }
331 catch (IOException e) {
332 Log.warn ("Failed to lookup the user configurations.", e);
333 }
334 }
335 if (addSysProps) {
336 final SystemPropertyConfiguration systemConfig
337 = new SystemPropertyConfiguration();
338 globalConfig.insertConfiguration(systemConfig);
339 }
340 return globalConfig;
341 }
342
343 /**
344 * Returns the global configuration as extended configuration.
345 *
346 * @return the extended configuration.
347 */
348 public synchronized ExtendedConfiguration getExtendedConfig ()
349 {
350 if (this.extWrapper == null) {
351 this.extWrapper = new ExtendedConfigurationWrapper(getGlobalConfig());
352 }
353 return this.extWrapper;
354 }
355 }