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