1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.eclipse.jetty.webapp;
15
16 import java.io.File;
17 import java.io.IOException;
18 import java.net.URL;
19 import java.net.URLClassLoader;
20 import java.security.CodeSource;
21 import java.security.PermissionCollection;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.Enumeration;
25 import java.util.HashSet;
26 import java.util.List;
27 import java.util.Set;
28 import java.util.StringTokenizer;
29
30 import org.eclipse.jetty.util.StringUtil;
31 import org.eclipse.jetty.util.log.Log;
32 import org.eclipse.jetty.util.log.Logger;
33 import org.eclipse.jetty.util.resource.Resource;
34 import org.eclipse.jetty.util.resource.ResourceCollection;
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 public class WebAppClassLoader extends URLClassLoader
56 {
57 private static final Logger LOG = Log.getLogger(WebAppClassLoader.class);
58
59 private final Context _context;
60 private final ClassLoader _parent;
61 private final Set<String> _extensions=new HashSet<String>();
62 private String _name=String.valueOf(hashCode());
63
64
65
66
67 public interface Context
68 {
69
70
71
72
73
74
75
76
77 Resource newResource(String urlOrPath) throws IOException;
78
79
80
81
82
83 PermissionCollection getPermissions();
84
85
86
87
88
89
90
91
92
93 boolean isSystemClass(String clazz);
94
95
96
97
98
99
100
101
102
103
104 boolean isServerClass(String clazz);
105
106
107
108
109
110
111
112
113 boolean isParentLoaderPriority();
114
115
116 String getExtraClasspath();
117
118 }
119
120
121
122
123 public WebAppClassLoader(Context context)
124 throws IOException
125 {
126 this(null,context);
127 }
128
129
130
131
132 public WebAppClassLoader(ClassLoader parent, Context context)
133 throws IOException
134 {
135 super(new URL[]{},parent!=null?parent
136 :(Thread.currentThread().getContextClassLoader()!=null?Thread.currentThread().getContextClassLoader()
137 :(WebAppClassLoader.class.getClassLoader()!=null?WebAppClassLoader.class.getClassLoader()
138 :ClassLoader.getSystemClassLoader())));
139 _parent=getParent();
140 _context=context;
141 if (_parent==null)
142 throw new IllegalArgumentException("no parent classloader!");
143
144 _extensions.add(".jar");
145 _extensions.add(".zip");
146
147
148 String extensions = System.getProperty(WebAppClassLoader.class.getName() + ".extensions");
149 if(extensions!=null)
150 {
151 StringTokenizer tokenizer = new StringTokenizer(extensions, ",;");
152 while(tokenizer.hasMoreTokens())
153 _extensions.add(tokenizer.nextToken().trim());
154 }
155
156 if (context.getExtraClasspath()!=null)
157 addClassPath(context.getExtraClasspath());
158 }
159
160
161
162
163
164 public String getName()
165 {
166 return _name;
167 }
168
169
170
171
172
173 public void setName(String name)
174 {
175 _name=name;
176 }
177
178
179
180 public Context getContext()
181 {
182 return _context;
183 }
184
185
186
187
188
189
190
191 public void addClassPath(Resource resource)
192 throws IOException
193 {
194 if (resource instanceof ResourceCollection)
195 {
196 for (Resource r : ((ResourceCollection)resource).getResources())
197 addClassPath(r);
198 }
199 else
200 {
201 addClassPath(resource.toString());
202 }
203 }
204
205
206
207
208
209
210
211 public void addClassPath(String classPath)
212 throws IOException
213 {
214 if (classPath == null)
215 return;
216
217 StringTokenizer tokenizer= new StringTokenizer(classPath, ",;");
218 while (tokenizer.hasMoreTokens())
219 {
220 Resource resource= _context.newResource(tokenizer.nextToken().trim());
221 if (LOG.isDebugEnabled())
222 LOG.debug("Path resource=" + resource);
223
224
225 if (resource.isDirectory() && resource instanceof ResourceCollection)
226 addClassPath(resource);
227 else
228 {
229
230 File file= resource.getFile();
231 if (file != null)
232 {
233 URL url= resource.getURL();
234 addURL(url);
235 }
236 else if (resource.isDirectory())
237 addURL(resource.getURL());
238 else
239 throw new IllegalArgumentException("!file: "+resource);
240 }
241 }
242 }
243
244
245
246
247
248 private boolean isFileSupported(String file)
249 {
250 int dot = file.lastIndexOf('.');
251 return dot!=-1 && _extensions.contains(file.substring(dot));
252 }
253
254
255
256
257
258
259 public void addJars(Resource lib)
260 {
261 if (lib.exists() && lib.isDirectory())
262 {
263 String[] files=lib.list();
264 for (int f=0;files!=null && f<files.length;f++)
265 {
266 try
267 {
268 Resource fn=lib.addPath(files[f]);
269 String fnlc=fn.getName().toLowerCase();
270
271 if (isFileSupported(fnlc))
272 {
273 String jar=fn.toString();
274 jar=StringUtil.replace(jar, ",", "%2C");
275 jar=StringUtil.replace(jar, ";", "%3B");
276 addClassPath(jar);
277 }
278 }
279 catch (Exception ex)
280 {
281 LOG.warn(Log.EXCEPTION,ex);
282 }
283 }
284 }
285 }
286
287
288 public PermissionCollection getPermissions(CodeSource cs)
289 {
290
291 PermissionCollection permissions=_context.getPermissions();
292 PermissionCollection pc= (permissions == null) ? super.getPermissions(cs) : permissions;
293 return pc;
294 }
295
296
297 public Enumeration<URL> getResources(String name) throws IOException
298 {
299 boolean system_class=_context.isSystemClass(name);
300 boolean server_class=_context.isServerClass(name);
301
302 List<URL> from_parent = toList(server_class?null:_parent.getResources(name));
303 List<URL> from_webapp = toList((system_class&&!from_parent.isEmpty())?null:this.findResources(name));
304
305 if (_context.isParentLoaderPriority())
306 {
307 from_parent.addAll(from_webapp);
308 return Collections.enumeration(from_parent);
309 }
310 from_webapp.addAll(from_parent);
311 return Collections.enumeration(from_webapp);
312 }
313
314
315 private List<URL> toList(Enumeration<URL> e)
316 {
317 if (e==null)
318 return new ArrayList<URL>();
319 return Collections.list(e);
320 }
321
322
323
324
325
326
327
328
329
330 public URL getResource(String name)
331 {
332 URL url= null;
333 boolean tried_parent= false;
334 boolean system_class=_context.isSystemClass(name);
335 boolean server_class=_context.isServerClass(name);
336
337 if (system_class && server_class)
338 return null;
339
340 if (_parent!=null &&(_context.isParentLoaderPriority() || system_class ) && !server_class)
341 {
342 tried_parent= true;
343
344 if (_parent!=null)
345 url= _parent.getResource(name);
346 }
347
348 if (url == null)
349 {
350 url= this.findResource(name);
351
352 if (url == null && name.startsWith("/"))
353 {
354 if (LOG.isDebugEnabled())
355 LOG.debug("HACK leading / off " + name);
356 url= this.findResource(name.substring(1));
357 }
358 }
359
360 if (url == null && !tried_parent && !server_class )
361 {
362 if (_parent!=null)
363 url= _parent.getResource(name);
364 }
365
366 if (url != null)
367 if (LOG.isDebugEnabled())
368 LOG.debug("getResource("+name+")=" + url);
369
370 return url;
371 }
372
373
374 @Override
375 public Class<?> loadClass(String name) throws ClassNotFoundException
376 {
377 return loadClass(name, false);
378 }
379
380
381 @Override
382 protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
383 {
384 Class<?> c= findLoadedClass(name);
385 ClassNotFoundException ex= null;
386 boolean tried_parent= false;
387
388 boolean system_class=_context.isSystemClass(name);
389 boolean server_class=_context.isServerClass(name);
390
391 if (system_class && server_class)
392 {
393 return null;
394 }
395
396 if (c == null && _parent!=null && (_context.isParentLoaderPriority() || system_class) && !server_class)
397 {
398 tried_parent= true;
399 try
400 {
401 c= _parent.loadClass(name);
402 if (LOG.isDebugEnabled())
403 LOG.debug("loaded " + c);
404 }
405 catch (ClassNotFoundException e)
406 {
407 ex= e;
408 }
409 }
410
411 if (c == null)
412 {
413 try
414 {
415 c= this.findClass(name);
416 }
417 catch (ClassNotFoundException e)
418 {
419 ex= e;
420 }
421 }
422
423 if (c == null && _parent!=null && !tried_parent && !server_class )
424 c= _parent.loadClass(name);
425
426 if (c == null)
427 throw ex;
428
429 if (resolve)
430 resolveClass(c);
431
432 if (LOG.isDebugEnabled())
433 LOG.debug("loaded " + c+ " from "+c.getClassLoader());
434
435 return c;
436 }
437
438
439 public String toString()
440 {
441 return "WebAppClassLoader=" + _name+"@"+Long.toHexString(hashCode());
442 }
443 }