1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/**
* $RCSfile$
* $Revision: 2993 $
* $Date: 2005-10-24 18:11:33 -0300 (Mon, 24 Oct 2005) $
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.wildfire.container;
import org.jivesoftware.util.Log;
import java.io.File;
import java.io.FilenameFilter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Collection;
/**
* ClassLoader for plugins. It searches the plugin directory for classes
* and JAR files, then constructs a class loader for the resources found.
* Resources are loaded as follows:<ul>
* <p/>
* <li>Any JAR files in the <tt>lib</tt> will be added to the classpath.
* <li>Any files in the classes directory will be added to the classpath.
* </ul>
*
* @author Derek DeMoro
*/
class PluginClassLoader {
private URLClassLoader classLoader;
private final List<URL> list = new ArrayList<URL>();
/**
* Constructs a plugin loader for the given plugin directory.
*
* @param pluginDir the plugin directory.
* @throws SecurityException if the created class loader violates
* existing security constraints.
*/
public PluginClassLoader(File pluginDir) throws SecurityException {
addDirectory(pluginDir);
}
/**
* Adds a directory to the class loader. The {@link #initialize()} method should be called
* after adding the directory to make the change take effect.
*
* @param directory the directory.
*/
public void addDirectory(File directory) {
try {
File classesDir = new File(directory, "classes");
if (classesDir.exists()) {
list.add(classesDir.toURL());
}
File libDir = new File(directory, "lib");
File[] jars = libDir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.endsWith(".jar") || name.endsWith(".zip");
}
});
if (jars != null) {
for (int i = 0; i < jars.length; i++) {
if (jars[i] != null && jars[i].isFile()) {
list.add(jars[i].toURL());
}
}
}
}
catch (MalformedURLException mue) {
Log.error(mue);
}
}
public Collection<URL> getURLS(){
return list;
}
/**
* Adds a URL to the class loader. The {@link #initialize()} method should be called
* after adding the URL to make the change take effect.
*
* @param url the url.
*/
public void addURL(URL url) {
list.add(url);
}
/**
* Initializes the class loader with all configured classpath URLs. This method
* can be called multiple times if the list of URLs changes.
*/
public void initialize() {
Iterator urls = list.iterator();
URL[] urlArray = new URL[list.size()];
for (int i = 0; urls.hasNext(); i++) {
urlArray[i] = (URL)urls.next();
}
// If the classloader is to be used by a child plugin, we should
// never use the ContextClassLoader, but only reuse the plugin classloader itself.
if (classLoader != null) {
classLoader = new URLClassLoader(urlArray, classLoader);
}
else {
classLoader = new URLClassLoader(urlArray, findParentClassLoader());
}
}
/**
* Load a class using this plugin class loader.
*
* @param name the fully qualified name of the class to load.
* @return The module object loaded
* @throws ClassNotFoundException if the class could not be loaded by this class loader.
* @throws IllegalAccessException if the class constructor was private or protected.
* @throws InstantiationException if the class could not be instantiated (initialization error).
* @throws SecurityException if the custom class loader not allowed.
*/
public Class loadClass(String name) throws ClassNotFoundException, IllegalAccessException,
InstantiationException, SecurityException {
return classLoader.loadClass(name);
}
/**
* Destroys this class loader.
*/
public void destroy() {
classLoader = null;
}
/**
* Locates the best parent class loader based on context.
*
* @return the best parent classloader to use.
*/
private ClassLoader findParentClassLoader() {
ClassLoader parent = Thread.currentThread().getContextClassLoader();
if (parent == null) {
parent = this.getClass().getClassLoader();
}
if (parent == null) {
parent = ClassLoader.getSystemClassLoader();
}
return parent;
}
}