001/**
002 * Copyright 2005-2016 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 */
016package 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 */
028public 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 suppressStartupFailure = 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.setSuppressStartupFailure(suppressStartupFailure);
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 suppressed.  If it is indicated that startup failure
141         * suppression is not desired, then startup errors will be thrown directly from calls to
142         * load().
143         */
144        public void setSuppressStartupFailure(boolean suppressStartupFailure) {
145                this.suppressStartupFailure = suppressStartupFailure;
146        }
147        
148}