    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    }