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