001    /**
002     * Copyright 2005-2013 The Kuali Foundation
003     *
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.opensource.org/licenses/ecl2.php
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.rice.kew.plugin;
017    
018    /**
019     * A PluginEnvironment represents a Plugin and the PluginLoader from which it was loaded.
020     * Grouping these together allows us to execute a reload of the Plugin since the Plugin
021     * itself is not responsible for handling how it's own loading or reloading.
022     * 
023     * <p>The PluginEnvironment also keeps a reference to the PluginRegistry because this
024     * allows it to add and remove Plugins as child resource loaders of the registry.
025     *
026     * @author Kuali Rice Team (rice.collab@kuali.org)
027     */
028    public class PluginEnvironment implements Reloadable {
029    
030            private boolean loaded = false;
031            private Plugin plugin;
032            private final PluginLoader loader;
033            private final PluginRegistry registry;
034            private boolean supressStartupFailure = true;
035            
036            /**
037             * Constructs an unloaded PluginEnvironment from the given PluginLoader and PluginRegistry.
038             * The environment will not be loaded until the first time that load() is executed.
039             */
040            public PluginEnvironment(PluginLoader loader, PluginRegistry registry) {
041                    this.loader = loader;
042                    this.registry = registry;
043            }
044            
045            /**
046             * Constructs a PluginEnvironment representing the given loaded Plugin.  Environments created
047             * in this manner will indicate that they are loaded from the moment they are constructed.
048             */
049            public PluginEnvironment(Plugin plugin, PluginLoader loader, PluginRegistry registry) {
050                    this(loader, registry);
051                    this.plugin = plugin;
052                    this.loaded = true;
053            }
054    
055            /**
056             * Returns true if this environment has been loaded, false otherwise.  If this method returns
057             * false then getPlugin() may return null if the environment was never loaded after construction.
058             */
059            public boolean isLoaded() {
060                    return loaded;
061            }
062            
063        /**
064             * Returns a boolean indicating whether or not this PluginEnvironment is truly reloadable.
065             * 
066             * This will return false if the Plugin represents a plugin which can not be reloaded.
067             */
068            public boolean isReloadable() {
069                return true;
070            }
071    
072            /**
073             * Indicates whether or not a reload of this environment is needed.  If this method
074             * returns true, it should continue to return true until a reload() is executed.
075             */
076            public synchronized boolean isReloadNeeded() {
077                    return loader.isModified();
078            }
079            
080            /**
081             * Reloads the environment by effectively executing an unload() followed by a load().
082             */
083            public synchronized void reload() throws Exception {
084                    unload();
085                    load();
086            }
087            
088            /**
089             * Loads the plugin from the PluginLoader.  This will also start the Plugin and add it
090             * to the PluginRegistry's resoure loaders.
091             */
092            public synchronized void load() throws Exception {
093                plugin = loader.load();
094                    plugin.setSupressStartupFailure(supressStartupFailure);
095                    // it's important that the plugin is added to the resource loading system prior to startup because
096                    // startup may need to grab services
097                    registry.addResourceLoader(plugin);
098                    plugin.start();
099                    loaded = true;
100            }
101    
102            /**
103             * Unloads the plugin.  The effectively shuts the plugin down and removes it from the
104             * PluginRegistry's resource loaders.
105             * @throws Exception
106             */
107            public synchronized void unload() throws Exception {
108                if (plugin != null) {
109                    plugin.stop();
110                    // it's important that the plugin be removed from the resource loading system after shutdown in
111                    // case the plugin needs to access the resource loader during shutdown
112                    registry.removeResourceLoader(plugin.getName());
113                }
114                    loaded = false;
115            }
116            
117            public String getPluginName() {
118                if (getPlugin() != null) {
119                    return getPlugin().getName().getLocalPart();
120                }
121                return loader.getPluginName();
122            }
123            
124            /**
125             * Gets the Plugin represented by this environment.  May be null if this environment has not
126             * yet been loaded.
127             */
128            public Plugin getPlugin() {
129                    return plugin;
130            }
131    
132            /**
133             * Gets the PluginLoader which loaded the Plugin in this environment.
134             */
135            public PluginLoader getLoader() {
136                    return loader;
137            }
138            
139            /**
140             * By default, startup failure is supressed.  If it is indicated that startup failure
141             * supression is not desired, then startup errors will be thrown directly from calls to
142             * load().
143             */
144            public void setSupressStartupFailure(boolean supressStartupFailure) {
145                    this.supressStartupFailure = supressStartupFailure;
146            }
147            
148    }