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