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