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.13 2005/11/03 09:54:59 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.lang.reflect.Method;
048    
049    import org.jfree.base.config.HierarchicalConfiguration;
050    import org.jfree.base.config.PropertyFileConfiguration;
051    import org.jfree.base.config.SystemPropertyConfiguration;
052    import org.jfree.base.modules.PackageManager;
053    import org.jfree.base.modules.SubSystem;
054    import org.jfree.util.Configuration;
055    import org.jfree.util.Log;
056    import org.jfree.util.ObjectUtilities;
057    import org.jfree.util.ExtendedConfiguration;
058    import org.jfree.util.ExtendedConfigurationWrapper;
059    
060    /**
061     * The common base for all Boot classes.
062     * <p>
063     * This initializes the subsystem and all dependent subsystems.
064     * Implementors of this class have to provide a public static
065     * getInstance() method which returns a singleton instance of the
066     * booter implementation.
067     * <p>
068     * Further creation of Boot object should be prevented using
069     * protected or private constructors in that class, or proper
070     * initialzation cannot be guaranteed.
071     *
072     * @author Thomas Morgner
073     */
074    public abstract class AbstractBoot implements SubSystem {
075    
076        /** The configuration wrapper around the plain configuration. */
077        private ExtendedConfigurationWrapper extWrapper;
078    
079        /** A packageManager instance of the package manager. */
080        private PackageManager packageManager;
081      
082        /** Global configuration. */
083        private Configuration globalConfig;
084    
085        /** A flag indicating whether the booting is currenly in progress. */
086        private boolean bootInProgress;
087        
088        /** A flag indicating whether the booting is complete. */
089        private boolean bootDone;
090    
091        /**
092         * Default constructor.
093         */
094        protected AbstractBoot() {
095        }
096    
097        /**
098         * Returns the packageManager instance of the package manager.
099         *
100         * @return The package manager.
101         */
102        public synchronized PackageManager getPackageManager() {
103            if (this.packageManager == null) {
104                this.packageManager = PackageManager.createInstance(this);
105            }
106            return this.packageManager;
107        }
108    
109        /**
110         * Returns the global configuration.
111         * 
112         * @return The global configuration.
113         */
114        public synchronized Configuration getGlobalConfig() {
115            if (this.globalConfig == null) {
116                this.globalConfig = loadConfiguration();
117                start();
118            }
119            return this.globalConfig;
120        }
121    
122        /**
123         * Checks, whether the booting is in progress.
124         *
125         * @return true, if the booting is in progress, false otherwise.
126         */
127        public final synchronized boolean isBootInProgress() {
128            return this.bootInProgress;
129        }
130    
131        /**
132         * Checks, whether the booting is complete.
133         *
134         * @return true, if the booting is complete, false otherwise.
135         */
136        public final synchronized boolean isBootDone() {
137            return this.bootDone;
138        }
139    
140        /**
141         * Loads the configuration. This will be called exactly once.
142         * 
143         * @return The configuration.
144         */
145        protected abstract Configuration loadConfiguration();
146    
147        /**
148         * Starts the boot process.
149         */
150        public final void start() {
151    
152            synchronized (this) {
153                if (isBootInProgress() || isBootDone()) {
154                    return;
155                }
156                this.bootInProgress = true;
157            }
158    
159            // boot dependent libraries ...
160            final BootableProjectInfo info = getProjectInfo();
161            if (info != null) {
162                Log.info (info.getName() + " " + info.getVersion());
163                final BootableProjectInfo[] childs = info.getDependencies();
164                for (int i = 0; i < childs.length; i++) {
165                    final AbstractBoot boot = loadBooter(childs[i].getBootClass());
166                    if (boot != null) {
167                        boot.start();
168                    }
169                }
170            }
171            performBoot();
172    
173            synchronized (this) {
174                this.bootInProgress = false;
175                this.bootDone = true;
176            }
177        }
178    
179        /**
180         * Performs the boot.
181         */
182        protected abstract void performBoot();
183    
184        /**
185         * Returns the project info.
186         *
187         * @return The project info.
188         */
189        protected abstract BootableProjectInfo getProjectInfo();
190    
191        /**
192         * Loads the specified booter implementation.
193         * 
194         * @param classname  the class name.
195         * 
196         * @return The boot class.
197         */
198        protected AbstractBoot loadBooter(final String classname) {
199            if (classname == null) {
200                return null;
201            }
202            try {
203                final Class c = ObjectUtilities.getClassLoader(
204                        getClass()).loadClass(classname);
205                final Method m = c.getMethod("getInstance", (Class[]) null);
206                return (AbstractBoot) m.invoke(null, (Object[]) null);
207            }
208            catch (Exception e) {
209                Log.info ("Unable to boot dependent class: " + classname);
210                return null;
211            }
212        }
213    
214        /**
215         * Creates a default configuration setup, which loads its settings from
216         * the static configuration (defaults provided by the developers of the
217         * library) and the user configuration (settings provided by the deployer).
218         * The deployer's settings override the developer's settings.
219         *
220         * If the parameter <code>addSysProps</code> is set to true, the system
221         * properties will be added as third configuration layer. The system 
222         * properties configuration allows to override all other settings.
223         *
224         * @param staticConfig the resource name of the developers configuration
225         * @param userConfig the resource name of the deployers configuration
226         * @param addSysProps a flag defining whether to include the system 
227         *                    properties into the configuration.
228         * @return the configured Configuration instance.
229         */
230        protected Configuration createDefaultHierarchicalConfiguration
231            (final String staticConfig, final String userConfig, 
232                    final boolean addSysProps)
233        {
234            final HierarchicalConfiguration globalConfig 
235                = new HierarchicalConfiguration();
236    
237            if (staticConfig != null) {
238              final PropertyFileConfiguration rootProperty 
239                  = new PropertyFileConfiguration();
240              rootProperty.load(staticConfig);
241              globalConfig.insertConfiguration(rootProperty);
242              globalConfig.insertConfiguration(
243                      getPackageManager().getPackageConfiguration());
244            }
245            if (userConfig != null)
246            {
247              final PropertyFileConfiguration baseProperty 
248                  = new PropertyFileConfiguration();
249              baseProperty.load(userConfig);
250              globalConfig.insertConfiguration(baseProperty);
251            }
252            final SystemPropertyConfiguration systemConfig 
253                = new SystemPropertyConfiguration();
254            globalConfig.insertConfiguration(systemConfig);
255            return globalConfig;
256        }
257    
258        /**
259         * Returns the global configuration as extended configuration.
260         *
261         * @return the extended configuration.
262         */
263        public synchronized ExtendedConfiguration getExtendedConfig ()
264        {
265          if (extWrapper == null)
266          {
267            extWrapper = new ExtendedConfigurationWrapper(getGlobalConfig());
268          }
269          return extWrapper;
270        }
271    }