1343 |
15 Sep 05 |
nicklas |
1 |
/* |
1343 |
15 Sep 05 |
nicklas |
$Id$ |
1343 |
15 Sep 05 |
nicklas |
3 |
|
3675 |
16 Aug 07 |
jari |
Copyright (C) 2005 Nicklas Nordborg |
4889 |
06 Apr 09 |
nicklas |
Copyright (C) 2006 Jari Häkkinen, Nicklas Nordborg |
3675 |
16 Aug 07 |
jari |
Copyright (C) 2007 Nicklas Nordborg, Martin Svensson |
1343 |
15 Sep 05 |
nicklas |
7 |
|
2304 |
22 May 06 |
jari |
This file is part of BASE - BioArray Software Environment. |
2304 |
22 May 06 |
jari |
Available at http://base.thep.lu.se/ |
1343 |
15 Sep 05 |
nicklas |
10 |
|
1343 |
15 Sep 05 |
nicklas |
BASE is free software; you can redistribute it and/or |
1343 |
15 Sep 05 |
nicklas |
modify it under the terms of the GNU General Public License |
4479 |
05 Sep 08 |
jari |
as published by the Free Software Foundation; either version 3 |
1343 |
15 Sep 05 |
nicklas |
of the License, or (at your option) any later version. |
1343 |
15 Sep 05 |
nicklas |
15 |
|
1343 |
15 Sep 05 |
nicklas |
BASE is distributed in the hope that it will be useful, |
1343 |
15 Sep 05 |
nicklas |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
1343 |
15 Sep 05 |
nicklas |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1343 |
15 Sep 05 |
nicklas |
GNU General Public License for more details. |
1343 |
15 Sep 05 |
nicklas |
20 |
|
1343 |
15 Sep 05 |
nicklas |
You should have received a copy of the GNU General Public License |
4515 |
11 Sep 08 |
jari |
along with BASE. If not, see <http://www.gnu.org/licenses/>. |
1343 |
15 Sep 05 |
nicklas |
23 |
*/ |
1343 |
15 Sep 05 |
nicklas |
24 |
package net.sf.basedb.util; |
1343 |
15 Sep 05 |
nicklas |
25 |
|
4323 |
30 May 08 |
nicklas |
26 |
import java.util.ArrayList; |
4323 |
30 May 08 |
nicklas |
27 |
import java.util.List; |
1343 |
15 Sep 05 |
nicklas |
28 |
import java.util.Map; |
1343 |
15 Sep 05 |
nicklas |
29 |
import java.util.HashMap; |
7192 |
29 Aug 16 |
nicklas |
30 |
import java.util.Iterator; |
1345 |
19 Sep 05 |
nicklas |
31 |
import java.util.Enumeration; |
4393 |
13 Aug 08 |
nicklas |
32 |
import java.util.Vector; |
1343 |
15 Sep 05 |
nicklas |
33 |
import java.util.jar.JarFile; |
1343 |
15 Sep 05 |
nicklas |
34 |
import java.util.jar.JarEntry; |
1345 |
19 Sep 05 |
nicklas |
35 |
import java.util.jar.Manifest; |
7718 |
22 May 19 |
nicklas |
36 |
|
1345 |
19 Sep 05 |
nicklas |
37 |
import java.util.jar.Attributes; |
5394 |
25 Aug 10 |
nicklas |
38 |
import java.util.jar.Attributes.Name; |
1345 |
19 Sep 05 |
nicklas |
39 |
import java.io.File; |
1343 |
15 Sep 05 |
nicklas |
40 |
import java.io.InputStream; |
1343 |
15 Sep 05 |
nicklas |
41 |
import java.io.IOException; |
5622 |
03 May 11 |
nicklas |
42 |
import java.io.OutputStream; |
1345 |
19 Sep 05 |
nicklas |
43 |
import java.net.URL; |
1345 |
19 Sep 05 |
nicklas |
44 |
import java.net.MalformedURLException; |
1343 |
15 Sep 05 |
nicklas |
45 |
|
5622 |
03 May 11 |
nicklas |
46 |
import net.sf.basedb.core.Application; |
3078 |
22 Jan 07 |
nicklas |
47 |
import net.sf.basedb.core.InvalidDataException; |
3078 |
22 Jan 07 |
nicklas |
48 |
|
1343 |
15 Sep 05 |
nicklas |
49 |
/** |
1343 |
15 Sep 05 |
nicklas |
A class loader implementation that loads classes from JAR files. |
1345 |
19 Sep 05 |
nicklas |
Each JAR file requires a separate instance of this class. Use |
1635 |
18 Nov 05 |
nicklas |
the {@link #getInstance(String)} method to get an existing or create |
1345 |
19 Sep 05 |
nicklas |
a new instance for a specific JAR file. If the classes in the JAR file |
1345 |
19 Sep 05 |
nicklas |
requires other classes in another JAR file to work, the paths to those |
1345 |
19 Sep 05 |
nicklas |
JAR files must be listed in the <code>Class-Path</code> attribute in the |
1345 |
19 Sep 05 |
nicklas |
<code>META-INF/MANIFEST.MF</code> file. For example: |
1345 |
19 Sep 05 |
nicklas |
<pre class="code"> |
1345 |
19 Sep 05 |
nicklas |
Manifest-Version: 1.0 |
1345 |
19 Sep 05 |
nicklas |
Class-Path: OtherJarPlugin.jar |
1345 |
19 Sep 05 |
nicklas |
</pre> |
1343 |
15 Sep 05 |
nicklas |
61 |
|
1345 |
19 Sep 05 |
nicklas |
If more than one JAR is needed separate them with one or more spaces. |
1345 |
19 Sep 05 |
nicklas |
Note! It is only the <code>Class-Path</code> entry for the JAR file passed |
1584 |
10 Nov 05 |
nicklas |
to the {@link #getInstance(String)} method that is checked. The manifest |
1345 |
19 Sep 05 |
nicklas |
file is not checked for the other JARs. |
5013 |
25 Jun 09 |
nicklas |
<p> |
5013 |
25 Jun 09 |
nicklas |
This class loader will by default first look in the specified JAR files |
5013 |
25 Jun 09 |
nicklas |
for a class or resource and only if not found delegate to the parent class |
5013 |
25 Jun 09 |
nicklas |
loader. This behaviour can be changed by calling {@link #setDelegateFirst(boolean)} |
5013 |
25 Jun 09 |
nicklas |
or by setting <code>X-Delegate-First : true</code> in the <code>MANIFEST.MF</code> |
5013 |
25 Jun 09 |
nicklas |
file in the main JAR file. |
1345 |
19 Sep 05 |
nicklas |
72 |
|
1343 |
15 Sep 05 |
nicklas |
@author Nicklas |
1343 |
15 Sep 05 |
nicklas |
@version 2.0 |
1343 |
15 Sep 05 |
nicklas |
@base.modified $Date$ |
1343 |
15 Sep 05 |
nicklas |
76 |
*/ |
1343 |
15 Sep 05 |
nicklas |
77 |
public final class JarClassLoader |
1343 |
15 Sep 05 |
nicklas |
78 |
extends ClassLoader |
1343 |
15 Sep 05 |
nicklas |
79 |
{ |
1343 |
15 Sep 05 |
nicklas |
80 |
|
6444 |
09 Apr 14 |
nicklas |
81 |
private static final org.slf4j.Logger log = |
6444 |
09 Apr 14 |
nicklas |
82 |
org.slf4j.LoggerFactory.getLogger(JarClassLoader.class); |
4321 |
29 May 08 |
nicklas |
83 |
|
1343 |
15 Sep 05 |
nicklas |
84 |
/** |
1343 |
15 Sep 05 |
nicklas |
A map of all loaded class loaders. |
1343 |
15 Sep 05 |
nicklas |
86 |
*/ |
3631 |
03 Aug 07 |
nicklas |
87 |
private static final HashMap<String, JarClassLoader> classLoaders = |
3631 |
03 Aug 07 |
nicklas |
88 |
new HashMap<String, JarClassLoader>(); |
1343 |
15 Sep 05 |
nicklas |
89 |
|
1343 |
15 Sep 05 |
nicklas |
90 |
/** |
1343 |
15 Sep 05 |
nicklas |
Get a class loader for the specified JAR file. If a class loader for |
1343 |
15 Sep 05 |
nicklas |
the specified file already exists, that class loader is returned, otherwise |
1343 |
15 Sep 05 |
nicklas |
a new class loader is created. |
1343 |
15 Sep 05 |
nicklas |
94 |
|
1343 |
15 Sep 05 |
nicklas |
@param jarPath The path to a JAR file |
1343 |
15 Sep 05 |
nicklas |
@return A class loader |
1343 |
15 Sep 05 |
nicklas |
@throws IOException If the jar file can't be loaded |
1343 |
15 Sep 05 |
nicklas |
98 |
*/ |
1343 |
15 Sep 05 |
nicklas |
99 |
public static final ClassLoader getInstance(String jarPath) |
1343 |
15 Sep 05 |
nicklas |
100 |
throws IOException |
1343 |
15 Sep 05 |
nicklas |
101 |
{ |
3631 |
03 Aug 07 |
nicklas |
102 |
return getInstance(jarPath, false); |
3631 |
03 Aug 07 |
nicklas |
103 |
} |
3631 |
03 Aug 07 |
nicklas |
104 |
|
3631 |
03 Aug 07 |
nicklas |
105 |
/** |
3631 |
03 Aug 07 |
nicklas |
Get a class loader for the specified JAR file, optionally unloading an the old |
3631 |
03 Aug 07 |
nicklas |
one if the JAR file has been modified. A new class loader is created if no |
3631 |
03 Aug 07 |
nicklas |
class loader exists or if <code>autoUnload</code> is <code>true</code> and the JAR file |
3631 |
03 Aug 07 |
nicklas |
has changed since the existing class loader was created. |
3631 |
03 Aug 07 |
nicklas |
110 |
|
3631 |
03 Aug 07 |
nicklas |
@param jarPath The path to a JAR file |
4323 |
30 May 08 |
nicklas |
@param autoUnload If TRUE the old class loaded will automatically be unloaded if the |
4323 |
30 May 08 |
nicklas |
JAR file or any one it depends on (listed in the Class-Path attribute in the manifest file) |
4323 |
30 May 08 |
nicklas |
has been modified (if the timestamp and/or size) is different |
3631 |
03 Aug 07 |
nicklas |
@return A class loader |
3631 |
03 Aug 07 |
nicklas |
@throws IOException If the jar file can't be loaded |
3631 |
03 Aug 07 |
nicklas |
@since 2.4 |
3631 |
03 Aug 07 |
nicklas |
118 |
*/ |
3631 |
03 Aug 07 |
nicklas |
119 |
public static final ClassLoader getInstance(String jarPath, boolean autoUnload) |
3631 |
03 Aug 07 |
nicklas |
120 |
throws IOException |
3631 |
03 Aug 07 |
nicklas |
121 |
{ |
3631 |
03 Aug 07 |
nicklas |
122 |
JarClassLoader cl = classLoaders.get(jarPath); |
3631 |
03 Aug 07 |
nicklas |
123 |
if (cl != null && autoUnload) |
3631 |
03 Aug 07 |
nicklas |
124 |
{ |
3631 |
03 Aug 07 |
nicklas |
// Check if JAR file exists and has same timestamp and size |
4323 |
30 May 08 |
nicklas |
126 |
if (cl.hasChanged(true)) cl = null; |
3631 |
03 Aug 07 |
nicklas |
127 |
} |
1343 |
15 Sep 05 |
nicklas |
128 |
if (cl == null) |
1343 |
15 Sep 05 |
nicklas |
129 |
{ |
1343 |
15 Sep 05 |
nicklas |
130 |
cl = new JarClassLoader(jarPath); |
1343 |
15 Sep 05 |
nicklas |
131 |
synchronized (classLoaders) |
1343 |
15 Sep 05 |
nicklas |
132 |
{ |
1343 |
15 Sep 05 |
nicklas |
133 |
classLoaders.put(jarPath, cl); |
1343 |
15 Sep 05 |
nicklas |
134 |
} |
1343 |
15 Sep 05 |
nicklas |
135 |
} |
1343 |
15 Sep 05 |
nicklas |
136 |
return cl; |
1343 |
15 Sep 05 |
nicklas |
137 |
} |
3631 |
03 Aug 07 |
nicklas |
138 |
|
1343 |
15 Sep 05 |
nicklas |
139 |
/** |
3760 |
20 Sep 07 |
martin |
Get a new class loader for the specified jar file. |
3760 |
20 Sep 07 |
martin |
@param jarPath The path to the jar file |
3760 |
20 Sep 07 |
martin |
@return A class loader object |
3760 |
20 Sep 07 |
martin |
@throws IOException If the jar file can't be loaded |
3760 |
20 Sep 07 |
martin |
144 |
*/ |
3760 |
20 Sep 07 |
martin |
145 |
public static final ClassLoader newInstance(String jarPath) |
3760 |
20 Sep 07 |
martin |
146 |
throws IOException |
3760 |
20 Sep 07 |
martin |
147 |
{ |
3760 |
20 Sep 07 |
martin |
148 |
return new JarClassLoader(jarPath); |
3760 |
20 Sep 07 |
martin |
149 |
} |
3760 |
20 Sep 07 |
martin |
150 |
|
3760 |
20 Sep 07 |
martin |
151 |
/** |
1343 |
15 Sep 05 |
nicklas |
Check if a class loader for the given JAR file exists. |
1343 |
15 Sep 05 |
nicklas |
@param jarPath The path to the JAR file |
1343 |
15 Sep 05 |
nicklas |
@return TRUE if a class loader exists, FALSE otherwise |
1343 |
15 Sep 05 |
nicklas |
155 |
*/ |
1343 |
15 Sep 05 |
nicklas |
156 |
public static final boolean exists(String jarPath) |
1343 |
15 Sep 05 |
nicklas |
157 |
{ |
1343 |
15 Sep 05 |
nicklas |
158 |
return classLoaders.containsKey(jarPath); |
1343 |
15 Sep 05 |
nicklas |
159 |
} |
1343 |
15 Sep 05 |
nicklas |
160 |
|
1343 |
15 Sep 05 |
nicklas |
161 |
/** |
1345 |
19 Sep 05 |
nicklas |
The main JAR file to load classes from. |
1343 |
15 Sep 05 |
nicklas |
163 |
*/ |
1345 |
19 Sep 05 |
nicklas |
164 |
private final File mainJarFile; |
1345 |
19 Sep 05 |
nicklas |
165 |
|
1345 |
19 Sep 05 |
nicklas |
166 |
/** |
1345 |
19 Sep 05 |
nicklas |
Contains mappings from class names to the JAR file in which |
1345 |
19 Sep 05 |
nicklas |
the class implementation can be found. |
1345 |
19 Sep 05 |
nicklas |
169 |
*/ |
4393 |
13 Aug 08 |
nicklas |
170 |
private final Map<String, List<File>> classPath; |
5013 |
25 Jun 09 |
nicklas |
171 |
|
5013 |
25 Jun 09 |
nicklas |
172 |
/** |
5013 |
25 Jun 09 |
nicklas |
If we should delegate to the parent class loader first. |
5013 |
25 Jun 09 |
nicklas |
174 |
*/ |
5013 |
25 Jun 09 |
nicklas |
175 |
private boolean delegateFirst; |
1343 |
15 Sep 05 |
nicklas |
176 |
|
1343 |
15 Sep 05 |
nicklas |
177 |
/** |
4323 |
30 May 08 |
nicklas |
For keeping track of jar files listed by Class-Path entry |
4323 |
30 May 08 |
nicklas |
in the manifest file. |
4323 |
30 May 08 |
nicklas |
180 |
*/ |
5394 |
25 Aug 10 |
nicklas |
181 |
private final Map<File, JarInfo> jarFiles; |
7192 |
29 Aug 16 |
nicklas |
182 |
|
7192 |
29 Aug 16 |
nicklas |
183 |
/** |
7192 |
29 Aug 16 |
nicklas |
Class loaders for extensions. |
7192 |
29 Aug 16 |
nicklas |
185 |
*/ |
7192 |
29 Aug 16 |
nicklas |
186 |
private final List<JarClassLoaderProxy> proxyLoaders; |
4323 |
30 May 08 |
nicklas |
187 |
|
4323 |
30 May 08 |
nicklas |
188 |
/** |
3631 |
03 Aug 07 |
nicklas |
The timestamp of the JAR file. |
3631 |
03 Aug 07 |
nicklas |
190 |
*/ |
3631 |
03 Aug 07 |
nicklas |
191 |
private final long jarTimeStamp; |
3631 |
03 Aug 07 |
nicklas |
192 |
|
3631 |
03 Aug 07 |
nicklas |
193 |
/** |
3631 |
03 Aug 07 |
nicklas |
The size of the JAR file. |
3631 |
03 Aug 07 |
nicklas |
195 |
*/ |
3631 |
03 Aug 07 |
nicklas |
196 |
private final long jarSize; |
3631 |
03 Aug 07 |
nicklas |
197 |
|
3631 |
03 Aug 07 |
nicklas |
198 |
|
3631 |
03 Aug 07 |
nicklas |
199 |
/** |
1343 |
15 Sep 05 |
nicklas |
Create a new JAR file class loader. |
1343 |
15 Sep 05 |
nicklas |
@param jarPath The path to the JAR file |
3078 |
22 Jan 07 |
nicklas |
@throws InvalidDataException If the JAR file can't be loaded |
3078 |
22 Jan 07 |
nicklas |
@throws IOException If there is another IO-related error |
1343 |
15 Sep 05 |
nicklas |
204 |
*/ |
1343 |
15 Sep 05 |
nicklas |
205 |
private JarClassLoader(String jarPath) |
1343 |
15 Sep 05 |
nicklas |
206 |
throws IOException |
1343 |
15 Sep 05 |
nicklas |
207 |
{ |
1347 |
19 Sep 05 |
nicklas |
208 |
super(Thread.currentThread().getContextClassLoader()); |
4391 |
12 Aug 08 |
nicklas |
209 |
log.debug("Creating JarClassLoader: file=" + jarPath); |
1345 |
19 Sep 05 |
nicklas |
210 |
mainJarFile = new File(jarPath); |
4323 |
30 May 08 |
nicklas |
211 |
if (!mainJarFile.exists() || !mainJarFile.isFile()) |
4323 |
30 May 08 |
nicklas |
212 |
{ |
4323 |
30 May 08 |
nicklas |
213 |
throw new InvalidDataException("JAR file not found: " + jarPath); |
4323 |
30 May 08 |
nicklas |
214 |
} |
3631 |
03 Aug 07 |
nicklas |
215 |
this.jarTimeStamp = mainJarFile.lastModified(); |
3631 |
03 Aug 07 |
nicklas |
216 |
this.jarSize = mainJarFile.length(); |
5013 |
25 Jun 09 |
nicklas |
217 |
this.delegateFirst = false; |
4393 |
13 Aug 08 |
nicklas |
218 |
classPath = new HashMap<String, List<File>>(); |
5394 |
25 Aug 10 |
nicklas |
219 |
jarFiles = new HashMap<File, JarInfo>(); |
7192 |
29 Aug 16 |
nicklas |
220 |
proxyLoaders = new ArrayList<JarClassLoaderProxy>(); |
1345 |
19 Sep 05 |
nicklas |
221 |
loadJarFile(mainJarFile, true); |
1343 |
15 Sep 05 |
nicklas |
222 |
} |
1345 |
19 Sep 05 |
nicklas |
223 |
|
7194 |
30 Aug 16 |
nicklas |
224 |
@Override |
7194 |
30 Aug 16 |
nicklas |
225 |
public String toString() |
7194 |
30 Aug 16 |
nicklas |
226 |
{ |
7194 |
30 Aug 16 |
nicklas |
227 |
return super.toString() + "[" + mainJarFile + "]"; |
7194 |
30 Aug 16 |
nicklas |
228 |
} |
7194 |
30 Aug 16 |
nicklas |
229 |
|
1343 |
15 Sep 05 |
nicklas |
230 |
/* |
1345 |
19 Sep 05 |
nicklas |
From the ClassLoader class |
1343 |
15 Sep 05 |
nicklas |
232 |
------------------------------------------- |
1343 |
15 Sep 05 |
nicklas |
233 |
*/ |
4391 |
12 Aug 08 |
nicklas |
234 |
@Override |
2031 |
21 Feb 06 |
nicklas |
235 |
protected Class<?> findClass(String name) |
1343 |
15 Sep 05 |
nicklas |
236 |
throws ClassNotFoundException |
1343 |
15 Sep 05 |
nicklas |
237 |
{ |
4391 |
12 Aug 08 |
nicklas |
238 |
log.debug("findClass: " + name); |
4393 |
13 Aug 08 |
nicklas |
239 |
List<File> files = classPath.get(classNameToPath(name)); |
4393 |
13 Aug 08 |
nicklas |
240 |
if (files == null || files.isEmpty()) |
1345 |
19 Sep 05 |
nicklas |
241 |
{ |
1345 |
19 Sep 05 |
nicklas |
242 |
throw new ClassNotFoundException(name); |
1345 |
19 Sep 05 |
nicklas |
243 |
} |
5394 |
25 Aug 10 |
nicklas |
244 |
File file = files.get(0); |
5394 |
25 Aug 10 |
nicklas |
245 |
byte[] b = loadClassData(file, name); |
5394 |
25 Aug 10 |
nicklas |
246 |
int i = name.lastIndexOf('.'); |
5394 |
25 Aug 10 |
nicklas |
247 |
if (i > 0) |
5394 |
25 Aug 10 |
nicklas |
248 |
{ |
5394 |
25 Aug 10 |
nicklas |
249 |
String packageName = name.substring(0, i); |
7718 |
22 May 19 |
nicklas |
250 |
if (!isPackageDefined(packageName)) |
5394 |
25 Aug 10 |
nicklas |
251 |
{ |
5394 |
25 Aug 10 |
nicklas |
252 |
JarInfo info = jarFiles.get(file); |
5394 |
25 Aug 10 |
nicklas |
253 |
Manifest mf = info != null ? info.manifest : null; |
7718 |
22 May 19 |
nicklas |
254 |
definePackage(packageName, mf); |
5394 |
25 Aug 10 |
nicklas |
255 |
} |
5394 |
25 Aug 10 |
nicklas |
256 |
} |
5394 |
25 Aug 10 |
nicklas |
257 |
Class<?> clazz = defineClass(name, b, 0, b.length); |
5394 |
25 Aug 10 |
nicklas |
258 |
return clazz; |
1343 |
15 Sep 05 |
nicklas |
259 |
} |
1345 |
19 Sep 05 |
nicklas |
260 |
|
7718 |
22 May 19 |
nicklas |
// Safety limit to avoid endless loops in case parent class loaders are incorrectly linked |
7718 |
22 May 19 |
nicklas |
262 |
private static final int MAX_PARENTS = 20; |
7718 |
22 May 19 |
nicklas |
263 |
private boolean isPackageDefined(String name) |
7718 |
22 May 19 |
nicklas |
264 |
{ |
7718 |
22 May 19 |
nicklas |
265 |
ClassLoader c = this; |
7718 |
22 May 19 |
nicklas |
266 |
for (int i = 0; c != null && i < MAX_PARENTS; i++) |
7718 |
22 May 19 |
nicklas |
267 |
{ |
7718 |
22 May 19 |
nicklas |
268 |
if (c.getDefinedPackage(name) != null) return true; |
7718 |
22 May 19 |
nicklas |
269 |
c = c.getParent(); |
7718 |
22 May 19 |
nicklas |
270 |
} |
7718 |
22 May 19 |
nicklas |
271 |
return false; |
7718 |
22 May 19 |
nicklas |
272 |
} |
7718 |
22 May 19 |
nicklas |
273 |
|
4391 |
12 Aug 08 |
nicklas |
274 |
@Override |
1345 |
19 Sep 05 |
nicklas |
275 |
protected URL findResource(String name) |
1345 |
19 Sep 05 |
nicklas |
276 |
{ |
4391 |
12 Aug 08 |
nicklas |
277 |
log.debug("findResource: " + name); |
1345 |
19 Sep 05 |
nicklas |
278 |
URL url = null; |
1345 |
19 Sep 05 |
nicklas |
279 |
try |
1345 |
19 Sep 05 |
nicklas |
280 |
{ |
4393 |
13 Aug 08 |
nicklas |
281 |
List<File> files = classPath.get(name); |
4393 |
13 Aug 08 |
nicklas |
282 |
if (files != null && files.size() > 0) |
1345 |
19 Sep 05 |
nicklas |
283 |
{ |
4393 |
13 Aug 08 |
nicklas |
284 |
if (log.isDebugEnabled()) log.debug("Found: " + files); |
4393 |
13 Aug 08 |
nicklas |
285 |
String newUrl = "jar:"+files.get(0).toURI().toURL()+"!/"+name; |
1345 |
19 Sep 05 |
nicklas |
286 |
url = new URL(newUrl); |
1345 |
19 Sep 05 |
nicklas |
287 |
} |
4391 |
12 Aug 08 |
nicklas |
288 |
else |
4391 |
12 Aug 08 |
nicklas |
289 |
{ |
4391 |
12 Aug 08 |
nicklas |
290 |
log.debug("Not found: " + name); |
4391 |
12 Aug 08 |
nicklas |
291 |
} |
1345 |
19 Sep 05 |
nicklas |
292 |
} |
1345 |
19 Sep 05 |
nicklas |
293 |
catch (MalformedURLException ex) |
1345 |
19 Sep 05 |
nicklas |
294 |
{ |
1345 |
19 Sep 05 |
nicklas |
295 |
ex.printStackTrace(); |
1345 |
19 Sep 05 |
nicklas |
296 |
} |
1345 |
19 Sep 05 |
nicklas |
297 |
return url; |
1345 |
19 Sep 05 |
nicklas |
298 |
} |
1345 |
19 Sep 05 |
nicklas |
299 |
|
4391 |
12 Aug 08 |
nicklas |
300 |
@Override |
4393 |
13 Aug 08 |
nicklas |
301 |
protected Enumeration<URL> findResources(String name) |
4393 |
13 Aug 08 |
nicklas |
302 |
{ |
4393 |
13 Aug 08 |
nicklas |
303 |
log.debug("findResources: " + name); |
4393 |
13 Aug 08 |
nicklas |
304 |
Enumeration<URL> url = null; |
4393 |
13 Aug 08 |
nicklas |
305 |
try |
4393 |
13 Aug 08 |
nicklas |
306 |
{ |
4393 |
13 Aug 08 |
nicklas |
307 |
List<File> files = classPath.get(name); |
4393 |
13 Aug 08 |
nicklas |
308 |
if (files != null && files.size() > 0) |
4393 |
13 Aug 08 |
nicklas |
309 |
{ |
4393 |
13 Aug 08 |
nicklas |
310 |
if (log.isDebugEnabled()) log.debug("Found: " + files); |
5013 |
25 Jun 09 |
nicklas |
311 |
Vector<URL> v = new Vector<URL>(files.size()); |
4393 |
13 Aug 08 |
nicklas |
312 |
for (File f : files) |
4393 |
13 Aug 08 |
nicklas |
313 |
{ |
4393 |
13 Aug 08 |
nicklas |
314 |
String newUrl = "jar:"+f.toURI().toURL()+"!/"+name; |
4393 |
13 Aug 08 |
nicklas |
315 |
v.add(new URL(newUrl)); |
4393 |
13 Aug 08 |
nicklas |
316 |
} |
4393 |
13 Aug 08 |
nicklas |
317 |
url = v.elements(); |
4393 |
13 Aug 08 |
nicklas |
318 |
} |
4393 |
13 Aug 08 |
nicklas |
319 |
else |
4393 |
13 Aug 08 |
nicklas |
320 |
{ |
4393 |
13 Aug 08 |
nicklas |
321 |
log.debug("Not found: " + name); |
4393 |
13 Aug 08 |
nicklas |
322 |
} |
4393 |
13 Aug 08 |
nicklas |
323 |
} |
4393 |
13 Aug 08 |
nicklas |
324 |
catch (MalformedURLException ex) |
4393 |
13 Aug 08 |
nicklas |
325 |
{ |
4393 |
13 Aug 08 |
nicklas |
326 |
ex.printStackTrace(); |
4393 |
13 Aug 08 |
nicklas |
327 |
} |
4393 |
13 Aug 08 |
nicklas |
328 |
return url; |
4393 |
13 Aug 08 |
nicklas |
329 |
} |
4393 |
13 Aug 08 |
nicklas |
330 |
|
4393 |
13 Aug 08 |
nicklas |
331 |
@Override |
4391 |
12 Aug 08 |
nicklas |
332 |
protected Class<?> loadClass(String name, boolean resolve) |
4391 |
12 Aug 08 |
nicklas |
333 |
throws ClassNotFoundException |
4391 |
12 Aug 08 |
nicklas |
334 |
{ |
4391 |
12 Aug 08 |
nicklas |
335 |
if (log.isDebugEnabled()) log.debug("loadClass: " + name); |
5013 |
25 Jun 09 |
nicklas |
336 |
|
5013 |
25 Jun 09 |
nicklas |
// 1. Check if the class has already been loaded |
6875 |
20 Apr 15 |
nicklas |
338 |
Class<?> c = findLoadedClass(name); |
5013 |
25 Jun 09 |
nicklas |
339 |
if (log.isDebugEnabled()) log.debug("loaded class (" + name + "): " + c); |
5013 |
25 Jun 09 |
nicklas |
340 |
|
5013 |
25 Jun 09 |
nicklas |
341 |
ClassLoader system = ClassLoader.getSystemClassLoader(); |
5013 |
25 Jun 09 |
nicklas |
342 |
ClassLoader parent = getParent(); |
5013 |
25 Jun 09 |
nicklas |
343 |
|
5013 |
25 Jun 09 |
nicklas |
// 2. Check the system class loader |
7192 |
29 Aug 16 |
nicklas |
345 |
if (c == null && parent != system) |
7192 |
29 Aug 16 |
nicklas |
346 |
{ |
7192 |
29 Aug 16 |
nicklas |
347 |
c = loadClassInternal(system, name); |
7192 |
29 Aug 16 |
nicklas |
348 |
if (log.isDebugEnabled()) log.debug("system class (" + name + "): " + c); |
7192 |
29 Aug 16 |
nicklas |
349 |
} |
5013 |
25 Jun 09 |
nicklas |
350 |
|
5013 |
25 Jun 09 |
nicklas |
// 3. Delegate to parent class loader |
7192 |
29 Aug 16 |
nicklas |
352 |
if (c == null && delegateFirst) |
7192 |
29 Aug 16 |
nicklas |
353 |
{ |
7192 |
29 Aug 16 |
nicklas |
354 |
c = loadClassInternal(parent, name); |
7192 |
29 Aug 16 |
nicklas |
355 |
if (log.isDebugEnabled()) log.debug("parent class (" + name + "): " + c); |
7192 |
29 Aug 16 |
nicklas |
356 |
} |
5013 |
25 Jun 09 |
nicklas |
357 |
|
5013 |
25 Jun 09 |
nicklas |
// 4. Look for the class in this class path |
5013 |
25 Jun 09 |
nicklas |
359 |
if (c == null) |
5013 |
25 Jun 09 |
nicklas |
360 |
{ |
5013 |
25 Jun 09 |
nicklas |
361 |
try |
5013 |
25 Jun 09 |
nicklas |
362 |
{ |
5013 |
25 Jun 09 |
nicklas |
363 |
c = findClass(name); |
5013 |
25 Jun 09 |
nicklas |
364 |
} |
5013 |
25 Jun 09 |
nicklas |
365 |
catch (ClassNotFoundException ex) |
5013 |
25 Jun 09 |
nicklas |
366 |
{} |
7192 |
29 Aug 16 |
nicklas |
367 |
if (log.isDebugEnabled()) log.debug("my class (" + name + "): " + c); |
5013 |
25 Jun 09 |
nicklas |
368 |
} |
5013 |
25 Jun 09 |
nicklas |
369 |
|
7194 |
30 Aug 16 |
nicklas |
// 5. Side-load from proxied JAR files (eg. other extensions) |
7192 |
29 Aug 16 |
nicklas |
371 |
Iterator<JarClassLoaderProxy> it = proxyLoaders.iterator(); |
7192 |
29 Aug 16 |
nicklas |
372 |
while (c == null && it.hasNext()) |
7192 |
29 Aug 16 |
nicklas |
373 |
{ |
7192 |
29 Aug 16 |
nicklas |
374 |
JarClassLoaderProxy proxyLoader = it.next(); |
7192 |
29 Aug 16 |
nicklas |
375 |
c = proxyLoader.findClass(name); |
7192 |
29 Aug 16 |
nicklas |
376 |
if (log.isDebugEnabled()) log.debug("proxy class (" + proxyLoader.jarPath + "; " + name + "): " + c); |
7192 |
29 Aug 16 |
nicklas |
377 |
} |
7192 |
29 Aug 16 |
nicklas |
378 |
|
7194 |
30 Aug 16 |
nicklas |
// 6. Delegate to parent class loader if it hasn't been done |
7194 |
30 Aug 16 |
nicklas |
380 |
if (c == null && !delegateFirst) |
7194 |
30 Aug 16 |
nicklas |
381 |
{ |
7194 |
30 Aug 16 |
nicklas |
382 |
c = loadClassInternal(parent, name); |
7194 |
30 Aug 16 |
nicklas |
383 |
if (log.isDebugEnabled()) log.debug("parent class (" + name + "): " + c); |
7194 |
30 Aug 16 |
nicklas |
384 |
} |
7194 |
30 Aug 16 |
nicklas |
385 |
|
5013 |
25 Jun 09 |
nicklas |
386 |
if (c == null) |
5013 |
25 Jun 09 |
nicklas |
387 |
{ |
5013 |
25 Jun 09 |
nicklas |
// Class not found |
5013 |
25 Jun 09 |
nicklas |
389 |
throw new ClassNotFoundException(name); |
5013 |
25 Jun 09 |
nicklas |
390 |
} |
5013 |
25 Jun 09 |
nicklas |
391 |
|
5013 |
25 Jun 09 |
nicklas |
392 |
if (resolve) resolveClass(c); |
5013 |
25 Jun 09 |
nicklas |
393 |
return c; |
4391 |
12 Aug 08 |
nicklas |
394 |
} |
4391 |
12 Aug 08 |
nicklas |
395 |
|
4391 |
12 Aug 08 |
nicklas |
396 |
@Override |
4391 |
12 Aug 08 |
nicklas |
397 |
public URL getResource(String name) |
4391 |
12 Aug 08 |
nicklas |
398 |
{ |
4391 |
12 Aug 08 |
nicklas |
399 |
if (log.isDebugEnabled()) log.debug("getResource: " + name); |
5013 |
25 Jun 09 |
nicklas |
400 |
URL url = null; |
5013 |
25 Jun 09 |
nicklas |
401 |
ClassLoader parent = getParent(); |
5013 |
25 Jun 09 |
nicklas |
402 |
|
5013 |
25 Jun 09 |
nicklas |
// 1. Check with parent loader if delegating |
5013 |
25 Jun 09 |
nicklas |
404 |
if (delegateFirst) |
5013 |
25 Jun 09 |
nicklas |
405 |
{ |
5013 |
25 Jun 09 |
nicklas |
406 |
if (parent != null) url = parent.getResource(name); |
5013 |
25 Jun 09 |
nicklas |
407 |
} |
5013 |
25 Jun 09 |
nicklas |
408 |
|
5013 |
25 Jun 09 |
nicklas |
// 2. Check with this class loader |
5013 |
25 Jun 09 |
nicklas |
410 |
if (url == null) url = findResource(name); |
5013 |
25 Jun 09 |
nicklas |
411 |
|
7196 |
30 Aug 16 |
nicklas |
// 3. Side-load from proxied JAR files (eg. other extensions) |
7196 |
30 Aug 16 |
nicklas |
413 |
if (url == null) |
7196 |
30 Aug 16 |
nicklas |
414 |
{ |
7196 |
30 Aug 16 |
nicklas |
415 |
Iterator<JarClassLoaderProxy> it = proxyLoaders.iterator(); |
7196 |
30 Aug 16 |
nicklas |
416 |
while (url == null && it.hasNext()) |
7196 |
30 Aug 16 |
nicklas |
417 |
{ |
7196 |
30 Aug 16 |
nicklas |
418 |
JarClassLoaderProxy proxyLoader = it.next(); |
7196 |
30 Aug 16 |
nicklas |
419 |
url = proxyLoader.findResource(name); |
7196 |
30 Aug 16 |
nicklas |
420 |
} |
7196 |
30 Aug 16 |
nicklas |
421 |
} |
7196 |
30 Aug 16 |
nicklas |
422 |
|
5013 |
25 Jun 09 |
nicklas |
// 3. Check with parent loader if not done so already |
5013 |
25 Jun 09 |
nicklas |
424 |
if (url == null && !delegateFirst) |
5013 |
25 Jun 09 |
nicklas |
425 |
{ |
5013 |
25 Jun 09 |
nicklas |
426 |
if (parent != null) url = parent.getResource(name); |
5013 |
25 Jun 09 |
nicklas |
427 |
} |
5013 |
25 Jun 09 |
nicklas |
428 |
return url; |
4391 |
12 Aug 08 |
nicklas |
429 |
} |
4393 |
13 Aug 08 |
nicklas |
430 |
|
4393 |
13 Aug 08 |
nicklas |
431 |
@Override |
4393 |
13 Aug 08 |
nicklas |
432 |
public Enumeration<URL> getResources(String name) |
4393 |
13 Aug 08 |
nicklas |
433 |
throws IOException |
4393 |
13 Aug 08 |
nicklas |
434 |
{ |
4393 |
13 Aug 08 |
nicklas |
435 |
if (log.isDebugEnabled()) log.debug("getResources: " + name); |
5013 |
25 Jun 09 |
nicklas |
436 |
ClassLoader parent = getParent(); |
5013 |
25 Jun 09 |
nicklas |
437 |
Vector<URL> resources = new Vector<URL>(); |
5013 |
25 Jun 09 |
nicklas |
438 |
|
5013 |
25 Jun 09 |
nicklas |
439 |
Enumeration<URL> parentResources = null; |
5013 |
25 Jun 09 |
nicklas |
440 |
if (parent != null) |
5013 |
25 Jun 09 |
nicklas |
441 |
{ |
5013 |
25 Jun 09 |
nicklas |
442 |
parentResources = parent.getResources(name); |
5013 |
25 Jun 09 |
nicklas |
443 |
} |
5013 |
25 Jun 09 |
nicklas |
444 |
Enumeration<URL> myResources = findResources(name); |
5013 |
25 Jun 09 |
nicklas |
445 |
|
5013 |
25 Jun 09 |
nicklas |
446 |
if (delegateFirst) addResources(resources, parentResources); |
5013 |
25 Jun 09 |
nicklas |
447 |
addResources(resources, myResources); |
7196 |
30 Aug 16 |
nicklas |
448 |
Iterator<JarClassLoaderProxy> it = proxyLoaders.iterator(); |
7196 |
30 Aug 16 |
nicklas |
449 |
while (it.hasNext()) |
7196 |
30 Aug 16 |
nicklas |
450 |
{ |
7196 |
30 Aug 16 |
nicklas |
451 |
JarClassLoaderProxy proxyLoader = it.next(); |
7196 |
30 Aug 16 |
nicklas |
452 |
addResources(resources, proxyLoader.findResources(name)); |
7196 |
30 Aug 16 |
nicklas |
453 |
} |
7196 |
30 Aug 16 |
nicklas |
454 |
|
5013 |
25 Jun 09 |
nicklas |
455 |
if (!delegateFirst) addResources(resources, parentResources); |
5013 |
25 Jun 09 |
nicklas |
456 |
|
5013 |
25 Jun 09 |
nicklas |
457 |
return resources.elements(); |
4393 |
13 Aug 08 |
nicklas |
458 |
} |
1343 |
15 Sep 05 |
nicklas |
459 |
// ------------------------------------------- |
1343 |
15 Sep 05 |
nicklas |
460 |
|
1343 |
15 Sep 05 |
nicklas |
461 |
/** |
5013 |
25 Jun 09 |
nicklas |
If the class loader should delegate to the parent class loader |
5013 |
25 Jun 09 |
nicklas |
before trying to find the class by it's own. |
5013 |
25 Jun 09 |
nicklas |
@param delegateFirst TRUE to delegate to parent first, FALSE to |
5013 |
25 Jun 09 |
nicklas |
only delegate if the class is not found |
5013 |
25 Jun 09 |
nicklas |
@since 2.13 |
5013 |
25 Jun 09 |
nicklas |
467 |
*/ |
5013 |
25 Jun 09 |
nicklas |
468 |
public void setDelegateFirst(boolean delegateFirst) |
5013 |
25 Jun 09 |
nicklas |
469 |
{ |
5013 |
25 Jun 09 |
nicklas |
470 |
this.delegateFirst = delegateFirst; |
5013 |
25 Jun 09 |
nicklas |
471 |
} |
5013 |
25 Jun 09 |
nicklas |
472 |
|
5013 |
25 Jun 09 |
nicklas |
473 |
/** |
5013 |
25 Jun 09 |
nicklas |
If this class loader delegates to the parent class loader |
5013 |
25 Jun 09 |
nicklas |
before or after trying to find the class by itself. |
5013 |
25 Jun 09 |
nicklas |
@since 2.13 |
5013 |
25 Jun 09 |
nicklas |
477 |
*/ |
5013 |
25 Jun 09 |
nicklas |
478 |
public boolean getDelegateFirst() |
5013 |
25 Jun 09 |
nicklas |
479 |
{ |
5013 |
25 Jun 09 |
nicklas |
480 |
return delegateFirst; |
5013 |
25 Jun 09 |
nicklas |
481 |
} |
5013 |
25 Jun 09 |
nicklas |
482 |
|
5013 |
25 Jun 09 |
nicklas |
483 |
/** |
4323 |
30 May 08 |
nicklas |
Check if the JAR file this class loader loads is classes |
4323 |
30 May 08 |
nicklas |
from has changed since this class loader was created. |
4323 |
30 May 08 |
nicklas |
@param checkSecondary TRUE to also check secondary JAR files |
4323 |
30 May 08 |
nicklas |
listed in the Class-Path entry of the manifest file |
4323 |
30 May 08 |
nicklas |
@since 2.8 |
4323 |
30 May 08 |
nicklas |
489 |
*/ |
4323 |
30 May 08 |
nicklas |
490 |
public boolean hasChanged(boolean checkSecondary) |
4323 |
30 May 08 |
nicklas |
491 |
{ |
7226 |
15 Nov 16 |
nicklas |
492 |
if (log.isDebugEnabled()) |
7226 |
15 Nov 16 |
nicklas |
493 |
{ |
7226 |
15 Nov 16 |
nicklas |
494 |
log.debug("Checking if JAR has changed: " + mainJarFile); |
7226 |
15 Nov 16 |
nicklas |
495 |
} |
4323 |
30 May 08 |
nicklas |
496 |
boolean isSame = mainJarFile.exists() && |
4323 |
30 May 08 |
nicklas |
497 |
mainJarFile.lastModified() == jarTimeStamp && mainJarFile.length() == jarSize; |
7226 |
15 Nov 16 |
nicklas |
498 |
if (!isSame) |
7226 |
15 Nov 16 |
nicklas |
499 |
{ |
7226 |
15 Nov 16 |
nicklas |
500 |
log.debug("Main JAR file has changed: " + mainJarFile); |
7226 |
15 Nov 16 |
nicklas |
501 |
return true; |
7226 |
15 Nov 16 |
nicklas |
502 |
} |
4323 |
30 May 08 |
nicklas |
503 |
if (checkSecondary) |
4323 |
30 May 08 |
nicklas |
504 |
{ |
5394 |
25 Aug 10 |
nicklas |
505 |
for (JarInfo info : jarFiles.values()) |
4323 |
30 May 08 |
nicklas |
506 |
{ |
4323 |
30 May 08 |
nicklas |
507 |
File jarFile = info.jarFile; |
7226 |
15 Nov 16 |
nicklas |
508 |
if (jarFile.equals(mainJarFile)) continue; // We have already checked this one |
7226 |
15 Nov 16 |
nicklas |
509 |
|
7226 |
15 Nov 16 |
nicklas |
510 |
if (log.isDebugEnabled()) |
7226 |
15 Nov 16 |
nicklas |
511 |
{ |
7226 |
15 Nov 16 |
nicklas |
512 |
log.debug("Checking if secondary JAR has changed: " + jarFile); |
7226 |
15 Nov 16 |
nicklas |
513 |
} |
4390 |
12 Aug 08 |
nicklas |
514 |
if (jarFile.exists()) |
4390 |
12 Aug 08 |
nicklas |
515 |
{ |
4390 |
12 Aug 08 |
nicklas |
516 |
isSame = info.existed && |
4390 |
12 Aug 08 |
nicklas |
517 |
jarFile.lastModified() == info.lastModified && |
4390 |
12 Aug 08 |
nicklas |
518 |
jarFile.length() == info.size; |
4390 |
12 Aug 08 |
nicklas |
519 |
} |
4390 |
12 Aug 08 |
nicklas |
520 |
else |
4390 |
12 Aug 08 |
nicklas |
521 |
{ |
4390 |
12 Aug 08 |
nicklas |
522 |
isSame = !info.existed; |
4390 |
12 Aug 08 |
nicklas |
523 |
} |
7226 |
15 Nov 16 |
nicklas |
524 |
if (!isSame) |
7226 |
15 Nov 16 |
nicklas |
525 |
{ |
7226 |
15 Nov 16 |
nicklas |
526 |
log.debug("Secondary JAR file has changed: " + jarFile); |
7226 |
15 Nov 16 |
nicklas |
527 |
return true; |
7226 |
15 Nov 16 |
nicklas |
528 |
} |
4323 |
30 May 08 |
nicklas |
529 |
} |
7196 |
30 Aug 16 |
nicklas |
530 |
for (JarClassLoaderProxy proxy : proxyLoaders) |
7196 |
30 Aug 16 |
nicklas |
531 |
{ |
7226 |
15 Nov 16 |
nicklas |
532 |
if (log.isDebugEnabled()) |
7226 |
15 Nov 16 |
nicklas |
533 |
{ |
7226 |
15 Nov 16 |
nicklas |
534 |
log.debug("Checking if proxy JAR has changed: " + proxy.jarPath); |
7226 |
15 Nov 16 |
nicklas |
535 |
} |
7226 |
15 Nov 16 |
nicklas |
536 |
isSame = !proxy.hasChanged(); |
7226 |
15 Nov 16 |
nicklas |
537 |
if (!isSame) |
7226 |
15 Nov 16 |
nicklas |
538 |
{ |
7226 |
15 Nov 16 |
nicklas |
539 |
log.debug("Proxy JAR has changed: " + proxy.jarPath); |
7226 |
15 Nov 16 |
nicklas |
540 |
return true; |
7226 |
15 Nov 16 |
nicklas |
541 |
} |
7196 |
30 Aug 16 |
nicklas |
542 |
} |
4323 |
30 May 08 |
nicklas |
543 |
} |
7226 |
15 Nov 16 |
nicklas |
544 |
|
7226 |
15 Nov 16 |
nicklas |
545 |
if (log.isDebugEnabled()) log.debug("JAR has not changed: " + mainJarFile); |
4323 |
30 May 08 |
nicklas |
546 |
return false; |
4323 |
30 May 08 |
nicklas |
547 |
} |
4323 |
30 May 08 |
nicklas |
548 |
|
4323 |
30 May 08 |
nicklas |
549 |
/** |
1345 |
19 Sep 05 |
nicklas |
Convert a class name to a file path. Ie. replace dots with slahses and add .class |
6898 |
12 May 15 |
nicklas |
to the end: net.sf.basedb.util.JarClassLoader -> net/sf/basedb/util/JarClassLoader.class |
1345 |
19 Sep 05 |
nicklas |
552 |
*/ |
1345 |
19 Sep 05 |
nicklas |
553 |
private String classNameToPath(String className) |
1345 |
19 Sep 05 |
nicklas |
554 |
{ |
1345 |
19 Sep 05 |
nicklas |
555 |
return className.replaceAll("\\.", "/")+".class"; |
1345 |
19 Sep 05 |
nicklas |
556 |
} |
1345 |
19 Sep 05 |
nicklas |
557 |
|
1345 |
19 Sep 05 |
nicklas |
558 |
/** |
1345 |
19 Sep 05 |
nicklas |
Open the specified JAR file, list all entries and put them in the |
1345 |
19 Sep 05 |
nicklas |
{@link #classPath} mapping. |
1345 |
19 Sep 05 |
nicklas |
@param file The JAR file to open |
1345 |
19 Sep 05 |
nicklas |
@param followClassPath If the MANIFEST file should be checked for |
1345 |
19 Sep 05 |
nicklas |
a <code>Class-Path</code> entry that lists other JAR files |
1345 |
19 Sep 05 |
nicklas |
that also should be checked. |
1345 |
19 Sep 05 |
nicklas |
@throws IOException If there is an error reading the JAR files |
1345 |
19 Sep 05 |
nicklas |
566 |
*/ |
1345 |
19 Sep 05 |
nicklas |
567 |
private void loadJarFile(File file, boolean followClassPath) |
1345 |
19 Sep 05 |
nicklas |
568 |
throws IOException |
1345 |
19 Sep 05 |
nicklas |
569 |
{ |
4391 |
12 Aug 08 |
nicklas |
570 |
log.debug("loadJarFile: file=" + file); |
5394 |
25 Aug 10 |
nicklas |
571 |
JarInfo info = new JarInfo(file); |
5394 |
25 Aug 10 |
nicklas |
572 |
jarFiles.put(file, info); |
4321 |
29 May 08 |
nicklas |
573 |
if (!file.exists() || !file.isFile()) |
4321 |
29 May 08 |
nicklas |
574 |
{ |
4389 |
12 Aug 08 |
nicklas |
575 |
log.warn("File not found: " + file); |
4389 |
12 Aug 08 |
nicklas |
576 |
return; |
4321 |
29 May 08 |
nicklas |
577 |
} |
1345 |
19 Sep 05 |
nicklas |
578 |
JarFile jarFile = new JarFile(file); |
6880 |
21 Apr 15 |
nicklas |
579 |
try |
1345 |
19 Sep 05 |
nicklas |
580 |
{ |
6880 |
21 Apr 15 |
nicklas |
581 |
Manifest manifest = jarFile.getManifest(); |
6880 |
21 Apr 15 |
nicklas |
582 |
info.manifest = manifest; |
6880 |
21 Apr 15 |
nicklas |
583 |
Enumeration<JarEntry> entries = jarFile.entries(); |
6880 |
21 Apr 15 |
nicklas |
584 |
while (entries.hasMoreElements()) |
5014 |
25 Jun 09 |
martin |
585 |
{ |
6880 |
21 Apr 15 |
nicklas |
586 |
JarEntry jarEntry = entries.nextElement(); |
6880 |
21 Apr 15 |
nicklas |
587 |
if (jarEntry.isDirectory()) |
6880 |
21 Apr 15 |
nicklas |
588 |
{ |
6880 |
21 Apr 15 |
nicklas |
/* #### CONTINUE-STATEMENT #### */ |
6880 |
21 Apr 15 |
nicklas |
590 |
continue; |
6880 |
21 Apr 15 |
nicklas |
591 |
} |
6880 |
21 Apr 15 |
nicklas |
592 |
String name = jarEntry.getName(); |
6880 |
21 Apr 15 |
nicklas |
593 |
log.trace("Adding: " + name); |
6880 |
21 Apr 15 |
nicklas |
594 |
List<File> list = classPath.get(name); |
6880 |
21 Apr 15 |
nicklas |
595 |
if (list == null) |
6880 |
21 Apr 15 |
nicklas |
596 |
{ |
6880 |
21 Apr 15 |
nicklas |
597 |
list = new ArrayList<File>(); |
6880 |
21 Apr 15 |
nicklas |
598 |
classPath.put(name, list); |
6880 |
21 Apr 15 |
nicklas |
599 |
} |
6880 |
21 Apr 15 |
nicklas |
600 |
list.add(file); |
5014 |
25 Jun 09 |
martin |
601 |
} |
6880 |
21 Apr 15 |
nicklas |
602 |
if (followClassPath && manifest != null) |
1345 |
19 Sep 05 |
nicklas |
603 |
{ |
7192 |
29 Aug 16 |
nicklas |
604 |
File directory = file.getParentFile(); |
6880 |
21 Apr 15 |
nicklas |
605 |
Attributes attr = manifest.getMainAttributes(); |
6880 |
21 Apr 15 |
nicklas |
606 |
if (attr != null) |
1345 |
19 Sep 05 |
nicklas |
607 |
{ |
6880 |
21 Apr 15 |
nicklas |
608 |
String cp = attr.getValue(Attributes.Name.CLASS_PATH); |
6880 |
21 Apr 15 |
nicklas |
609 |
log.debug("Class path of JAR file '" + file + "': " + cp); |
6880 |
21 Apr 15 |
nicklas |
610 |
if (cp != null) |
1345 |
19 Sep 05 |
nicklas |
611 |
{ |
6880 |
21 Apr 15 |
nicklas |
612 |
String[] cps = cp.split("\\s+"); |
6880 |
21 Apr 15 |
nicklas |
613 |
for (int i = 0; i < cps.length; ++i) |
1345 |
19 Sep 05 |
nicklas |
614 |
{ |
6880 |
21 Apr 15 |
nicklas |
615 |
if (cps[i] != null && !cps[i].trim().equals("")) |
5622 |
03 May 11 |
nicklas |
616 |
{ |
7192 |
29 Aug 16 |
nicklas |
617 |
File classPathFile = new File(directory, cps[i]); |
6880 |
21 Apr 15 |
nicklas |
618 |
if (!classPathFile.exists()) |
5622 |
03 May 11 |
nicklas |
619 |
{ |
6880 |
21 Apr 15 |
nicklas |
620 |
log.debug("Referenced JAR file doesn't exist: '" + cps[i]); |
6880 |
21 Apr 15 |
nicklas |
// See if the requested file exists under META-INF |
6880 |
21 Apr 15 |
nicklas |
622 |
JarEntry entry = jarFile.getJarEntry("META-INF/" + cps[i]); |
6880 |
21 Apr 15 |
nicklas |
623 |
if (entry != null) |
5622 |
03 May 11 |
nicklas |
624 |
{ |
6880 |
21 Apr 15 |
nicklas |
625 |
log.debug("Extracting JAR from META-INF/" + cps[i] + " to jar.cache"); |
6880 |
21 Apr 15 |
nicklas |
// Extract it to userfiles directory (if we have to) |
6880 |
21 Apr 15 |
nicklas |
627 |
classPathFile = new File(Application.getUserFilesDirectory(), |
6880 |
21 Apr 15 |
nicklas |
628 |
"jar.cache/" + file.getName() + "/" + classPathFile.getName()); |
6880 |
21 Apr 15 |
nicklas |
629 |
boolean exists = classPathFile.exists(); |
6880 |
21 Apr 15 |
nicklas |
630 |
boolean sameTime = exists && classPathFile.lastModified() == entry.getTime(); |
6880 |
21 Apr 15 |
nicklas |
631 |
boolean sameSize = exists && classPathFile.length() == entry.getSize(); |
6880 |
21 Apr 15 |
nicklas |
632 |
if (!exists || !sameTime || !sameSize) |
5622 |
03 May 11 |
nicklas |
633 |
{ |
6880 |
21 Apr 15 |
nicklas |
634 |
classPathFile.getParentFile().mkdirs(); |
6880 |
21 Apr 15 |
nicklas |
635 |
InputStream in = null; |
6880 |
21 Apr 15 |
nicklas |
636 |
OutputStream out = null; |
6880 |
21 Apr 15 |
nicklas |
637 |
try |
6880 |
21 Apr 15 |
nicklas |
638 |
{ |
6880 |
21 Apr 15 |
nicklas |
639 |
in = jarFile.getInputStream(entry); |
6880 |
21 Apr 15 |
nicklas |
640 |
out = FileUtil.getOutputStream(classPathFile); |
6880 |
21 Apr 15 |
nicklas |
641 |
FileUtil.copy(in, out); |
6880 |
21 Apr 15 |
nicklas |
642 |
} |
6880 |
21 Apr 15 |
nicklas |
643 |
finally |
6880 |
21 Apr 15 |
nicklas |
644 |
{ |
6880 |
21 Apr 15 |
nicklas |
645 |
FileUtil.close(in); |
6880 |
21 Apr 15 |
nicklas |
646 |
FileUtil.close(out); |
6880 |
21 Apr 15 |
nicklas |
647 |
} |
5622 |
03 May 11 |
nicklas |
648 |
} |
5622 |
03 May 11 |
nicklas |
649 |
} |
7192 |
29 Aug 16 |
nicklas |
650 |
loadJarFile(classPathFile, false); |
5622 |
03 May 11 |
nicklas |
651 |
} |
7192 |
29 Aug 16 |
nicklas |
652 |
else |
7192 |
29 Aug 16 |
nicklas |
653 |
{ |
7192 |
29 Aug 16 |
nicklas |
654 |
proxyLoaders.add(new JarClassLoaderProxy(classPathFile.getAbsolutePath())); |
7192 |
29 Aug 16 |
nicklas |
655 |
} |
5622 |
03 May 11 |
nicklas |
656 |
} |
1345 |
19 Sep 05 |
nicklas |
657 |
} |
1345 |
19 Sep 05 |
nicklas |
658 |
} |
6880 |
21 Apr 15 |
nicklas |
659 |
if (file == mainJarFile) |
6880 |
21 Apr 15 |
nicklas |
660 |
{ |
6880 |
21 Apr 15 |
nicklas |
661 |
delegateFirst = Values.getBoolean(attr.getValue("X-Delegate-First"), delegateFirst); |
6880 |
21 Apr 15 |
nicklas |
662 |
} |
1345 |
19 Sep 05 |
nicklas |
663 |
} |
1345 |
19 Sep 05 |
nicklas |
664 |
} |
1345 |
19 Sep 05 |
nicklas |
665 |
} |
6880 |
21 Apr 15 |
nicklas |
666 |
finally |
6880 |
21 Apr 15 |
nicklas |
667 |
{ |
6880 |
21 Apr 15 |
nicklas |
668 |
FileUtil.close(jarFile); |
6880 |
21 Apr 15 |
nicklas |
669 |
} |
1345 |
19 Sep 05 |
nicklas |
670 |
} |
1345 |
19 Sep 05 |
nicklas |
671 |
|
1345 |
19 Sep 05 |
nicklas |
672 |
/** |
1343 |
15 Sep 05 |
nicklas |
Load the byte[] of the given class. |
1343 |
15 Sep 05 |
nicklas |
674 |
|
1345 |
19 Sep 05 |
nicklas |
@param file The JAR file in which the class implmentation is located |
1343 |
15 Sep 05 |
nicklas |
@param name The name of the class using regular naming convention, |
1343 |
15 Sep 05 |
nicklas |
ie. net.sf.basedb.util.JarClassLoader |
1343 |
15 Sep 05 |
nicklas |
@throws ClassNotFoundException If the class can't be loaded |
1343 |
15 Sep 05 |
nicklas |
679 |
*/ |
1345 |
19 Sep 05 |
nicklas |
680 |
private byte[] loadClassData(File file, String name) |
1343 |
15 Sep 05 |
nicklas |
681 |
throws ClassNotFoundException |
1343 |
15 Sep 05 |
nicklas |
682 |
{ |
4391 |
12 Aug 08 |
nicklas |
683 |
log.debug("loadClassData: " + name + " from file: " + file); |
1343 |
15 Sep 05 |
nicklas |
684 |
InputStream in = null; |
6880 |
21 Apr 15 |
nicklas |
685 |
JarFile jarFile = null; |
1343 |
15 Sep 05 |
nicklas |
686 |
try |
1343 |
15 Sep 05 |
nicklas |
687 |
{ |
6880 |
21 Apr 15 |
nicklas |
688 |
jarFile = new JarFile(file); |
1343 |
15 Sep 05 |
nicklas |
// Get the jar entry and open an input stream to read the file |
1345 |
19 Sep 05 |
nicklas |
690 |
JarEntry jarEntry = jarFile.getJarEntry(classNameToPath(name)); |
1345 |
19 Sep 05 |
nicklas |
691 |
if (jarEntry == null) |
1345 |
19 Sep 05 |
nicklas |
692 |
{ |
1345 |
19 Sep 05 |
nicklas |
693 |
throw new ClassNotFoundException(name+" in file "+file); |
1345 |
19 Sep 05 |
nicklas |
694 |
} |
1345 |
19 Sep 05 |
nicklas |
695 |
in = jarFile.getInputStream(jarEntry); |
3994 |
22 Nov 07 |
enell |
696 |
int classSize = (int)jarEntry.getSize(); |
3994 |
22 Nov 07 |
enell |
697 |
byte[] b = new byte[classSize]; |
3994 |
22 Nov 07 |
enell |
698 |
int totalRead = 0; |
3994 |
22 Nov 07 |
enell |
699 |
while (totalRead < classSize) |
3994 |
22 Nov 07 |
enell |
700 |
{ |
3994 |
22 Nov 07 |
enell |
701 |
int numRead = in.read(b, totalRead, b.length - totalRead); |
3994 |
22 Nov 07 |
enell |
702 |
if (numRead == -1) break; |
3994 |
22 Nov 07 |
enell |
703 |
totalRead += numRead; |
4391 |
12 Aug 08 |
nicklas |
704 |
log.debug("loadClassData: size=" + classSize + "; loaded=" + totalRead); |
3994 |
22 Nov 07 |
enell |
705 |
} |
3994 |
22 Nov 07 |
enell |
706 |
if (totalRead != classSize) |
3994 |
22 Nov 07 |
enell |
707 |
{ |
3994 |
22 Nov 07 |
enell |
708 |
throw new ClassFormatError("Could not read the complete class for " + |
3994 |
22 Nov 07 |
enell |
709 |
name + ": " + totalRead + " bytes; expected " + classSize + " bytes"); |
3994 |
22 Nov 07 |
enell |
710 |
} |
1343 |
15 Sep 05 |
nicklas |
711 |
return b; |
1343 |
15 Sep 05 |
nicklas |
712 |
} |
1343 |
15 Sep 05 |
nicklas |
713 |
catch (Throwable ex) |
1343 |
15 Sep 05 |
nicklas |
714 |
{ |
1343 |
15 Sep 05 |
nicklas |
715 |
throw new ClassNotFoundException(name, ex); |
1343 |
15 Sep 05 |
nicklas |
716 |
} |
1343 |
15 Sep 05 |
nicklas |
717 |
finally |
1343 |
15 Sep 05 |
nicklas |
718 |
{ |
5384 |
13 Aug 10 |
nicklas |
719 |
FileUtil.close(in); |
6880 |
21 Apr 15 |
nicklas |
720 |
FileUtil.close(jarFile); |
1343 |
15 Sep 05 |
nicklas |
721 |
} |
1343 |
15 Sep 05 |
nicklas |
722 |
} |
5394 |
25 Aug 10 |
nicklas |
723 |
/** |
5394 |
25 Aug 10 |
nicklas |
Define the package with the given name using information from a |
5394 |
25 Aug 10 |
nicklas |
manifest for vendor, title and version. The package should not |
5394 |
25 Aug 10 |
nicklas |
already exist. |
5394 |
25 Aug 10 |
nicklas |
@param name The name of the package |
5394 |
25 Aug 10 |
nicklas |
@param mf An optional manifest |
5394 |
25 Aug 10 |
nicklas |
@return A package |
5394 |
25 Aug 10 |
nicklas |
@since 2.16 |
5394 |
25 Aug 10 |
nicklas |
731 |
*/ |
5394 |
25 Aug 10 |
nicklas |
732 |
private Package definePackage(String name, Manifest mf) |
5394 |
25 Aug 10 |
nicklas |
733 |
{ |
5394 |
25 Aug 10 |
nicklas |
734 |
String specTitle = null; |
5394 |
25 Aug 10 |
nicklas |
735 |
String specVersion = null; |
5394 |
25 Aug 10 |
nicklas |
736 |
String specVendor = null; |
5394 |
25 Aug 10 |
nicklas |
737 |
String implTitle = null; |
5394 |
25 Aug 10 |
nicklas |
738 |
String implVersion = null; |
5394 |
25 Aug 10 |
nicklas |
739 |
String implVendor = null; |
5394 |
25 Aug 10 |
nicklas |
740 |
if (mf != null) |
5394 |
25 Aug 10 |
nicklas |
741 |
{ |
5394 |
25 Aug 10 |
nicklas |
// Check if attributes are defined for the given package path |
5394 |
25 Aug 10 |
nicklas |
743 |
String path = name.replace('.', '/') + "/"; |
5394 |
25 Aug 10 |
nicklas |
744 |
Attributes attr = mf.getAttributes(path); |
5394 |
25 Aug 10 |
nicklas |
745 |
if (attr != null) |
5394 |
25 Aug 10 |
nicklas |
746 |
{ |
5394 |
25 Aug 10 |
nicklas |
747 |
specTitle = attr.getValue(Name.SPECIFICATION_TITLE); |
5394 |
25 Aug 10 |
nicklas |
748 |
specVersion = attr.getValue(Name.SPECIFICATION_VERSION); |
5394 |
25 Aug 10 |
nicklas |
749 |
specVendor = attr.getValue(Name.SPECIFICATION_VENDOR); |
5394 |
25 Aug 10 |
nicklas |
750 |
implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE); |
5394 |
25 Aug 10 |
nicklas |
751 |
implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION); |
5394 |
25 Aug 10 |
nicklas |
752 |
implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR); |
5394 |
25 Aug 10 |
nicklas |
753 |
} |
5394 |
25 Aug 10 |
nicklas |
// Check global attributes |
5394 |
25 Aug 10 |
nicklas |
755 |
attr = mf.getMainAttributes(); |
5394 |
25 Aug 10 |
nicklas |
756 |
if (attr != null) |
5394 |
25 Aug 10 |
nicklas |
757 |
{ |
5394 |
25 Aug 10 |
nicklas |
758 |
if (specTitle == null) specTitle = attr.getValue(Name.SPECIFICATION_TITLE); |
5394 |
25 Aug 10 |
nicklas |
759 |
if (specVersion == null) specVersion = attr.getValue(Name.SPECIFICATION_VERSION); |
5394 |
25 Aug 10 |
nicklas |
760 |
if (specVendor == null) specVendor = attr.getValue(Name.SPECIFICATION_VENDOR); |
5394 |
25 Aug 10 |
nicklas |
761 |
if (implTitle == null) implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE); |
5394 |
25 Aug 10 |
nicklas |
762 |
if (implVersion == null) implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION); |
5394 |
25 Aug 10 |
nicklas |
763 |
if (implVendor == null) implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR); |
5394 |
25 Aug 10 |
nicklas |
764 |
} |
5394 |
25 Aug 10 |
nicklas |
765 |
} |
5394 |
25 Aug 10 |
nicklas |
766 |
return definePackage(name, specTitle, specVersion, specVendor, implTitle, implVersion, implVendor, null); |
5394 |
25 Aug 10 |
nicklas |
767 |
} |
4323 |
30 May 08 |
nicklas |
768 |
|
5013 |
25 Jun 09 |
nicklas |
769 |
private Class<?> loadClassInternal(ClassLoader loader, String name) |
5013 |
25 Jun 09 |
nicklas |
770 |
{ |
5013 |
25 Jun 09 |
nicklas |
771 |
Class<?> c = null; |
5013 |
25 Jun 09 |
nicklas |
772 |
if (loader != null) |
5013 |
25 Jun 09 |
nicklas |
773 |
{ |
5013 |
25 Jun 09 |
nicklas |
774 |
try |
5013 |
25 Jun 09 |
nicklas |
775 |
{ |
5013 |
25 Jun 09 |
nicklas |
776 |
c = loader.loadClass(name); |
5013 |
25 Jun 09 |
nicklas |
777 |
} |
5013 |
25 Jun 09 |
nicklas |
778 |
catch (ClassNotFoundException ex) |
5013 |
25 Jun 09 |
nicklas |
779 |
{} |
5013 |
25 Jun 09 |
nicklas |
780 |
} |
5013 |
25 Jun 09 |
nicklas |
781 |
return c; |
5013 |
25 Jun 09 |
nicklas |
782 |
} |
5013 |
25 Jun 09 |
nicklas |
783 |
|
5013 |
25 Jun 09 |
nicklas |
784 |
private void addResources(Vector<URL> resources, Enumeration<URL> e) |
5013 |
25 Jun 09 |
nicklas |
785 |
{ |
5013 |
25 Jun 09 |
nicklas |
786 |
if (e == null) return; |
5013 |
25 Jun 09 |
nicklas |
787 |
while (e.hasMoreElements()) |
5013 |
25 Jun 09 |
nicklas |
788 |
{ |
5013 |
25 Jun 09 |
nicklas |
789 |
resources.add(e.nextElement()); |
5013 |
25 Jun 09 |
nicklas |
790 |
} |
5013 |
25 Jun 09 |
nicklas |
791 |
} |
5013 |
25 Jun 09 |
nicklas |
792 |
|
4323 |
30 May 08 |
nicklas |
793 |
static class JarInfo |
4323 |
30 May 08 |
nicklas |
794 |
{ |
4323 |
30 May 08 |
nicklas |
795 |
final File jarFile; |
5394 |
25 Aug 10 |
nicklas |
796 |
Manifest manifest; |
4390 |
12 Aug 08 |
nicklas |
797 |
final boolean existed; |
4323 |
30 May 08 |
nicklas |
798 |
final long lastModified; |
4323 |
30 May 08 |
nicklas |
799 |
final long size; |
4323 |
30 May 08 |
nicklas |
800 |
|
4323 |
30 May 08 |
nicklas |
801 |
JarInfo(File jarFile) |
4323 |
30 May 08 |
nicklas |
802 |
{ |
4323 |
30 May 08 |
nicklas |
803 |
this.jarFile = jarFile; |
4390 |
12 Aug 08 |
nicklas |
804 |
this.existed = jarFile.exists(); |
4323 |
30 May 08 |
nicklas |
805 |
this.size = jarFile.length(); |
4323 |
30 May 08 |
nicklas |
806 |
this.lastModified = jarFile.lastModified(); |
4323 |
30 May 08 |
nicklas |
807 |
} |
4323 |
30 May 08 |
nicklas |
808 |
} |
7192 |
29 Aug 16 |
nicklas |
809 |
|
7192 |
29 Aug 16 |
nicklas |
810 |
/** |
7192 |
29 Aug 16 |
nicklas |
A proxy class loader is typically needed when one extension |
7192 |
29 Aug 16 |
nicklas |
depends on another extension. The proxy is needed since |
7192 |
29 Aug 16 |
nicklas |
we want to use lazy initialization of the other class loaders. |
7192 |
29 Aug 16 |
nicklas |
They may not be needed immediately. The proxy will also make it |
7192 |
29 Aug 16 |
nicklas |
possible to avoid infinite recursion in case two extensions |
7192 |
29 Aug 16 |
nicklas |
depend on each other. |
7192 |
29 Aug 16 |
nicklas |
<p> |
7192 |
29 Aug 16 |
nicklas |
818 |
|
7192 |
29 Aug 16 |
nicklas |
Once a real class loader has been aquired it will be kept |
7192 |
29 Aug 16 |
nicklas |
until the main class loader is discared. Note that the |
7192 |
29 Aug 16 |
nicklas |
{@link JarClassLoader#hasChanged(boolean)} is not used for |
7192 |
29 Aug 16 |
nicklas |
automatic reloading since that may cause class-cast exceptions. |
7192 |
29 Aug 16 |
nicklas |
<p> |
7192 |
29 Aug 16 |
nicklas |
824 |
|
7192 |
29 Aug 16 |
nicklas |
The proxy is also used to limit the search for classes to |
7192 |
29 Aug 16 |
nicklas |
classes that are directly handled directly by the other class |
7192 |
29 Aug 16 |
nicklas |
loader. The system and parent class loaders are not searched again |
7192 |
29 Aug 16 |
nicklas |
since they are already searched in the main class loader. |
7192 |
29 Aug 16 |
nicklas |
829 |
|
7192 |
29 Aug 16 |
nicklas |
@since 3.10 |
7192 |
29 Aug 16 |
nicklas |
831 |
*/ |
7192 |
29 Aug 16 |
nicklas |
832 |
static class JarClassLoaderProxy |
7192 |
29 Aug 16 |
nicklas |
833 |
{ |
7192 |
29 Aug 16 |
nicklas |
834 |
|
7192 |
29 Aug 16 |
nicklas |
835 |
final String jarPath; |
7192 |
29 Aug 16 |
nicklas |
836 |
private JarClassLoader loader; |
7192 |
29 Aug 16 |
nicklas |
837 |
private boolean isInitialized; |
7192 |
29 Aug 16 |
nicklas |
838 |
|
7192 |
29 Aug 16 |
nicklas |
839 |
/** |
7192 |
29 Aug 16 |
nicklas |
Creates a proxy class loader for the given JAR file. |
7192 |
29 Aug 16 |
nicklas |
841 |
*/ |
7192 |
29 Aug 16 |
nicklas |
842 |
JarClassLoaderProxy(String jarPath) |
7192 |
29 Aug 16 |
nicklas |
843 |
{ |
7192 |
29 Aug 16 |
nicklas |
844 |
this.jarPath = jarPath; |
7192 |
29 Aug 16 |
nicklas |
845 |
this.isInitialized = false; |
7192 |
29 Aug 16 |
nicklas |
846 |
} |
7192 |
29 Aug 16 |
nicklas |
847 |
|
7192 |
29 Aug 16 |
nicklas |
848 |
/** |
7192 |
29 Aug 16 |
nicklas |
Initialize the proxy. |
7192 |
29 Aug 16 |
nicklas |
850 |
*/ |
7192 |
29 Aug 16 |
nicklas |
851 |
private synchronized void init() |
7192 |
29 Aug 16 |
nicklas |
852 |
{ |
7192 |
29 Aug 16 |
nicklas |
853 |
if (isInitialized) return; |
7192 |
29 Aug 16 |
nicklas |
854 |
if (log.isDebugEnabled()) log.debug("JarClassLoaderProxy.init[" + jarPath + "]"); |
7192 |
29 Aug 16 |
nicklas |
855 |
|
7192 |
29 Aug 16 |
nicklas |
856 |
try |
7192 |
29 Aug 16 |
nicklas |
857 |
{ |
7192 |
29 Aug 16 |
nicklas |
858 |
loader = (JarClassLoader)JarClassLoader.getInstance(jarPath, true); |
7192 |
29 Aug 16 |
nicklas |
859 |
} |
7192 |
29 Aug 16 |
nicklas |
860 |
catch (IOException ex) |
7192 |
29 Aug 16 |
nicklas |
861 |
{} |
7192 |
29 Aug 16 |
nicklas |
862 |
isInitialized = true; |
7192 |
29 Aug 16 |
nicklas |
863 |
} |
7192 |
29 Aug 16 |
nicklas |
864 |
|
7192 |
29 Aug 16 |
nicklas |
865 |
|
7192 |
29 Aug 16 |
nicklas |
866 |
Class<?> findClass(String name) |
7192 |
29 Aug 16 |
nicklas |
867 |
{ |
7192 |
29 Aug 16 |
nicklas |
868 |
if (log.isDebugEnabled()) log.debug("JarClassLoaderProxy.findClass[" + jarPath + "]: " + name); |
7192 |
29 Aug 16 |
nicklas |
869 |
if (!isInitialized) init(); |
7192 |
29 Aug 16 |
nicklas |
870 |
|
7192 |
29 Aug 16 |
nicklas |
871 |
Class<?> c = null; |
7192 |
29 Aug 16 |
nicklas |
872 |
if (loader != null) |
7192 |
29 Aug 16 |
nicklas |
873 |
{ |
7192 |
29 Aug 16 |
nicklas |
874 |
try |
7192 |
29 Aug 16 |
nicklas |
875 |
{ |
7192 |
29 Aug 16 |
nicklas |
// 1. Check if the class has already been loaded |
7192 |
29 Aug 16 |
nicklas |
877 |
c = loader.findLoadedClass(name); |
7192 |
29 Aug 16 |
nicklas |
878 |
if (log.isDebugEnabled()) log.debug("JarClassLoaderProxy.findClass[" + jarPath + "]: loaded class (" + name + "): " + c); |
7192 |
29 Aug 16 |
nicklas |
879 |
|
7192 |
29 Aug 16 |
nicklas |
// 2. Otherwise try to load the class without searching parent or system class loaders |
7192 |
29 Aug 16 |
nicklas |
881 |
if (c == null) |
7192 |
29 Aug 16 |
nicklas |
882 |
{ |
7192 |
29 Aug 16 |
nicklas |
883 |
c = loader.findClass(name); |
7192 |
29 Aug 16 |
nicklas |
884 |
if (log.isDebugEnabled()) log.debug("JarClassLoaderProxy.findClass[" + jarPath + "]: found class (" + name + "): " + c); |
7192 |
29 Aug 16 |
nicklas |
885 |
} |
7192 |
29 Aug 16 |
nicklas |
886 |
} |
7192 |
29 Aug 16 |
nicklas |
887 |
catch (ClassNotFoundException ex) |
7192 |
29 Aug 16 |
nicklas |
888 |
{} |
7192 |
29 Aug 16 |
nicklas |
889 |
} |
7192 |
29 Aug 16 |
nicklas |
890 |
return c; |
7192 |
29 Aug 16 |
nicklas |
891 |
} |
7196 |
30 Aug 16 |
nicklas |
892 |
|
7196 |
30 Aug 16 |
nicklas |
893 |
URL findResource(String name) |
7196 |
30 Aug 16 |
nicklas |
894 |
{ |
7196 |
30 Aug 16 |
nicklas |
895 |
if (log.isDebugEnabled()) log.debug("JarClassLoaderProxy.findResource[" + jarPath + "]: " + name); |
7196 |
30 Aug 16 |
nicklas |
896 |
if (!isInitialized) init(); |
7196 |
30 Aug 16 |
nicklas |
897 |
|
7196 |
30 Aug 16 |
nicklas |
898 |
URL url = null; |
7196 |
30 Aug 16 |
nicklas |
899 |
if (loader != null) |
7196 |
30 Aug 16 |
nicklas |
900 |
{ |
7196 |
30 Aug 16 |
nicklas |
901 |
url = loader.findResource(name); |
7196 |
30 Aug 16 |
nicklas |
902 |
} |
7196 |
30 Aug 16 |
nicklas |
903 |
return url; |
7196 |
30 Aug 16 |
nicklas |
904 |
} |
7196 |
30 Aug 16 |
nicklas |
905 |
|
7196 |
30 Aug 16 |
nicklas |
906 |
Enumeration<URL> findResources(String name) |
7196 |
30 Aug 16 |
nicklas |
907 |
{ |
7196 |
30 Aug 16 |
nicklas |
908 |
if (log.isDebugEnabled()) log.debug("JarClassLoaderProxy.findResources[" + jarPath + "]: " + name); |
7196 |
30 Aug 16 |
nicklas |
909 |
if (!isInitialized) init(); |
7196 |
30 Aug 16 |
nicklas |
910 |
|
7196 |
30 Aug 16 |
nicklas |
911 |
Enumeration<URL> url = null; |
7196 |
30 Aug 16 |
nicklas |
912 |
if (loader != null) |
7196 |
30 Aug 16 |
nicklas |
913 |
{ |
7196 |
30 Aug 16 |
nicklas |
914 |
url = loader.findResources(name); |
7196 |
30 Aug 16 |
nicklas |
915 |
} |
7196 |
30 Aug 16 |
nicklas |
916 |
return url; |
7196 |
30 Aug 16 |
nicklas |
917 |
} |
7196 |
30 Aug 16 |
nicklas |
918 |
|
7196 |
30 Aug 16 |
nicklas |
919 |
boolean hasChanged() |
7196 |
30 Aug 16 |
nicklas |
920 |
{ |
7196 |
30 Aug 16 |
nicklas |
921 |
if (!isInitialized) return false; |
7196 |
30 Aug 16 |
nicklas |
922 |
if (loader != null) return loader.hasChanged(true); |
7196 |
30 Aug 16 |
nicklas |
923 |
return new File(jarPath).exists(); |
7196 |
30 Aug 16 |
nicklas |
924 |
} |
7192 |
29 Aug 16 |
nicklas |
925 |
} |
1343 |
15 Sep 05 |
nicklas |
926 |
} |