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