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