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