1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.eclipse.jetty.webapp;
15
16 import java.io.File;
17 import java.io.IOException;
18 import java.net.MalformedURLException;
19 import java.net.URL;
20 import java.security.PermissionCollection;
21 import java.util.EventListener;
22 import java.util.HashMap;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.jar.JarFile;
26
27 import javax.servlet.http.HttpSessionActivationListener;
28 import javax.servlet.http.HttpSessionAttributeListener;
29 import javax.servlet.http.HttpSessionBindingListener;
30 import javax.servlet.http.HttpSessionListener;
31
32 import org.eclipse.jetty.security.SecurityHandler;
33 import org.eclipse.jetty.server.Connector;
34 import org.eclipse.jetty.server.HandlerContainer;
35 import org.eclipse.jetty.server.Server;
36 import org.eclipse.jetty.server.handler.ContextHandler;
37 import org.eclipse.jetty.server.handler.ErrorHandler;
38 import org.eclipse.jetty.server.session.SessionHandler;
39 import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
40 import org.eclipse.jetty.servlet.ServletContextHandler;
41 import org.eclipse.jetty.servlet.ServletHandler;
42 import org.eclipse.jetty.util.LazyList;
43 import org.eclipse.jetty.util.Loader;
44 import org.eclipse.jetty.util.StringUtil;
45 import org.eclipse.jetty.util.URIUtil;
46 import org.eclipse.jetty.util.log.Log;
47 import org.eclipse.jetty.util.resource.Resource;
48 import org.eclipse.jetty.util.resource.ResourceCollection;
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65 public class WebAppContext extends ServletContextHandler
66 {
67 public static final String TEMPDIR = "javax.servlet.context.tempdir";
68 public final static String WEB_DEFAULTS_XML="org/eclipse/jetty/webapp/webdefault.xml";
69 public final static String ERROR_PAGE="org.eclipse.jetty.server.error_page";
70 public final static String SERVER_CONFIG = "org.eclipse.jetty.webapp.configuration";
71 public final static String SERVER_SYS_CLASSES = "org.eclipse.jetty.webapp.systemClasses";
72 public final static String SERVER_SRV_CLASSES = "org.eclipse.jetty.webapp.serverClasses";
73
74 private static String[] __dftConfigurationClasses =
75 {
76 "org.eclipse.jetty.webapp.WebInfConfiguration",
77 "org.eclipse.jetty.webapp.WebXmlConfiguration",
78 "org.eclipse.jetty.webapp.MetaInfConfiguration",
79 "org.eclipse.jetty.webapp.FragmentConfiguration",
80 "org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
81 "org.eclipse.jetty.webapp.TagLibConfiguration"
82 } ;
83
84
85
86
87 private final static String[] __dftSystemClasses =
88 {
89 "java.",
90 "javax.",
91 "org.xml.",
92 "org.w3c.",
93 "apache.commons.logging.",
94 "org.eclipse.jetty.continuation.",
95 "org.eclipse.jetty.jndi.",
96 "org.eclipse.jetty.plus.jaas.",
97 "org.eclipse.jetty.websocket.",
98 "org.eclipse.jetty.servlet.DefaultServlet"
99 } ;
100
101
102
103
104
105 private final static String[] __dftServerClasses =
106 {
107 "-org.eclipse.jetty.continuation.",
108 "-org.eclipse.jetty.jndi.",
109 "-org.eclipse.jetty.plus.jaas.",
110 "-org.eclipse.jetty.websocket.",
111 "-org.eclipse.jetty.servlet.DefaultServlet",
112 "org.eclipse.jetty."
113 } ;
114
115 private String[] _configurationClasses = __dftConfigurationClasses;
116 private ClasspathPattern _systemClasses = null;
117 private ClasspathPattern _serverClasses = null;
118
119 private Configuration[] _configurations;
120 private String _defaultsDescriptor=WEB_DEFAULTS_XML;
121 private String _descriptor=null;
122 private String _overrideDescriptor=null;
123 private boolean _distributable=false;
124 private boolean _extractWAR=true;
125 private boolean _copyDir=false;
126 private boolean _logUrlOnStart =false;
127 private boolean _parentLoaderPriority= Boolean.getBoolean("org.eclipse.jetty.server.webapp.parentLoaderPriority");
128 private PermissionCollection _permissions;
129
130 private File _tmpDir;
131 private String _war;
132 private String _extraClasspath;
133 private Throwable _unavailableException;
134
135 private Map _resourceAliases;
136 private boolean _ownClassLoader=false;
137 private boolean _configurationDiscovered=true;
138 private boolean _configurationClassesSet=false;
139 private boolean _configurationsSet=false;
140
141 public static WebAppContext getCurrentWebAppContext()
142 {
143 ContextHandler.Context context=ContextHandler.getCurrentContext();
144 if (context!=null)
145 {
146 ContextHandler handler = context.getContextHandler();
147 if (handler instanceof WebAppContext)
148 return (WebAppContext)handler;
149 }
150 return null;
151 }
152
153
154 public WebAppContext()
155 {
156 super(SESSIONS|SECURITY);
157 _scontext=new Context();
158 setErrorHandler(new ErrorPageErrorHandler());
159 }
160
161
162
163
164
165
166 public WebAppContext(String webApp,String contextPath)
167 {
168 super(null,contextPath,SESSIONS|SECURITY);
169 _scontext=new Context();
170 setContextPath(contextPath);
171 setWar(webApp);
172 setErrorHandler(new ErrorPageErrorHandler());
173 }
174
175
176
177
178
179
180
181 public WebAppContext(HandlerContainer parent, String webApp, String contextPath)
182 {
183 super(parent,contextPath,SESSIONS|SECURITY);
184 _scontext=new Context();
185 setWar(webApp);
186 setErrorHandler(new ErrorPageErrorHandler());
187 }
188
189
190
191
192 public WebAppContext(SessionHandler sessionHandler, SecurityHandler securityHandler, ServletHandler servletHandler, ErrorHandler errorHandler)
193 {
194 super(null,sessionHandler,securityHandler,servletHandler,errorHandler);
195 _scontext=new Context();
196 setErrorHandler(errorHandler!=null?errorHandler:new ErrorPageErrorHandler());
197 }
198
199
200
201
202
203 @Override
204 public void setDisplayName(String servletContextName)
205 {
206 super.setDisplayName(servletContextName);
207 ClassLoader cl = getClassLoader();
208 if (cl!=null && cl instanceof WebAppClassLoader)
209 ((WebAppClassLoader)cl).setName(servletContextName);
210 }
211
212
213
214
215
216 public Throwable getUnavailableException()
217 {
218 return _unavailableException;
219 }
220
221
222
223
224
225
226
227
228
229
230 public void setResourceAlias(String alias, String uri)
231 {
232 if (_resourceAliases == null)
233 _resourceAliases= new HashMap(5);
234 _resourceAliases.put(alias, uri);
235 }
236
237
238 public Map getResourceAliases()
239 {
240 if (_resourceAliases == null)
241 return null;
242 return _resourceAliases;
243 }
244
245
246 public void setResourceAliases(Map map)
247 {
248 _resourceAliases = map;
249 }
250
251
252 public String getResourceAlias(String alias)
253 {
254 if (_resourceAliases == null)
255 return null;
256 return (String)_resourceAliases.get(alias);
257 }
258
259
260 public String removeResourceAlias(String alias)
261 {
262 if (_resourceAliases == null)
263 return null;
264 return (String)_resourceAliases.remove(alias);
265 }
266
267
268
269
270
271 @Override
272 public void setClassLoader(ClassLoader classLoader)
273 {
274 super.setClassLoader(classLoader);
275 if (classLoader!=null && classLoader instanceof WebAppClassLoader)
276 ((WebAppClassLoader)classLoader).setName(getDisplayName());
277 }
278
279
280 @Override
281 public Resource getResource(String uriInContext) throws MalformedURLException
282 {
283 IOException ioe= null;
284 Resource resource= null;
285 int loop=0;
286 while (uriInContext!=null && loop++<100)
287 {
288 try
289 {
290 resource= super.getResource(uriInContext);
291 if (resource != null && resource.exists())
292 return resource;
293
294 uriInContext = getResourceAlias(uriInContext);
295 }
296 catch (IOException e)
297 {
298 Log.ignore(e);
299 if (ioe==null)
300 ioe= e;
301 }
302 }
303
304 if (ioe != null && ioe instanceof MalformedURLException)
305 throw (MalformedURLException)ioe;
306
307 return resource;
308 }
309
310
311
312
313
314
315
316 public boolean isConfigurationDiscovered()
317 {
318 return _configurationDiscovered;
319 }
320
321
322
323
324
325
326
327
328
329
330
331 public void setConfigurationDiscovered(boolean discovered)
332 {
333 _configurationDiscovered = discovered;
334 }
335
336
337
338
339
340 @Override
341 protected void doStart() throws Exception
342 {
343 try
344 {
345
346 loadConfigurations();
347
348
349 loadSystemClasses();
350
351
352 loadServerClasses();
353
354
355 _ownClassLoader=false;
356 if (getClassLoader()==null)
357 {
358 WebAppClassLoader classLoader = new WebAppClassLoader(this);
359 setClassLoader(classLoader);
360 _ownClassLoader=true;
361 }
362
363 if (Log.isDebugEnabled())
364 {
365 ClassLoader loader = getClassLoader();
366 Log.debug("Thread Context class loader is: " + loader);
367 loader=loader.getParent();
368 while(loader!=null)
369 {
370 Log.debug("Parent class loader is: " + loader);
371 loader=loader.getParent();
372 }
373 }
374
375
376
377
378 for (int i=0;i<_configurations.length;i++)
379 _configurations[i].preConfigure(this);
380
381 super.doStart();
382
383
384 for (int i=0;i<_configurations.length;i++)
385 _configurations[i].postConfigure(this);
386
387
388 if (isLogUrlOnStart())
389 dumpUrl();
390 }
391 catch (Exception e)
392 {
393
394 Log.warn("Failed startup of context "+this, e);
395 _unavailableException=e;
396 setAvailable(false);
397 }
398 }
399
400
401
402
403
404 public void dumpUrl()
405 {
406 Connector[] connectors = getServer().getConnectors();
407 for (int i=0;i<connectors.length;i++)
408 {
409 String connectorName = connectors[i].getName();
410 String displayName = getDisplayName();
411 if (displayName == null)
412 displayName = "WebApp@"+connectors.hashCode();
413
414 Log.info(displayName + " at http://" + connectorName + getContextPath());
415 }
416 }
417
418
419
420
421
422 @Override
423 protected void doStop() throws Exception
424 {
425 super.doStop();
426
427 try
428 {
429 for (int i=_configurations.length;i-->0;)
430 _configurations[i].deconfigure(this);
431
432 _configurations=null;
433
434 }
435 finally
436 {
437 if (_ownClassLoader)
438 setClassLoader(null);
439
440 setAvailable(true);
441 _unavailableException=null;
442 }
443 }
444
445
446
447
448
449 public String[] getConfigurationClasses()
450 {
451 return _configurationClasses;
452 }
453
454
455
456
457
458 public Configuration[] getConfigurations()
459 {
460 return _configurations;
461 }
462
463
464
465
466
467
468 public String getDefaultsDescriptor()
469 {
470 return _defaultsDescriptor;
471 }
472
473
474
475
476
477
478 public String getOverrideDescriptor()
479 {
480 return _overrideDescriptor;
481 }
482
483
484
485
486
487 public PermissionCollection getPermissions()
488 {
489 return _permissions;
490 }
491
492
493
494
495
496
497 public String[] getServerClasses()
498 {
499 if (_serverClasses == null)
500 loadServerClasses();
501
502 return _serverClasses.getPatterns();
503 }
504
505 public void addServerClass(String classname)
506 {
507 if (_serverClasses == null)
508 loadServerClasses();
509
510 _serverClasses.addPattern(classname);
511 }
512
513
514
515
516
517
518 public String[] getSystemClasses()
519 {
520 if (_systemClasses == null)
521 loadSystemClasses();
522
523 return _systemClasses.getPatterns();
524 }
525
526 public void addSystemClass(String classname)
527 {
528 if (_systemClasses == null)
529 loadSystemClasses();
530
531 _systemClasses.addPattern(classname);
532 }
533
534
535 public boolean isServerClass(String name)
536 {
537 if (_serverClasses == null)
538 loadServerClasses();
539
540 return _serverClasses.match(name);
541 }
542
543
544 public boolean isSystemClass(String name)
545 {
546 if (_systemClasses == null)
547 loadSystemClasses();
548
549 return _systemClasses.match(name);
550 }
551
552 private void loadSystemClasses()
553 {
554 if (_systemClasses != null)
555 return;
556
557
558
559 Server server = getServer();
560 if (server != null)
561 {
562 Object systemClasses = server.getAttribute(SERVER_SYS_CLASSES);
563 if (systemClasses != null && systemClasses instanceof String[])
564 _systemClasses = ClasspathPattern.fromArray((String[])systemClasses);
565 }
566
567 if (_systemClasses == null)
568 _systemClasses = ClasspathPattern.fromArray(__dftSystemClasses);
569 }
570
571 private void loadServerClasses()
572 {
573 if (_serverClasses != null)
574 return;
575
576
577
578 Server server = getServer();
579 if (server != null)
580 {
581 Object serverClasses = server.getAttribute(SERVER_SRV_CLASSES);
582 if (serverClasses != null || serverClasses instanceof String[])
583 _serverClasses = ClasspathPattern.fromArray((String[])serverClasses);
584 }
585
586 if (_serverClasses == null)
587 _serverClasses = ClasspathPattern.fromArray(__dftServerClasses);
588 }
589
590
591
592
593
594 public String getWar()
595 {
596 if (_war==null)
597 _war=getResourceBase();
598 return _war;
599 }
600
601
602 public Resource getWebInf() throws IOException
603 {
604 if (super.getBaseResource() == null)
605 return null;
606
607
608 Resource web_inf= super.getBaseResource().addPath("WEB-INF/");
609 if (!web_inf.exists() || !web_inf.isDirectory())
610 return null;
611
612 return web_inf;
613 }
614
615
616
617
618
619 public boolean isDistributable()
620 {
621 return _distributable;
622 }
623
624
625
626
627
628 public boolean isExtractWAR()
629 {
630 return _extractWAR;
631 }
632
633
634
635
636
637 public boolean isCopyWebDir()
638 {
639 return _copyDir;
640 }
641
642
643
644
645
646 public boolean isParentLoaderPriority()
647 {
648 return _parentLoaderPriority;
649 }
650
651
652
653 public String[] getDefaultConfigurationClasses ()
654 {
655 return __dftConfigurationClasses;
656 }
657
658
659
660 protected void loadConfigurations()
661 throws Exception
662 {
663
664 if (_configurations!=null)
665 return;
666
667
668 if (!_configurationClassesSet)
669 _configurationClasses=__dftConfigurationClasses;
670
671 _configurations = new Configuration[_configurationClasses.length];
672 for (int i = 0; i < _configurationClasses.length; i++)
673 {
674 _configurations[i]=(Configuration)Loader.loadClass(this.getClass(), _configurationClasses[i]).newInstance();
675 }
676 }
677
678
679 @Override
680 protected boolean isProtectedTarget(String target)
681 {
682 while (target.startsWith("//"))
683 target=URIUtil.compactPath(target);
684
685 return StringUtil.startsWithIgnoreCase(target, "/web-inf") || StringUtil.startsWithIgnoreCase(target, "/meta-inf");
686 }
687
688
689
690 @Override
691 public String toString()
692 {
693 return super.toString()+(_war==null?"":(","+_war));
694 }
695
696
697
698
699
700
701
702
703
704 public void setConfigurationClasses(String[] configurations)
705 {
706 _configurationClasses = configurations==null?null:(String[])configurations.clone();
707 _configurationClassesSet = true;
708 }
709
710
711
712
713
714 public void setConfigurations(Configuration[] configurations)
715 {
716 _configurations = configurations==null?null:(Configuration[])configurations.clone();
717 _configurationsSet = true;
718 }
719
720
721
722
723
724
725 public void setDefaultsDescriptor(String defaultsDescriptor)
726 {
727 _defaultsDescriptor = defaultsDescriptor;
728 }
729
730
731
732
733
734
735 public void setOverrideDescriptor(String overrideDescriptor)
736 {
737 _overrideDescriptor = overrideDescriptor;
738 }
739
740
741
742
743
744 public String getDescriptor()
745 {
746 return _descriptor;
747 }
748
749
750
751
752
753 public void setDescriptor(String descriptor)
754 {
755 _descriptor=descriptor;
756 }
757
758
759
760
761
762 public void setDistributable(boolean distributable)
763 {
764 this._distributable = distributable;
765 }
766
767
768 @Override
769 public void setEventListeners(EventListener[] eventListeners)
770 {
771 if (_sessionHandler!=null)
772 _sessionHandler.clearEventListeners();
773
774 super.setEventListeners(eventListeners);
775
776 for (int i=0; eventListeners!=null && i<eventListeners.length;i ++)
777 {
778 EventListener listener = eventListeners[i];
779
780 if ((listener instanceof HttpSessionActivationListener)
781 || (listener instanceof HttpSessionAttributeListener)
782 || (listener instanceof HttpSessionBindingListener)
783 || (listener instanceof HttpSessionListener))
784 {
785 if (_sessionHandler!=null)
786 _sessionHandler.addEventListener(listener);
787 }
788
789 }
790 }
791
792
793
794
795
796
797 @Override
798 public void addEventListener(EventListener listener)
799 {
800 setEventListeners((EventListener[])LazyList.addToArray(getEventListeners(), listener, EventListener.class));
801 }
802
803
804
805
806
807
808 public void setExtractWAR(boolean extractWAR)
809 {
810 _extractWAR = extractWAR;
811 }
812
813
814
815
816
817
818 public void setCopyWebDir(boolean copy)
819 {
820 _copyDir = copy;
821 }
822
823
824
825
826
827 public void setParentLoaderPriority(boolean java2compliant)
828 {
829 _parentLoaderPriority = java2compliant;
830 }
831
832
833
834
835
836 public void setPermissions(PermissionCollection permissions)
837 {
838 _permissions = permissions;
839 }
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856 public void setServerClasses(String[] serverClasses)
857 {
858 _serverClasses = ClasspathPattern.fromArray(serverClasses);
859 }
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876 public void setSystemClasses(String[] systemClasses)
877 {
878 _systemClasses = ClasspathPattern.fromArray(systemClasses);
879 }
880
881
882
883
884
885
886
887 public void setTempDirectory(File dir)
888 {
889 if (isStarted())
890 throw new IllegalStateException("Started");
891
892 if (dir!=null)
893 {
894 try{dir=new File(dir.getCanonicalPath());}
895 catch (IOException e){Log.warn(Log.EXCEPTION,e);}
896 }
897
898 if (dir!=null && !dir.exists())
899 {
900 dir.mkdir();
901 dir.deleteOnExit();
902 }
903
904 if (dir!=null && ( !dir.exists() || !dir.isDirectory() || !dir.canWrite()))
905 throw new IllegalArgumentException("Bad temp directory: "+dir);
906
907 _tmpDir=dir;
908 setAttribute(TEMPDIR,_tmpDir);
909 }
910
911 public File getTempDirectory ()
912 {
913 return _tmpDir;
914 }
915
916
917
918
919
920 public void setWar(String war)
921 {
922 _war = war;
923 }
924
925
926
927
928
929
930
931
932 public String getExtraClasspath()
933 {
934 return _extraClasspath;
935 }
936
937
938
939
940
941
942
943 public void setExtraClasspath(String extraClasspath)
944 {
945 _extraClasspath=extraClasspath;
946 }
947
948
949 public boolean isLogUrlOnStart()
950 {
951 return _logUrlOnStart;
952 }
953
954
955
956
957
958
959
960 public void setLogUrlOnStart(boolean logOnStart)
961 {
962 this._logUrlOnStart = logOnStart;
963 }
964
965
966
967 @Override
968 public void setServer(Server server)
969 {
970 super.setServer(server);
971
972
973
974
975 if (!_configurationsSet && !_configurationClassesSet && server != null)
976 {
977 String[] serverConfigs = (String[])server.getAttribute(SERVER_CONFIG);
978 if (serverConfigs != null)
979 setConfigurationClasses(serverConfigs);
980 }
981 }
982
983
984 @Override
985 protected void startContext()
986 throws Exception
987 {
988
989
990
991 for (int i=0;i<_configurations.length;i++)
992 _configurations[i].configure(this);
993
994
995 super.startContext();
996 }
997
998
999 public class Context extends ServletContextHandler.Context
1000 {
1001
1002 public URL getResource(String path) throws MalformedURLException
1003 {
1004 Resource resource=WebAppContext.this.getResource(path);
1005 if (resource==null || !resource.exists())
1006 return null;
1007
1008
1009 if (resource.isDirectory() && resource instanceof ResourceCollection && !WebAppContext.this.isExtractWAR())
1010 {
1011 Resource[] resources = ((ResourceCollection)resource).getResources();
1012 for (int i=resources.length;i-->0;)
1013 {
1014 if (resources[i].getName().startsWith("jar:file"))
1015 return resources[i].getURL();
1016 }
1017 }
1018
1019 return resource.getURL();
1020 }
1021 }
1022
1023 }