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.toString());
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 return;
226
227
228
229
230
231 Object t = context.getAttribute(WebAppContext.TEMPDIR);
232 if (t != null)
233 {
234
235 if (t instanceof File)
236 {
237 tmpDir=(File)t;
238 if (tmpDir.isDirectory() && tmpDir.canWrite())
239 {
240 context.setTempDirectory(tmpDir);
241 return;
242 }
243 }
244
245 if (t instanceof String)
246 {
247 try
248 {
249 tmpDir=new File((String)t);
250
251 if (tmpDir.isDirectory() && tmpDir.canWrite())
252 {
253 context.setAttribute(context.TEMPDIR,tmpDir);
254 context.setTempDirectory(tmpDir);
255 return;
256 }
257 }
258 catch(Exception e)
259 {
260 Log.warn(Log.EXCEPTION,e);
261 }
262 }
263 }
264
265
266 String temp = getCanonicalNameForWebAppTmpDir(context);
267
268 try
269 {
270
271 File work = new File(System.getProperty("jetty.home"),"work");
272 if (!work.exists() || !work.canWrite() || !work.isDirectory())
273 work = null;
274
275 if (work!=null)
276 makeTempDirectory(work, context, false);
277 else
278 makeTempDirectory(new File(System.getProperty("java.io.tmpdir")), context, true);
279 }
280 catch(Exception e)
281 {
282 tmpDir=null;
283 Log.ignore(e);
284 }
285
286
287
288 if (context.getTempDirectory() == null)
289 {
290 try
291 {
292
293 tmpDir=File.createTempFile("JettyContext","");
294 if (tmpDir.exists())
295 tmpDir.delete();
296 tmpDir.mkdir();
297 tmpDir.deleteOnExit();
298 setTempDirectory(tmpDir, context);
299 }
300 catch(IOException e)
301 {
302 Log.warn("tmpdir",e); System.exit(1);
303 }
304 }
305 }
306
307
308 public void makeTempDirectory (File parent, WebAppContext context, boolean deleteExisting)
309 throws IOException
310 {
311 if (parent != null && parent.exists() && parent.canWrite() && parent.isDirectory())
312 {
313 String temp = getCanonicalNameForWebAppTmpDir(context);
314 File tmpDir = new File(parent,temp);
315
316 if (deleteExisting && tmpDir.exists())
317 {
318 if (!IO.delete(tmpDir))
319 {
320 if(Log.isDebugEnabled())Log.debug("Failed to delete temp dir "+tmpDir);
321 }
322
323
324 if (tmpDir.exists())
325 {
326 String old=tmpDir.toString();
327 tmpDir=File.createTempFile(temp+"_","");
328 if (tmpDir.exists())
329 tmpDir.delete();
330 Log.warn("Can't reuse "+old+", using "+tmpDir);
331 }
332 }
333
334 if (!tmpDir.exists())
335 tmpDir.mkdir();
336
337
338 if (!isTempWorkDirectory(tmpDir))
339 {
340 tmpDir.deleteOnExit();
341
342 File sentinel = new File(tmpDir, ".active");
343 if(!sentinel.exists())
344 sentinel.mkdir();
345 }
346 setTempDirectory(tmpDir, context);
347 }
348 }
349
350
351 public void setTempDirectory (File tmpDir, WebAppContext context)
352 {
353 context.setAttribute(TEMPDIR_CREATED, Boolean.TRUE);
354 context.setAttribute(context.TEMPDIR,tmpDir);
355 context.setTempDirectory(tmpDir);
356 if(Log.isDebugEnabled())Log.debug("Set temp dir "+tmpDir);
357 }
358
359
360 public void unpack (WebAppContext context) throws IOException
361 {
362 Resource web_app = context.getBaseResource();
363
364 if (web_app == null)
365 {
366 String war = context.getWar();
367 if (war!=null && war.length()>0)
368 web_app = context.newResource(war);
369 else
370 web_app=context.getBaseResource();
371
372
373 if (web_app.getAlias() != null)
374 {
375 Log.debug(web_app + " anti-aliased to " + web_app.getAlias());
376 web_app = context.newResource(web_app.getAlias());
377 }
378
379 if (Log.isDebugEnabled())
380 Log.debug("Try webapp=" + web_app + ", exists=" + web_app.exists() + ", directory=" + web_app.isDirectory());
381
382
383 if (web_app.exists() && !web_app.isDirectory() && !web_app.toString().startsWith("jar:"))
384 {
385
386 Resource jarWebApp = JarResource.newJarResource(web_app);
387 if (jarWebApp.exists() && jarWebApp.isDirectory())
388 web_app= jarWebApp;
389 }
390
391
392 if (web_app.exists() && (
393 (context.isCopyWebDir() && web_app.getFile() != null && web_app.getFile().isDirectory()) ||
394 (context.isExtractWAR() && web_app.getFile() != null && !web_app.getFile().isDirectory()) ||
395 (context.isExtractWAR() && web_app.getFile() == null) ||
396 !web_app.isDirectory())
397 )
398 {
399
400 File extractedWebAppDir = null;
401
402 if (war!=null)
403 {
404
405 File warfile=Resource.newResource(war).getFile();
406 if (warfile!=null)
407 {
408 File sibling = new File(warfile.getParent(),warfile.getName().substring(0,warfile.getName().length()-4));
409 if (sibling.exists() && sibling.isDirectory() && sibling.canWrite())
410 extractedWebAppDir=sibling;
411 }
412 }
413
414 if (extractedWebAppDir==null)
415
416 extractedWebAppDir= new File(context.getTempDirectory(), "webapp");
417
418 if (web_app.getFile()!=null && web_app.getFile().isDirectory())
419 {
420
421 Log.info("Copy " + web_app + " to " + extractedWebAppDir);
422 web_app.copyTo(extractedWebAppDir);
423 }
424 else
425 {
426 if (!extractedWebAppDir.exists())
427 {
428
429 extractedWebAppDir.mkdir();
430 Log.info("Extract " + web_app + " to " + extractedWebAppDir);
431 Resource jar_web_app = JarResource.newJarResource(web_app);
432 jar_web_app.copyTo(extractedWebAppDir);
433 }
434 else
435 {
436
437 if (web_app.lastModified() > extractedWebAppDir.lastModified())
438 {
439 extractedWebAppDir.delete();
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 }
446 }
447 web_app = Resource.newResource(extractedWebAppDir.getCanonicalPath());
448 }
449
450
451 if (!web_app.exists() || !web_app.isDirectory())
452 {
453 Log.warn("Web application not found " + war);
454 throw new java.io.FileNotFoundException(war);
455 }
456
457
458 context.setBaseResource(web_app);
459
460 if (Log.isDebugEnabled())
461 Log.debug("webapp=" + web_app);
462 }
463
464 _preUnpackBaseResource = context.getBaseResource();
465
466
467 Resource web_inf= web_app.addPath("WEB-INF/");
468
469 if (web_inf instanceof ResourceCollection ||
470 web_inf.exists() &&
471 web_inf.isDirectory() &&
472 (web_inf.getFile()==null || !web_inf.getFile().isDirectory()))
473 {
474 File extractedWebInfDir= new File(context.getTempDirectory(), "webinf");
475 if (extractedWebInfDir.exists())
476 extractedWebInfDir.delete();
477 extractedWebInfDir.mkdir();
478 Resource web_inf_lib = web_inf.addPath("lib/");
479 File webInfDir=new File(extractedWebInfDir,"WEB-INF");
480 webInfDir.mkdir();
481
482 if (web_inf_lib.exists())
483 {
484 File webInfLibDir = new File(webInfDir, "lib");
485 webInfLibDir.mkdir();
486
487 Log.info("Copying WEB-INF/lib " + web_inf_lib + " to " + webInfLibDir);
488 web_inf_lib.copyTo(webInfLibDir);
489 }
490
491 Resource web_inf_classes = web_inf.addPath("classes/");
492 if (web_inf_classes.exists())
493 {
494 File webInfClassesDir = new File(webInfDir, "classes");
495 webInfClassesDir.mkdir();
496 Log.info("Copying WEB-INF/classes from "+web_inf_classes+" to "+webInfClassesDir.getAbsolutePath());
497 web_inf_classes.copyTo(webInfClassesDir);
498 }
499
500 web_inf=Resource.newResource(extractedWebInfDir.toURL());
501
502 ResourceCollection rc = new ResourceCollection(new Resource[]{web_inf,web_app});
503
504 if (Log.isDebugEnabled())
505 Log.debug("context.resourcebase = "+rc);
506
507 context.setBaseResource(rc);
508 }
509 }
510
511
512 public File findWorkDirectory (WebAppContext context) throws IOException
513 {
514 if (context.getBaseResource() != null)
515 {
516 Resource web_inf = context.getWebInf();
517 if (web_inf !=null && web_inf.exists())
518 {
519 return new File(web_inf.getFile(),"work");
520 }
521 }
522 return null;
523 }
524
525
526
527
528
529
530
531
532
533 public boolean isTempWorkDirectory (File tmpDir)
534 {
535 if (tmpDir == null)
536 return false;
537 if (tmpDir.getName().equalsIgnoreCase("work"))
538 return true;
539 File t = tmpDir.getParentFile();
540 if (t == null)
541 return false;
542 return (t.getName().equalsIgnoreCase("work"));
543 }
544
545
546
547
548
549
550
551
552
553
554
555 public String getCanonicalNameForWebAppTmpDir (WebAppContext context)
556 {
557 StringBuffer canonicalName = new StringBuffer();
558 canonicalName.append("Jetty");
559
560
561 Connector[] connectors = context.getServer().getConnectors();
562
563
564
565 canonicalName.append("_");
566 String host = (connectors==null||connectors[0]==null?"":connectors[0].getHost());
567 if (host == null)
568 host = "0.0.0.0";
569 canonicalName.append(host.replace('.', '_'));
570
571
572 canonicalName.append("_");
573
574 int port = (connectors==null||connectors[0]==null?0:connectors[0].getLocalPort());
575
576
577 if (port < 0)
578 port = connectors[0].getPort();
579 canonicalName.append(port);
580
581
582
583 canonicalName.append("_");
584 try
585 {
586 Resource resource = context.getBaseResource();
587 if (resource == null)
588 {
589 if (context.getWar()==null || context.getWar().length()==0)
590 resource=context.newResource(context.getResourceBase());
591
592
593 resource = context.newResource(context.getWar());
594 }
595
596 String tmp = URIUtil.decodePath(resource.getURL().getPath());
597 if (tmp.endsWith("/"))
598 tmp = tmp.substring(0, tmp.length()-1);
599 if (tmp.endsWith("!"))
600 tmp = tmp.substring(0, tmp.length() -1);
601
602 int i = tmp.lastIndexOf("/");
603 canonicalName.append(tmp.substring(i+1, tmp.length()));
604 }
605 catch (Exception e)
606 {
607 Log.warn("Can't generate resourceBase as part of webapp tmp dir name", e);
608 }
609
610
611 canonicalName.append("_");
612 String contextPath = context.getContextPath();
613 contextPath=contextPath.replace('/','_');
614 contextPath=contextPath.replace('\\','_');
615 canonicalName.append(contextPath);
616
617
618 canonicalName.append("_");
619 String[] vhosts = context.getVirtualHosts();
620 if (vhosts == null || vhosts.length <= 0)
621 canonicalName.append("");
622 else
623 canonicalName.append(vhosts[0]);
624
625
626 String hash = Integer.toString(canonicalName.toString().hashCode(),36);
627 canonicalName.append("_");
628 canonicalName.append(hash);
629
630
631 for (int i=0;i<canonicalName.length();i++)
632 {
633 char c=canonicalName.charAt(i);
634 if (!Character.isJavaIdentifierPart(c))
635 canonicalName.setCharAt(i,'.');
636 }
637
638 return canonicalName.toString();
639 }
640
641
642
643
644
645
646
647 protected List<Resource> findJars (WebAppContext context)
648 throws Exception
649 {
650 List<Resource> jarResources = new ArrayList<Resource>();
651
652 Resource web_inf = context.getWebInf();
653 if (web_inf==null || !web_inf.exists())
654 return null;
655
656 Resource web_inf_lib = web_inf.addPath("/lib");
657
658
659 if (web_inf_lib.exists() && web_inf_lib.isDirectory())
660 {
661 String[] files=web_inf_lib.list();
662 for (int f=0;files!=null && f<files.length;f++)
663 {
664 try
665 {
666 Resource file = web_inf_lib.addPath(files[f]);
667 String fnlc = file.getName().toLowerCase();
668 int dot = fnlc.lastIndexOf('.');
669 String extension = (dot < 0 ? null : fnlc.substring(dot));
670 if (extension != null && (extension.equals(".jar") || extension.equals(".zip")))
671 {
672 jarResources.add(file);
673 }
674 }
675 catch (Exception ex)
676 {
677 Log.warn(Log.EXCEPTION,ex);
678 }
679 }
680 }
681 return jarResources;
682 }
683 }