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