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.IOException;
021: import java.net.MalformedURLException;
022: import java.net.URL;
023: import java.net.URLClassLoader;
024: import java.util.Enumeration;
025:
026: import org.kuali.rice.lifecycle.Lifecycle;
027:
028: import edu.iu.uis.eden.plugin.manifest.PluginManifest;
029: import edu.iu.uis.eden.util.SimpleEnumeration;
030:
031: /**
032: * A simple class loader implementation which looks at itself before delegating to its parent.
033: *
034: * @author ewestfal
035: */
036: public class PluginClassLoader extends URLClassLoader implements
037: Lifecycle {//implements Modifiable {
038: static final String CLASSES_DIR = "classes";
039: static final String LIB_DIR = "lib";
040: private static final String[] SYSTEM_CLASSES = new String[] {
041: "java.", "javax.servlet.", "javax.xml.",
042: "javax.management.", "org.xml.", "org.w3c." };
043:
044: //private ModificationTracker modTracker = new ModificationTracker();
045: //this is purposely typed.
046: private PluginManifest config;
047: private boolean started = false;
048:
049: public PluginClassLoader() {
050: super (new URL[0]);
051: }
052:
053: public PluginClassLoader(ClassLoader parent) {
054: super (new URL[0], parent);
055: }
056:
057: public PluginClassLoader(ClassLoader parent, File sharedDirectory,
058: File pluginDirectory) throws MalformedURLException {
059: super (new URL[0], parent);
060: if (sharedDirectory != null) {
061: addClassesDirectory(new File(sharedDirectory, CLASSES_DIR));
062: addLibDirectory(new File(sharedDirectory, LIB_DIR));
063: }
064: addClassesDirectory(new File(pluginDirectory, CLASSES_DIR));
065: addLibDirectory(new File(pluginDirectory, LIB_DIR));
066: }
067:
068: public void addClassesDirectory(File classesDir)
069: throws MalformedURLException {
070: if (classesDir != null && classesDir.isDirectory()) {
071: addURL(classesDir.toURL());
072: }
073: }
074:
075: public void addLibDirectory(File libDir)
076: throws MalformedURLException {
077: File[] jars = PluginUtils.findJars(libDir);
078: for (int index = 0; index < jars.length; index++) {
079: addURL(jars[index].toURL());
080: }
081: }
082:
083: public Class loadClass(String className)
084: throws ClassNotFoundException {
085: return loadClass(className, false);
086: }
087:
088: public void addURL(URL url) {
089: super .addURL(url);
090: //modTracker.addURL(url);
091: }
092:
093: //public boolean isModified() {
094: // return modTracker.isModified();
095: //}
096:
097: public synchronized Class loadClass(String name, boolean resolve)
098: throws ClassNotFoundException {
099: Class loadedClass = loadExistingClass(name, resolve);
100: if (loadedClass != null) {
101: return loadedClass;
102: }
103: loadedClass = loadSystemClass(name, resolve);
104: if (loadedClass != null) {
105: return loadedClass;
106: }
107: loadedClass = loadLocalClass(name, resolve);
108: if (loadedClass != null) {
109: return loadedClass;
110: }
111: loadedClass = loadParentClass(name, resolve);
112: if (loadedClass != null) {
113: return loadedClass;
114: }
115: throw new ClassNotFoundException(name);
116: }
117:
118: public URL getResource(String name) {
119: URL resource = findResource(name);
120: if (resource == null) {
121: resource = getParent().getResource(name);
122: }
123: return resource;
124: }
125:
126: public Enumeration<URL> getResources(String name)
127: throws IOException {
128: Enumeration<URL> localResources = findResources(name);
129: Enumeration<URL> parentResources = getParent().getResources(
130: name);
131: return new SimpleEnumeration<URL>(localResources,
132: parentResources);
133: }
134:
135: private Class loadExistingClass(String name, boolean resolve) {
136: Class loadedClass = findLoadedClass(name);
137: if (loadedClass != null && resolve) {
138: resolveClass(loadedClass);
139: }
140: return loadedClass;
141: }
142:
143: private Class loadSystemClass(String name, boolean resolve) {
144: Class loadedClass = null;
145: if (isSystemClass(name)) {
146: try {
147: loadedClass = getSystemClassLoader().loadClass(name);
148: if (loadedClass != null && resolve) {
149: resolveClass(loadedClass);
150: }
151: } catch (ClassNotFoundException e) {
152: // not found in system class loader
153: }
154: }
155: return loadedClass;
156: }
157:
158: private Class loadLocalClass(String name, boolean resolve) {
159: Class loadedClass = null;
160: try {
161: loadedClass = findClass(name);
162: if (loadedClass != null && resolve) {
163: resolveClass(loadedClass);
164: }
165: } catch (ClassNotFoundException e) {
166: // not found locally
167: }
168: return loadedClass;
169: }
170:
171: private Class loadParentClass(String name, boolean resolve) {
172: Class loadedClass = null;
173: try {
174: loadedClass = getParent().loadClass(name);
175: if (loadedClass != null && resolve) {
176: resolveClass(loadedClass);
177: }
178: } catch (ClassNotFoundException e) {
179: // not found in parent
180: }
181: return loadedClass;
182: }
183:
184: /**
185: * This method modeled on the isSystemPath method in Jetty's ContextLoader.
186: *
187: * When loading classes from the system classloader, we really only want to load certain classes
188: * from there so this will tell us whether or not the class name given is one we want to load
189: * from the system classloader.
190: */
191: private boolean isSystemClass(String name) {
192: name = name.replace('/', '.');
193: while (name.startsWith(".")) {
194: name = name.substring(1);
195: }
196: for (int index = 0; index < SYSTEM_CLASSES.length; index++) {
197: String systemClass = SYSTEM_CLASSES[index];
198: if (systemClass.endsWith(".")) {
199: if (name.startsWith(systemClass)) {
200: return true;
201: }
202: } else if (name.equals(systemClass)) {
203: return true;
204: }
205: }
206: return false;
207: }
208:
209: public String toString() {
210: StringBuffer sb = new StringBuffer("[PluginClassLoader: urls=");
211: URL[] urls = getURLs();
212: if (urls == null) {
213: sb.append("null");
214: } else {
215: for (int i = 0; i < urls.length; i++) {
216: sb.append(urls[i]);
217: sb.append(",");
218: }
219: // remove trailing comma
220: if (urls.length > 1) {
221: sb.setLength(sb.length() - 1);
222: }
223: }
224: sb.append("]");
225: return sb.toString();
226: }
227:
228: public PluginManifest getConfig() {
229: return config;
230: }
231:
232: public void setConfig(PluginManifest config) {
233: this .config = config;
234: }
235:
236: public void start() {
237: started = true;
238: }
239:
240: public void stop() {
241: config = null;
242: started = false;
243: }
244:
245: public boolean isStarted() {
246: return started;
247: }
248: }
|