001: /*
002: * Copyright 2005-2006 The Kuali Foundation.
003: *
004: *
005: * Licensed under the Educational Community License, Version 1.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.opensource.org/licenses/ecl1.php
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package edu.iu.uis.eden.plugin;
018:
019: import java.io.File;
020: import java.io.FileNotFoundException;
021: import java.io.IOException;
022: import java.net.MalformedURLException;
023: import java.net.URL;
024:
025: import javax.xml.namespace.QName;
026:
027: import org.apache.log4j.Logger;
028: import org.kuali.rice.config.Config;
029: import org.kuali.rice.core.Core;
030: import org.kuali.rice.resourceloader.ContextClassLoaderBinder;
031:
032: import edu.iu.uis.eden.exception.InvalidXmlException;
033: import edu.iu.uis.eden.plugin.manifest.PluginManifest;
034: import edu.iu.uis.eden.plugin.manifest.PluginManifestParser;
035: import edu.iu.uis.eden.util.ClassLoaderUtils;
036: import edu.iu.uis.eden.util.Utilities;
037:
038: /**
039: * Abstract base PluginLoader implementation.
040: * Delegates to template methods to obtain plugin ClassLoader and plugin manifest file URL,
041: * then load the manifest under the plugin ClassLoader, and constructs a Plugin object.
042: *
043: * @author ahamid
044: * @author ewestfal
045: */
046: public abstract class BasePluginLoader implements PluginLoader {
047: private static final Logger LOG = Logger
048: .getLogger(BasePluginLoader.class);
049:
050: private static final String META_INF_PATH = "META-INF";
051: private static final String PLUGIN_MANIFEST_PATH = META_INF_PATH
052: + "/workflow.xml";
053:
054: protected final String simplePluginName;
055: protected final boolean institutionalPlugin;
056: protected String logPrefix;
057:
058: protected final ClassLoader parentClassLoader;
059: protected final Config parentConfig;
060: protected final File sharedPluginDirectory;
061: protected String pluginManifestPath = PLUGIN_MANIFEST_PATH;
062:
063: public BasePluginLoader(String simplePluginName,
064: File sharedPluginDirectory, ClassLoader parentClassLoader,
065: Config parentConfig, boolean institutionalPlugin) {
066: this .sharedPluginDirectory = sharedPluginDirectory;
067: if (parentClassLoader == null) {
068: parentClassLoader = ClassLoaderUtils
069: .getDefaultClassLoader();
070: }
071: this .parentClassLoader = parentClassLoader;
072: this .parentConfig = parentConfig;
073: this .institutionalPlugin = institutionalPlugin;
074: this .simplePluginName = simplePluginName;
075: this .logPrefix = simplePluginName;
076: }
077:
078: protected String getLogPrefix() {
079: return logPrefix;
080: }
081:
082: public void setPluginManifestPath(String pluginManifestPath) {
083: this .pluginManifestPath = pluginManifestPath;
084: }
085:
086: protected String getSimplePluginName() {
087: return simplePluginName;
088: }
089:
090: /**
091: * Template method that subclasses should implement to supply an appropriate
092: * plugin ClassLoader
093: * @return an appropriate PluginClassLoader
094: * @throws IOException if anything goes awry
095: */
096: protected abstract PluginClassLoader createPluginClassLoader()
097: throws IOException;
098:
099: /**
100: * Template method that subclasses should implement to supply an appropriate
101: * URL to the plugin's manifest
102: * @return an appropriate URL to the plugin's manifest
103: * @throws IOException if anything goes awry
104: */
105: protected abstract URL getPluginManifestURL()
106: throws PluginException, IOException;
107:
108: /**
109: * Loads and creates the Plugin.
110: */
111: public Plugin load() throws Exception {
112: PluginClassLoader classLoader = createPluginClassLoader();
113: LOG.info("Created plugin ClassLoader: " + classLoader);
114: ContextClassLoaderBinder.bind(classLoader);
115: try {
116: return loadWithinContextClassLoader(classLoader);
117: } finally {
118: ContextClassLoaderBinder.unbind();
119: }
120: }
121:
122: public boolean isRemoved() {
123: return false;
124: }
125:
126: /**
127: * Executes loading of the plugin within the current context classloader set to the Plugin's classloader.
128: */
129: protected Plugin loadWithinContextClassLoader(
130: PluginClassLoader classLoader) throws PluginException,
131: IOException {
132: URL url = getPluginManifestURL();
133: PluginManifest pluginManifest = loadPluginManifest(url);
134: QName qPluginName = getPluginName(pluginManifest);
135: classLoader.setConfig(pluginManifest);
136: Core.init(classLoader, pluginManifest);
137: configureExtraClasspath(classLoader, pluginManifest);
138: this .logPrefix = PluginUtils.getLogPrefix(qPluginName,
139: institutionalPlugin).toString();
140: LOG.info("Constructing plugin '" + simplePluginName
141: + "' with classloader: " + classLoader);
142: Plugin plugin = new Plugin(qPluginName, pluginManifest,
143: classLoader);
144: installResourceLoader(plugin);
145: installPluginListeners(plugin);
146: return plugin;
147: }
148:
149: protected void installResourceLoader(Plugin plugin) {
150: PluginUtils.installResourceLoader(plugin);
151: }
152:
153: protected void installPluginListeners(Plugin plugin) {
154: PluginUtils.installPluginListeners(plugin);
155: }
156:
157: protected void configureExtraClasspath(
158: PluginClassLoader classLoader, PluginManifest manifest)
159: throws MalformedURLException {
160: String extraClassesDirs = manifest
161: .getProperty(Config.EXTRA_CLASSES_DIR);
162: if (!Utilities.isEmpty(extraClassesDirs)) {
163: String[] extraClasses = extraClassesDirs.split(",");
164: for (int index = 0; index < extraClasses.length; index++) {
165: File extraClassesDir = new File(extraClasses[index]);
166: if (extraClassesDir.exists()) {
167: classLoader.addClassesDirectory(extraClassesDir);
168: }
169: }
170: }
171: String extraLibDirs = manifest
172: .getProperty(Config.EXTRA_LIB_DIR);
173: if (!Utilities.isEmpty(extraLibDirs)) {
174: String[] extraLibs = extraLibDirs.split(",");
175: for (int index = 0; index < extraLibs.length; index++) {
176: File extraLibDir = new File(extraLibs[index]);
177: if (extraLibDir.exists()) {
178: classLoader.addLibDirectory(extraLibDir);
179: }
180: }
181: }
182: }
183:
184: protected QName getPluginName(PluginManifest pluginManifest) {
185: String messageEntity = pluginManifest.getMessageEntity();
186: QName qPluginName = null;
187: if (messageEntity == null) {
188: qPluginName = new QName(Core.getCurrentContextConfig()
189: .getMessageEntity(), simplePluginName);
190: } else {
191: qPluginName = new QName(messageEntity, simplePluginName);
192: }
193: return qPluginName;
194: }
195:
196: protected PluginManifest loadPluginManifest(URL url) {
197: PluginManifestParser parser = new PluginManifestParser();
198: try {
199: PluginManifest pluginManifest = parser.parse(url,
200: parentConfig);
201: pluginManifest.parseConfig();
202: return pluginManifest;
203: } catch (FileNotFoundException e) {
204: throw new PluginException(
205: getLogPrefix()
206: + " Could not locate the plugin manifest file at path "
207: + url, e);
208: } catch (IOException ioe) {
209: throw new PluginException(getLogPrefix()
210: + " Could not read the plugin manifest file", ioe);
211: } catch (InvalidXmlException ixe) {
212: throw new PluginException(getLogPrefix()
213: + " Could not parse the plugin manifest file", ixe);
214: }
215: }
216: }
|