1 package org.eclipse.jetty.webapp;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.net.URI;
6 import java.net.URL;
7 import java.net.URLClassLoader;
8 import java.util.ArrayList;
9 import java.util.List;
10 import java.util.regex.Pattern;
11
12 import org.eclipse.jetty.server.Connector;
13 import org.eclipse.jetty.util.IO;
14 import org.eclipse.jetty.util.PatternMatcher;
15 import org.eclipse.jetty.util.URIUtil;
16 import org.eclipse.jetty.util.log.Log;
17 import org.eclipse.jetty.util.resource.JarResource;
18 import org.eclipse.jetty.util.resource.Resource;
19 import org.eclipse.jetty.util.resource.ResourceCollection;
20
21 public class WebInfConfiguration implements Configuration
22 {
23 public static final String TEMPDIR_CREATED = "org.eclipse.jetty.tmpdirCreated";
24 public static final String JAR_RESOURCES = "org.eclipse.jetty.jarList";
25 public static final String CONTAINER_JAR_PATTERN = "org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern";
26 public static final String WEBINF_JAR_PATTERN = "org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern";
27
28
29
30
31
32 public static final String RESOURCE_URLS = "org.eclipse.jetty.resources";
33
34
35
36
37 public void preConfigure(final WebAppContext context) throws Exception
38 {
39
40 resolveTempDirectory(context);
41
42
43 unpack (context);
44
45 File work = findWorkDirectory(context);
46 if (work != null)
47 makeTempDirectory(work, context, false);
48
49
50
51 String tmp = (String)context.getAttribute(WEBINF_JAR_PATTERN);
52 Pattern webInfPattern = (tmp==null?null:Pattern.compile(tmp));
53 tmp = (String)context.getAttribute(CONTAINER_JAR_PATTERN);
54 Pattern containerPattern = (tmp==null?null:Pattern.compile(tmp));
55
56 final ArrayList jarResources = new ArrayList<Resource>();
57 context.setAttribute(JAR_RESOURCES, jarResources);
58
59 PatternMatcher jarNameMatcher = new PatternMatcher ()
60 {
61 public void matched(URI uri) throws Exception
62 {
63 jarResources.add(Resource.newResource(uri));
64 }
65
66 };
67
68
69 ClassLoader loader = context.getClassLoader();
70 while (loader != null && (loader instanceof URLClassLoader))
71 {
72 URL[] urls = ((URLClassLoader)loader).getURLs();
73 if (urls != null)
74 {
75 URI[] containerUris = new URI[urls.length];
76 int i=0;
77 for (URL u : urls)
78 {
79 containerUris[i++] = u.toURI();
80 }
81 jarNameMatcher.match(containerPattern, containerUris, false);
82 }
83 loader = loader.getParent();
84 }
85
86
87
88 List<Resource> jars = findJars(context);
89
90 URI[] uris = null;
91 if (jars != null)
92 {
93 uris = new URI[jars.size()];
94 int i=0;
95 for (Resource r: jars)
96 {
97 uris[i++] = r.getURI();
98 }
99 }
100 jarNameMatcher.match(webInfPattern, uris, true);
101 }
102
103
104
105 public void postConfigure(WebAppContext context) throws Exception
106 {
107
108
109 }
110
111
112 public void configure(WebAppContext context) throws Exception
113 {
114
115 if (context.isStarted())
116 {
117 if (Log.isDebugEnabled()){Log.debug("Cannot configure webapp "+context+" after it is started");}
118 return;
119 }
120
121 Resource web_inf = context.getWebInf();
122
123
124 if (web_inf != null && web_inf.isDirectory() && context.getClassLoader() instanceof WebAppClassLoader)
125 {
126
127 Resource classes= web_inf.addPath("classes/");
128 if (classes.exists())
129 ((WebAppClassLoader)context.getClassLoader()).addClassPath(classes.toString());
130
131
132 Resource lib= web_inf.addPath("lib/");
133 if (lib.exists() || lib.isDirectory())
134 ((WebAppClassLoader)context.getClassLoader()).addJars(lib);
135 }
136
137
138 List<Resource> resources = (List<Resource>)context.getAttribute(RESOURCE_URLS);
139 if (resources!=null)
140 {
141 Resource[] collection=new Resource[resources.size()+1];
142 int i=0;
143 collection[i++]=context.getBaseResource();
144 for (Resource resource : resources)
145 collection[i++]=resource;
146 context.setBaseResource(new ResourceCollection(collection));
147 }
148 }
149
150 public void deconfigure(WebAppContext context) throws Exception
151 {
152
153 Boolean containerCreated = (Boolean)context.getAttribute(TEMPDIR_CREATED);
154
155 if (context.getTempDirectory()!=null && (containerCreated != null && containerCreated.booleanValue()) && !isTempWorkDirectory(context.getTempDirectory()))
156 {
157 IO.delete(context.getTempDirectory());
158 setTempDirectory(null, context);
159 }
160 }
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205 public void resolveTempDirectory (WebAppContext context)
206 {
207
208 File tmpDir = context.getTempDirectory();
209 if (tmpDir!=null && tmpDir.isDirectory() && tmpDir.canWrite())
210 return;
211
212
213
214
215
216 Object t = context.getAttribute(WebAppContext.TEMPDIR);
217 if (t != null)
218 {
219
220 if (t instanceof File)
221 {
222 tmpDir=(File)t;
223 if (tmpDir.isDirectory() && tmpDir.canWrite())
224 {
225 context.setTempDirectory(tmpDir);
226 return;
227 }
228 }
229
230 if (t instanceof String)
231 {
232 try
233 {
234 tmpDir=new File((String)t);
235
236 if (tmpDir.isDirectory() && tmpDir.canWrite())
237 {
238 context.setAttribute(context.TEMPDIR,tmpDir);
239 context.setTempDirectory(tmpDir);
240 return;
241 }
242 }
243 catch(Exception e)
244 {
245 Log.warn(Log.EXCEPTION,e);
246 }
247 }
248 }
249
250
251 String temp = getCanonicalNameForWebAppTmpDir(context);
252
253 try
254 {
255
256 File work = new File(System.getProperty("jetty.home"),"work");
257 if (!work.exists() || !work.canWrite() || !work.isDirectory())
258 work = null;
259
260 if (work!=null)
261 makeTempDirectory(work, context, false);
262 else
263 makeTempDirectory(new File(System.getProperty("java.io.tmpdir")), context, true);
264 }
265 catch(Exception e)
266 {
267 tmpDir=null;
268 Log.ignore(e);
269 }
270
271
272
273 if (context.getTempDirectory() == null)
274 {
275 try
276 {
277
278 tmpDir=File.createTempFile("JettyContext","");
279 if (tmpDir.exists())
280 tmpDir.delete();
281 tmpDir.mkdir();
282 tmpDir.deleteOnExit();
283 setTempDirectory(tmpDir, context);
284 }
285 catch(IOException e)
286 {
287 Log.warn("tmpdir",e); System.exit(1);
288 }
289 }
290 }
291
292
293 public void makeTempDirectory (File parent, WebAppContext context, boolean deleteExisting)
294 throws IOException
295 {
296 if (parent != null && parent.exists() && parent.canWrite() && parent.isDirectory())
297 {
298 String temp = getCanonicalNameForWebAppTmpDir(context);
299 File tmpDir = new File(parent,temp);
300
301 if (deleteExisting && tmpDir.exists())
302 {
303 if (!IO.delete(tmpDir))
304 {
305 if(Log.isDebugEnabled())Log.debug("Failed to delete temp dir "+tmpDir);
306 }
307
308
309 if (tmpDir.exists())
310 {
311 String old=tmpDir.toString();
312 tmpDir=File.createTempFile(temp+"_","");
313 if (tmpDir.exists())
314 tmpDir.delete();
315 Log.warn("Can't reuse "+old+", using "+tmpDir);
316 }
317 }
318
319 if (!tmpDir.exists())
320 tmpDir.mkdir();
321
322
323 if (!isTempWorkDirectory(tmpDir))
324 {
325 tmpDir.deleteOnExit();
326
327 File sentinel = new File(tmpDir, ".active");
328 if(!sentinel.exists())
329 sentinel.mkdir();
330 }
331 setTempDirectory(tmpDir, context);
332 }
333 }
334
335
336 public void setTempDirectory (File tmpDir, WebAppContext context)
337 {
338 context.setAttribute(TEMPDIR_CREATED, Boolean.TRUE);
339 context.setAttribute(context.TEMPDIR,tmpDir);
340 context.setTempDirectory(tmpDir);
341 if(Log.isDebugEnabled())Log.debug("Set temp dir "+tmpDir);
342 }
343
344
345 public void unpack (WebAppContext context) throws IOException
346 {
347 Resource web_app = context.getBaseResource();
348 if (web_app == null)
349 {
350 String war = context.getWar();
351 if (war==null || war.length()==0)
352 war=context.getResourceBase();
353
354
355 web_app = context.newResource(war);
356
357
358 if (web_app.getAlias() != null)
359 {
360 Log.debug(web_app + " anti-aliased to " + web_app.getAlias());
361 web_app = context.newResource(web_app.getAlias());
362 }
363
364 if (Log.isDebugEnabled())
365 Log.debug("Try webapp=" + web_app + ", exists=" + web_app.exists() + ", directory=" + web_app.isDirectory());
366
367
368 if (web_app.exists() && !web_app.isDirectory() && !web_app.toString().startsWith("jar:"))
369 {
370
371 Resource jarWebApp = context.newResource("jar:" + web_app + "!/");
372 if (jarWebApp.exists() && jarWebApp.isDirectory())
373 {
374 web_app= jarWebApp;
375 }
376 }
377
378
379 if (web_app.exists() &&
380 (
381 (context.isCopyWebDir() && web_app.getFile()!= null && web_app.getFile().isDirectory())
382 ||
383 (context.isExtractWAR() && web_app.getFile()!= null && !web_app.getFile().isDirectory())
384 ||
385 (context.isExtractWAR() && web_app.getFile() == null)
386 ||
387 !web_app.isDirectory()
388 ))
389 {
390
391 File extractedWebAppDir= new File(context.getTempDirectory(), "webapp");
392
393 if (web_app.getFile()!=null && web_app.getFile().isDirectory())
394 {
395
396 Log.info("Copy " + web_app.getFile() + " to " + extractedWebAppDir);
397 IO.copyDir(web_app.getFile(),extractedWebAppDir);
398 }
399 else
400 {
401 if (!extractedWebAppDir.exists())
402 {
403
404 extractedWebAppDir.mkdir();
405 Log.info("Extract " + war + " to " + extractedWebAppDir);
406 JarResource.extract(web_app, extractedWebAppDir, false);
407 }
408 else
409 {
410
411 if (web_app.lastModified() > extractedWebAppDir.lastModified())
412 {
413 extractedWebAppDir.delete();
414 extractedWebAppDir.mkdir();
415 Log.info("Extract " + war + " to " + extractedWebAppDir);
416 JarResource.extract(web_app, extractedWebAppDir, false);
417 }
418 }
419 }
420 web_app = Resource.newResource(extractedWebAppDir.getCanonicalPath());
421 }
422
423
424 if (!web_app.exists() || !web_app.isDirectory())
425 {
426 Log.warn("Web application not found " + war);
427 throw new java.io.FileNotFoundException(war);
428 }
429
430
431 context.setBaseResource(web_app);
432
433 if (Log.isDebugEnabled())
434 Log.debug("webapp=" + web_app);
435 }
436 }
437
438
439 public File findWorkDirectory (WebAppContext context) throws IOException
440 {
441 if (context.getBaseResource() != null)
442 {
443 Resource web_inf = context.getWebInf();
444 if (web_inf !=null && web_inf.exists())
445 {
446 return new File(web_inf.getFile(),"work");
447 }
448 }
449 return null;
450 }
451
452
453
454
455
456
457
458
459
460 public boolean isTempWorkDirectory (File tmpDir)
461 {
462 if (tmpDir == null)
463 return false;
464 if (tmpDir.getName().equalsIgnoreCase("work"))
465 return true;
466 File t = tmpDir.getParentFile();
467 if (t == null)
468 return false;
469 return (t.getName().equalsIgnoreCase("work"));
470 }
471
472
473
474
475
476
477
478
479
480
481
482 public String getCanonicalNameForWebAppTmpDir (WebAppContext context)
483 {
484 StringBuffer canonicalName = new StringBuffer();
485 canonicalName.append("Jetty");
486
487
488 Connector[] connectors = context.getServer().getConnectors();
489
490
491
492 canonicalName.append("_");
493 String host = (connectors==null||connectors[0]==null?"":connectors[0].getHost());
494 if (host == null)
495 host = "0.0.0.0";
496 canonicalName.append(host.replace('.', '_'));
497
498
499 canonicalName.append("_");
500
501 int port = (connectors==null||connectors[0]==null?0:connectors[0].getLocalPort());
502
503
504 if (port < 0)
505 port = connectors[0].getPort();
506 canonicalName.append(port);
507
508
509
510 canonicalName.append("_");
511 try
512 {
513 Resource resource = context.getBaseResource();
514 if (resource == null)
515 {
516 if (context.getWar()==null || context.getWar().length()==0)
517 resource=context.newResource(context.getResourceBase());
518
519
520 resource = context.newResource(context.getWar());
521 }
522
523 String tmp = URIUtil.decodePath(resource.getURL().getPath());
524 if (tmp.endsWith("/"))
525 tmp = tmp.substring(0, tmp.length()-1);
526 if (tmp.endsWith("!"))
527 tmp = tmp.substring(0, tmp.length() -1);
528
529 int i = tmp.lastIndexOf("/");
530 canonicalName.append(tmp.substring(i+1, tmp.length()));
531 }
532 catch (Exception e)
533 {
534 Log.warn("Can't generate resourceBase as part of webapp tmp dir name", e);
535 }
536
537
538 canonicalName.append("_");
539 String contextPath = context.getContextPath();
540 contextPath=contextPath.replace('/','_');
541 contextPath=contextPath.replace('\\','_');
542 canonicalName.append(contextPath);
543
544
545 canonicalName.append("_");
546 String[] vhosts = context.getVirtualHosts();
547 if (vhosts == null || vhosts.length <= 0)
548 canonicalName.append("");
549 else
550 canonicalName.append(vhosts[0]);
551
552
553 String hash = Integer.toString(canonicalName.toString().hashCode(),36);
554 canonicalName.append("_");
555 canonicalName.append(hash);
556
557
558 for (int i=0;i<canonicalName.length();i++)
559 {
560 char c=canonicalName.charAt(i);
561 if (!Character.isJavaIdentifierPart(c))
562 canonicalName.setCharAt(i,'.');
563 }
564
565 return canonicalName.toString();
566 }
567
568
569
570
571
572
573
574 protected List<Resource> findJars (WebAppContext context)
575 throws Exception
576 {
577 List<Resource> jarResources = new ArrayList<Resource>();
578
579 Resource web_inf = context.getWebInf();
580 Resource web_inf_lib = web_inf.addPath("/lib");
581
582
583 if (web_inf_lib.exists() && web_inf_lib.isDirectory())
584 {
585 String[] files=web_inf_lib.list();
586 for (int f=0;files!=null && f<files.length;f++)
587 {
588 try
589 {
590 Resource file = web_inf_lib.addPath(files[f]);
591 String fnlc = file.getName().toLowerCase();
592 int dot = fnlc.lastIndexOf('.');
593 String extension = (dot < 0 ? null : fnlc.substring(dot));
594 if (extension != null && (extension.equals(".jar") || extension.equals(".zip")))
595 {
596 jarResources.add(file);
597 }
598 }
599 catch (Exception ex)
600 {
601 Log.warn(Log.EXCEPTION,ex);
602 }
603 }
604 }
605 return jarResources;
606 }
607 }