1
17 package org.apache.catalina.startup;
18
19 import java.io.File;
20 import java.io.FileInputStream;
21 import java.io.FileNotFoundException;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.net.MalformedURLException;
25 import java.net.URISyntaxException;
26 import java.net.URL;
27 import java.net.URLConnection;
28 import java.util.ArrayList;
29 import java.util.Collections;
30 import java.util.HashMap;
31 import java.util.HashSet;
32 import java.util.LinkedHashMap;
33 import java.util.LinkedHashSet;
34 import java.util.List;
35 import java.util.Locale;
36 import java.util.Map;
37 import java.util.Map.Entry;
38 import java.util.Properties;
39 import java.util.Set;
40 import java.util.concurrent.ConcurrentHashMap;
41
42 import javax.servlet.MultipartConfigElement;
43 import javax.servlet.ServletContainerInitializer;
44 import javax.servlet.ServletContext;
45 import javax.servlet.SessionCookieConfig;
46 import javax.servlet.annotation.HandlesTypes;
47
48 import org.apache.catalina.Authenticator;
49 import org.apache.catalina.Container;
50 import org.apache.catalina.Context;
51 import org.apache.catalina.Engine;
52 import org.apache.catalina.Globals;
53 import org.apache.catalina.Host;
54 import org.apache.catalina.Lifecycle;
55 import org.apache.catalina.LifecycleEvent;
56 import org.apache.catalina.LifecycleListener;
57 import org.apache.catalina.Pipeline;
58 import org.apache.catalina.Server;
59 import org.apache.catalina.Service;
60 import org.apache.catalina.Valve;
61 import org.apache.catalina.WebResource;
62 import org.apache.catalina.WebResourceRoot;
63 import org.apache.catalina.Wrapper;
64 import org.apache.catalina.core.StandardContext;
65 import org.apache.catalina.core.StandardHost;
66 import org.apache.catalina.util.ContextName;
67 import org.apache.catalina.util.Introspection;
68 import org.apache.juli.logging.Log;
69 import org.apache.juli.logging.LogFactory;
70 import org.apache.tomcat.Jar;
71 import org.apache.tomcat.JarScanType;
72 import org.apache.tomcat.JarScanner;
73 import org.apache.tomcat.util.ExceptionUtils;
74 import org.apache.tomcat.util.bcel.classfile.AnnotationElementValue;
75 import org.apache.tomcat.util.bcel.classfile.AnnotationEntry;
76 import org.apache.tomcat.util.bcel.classfile.ArrayElementValue;
77 import org.apache.tomcat.util.bcel.classfile.ClassFormatException;
78 import org.apache.tomcat.util.bcel.classfile.ClassParser;
79 import org.apache.tomcat.util.bcel.classfile.ElementValue;
80 import org.apache.tomcat.util.bcel.classfile.ElementValuePair;
81 import org.apache.tomcat.util.bcel.classfile.JavaClass;
82 import org.apache.tomcat.util.buf.UriUtil;
83 import org.apache.tomcat.util.descriptor.InputSourceUtil;
84 import org.apache.tomcat.util.descriptor.XmlErrorHandler;
85 import org.apache.tomcat.util.descriptor.web.ContextEjb;
86 import org.apache.tomcat.util.descriptor.web.ContextEnvironment;
87 import org.apache.tomcat.util.descriptor.web.ContextLocalEjb;
88 import org.apache.tomcat.util.descriptor.web.ContextResource;
89 import org.apache.tomcat.util.descriptor.web.ContextResourceEnvRef;
90 import org.apache.tomcat.util.descriptor.web.ContextService;
91 import org.apache.tomcat.util.descriptor.web.ErrorPage;
92 import org.apache.tomcat.util.descriptor.web.FilterDef;
93 import org.apache.tomcat.util.descriptor.web.FilterMap;
94 import org.apache.tomcat.util.descriptor.web.FragmentJarScannerCallback;
95 import org.apache.tomcat.util.descriptor.web.JspPropertyGroup;
96 import org.apache.tomcat.util.descriptor.web.LoginConfig;
97 import org.apache.tomcat.util.descriptor.web.MessageDestinationRef;
98 import org.apache.tomcat.util.descriptor.web.MultipartDef;
99 import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
100 import org.apache.tomcat.util.descriptor.web.SecurityRoleRef;
101 import org.apache.tomcat.util.descriptor.web.ServletDef;
102 import org.apache.tomcat.util.descriptor.web.SessionConfig;
103 import org.apache.tomcat.util.descriptor.web.WebXml;
104 import org.apache.tomcat.util.descriptor.web.WebXmlParser;
105 import org.apache.tomcat.util.digester.Digester;
106 import org.apache.tomcat.util.digester.RuleSet;
107 import org.apache.tomcat.util.file.ConfigFileLoader;
108 import org.apache.tomcat.util.file.ConfigurationSource;
109 import org.apache.tomcat.util.res.StringManager;
110 import org.apache.tomcat.util.scan.JarFactory;
111 import org.xml.sax.InputSource;
112 import org.xml.sax.SAXParseException;
113
114
120 public class ContextConfig implements LifecycleListener {
121
122 private static final Log log = LogFactory.getLog(ContextConfig.class);
123
124
125
128 protected static final StringManager sm =
129 StringManager.getManager(Constants.Package);
130
131
132 protected static final LoginConfig DUMMY_LOGIN_CONFIG =
133 new LoginConfig("NONE", null, null, null);
134
135
136
141 protected static final Properties authenticators;
142
143 static {
144
145 Properties props = new Properties();
146 try (InputStream is = ContextConfig.class.getClassLoader().getResourceAsStream(
147 "org/apache/catalina/startup/Authenticators.properties")) {
148 if (is != null) {
149 props.load(is);
150 }
151 } catch (IOException ioe) {
152 props = null;
153 }
154 authenticators = props;
155 }
156
157
160 protected static long deploymentCount = 0L;
161
162
163
166 protected static final Map<Host,DefaultWebXmlCacheEntry> hostWebXmlCache =
167 new ConcurrentHashMap<>();
168
169
170
174 private static final Set<ServletContainerInitializer> EMPTY_SCI_SET = Collections.emptySet();
175
176
177
178
181 protected Map<String,Authenticator> customAuthenticators;
182
183
184
187 protected volatile Context context = null;
188
189
190
193 protected String defaultWebXml = null;
194
195
196
199 protected boolean ok = false;
200
201
202
205 protected String originalDocBase = null;
206
207
208
212 private File antiLockingDocBase = null;
213
214
215
218 protected final Map<ServletContainerInitializer, Set<Class<?>>> initializerClassMap =
219 new LinkedHashMap<>();
220
221
225 protected final Map<Class<?>, Set<ServletContainerInitializer>> typeInitializerMap =
226 new HashMap<>();
227
228
232 protected boolean handlesTypesAnnotations = false;
233
234
238 protected boolean handlesTypesNonAnnotations = false;
239
240
241
242
243
249 public String getDefaultWebXml() {
250 if (defaultWebXml == null) {
251 defaultWebXml = Constants.DefaultWebXml;
252 }
253 return defaultWebXml;
254 }
255
256
257
263 public void setDefaultWebXml(String path) {
264 this.defaultWebXml = path;
265 }
266
267
268
274 public void setCustomAuthenticators(
275 Map<String,Authenticator> customAuthenticators) {
276 this.customAuthenticators = customAuthenticators;
277 }
278
279
280
281
282
283
288 @Override
289 public void lifecycleEvent(LifecycleEvent event) {
290
291
292 try {
293 context = (Context) event.getLifecycle();
294 } catch (ClassCastException e) {
295 log.error(sm.getString("contextConfig.cce", event.getLifecycle()), e);
296 return;
297 }
298
299
300 if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {
301 configureStart();
302 } else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {
303 beforeStart();
304 } else if (event.getType().equals(Lifecycle.AFTER_START_EVENT)) {
305
306 if (originalDocBase != null) {
307 context.setDocBase(originalDocBase);
308 }
309 } else if (event.getType().equals(Lifecycle.CONFIGURE_STOP_EVENT)) {
310 configureStop();
311 } else if (event.getType().equals(Lifecycle.AFTER_INIT_EVENT)) {
312 init();
313 } else if (event.getType().equals(Lifecycle.AFTER_DESTROY_EVENT)) {
314 destroy();
315 }
316
317 }
318
319
320
321
322
323
326 protected void applicationAnnotationsConfig() {
327
328 long t1=System.currentTimeMillis();
329
330 WebAnnotationSet.loadApplicationAnnotations(context);
331
332 long t2=System.currentTimeMillis();
333 if (context instanceof StandardContext) {
334 ((StandardContext) context).setStartupTime(t2-t1+
335 ((StandardContext) context).getStartupTime());
336 }
337 }
338
339
340
344 protected void authenticatorConfig() {
345
346 LoginConfig loginConfig = context.getLoginConfig();
347 if (loginConfig == null) {
348
349 loginConfig = DUMMY_LOGIN_CONFIG;
350 context.setLoginConfig(loginConfig);
351 }
352
353
354 if (context.getAuthenticator() != null) {
355 return;
356 }
357
358
359 if (context.getRealm() == null) {
360 log.error(sm.getString("contextConfig.missingRealm"));
361 ok = false;
362 return;
363 }
364
365
370 Valve authenticator = null;
371 if (customAuthenticators != null) {
372 authenticator = (Valve) customAuthenticators.get(loginConfig.getAuthMethod());
373 }
374
375 if (authenticator == null) {
376 if (authenticators == null) {
377 log.error(sm.getString("contextConfig.authenticatorResources"));
378 ok = false;
379 return;
380 }
381
382
383 String authenticatorName = authenticators.getProperty(loginConfig.getAuthMethod());
384 if (authenticatorName == null) {
385 log.error(sm.getString("contextConfig.authenticatorMissing",
386 loginConfig.getAuthMethod()));
387 ok = false;
388 return;
389 }
390
391
392 try {
393 Class<?> authenticatorClass = Class.forName(authenticatorName);
394 authenticator = (Valve) authenticatorClass.getConstructor().newInstance();
395 } catch (Throwable t) {
396 ExceptionUtils.handleThrowable(t);
397 log.error(sm.getString(
398 "contextConfig.authenticatorInstantiate",
399 authenticatorName),
400 t);
401 ok = false;
402 }
403 }
404
405 if (authenticator != null) {
406 Pipeline pipeline = context.getPipeline();
407 if (pipeline != null) {
408 pipeline.addValve(authenticator);
409 if (log.isDebugEnabled()) {
410 log.debug(sm.getString(
411 "contextConfig.authenticatorConfigured",
412 loginConfig.getAuthMethod()));
413 }
414 }
415 }
416 }
417
418
419
424 protected Digester createContextDigester() {
425 Digester digester = new Digester();
426 digester.setValidating(false);
427 digester.setRulesValidation(true);
428 Map<Class<?>, List<String>> fakeAttributes = new HashMap<>();
429 List<String> objectAttrs = new ArrayList<>();
430 objectAttrs.add("className");
431 fakeAttributes.put(Object.class, objectAttrs);
432
433 List<String> contextAttrs = new ArrayList<>();
434 contextAttrs.add("source");
435 fakeAttributes.put(StandardContext.class, contextAttrs);
436 digester.setFakeAttributes(fakeAttributes);
437 RuleSet contextRuleSet = new ContextRuleSet("", false);
438 digester.addRuleSet(contextRuleSet);
439 RuleSet namingRuleSet = new NamingRuleSet("Context/");
440 digester.addRuleSet(namingRuleSet);
441 return digester;
442 }
443
444
445
449 protected void contextConfig(Digester digester) {
450
451 String defaultContextXml = null;
452
453
454 if (context instanceof StandardContext) {
455 defaultContextXml = ((StandardContext)context).getDefaultContextXml();
456 }
457
458 if (defaultContextXml == null) {
459 defaultContextXml = Constants.DefaultContextXml;
460 }
461
462 if (!context.getOverride()) {
463 try (ConfigurationSource.Resource contextXmlResource =
464 ConfigFileLoader.getSource().getResource(defaultContextXml)) {
465 URL defaultContextUrl = contextXmlResource.getURI().toURL();
466 processContextConfig(digester, defaultContextUrl, contextXmlResource.getInputStream());
467 } catch (MalformedURLException e) {
468 log.error(sm.getString("contextConfig.badUrl", defaultContextXml), e);
469 } catch (IOException e) {
470
471 }
472
473 String hostContextFile = Container.getConfigPath(context, Constants.HostContextXml);
474 try (ConfigurationSource.Resource contextXmlResource =
475 ConfigFileLoader.getSource().getResource(hostContextFile)) {
476 URL defaultContextUrl = contextXmlResource.getURI().toURL();
477 processContextConfig(digester, defaultContextUrl, contextXmlResource.getInputStream());
478 } catch (MalformedURLException e) {
479 log.error(sm.getString("contextConfig.badUrl", hostContextFile), e);
480 } catch (IOException e) {
481
482 }
483 }
484 if (context.getConfigFile() != null) {
485 processContextConfig(digester, context.getConfigFile(), null);
486 }
487
488 }
489
490
491
497 protected void processContextConfig(Digester digester, URL contextXml, InputStream stream) {
498
499 if (log.isDebugEnabled()) {
500 log.debug("Processing context [" + context.getName()
501 + "] configuration file [" + contextXml + "]");
502 }
503
504 InputSource source = null;
505
506 try {
507 source = new InputSource(contextXml.toString());
508 if (stream == null) {
509 URLConnection xmlConn = contextXml.openConnection();
510 xmlConn.setUseCaches(false);
511 stream = xmlConn.getInputStream();
512 }
513 } catch (Exception e) {
514 log.error(sm.getString("contextConfig.contextMissing",
515 contextXml) , e);
516 }
517
518 if (source == null) {
519 return;
520 }
521
522 try {
523 source.setByteStream(stream);
524 digester.setClassLoader(this.getClass().getClassLoader());
525 digester.setUseContextClassLoader(false);
526 digester.push(context.getParent());
527 digester.push(context);
528 XmlErrorHandler errorHandler = new XmlErrorHandler();
529 digester.setErrorHandler(errorHandler);
530 digester.parse(source);
531 if (errorHandler.getWarnings().size() > 0 ||
532 errorHandler.getErrors().size() > 0) {
533 errorHandler.logFindings(log, contextXml.toString());
534 ok = false;
535 }
536 if (log.isDebugEnabled()) {
537 log.debug("Successfully processed context [" + context.getName()
538 + "] configuration file [" + contextXml + "]");
539 }
540 } catch (SAXParseException e) {
541 log.error(sm.getString("contextConfig.contextParse",
542 context.getName()), e);
543 log.error(sm.getString("contextConfig.defaultPosition",
544 "" + e.getLineNumber(),
545 "" + e.getColumnNumber()));
546 ok = false;
547 } catch (Exception e) {
548 log.error(sm.getString("contextConfig.contextParse",
549 context.getName()), e);
550 ok = false;
551 } finally {
552 try {
553 if (stream != null) {
554 stream.close();
555 }
556 } catch (IOException e) {
557 log.error(sm.getString("contextConfig.contextClose"), e);
558 }
559 }
560 }
561
562
563
567 protected void fixDocBase() throws IOException {
568
569 Host host = (Host) context.getParent();
570 File appBase = host.getAppBaseFile();
571
572
573 String docBaseConfigured = context.getDocBase();
574
575 if (docBaseConfigured == null) {
576
577 String path = context.getPath();
578 if (path == null) {
579 return;
580 }
581 ContextName cn = new ContextName(path, context.getWebappVersion());
582 docBaseConfigured = cn.getBaseName();
583 }
584
585
586 String docBaseAbsolute;
587 File docBaseConfiguredFile = new File(docBaseConfigured);
588 if (!docBaseConfiguredFile.isAbsolute()) {
589 docBaseAbsolute = (new File(appBase, docBaseConfigured)).getAbsolutePath();
590 } else {
591 docBaseAbsolute = docBaseConfiguredFile.getAbsolutePath();
592 }
593 File docBaseAbsoluteFile = new File(docBaseAbsolute);
594 String originalDocBase = docBaseAbsolute;
595
596 ContextName cn = new ContextName(context.getPath(), context.getWebappVersion());
597 String pathName = cn.getBaseName();
598
599 boolean unpackWARs = true;
600 if (host instanceof StandardHost) {
601 unpackWARs = ((StandardHost) host).isUnpackWARs();
602 if (unpackWARs && context instanceof StandardContext) {
603 unpackWARs = ((StandardContext) context).getUnpackWAR();
604 }
605 }
606
607
608
609
610
611 boolean docBaseAbsoluteInAppBase = docBaseAbsolute.startsWith(appBase.getPath() + File.separatorChar);
612 if (docBaseAbsolute.toLowerCase(Locale.ENGLISH).endsWith(".war") && !docBaseAbsoluteFile.isDirectory()) {
613 URL war = UriUtil.buildJarUrl(docBaseAbsoluteFile);
614 if (unpackWARs) {
615 docBaseAbsolute = ExpandWar.expand(host, war, pathName);
616 docBaseAbsoluteFile = new File(docBaseAbsolute);
617 if (context instanceof StandardContext) {
618 ((StandardContext) context).setOriginalDocBase(originalDocBase);
619 }
620 } else {
621 ExpandWar.validate(host, war, pathName);
622 }
623 } else {
624 File docBaseAbsoluteFileWar = new File(docBaseAbsolute + ".war");
625 URL war = null;
626 if (docBaseAbsoluteFileWar.exists() && docBaseAbsoluteInAppBase) {
627 war = UriUtil.buildJarUrl(docBaseAbsoluteFileWar);
628 }
629 if (docBaseAbsoluteFile.exists()) {
630 if (war != null && unpackWARs) {
631
632
633
634
635 ExpandWar.expand(host, war, pathName);
636 }
637 } else {
638 if (war != null) {
639 if (unpackWARs) {
640 docBaseAbsolute = ExpandWar.expand(host, war, pathName);
641 docBaseAbsoluteFile = new File(docBaseAbsolute);
642 } else {
643 docBaseAbsoluteFile = docBaseAbsoluteFileWar;
644 ExpandWar.validate(host, war, pathName);
645 }
646 }
647 if (context instanceof StandardContext) {
648 ((StandardContext) context).setOriginalDocBase(originalDocBase);
649 }
650 }
651 }
652
653 String docBaseCanonical = docBaseAbsoluteFile.getCanonicalPath();
654
655
656 boolean docBaseCanonicalInAppBase = docBaseCanonical.startsWith(appBase.getPath() + File.separatorChar);
657 String docBase;
658 if (docBaseCanonicalInAppBase) {
659 docBase = docBaseCanonical.substring(appBase.getPath().length());
660 docBase = docBase.replace(File.separatorChar, '/');
661 if (docBase.startsWith("/")) {
662 docBase = docBase.substring(1);
663 }
664 } else {
665 docBase = docBaseCanonical.replace(File.separatorChar, '/');
666 }
667
668 context.setDocBase(docBase);
669 }
670
671
672 protected void antiLocking() {
673
674 if ((context instanceof StandardContext)
675 && ((StandardContext) context).getAntiResourceLocking()) {
676
677 Host host = (Host) context.getParent();
678 String docBase = context.getDocBase();
679 if (docBase == null) {
680 return;
681 }
682 originalDocBase = docBase;
683
684 File docBaseFile = new File(docBase);
685 if (!docBaseFile.isAbsolute()) {
686 docBaseFile = new File(host.getAppBaseFile(), docBase);
687 }
688
689 String path = context.getPath();
690 if (path == null) {
691 return;
692 }
693 ContextName cn = new ContextName(path, context.getWebappVersion());
694 docBase = cn.getBaseName();
695
696 if (originalDocBase.toLowerCase(Locale.ENGLISH).endsWith(".war")) {
697 antiLockingDocBase = new File(
698 System.getProperty("java.io.tmpdir"),
699 deploymentCount++ + "-" + docBase + ".war");
700 } else {
701 antiLockingDocBase = new File(
702 System.getProperty("java.io.tmpdir"),
703 deploymentCount++ + "-" + docBase);
704 }
705 antiLockingDocBase = antiLockingDocBase.getAbsoluteFile();
706
707 if (log.isDebugEnabled()) {
708 log.debug("Anti locking context[" + context.getName()
709 + "] setting docBase to " +
710 antiLockingDocBase.getPath());
711 }
712
713
714 ExpandWar.delete(antiLockingDocBase);
715 if (ExpandWar.copy(docBaseFile, antiLockingDocBase)) {
716 context.setDocBase(antiLockingDocBase.getPath());
717 }
718 }
719 }
720
721
722
725 protected synchronized void init() {
726
727
728 Digester contextDigester = createContextDigester();
729 contextDigester.getParser();
730
731 if (log.isDebugEnabled()) {
732 log.debug(sm.getString("contextConfig.init"));
733 }
734 context.setConfigured(false);
735 ok = true;
736
737 contextConfig(contextDigester);
738 }
739
740
741
744 protected synchronized void beforeStart() {
745
746 try {
747 fixDocBase();
748 } catch (IOException e) {
749 log.error(sm.getString(
750 "contextConfig.fixDocBase", context.getName()), e);
751 }
752
753 antiLocking();
754 }
755
756
757
760 protected synchronized void configureStart() {
761
762
763 if (log.isDebugEnabled()) {
764 log.debug(sm.getString("contextConfig.start"));
765 }
766
767 if (log.isDebugEnabled()) {
768 log.debug(sm.getString("contextConfig.xmlSettings",
769 context.getName(),
770 Boolean.valueOf(context.getXmlValidation()),
771 Boolean.valueOf(context.getXmlNamespaceAware())));
772 }
773
774 webConfig();
775
776 if (!context.getIgnoreAnnotations()) {
777 applicationAnnotationsConfig();
778 }
779 if (ok) {
780 validateSecurityRoles();
781 }
782
783
784 if (ok) {
785 authenticatorConfig();
786 }
787
788
789 if (log.isDebugEnabled()) {
790 log.debug("Pipeline Configuration:");
791 Pipeline pipeline = context.getPipeline();
792 Valve valves[] = null;
793 if (pipeline != null) {
794 valves = pipeline.getValves();
795 }
796 if (valves != null) {
797 for (int i = 0; i < valves.length; i++) {
798 log.debug(" " + valves[i].getClass().getName());
799 }
800 }
801 log.debug("======================");
802 }
803
804
805 if (ok) {
806 context.setConfigured(true);
807 } else {
808 log.error(sm.getString("contextConfig.unavailable"));
809 context.setConfigured(false);
810 }
811
812 }
813
814
815
818 protected synchronized void configureStop() {
819
820 if (log.isDebugEnabled()) {
821 log.debug(sm.getString("contextConfig.stop"));
822 }
823
824 int i;
825
826
827 Container[] children = context.findChildren();
828 for (i = 0; i < children.length; i++) {
829 context.removeChild(children[i]);
830 }
831
832
833
841
842
843 SecurityConstraint[] securityConstraints = context.findConstraints();
844 for (i = 0; i < securityConstraints.length; i++) {
845 context.removeConstraint(securityConstraints[i]);
846 }
847
848
849
855
856
857
863
864
865 ErrorPage[] errorPages = context.findErrorPages();
866 for (i = 0; i < errorPages.length; i++) {
867 context.removeErrorPage(errorPages[i]);
868 }
869
870
871 FilterDef[] filterDefs = context.findFilterDefs();
872 for (i = 0; i < filterDefs.length; i++) {
873 context.removeFilterDef(filterDefs[i]);
874 }
875
876
877 FilterMap[] filterMaps = context.findFilterMaps();
878 for (i = 0; i < filterMaps.length; i++) {
879 context.removeFilterMap(filterMaps[i]);
880 }
881
882
883
889
890
891 String[] mimeMappings = context.findMimeMappings();
892 for (i = 0; i < mimeMappings.length; i++) {
893 context.removeMimeMapping(mimeMappings[i]);
894 }
895
896
897 String[] parameters = context.findParameters();
898 for (i = 0; i < parameters.length; i++) {
899 context.removeParameter(parameters[i]);
900 }
901
902
903
909
910
911
918
919
920
926
927
928 String[] securityRoles = context.findSecurityRoles();
929 for (i = 0; i < securityRoles.length; i++) {
930 context.removeSecurityRole(securityRoles[i]);
931 }
932
933
934 String[] servletMappings = context.findServletMappings();
935 for (i = 0; i < servletMappings.length; i++) {
936 context.removeServletMapping(servletMappings[i]);
937 }
938
939
940
941
942 String[] welcomeFiles = context.findWelcomeFiles();
943 for (i = 0; i < welcomeFiles.length; i++) {
944 context.removeWelcomeFile(welcomeFiles[i]);
945 }
946
947
948 String[] wrapperLifecycles = context.findWrapperLifecycles();
949 for (i = 0; i < wrapperLifecycles.length; i++) {
950 context.removeWrapperLifecycle(wrapperLifecycles[i]);
951 }
952
953
954 String[] wrapperListeners = context.findWrapperListeners();
955 for (i = 0; i < wrapperListeners.length; i++) {
956 context.removeWrapperListener(wrapperListeners[i]);
957 }
958
959
960 if (antiLockingDocBase != null) {
961
962 ExpandWar.delete(antiLockingDocBase, false);
963 }
964
965
966 initializerClassMap.clear();
967 typeInitializerMap.clear();
968
969 ok = true;
970
971 }
972
973
974
977 protected synchronized void destroy() {
978
979 if (log.isDebugEnabled()) {
980 log.debug(sm.getString("contextConfig.destroy"));
981 }
982
983
984 Server s = getServer();
985 if (s != null && !s.getState().isAvailable()) {
986 return;
987 }
988
989
990 if (context instanceof StandardContext) {
991 String workDir = ((StandardContext) context).getWorkPath();
992 if (workDir != null) {
993 ExpandWar.delete(new File(workDir));
994 }
995 }
996 }
997
998
999 private Server getServer() {
1000 Container c = context;
1001 while (c != null && !(c instanceof Engine)) {
1002 c = c.getParent();
1003 }
1004
1005 if (c == null) {
1006 return null;
1007 }
1008
1009 Service s = ((Engine)c).getService();
1010
1011 if (s == null) {
1012 return null;
1013 }
1014
1015 return s.getServer();
1016 }
1017
1018
1025 protected void validateSecurityRoles() {
1026
1027
1028 SecurityConstraint constraints[] = context.findConstraints();
1029 for (int i = 0; i < constraints.length; i++) {
1030 String roles[] = constraints[i].findAuthRoles();
1031 for (int j = 0; j < roles.length; j++) {
1032 if (!"*".equals(roles[j]) &&
1033 !context.findSecurityRole(roles[j])) {
1034 log.warn(sm.getString("contextConfig.role.auth", roles[j]));
1035 context.addSecurityRole(roles[j]);
1036 }
1037 }
1038 }
1039
1040
1041 Container wrappers[] = context.findChildren();
1042 for (int i = 0; i < wrappers.length; i++) {
1043 Wrapper wrapper = (Wrapper) wrappers[i];
1044 String runAs = wrapper.getRunAs();
1045 if ((runAs != null) && !context.findSecurityRole(runAs)) {
1046 log.warn(sm.getString("contextConfig.role.runas", runAs));
1047 context.addSecurityRole(runAs);
1048 }
1049 String names[] = wrapper.findSecurityReferences();
1050 for (int j = 0; j < names.length; j++) {
1051 String link = wrapper.findSecurityReference(names[j]);
1052 if ((link != null) && !context.findSecurityRole(link)) {
1053 log.warn(sm.getString("contextConfig.role.link", link));
1054 context.addSecurityRole(link);
1055 }
1056 }
1057 }
1058
1059 }
1060
1061
1062 protected File getHostConfigBase() {
1063 File file = null;
1064 if (context.getParent() instanceof Host) {
1065 file = ((Host)context.getParent()).getConfigBaseFile();
1066 }
1067 return file;
1068 }
1069
1070
1077 protected void webConfig() {
1078
1086
1087
1103 WebXmlParser webXmlParser = new WebXmlParser(context.getXmlNamespaceAware(),
1104 context.getXmlValidation(), context.getXmlBlockExternal());
1105
1106 Set<WebXml> defaults = new HashSet<>();
1107 defaults.add(getDefaultWebXmlFragment(webXmlParser));
1108
1109 Set<WebXml> tomcatWebXml = new HashSet<>();
1110 tomcatWebXml.add(getTomcatWebXmlFragment(webXmlParser));
1111
1112 WebXml webXml = createWebXml();
1113
1114
1115 InputSource contextWebXml = getContextWebXmlSource();
1116 if (!webXmlParser.parseWebXml(contextWebXml, webXml, false)) {
1117 ok = false;
1118 }
1119
1120 ServletContext sContext = context.getServletContext();
1121
1122
1123
1124
1125
1126
1127
1128 Map<String,WebXml> fragments = processJarsForWebFragments(webXml, webXmlParser);
1129
1130
1131 Set<WebXml> orderedFragments = null;
1132 orderedFragments =
1133 WebXml.orderWebFragments(webXml, fragments, sContext);
1134
1135
1136 if (ok) {
1137 processServletContainerInitializers();
1138 }
1139
1140 if (!webXml.isMetadataComplete() || typeInitializerMap.size() > 0) {
1141
1142 processClasses(webXml, orderedFragments);
1143 }
1144
1145 if (!webXml.isMetadataComplete()) {
1146
1147
1148 if (ok) {
1149 ok = webXml.merge(orderedFragments);
1150 }
1151
1152
1153
1154 webXml.merge(tomcatWebXml);
1155
1156
1157
1158
1159 webXml.merge(defaults);
1160
1161
1162 if (ok) {
1163 convertJsps(webXml);
1164 }
1165
1166
1167 if (ok) {
1168 configureContext(webXml);
1169 }
1170 } else {
1171 webXml.merge(tomcatWebXml);
1172 webXml.merge(defaults);
1173 convertJsps(webXml);
1174 configureContext(webXml);
1175 }
1176
1177 if (context.getLogEffectiveWebXml()) {
1178 log.info(sm.getString("contextConfig.effectiveWebXml", webXml.toXml()));
1179 }
1180
1181
1182
1183 if (ok) {
1184
1185
1186 Set<WebXml> resourceJars = new LinkedHashSet<>();
1187 for (WebXml fragment : orderedFragments) {
1188 resourceJars.add(fragment);
1189 }
1190 for (WebXml fragment : fragments.values()) {
1191 if (!resourceJars.contains(fragment)) {
1192 resourceJars.add(fragment);
1193 }
1194 }
1195 processResourceJARs(resourceJars);
1196
1197
1198 }
1199
1200
1201
1202 if (ok) {
1203 for (Map.Entry<ServletContainerInitializer,
1204 Set<Class<?>>> entry :
1205 initializerClassMap.entrySet()) {
1206 if (entry.getValue().isEmpty()) {
1207 context.addServletContainerInitializer(
1208 entry.getKey(), null);
1209 } else {
1210 context.addServletContainerInitializer(
1211 entry.getKey(), entry.getValue());
1212 }
1213 }
1214 }
1215 }
1216
1217
1218 protected void processClasses(WebXml webXml, Set<WebXml> orderedFragments) {
1219
1220
1221 Map<String, JavaClassCacheEntry> javaClassCache = new HashMap<>();
1222
1223 if (ok) {
1224 WebResource[] webResources =
1225 context.getResources().listResources("/WEB-INF/classes");
1226
1227 for (WebResource webResource : webResources) {
1228
1229
1230 if ("META-INF".equals(webResource.getName())) {
1231 continue;
1232 }
1233 processAnnotationsWebResource(webResource, webXml,
1234 webXml.isMetadataComplete(), javaClassCache);
1235 }
1236 }
1237
1238
1239
1240
1241
1242 if (ok) {
1243 processAnnotations(
1244 orderedFragments, webXml.isMetadataComplete(), javaClassCache);
1245 }
1246
1247
1248 javaClassCache.clear();
1249 }
1250
1251
1252 private void configureContext(WebXml webxml) {
1253
1254
1255
1256 context.setPublicId(webxml.getPublicId());
1257
1258
1259 context.setEffectiveMajorVersion(webxml.getMajorVersion());
1260 context.setEffectiveMinorVersion(webxml.getMinorVersion());
1261
1262 for (Entry<String, String> entry : webxml.getContextParams().entrySet()) {
1263 context.addParameter(entry.getKey(), entry.getValue());
1264 }
1265 context.setDenyUncoveredHttpMethods(
1266 webxml.getDenyUncoveredHttpMethods());
1267 context.setDisplayName(webxml.getDisplayName());
1268 context.setDistributable(webxml.isDistributable());
1269 for (ContextLocalEjb ejbLocalRef : webxml.getEjbLocalRefs().values()) {
1270 context.getNamingResources().addLocalEjb(ejbLocalRef);
1271 }
1272 for (ContextEjb ejbRef : webxml.getEjbRefs().values()) {
1273 context.getNamingResources().addEjb(ejbRef);
1274 }
1275 for (ContextEnvironment environment : webxml.getEnvEntries().values()) {
1276 context.getNamingResources().addEnvironment(environment);
1277 }
1278 for (ErrorPage errorPage : webxml.getErrorPages().values()) {
1279 context.addErrorPage(errorPage);
1280 }
1281 for (FilterDef filter : webxml.getFilters().values()) {
1282 if (filter.getAsyncSupported() == null) {
1283 filter.setAsyncSupported("false");
1284 }
1285 context.addFilterDef(filter);
1286 }
1287 for (FilterMap filterMap : webxml.getFilterMappings()) {
1288 context.addFilterMap(filterMap);
1289 }
1290 context.setJspConfigDescriptor(webxml.getJspConfigDescriptor());
1291 for (String listener : webxml.getListeners()) {
1292 context.addApplicationListener(listener);
1293 }
1294 for (Entry<String, String> entry :
1295 webxml.getLocaleEncodingMappings().entrySet()) {
1296 context.addLocaleEncodingMappingParameter(entry.getKey(),
1297 entry.getValue());
1298 }
1299
1300 if (webxml.getLoginConfig() != null) {
1301 context.setLoginConfig(webxml.getLoginConfig());
1302 }
1303 for (MessageDestinationRef mdr :
1304 webxml.getMessageDestinationRefs().values()) {
1305 context.getNamingResources().addMessageDestinationRef(mdr);
1306 }
1307
1308
1309
1310 context.setIgnoreAnnotations(webxml.isMetadataComplete());
1311 for (Entry<String, String> entry :
1312 webxml.getMimeMappings().entrySet()) {
1313 context.addMimeMapping(entry.getKey(), entry.getValue());
1314 }
1315 context.setRequestCharacterEncoding(webxml.getRequestCharacterEncoding());
1316
1317 for (ContextResourceEnvRef resource :
1318 webxml.getResourceEnvRefs().values()) {
1319 context.getNamingResources().addResourceEnvRef(resource);
1320 }
1321 for (ContextResource resource : webxml.getResourceRefs().values()) {
1322 context.getNamingResources().addResource(resource);
1323 }
1324 context.setResponseCharacterEncoding(webxml.getResponseCharacterEncoding());
1325 boolean allAuthenticatedUsersIsAppRole =
1326 webxml.getSecurityRoles().contains(
1327 SecurityConstraint.ROLE_ALL_AUTHENTICATED_USERS);
1328 for (SecurityConstraint constraint : webxml.getSecurityConstraints()) {
1329 if (allAuthenticatedUsersIsAppRole) {
1330 constraint.treatAllAuthenticatedUsersAsApplicationRole();
1331 }
1332 context.addConstraint(constraint);
1333 }
1334 for (String role : webxml.getSecurityRoles()) {
1335 context.addSecurityRole(role);
1336 }
1337 for (ContextService service : webxml.getServiceRefs().values()) {
1338 context.getNamingResources().addService(service);
1339 }
1340 for (ServletDef servlet : webxml.getServlets().values()) {
1341 Wrapper wrapper = context.createWrapper();
1342
1343
1344
1345
1346
1347
1348 if (servlet.getLoadOnStartup() != null) {
1349 wrapper.setLoadOnStartup(servlet.getLoadOnStartup().intValue());
1350 }
1351 if (servlet.getEnabled() != null) {
1352 wrapper.setEnabled(servlet.getEnabled().booleanValue());
1353 }
1354 wrapper.setName(servlet.getServletName());
1355 Map<String,String> params = servlet.getParameterMap();
1356 for (Entry<String, String> entry : params.entrySet()) {
1357 wrapper.addInitParameter(entry.getKey(), entry.getValue());
1358 }
1359 wrapper.setRunAs(servlet.getRunAs());
1360 Set<SecurityRoleRef> roleRefs = servlet.getSecurityRoleRefs();
1361 for (SecurityRoleRef roleRef : roleRefs) {
1362 wrapper.addSecurityReference(
1363 roleRef.getName(), roleRef.getLink());
1364 }
1365 wrapper.setServletClass(servlet.getServletClass());
1366 MultipartDef multipartdef = servlet.getMultipartDef();
1367 if (multipartdef != null) {
1368 if (multipartdef.getMaxFileSize() != null &&
1369 multipartdef.getMaxRequestSize()!= null &&
1370 multipartdef.getFileSizeThreshold() != null) {
1371 wrapper.setMultipartConfigElement(new MultipartConfigElement(
1372 multipartdef.getLocation(),
1373 Long.parseLong(multipartdef.getMaxFileSize()),
1374 Long.parseLong(multipartdef.getMaxRequestSize()),
1375 Integer.parseInt(
1376 multipartdef.getFileSizeThreshold())));
1377 } else {
1378 wrapper.setMultipartConfigElement(new MultipartConfigElement(
1379 multipartdef.getLocation()));
1380 }
1381 }
1382 if (servlet.getAsyncSupported() != null) {
1383 wrapper.setAsyncSupported(
1384 servlet.getAsyncSupported().booleanValue());
1385 }
1386 wrapper.setOverridable(servlet.isOverridable());
1387 context.addChild(wrapper);
1388 }
1389 for (Entry<String, String> entry :
1390 webxml.getServletMappings().entrySet()) {
1391 context.addServletMappingDecoded(entry.getKey(), entry.getValue());
1392 }
1393 SessionConfig sessionConfig = webxml.getSessionConfig();
1394 if (sessionConfig != null) {
1395 if (sessionConfig.getSessionTimeout() != null) {
1396 context.setSessionTimeout(
1397 sessionConfig.getSessionTimeout().intValue());
1398 }
1399 SessionCookieConfig scc =
1400 context.getServletContext().getSessionCookieConfig();
1401 scc.setName(sessionConfig.getCookieName());
1402 scc.setDomain(sessionConfig.getCookieDomain());
1403 scc.setPath(sessionConfig.getCookiePath());
1404 scc.setComment(sessionConfig.getCookieComment());
1405 if (sessionConfig.getCookieHttpOnly() != null) {
1406 scc.setHttpOnly(sessionConfig.getCookieHttpOnly().booleanValue());
1407 }
1408 if (sessionConfig.getCookieSecure() != null) {
1409 scc.setSecure(sessionConfig.getCookieSecure().booleanValue());
1410 }
1411 if (sessionConfig.getCookieMaxAge() != null) {
1412 scc.setMaxAge(sessionConfig.getCookieMaxAge().intValue());
1413 }
1414 if (sessionConfig.getSessionTrackingModes().size() > 0) {
1415 context.getServletContext().setSessionTrackingModes(
1416 sessionConfig.getSessionTrackingModes());
1417 }
1418 }
1419
1420
1421
1422 for (String welcomeFile : webxml.getWelcomeFiles()) {
1423
1430 if (welcomeFile != null && welcomeFile.length() > 0) {
1431 context.addWelcomeFile(welcomeFile);
1432 }
1433 }
1434
1435
1436 for (JspPropertyGroup jspPropertyGroup :
1437 webxml.getJspPropertyGroups()) {
1438 String jspServletName = context.findServletMapping("*.jsp");
1439 if (jspServletName == null) {
1440 jspServletName = "jsp";
1441 }
1442 if (context.findChild(jspServletName) != null) {
1443 for (String urlPattern : jspPropertyGroup.getUrlPatterns()) {
1444 context.addServletMappingDecoded(urlPattern, jspServletName, true);
1445 }
1446 } else {
1447 if(log.isDebugEnabled()) {
1448 for (String urlPattern : jspPropertyGroup.getUrlPatterns()) {
1449 log.debug("Skipping " + urlPattern + " , no servlet " +
1450 jspServletName);
1451 }
1452 }
1453 }
1454 }
1455
1456 for (Entry<String, String> entry :
1457 webxml.getPostConstructMethods().entrySet()) {
1458 context.addPostConstructMethod(entry.getKey(), entry.getValue());
1459 }
1460
1461 for (Entry<String, String> entry :
1462 webxml.getPreDestroyMethods().entrySet()) {
1463 context.addPreDestroyMethod(entry.getKey(), entry.getValue());
1464 }
1465 }
1466
1467
1468 private WebXml getTomcatWebXmlFragment(WebXmlParser webXmlParser) {
1469
1470 WebXml webXmlTomcatFragment = createWebXml();
1471 webXmlTomcatFragment.setOverridable(true);
1472
1473
1474
1475
1476 webXmlTomcatFragment.setDistributable(true);
1477
1478
1479 webXmlTomcatFragment.setAlwaysAddWelcomeFiles(false);
1480
1481 WebResource resource = context.getResources().getResource(Constants.TomcatWebXml);
1482 if (resource.isFile()) {
1483 try {
1484 InputSource source = new InputSource(resource.getURL().toURI().toString());
1485 source.setByteStream(resource.getInputStream());
1486 if (!webXmlParser.parseWebXml(source, webXmlTomcatFragment, false)) {
1487 ok = false;
1488 }
1489 } catch (URISyntaxException e) {
1490 log.error(sm.getString("contextConfig.tomcatWebXmlError"), e);
1491 }
1492 }
1493 return webXmlTomcatFragment;
1494 }
1495
1496
1497 private WebXml getDefaultWebXmlFragment(WebXmlParser webXmlParser) {
1498
1499
1500 Host host = (Host) context.getParent();
1501
1502 DefaultWebXmlCacheEntry entry = hostWebXmlCache.get(host);
1503
1504 InputSource globalWebXml = getGlobalWebXmlSource();
1505 InputSource hostWebXml = getHostWebXmlSource();
1506
1507 long globalTimeStamp = 0;
1508 long hostTimeStamp = 0;
1509
1510 if (globalWebXml != null) {
1511 URLConnection uc = null;
1512 try {
1513 URL url = new URL(globalWebXml.getSystemId());
1514 uc = url.openConnection();
1515 globalTimeStamp = uc.getLastModified();
1516 } catch (IOException e) {
1517 globalTimeStamp = -1;
1518 } finally {
1519 if (uc != null) {
1520 try {
1521 uc.getInputStream().close();
1522 } catch (IOException e) {
1523 ExceptionUtils.handleThrowable(e);
1524 globalTimeStamp = -1;
1525 }
1526 }
1527 }
1528 }
1529
1530 if (hostWebXml != null) {
1531 URLConnection uc = null;
1532 try {
1533 URL url = new URL(hostWebXml.getSystemId());
1534 uc = url.openConnection();
1535 hostTimeStamp = uc.getLastModified();
1536 } catch (IOException e) {
1537 hostTimeStamp = -1;
1538 } finally {
1539 if (uc != null) {
1540 try {
1541 uc.getInputStream().close();
1542 } catch (IOException e) {
1543 ExceptionUtils.handleThrowable(e);
1544 hostTimeStamp = -1;
1545 }
1546 }
1547 }
1548 }
1549
1550 if (entry != null && entry.getGlobalTimeStamp() == globalTimeStamp &&
1551 entry.getHostTimeStamp() == hostTimeStamp) {
1552 InputSourceUtil.close(globalWebXml);
1553 InputSourceUtil.close(hostWebXml);
1554 return entry.getWebXml();
1555 }
1556
1557
1558
1559
1560 synchronized (host.getPipeline()) {
1561 entry = hostWebXmlCache.get(host);
1562 if (entry != null && entry.getGlobalTimeStamp() == globalTimeStamp &&
1563 entry.getHostTimeStamp() == hostTimeStamp) {
1564 return entry.getWebXml();
1565 }
1566
1567 WebXml webXmlDefaultFragment = createWebXml();
1568 webXmlDefaultFragment.setOverridable(true);
1569
1570
1571
1572 webXmlDefaultFragment.setDistributable(true);
1573
1574
1575 webXmlDefaultFragment.setAlwaysAddWelcomeFiles(false);
1576
1577
1578 if (globalWebXml == null) {
1579
1580 log.info(sm.getString("contextConfig.defaultMissing"));
1581 } else {
1582 if (!webXmlParser.parseWebXml(
1583 globalWebXml, webXmlDefaultFragment, false)) {
1584 ok = false;
1585 }
1586 }
1587
1588
1589
1590 webXmlDefaultFragment.setReplaceWelcomeFiles(true);
1591
1592 if (!webXmlParser.parseWebXml(
1593 hostWebXml, webXmlDefaultFragment, false)) {
1594 ok = false;
1595 }
1596
1597
1598 if (globalTimeStamp != -1 && hostTimeStamp != -1) {
1599 entry = new DefaultWebXmlCacheEntry(webXmlDefaultFragment,
1600 globalTimeStamp, hostTimeStamp);
1601 hostWebXmlCache.put(host, entry);
1602
1603
1604 host.addLifecycleListener(new HostWebXmlCacheCleaner());
1605 }
1606
1607 return webXmlDefaultFragment;
1608 }
1609 }
1610
1611
1612 private void convertJsps(WebXml webXml) {
1613 Map<String,String> jspInitParams;
1614 ServletDef jspServlet = webXml.getServlets().get("jsp");
1615 if (jspServlet == null) {
1616 jspInitParams = new HashMap<>();
1617 Wrapper w = (Wrapper) context.findChild("jsp");
1618 if (w != null) {
1619 String[] params = w.findInitParameters();
1620 for (String param : params) {
1621 jspInitParams.put(param, w.findInitParameter(param));
1622 }
1623 }
1624 } else {
1625 jspInitParams = jspServlet.getParameterMap();
1626 }
1627 for (ServletDef servletDef: webXml.getServlets().values()) {
1628 if (servletDef.getJspFile() != null) {
1629 convertJsp(servletDef, jspInitParams);
1630 }
1631 }
1632 }
1633
1634 private void convertJsp(ServletDef servletDef,
1635 Map<String,String> jspInitParams) {
1636 servletDef.setServletClass(org.apache.catalina.core.Constants.JSP_SERVLET_CLASS);
1637 String jspFile = servletDef.getJspFile();
1638 if ((jspFile != null) && !jspFile.startsWith("/")) {
1639 if (context.isServlet22()) {
1640 if(log.isDebugEnabled()) {
1641 log.debug(sm.getString("contextConfig.jspFile.warning",
1642 jspFile));
1643 }
1644 jspFile = "/" + jspFile;
1645 } else {
1646 throw new IllegalArgumentException
1647 (sm.getString("contextConfig.jspFile.error", jspFile));
1648 }
1649 }
1650 servletDef.getParameterMap().put("jspFile", jspFile);
1651 servletDef.setJspFile(null);
1652 for (Map.Entry<String, String> initParam: jspInitParams.entrySet()) {
1653 servletDef.addInitParameter(initParam.getKey(), initParam.getValue());
1654 }
1655 }
1656
1657 protected WebXml createWebXml() {
1658 return new WebXml();
1659 }
1660
1661
1664 protected void processServletContainerInitializers() {
1665
1666 List<ServletContainerInitializer> detectedScis;
1667 try {
1668 WebappServiceLoader<ServletContainerInitializer> loader = new WebappServiceLoader<>(context);
1669 detectedScis = loader.load(ServletContainerInitializer.class);
1670 } catch (IOException e) {
1671 log.error(sm.getString(
1672 "contextConfig.servletContainerInitializerFail",
1673 context.getName()),
1674 e);
1675 ok = false;
1676 return;
1677 }
1678
1679 for (ServletContainerInitializer sci : detectedScis) {
1680 initializerClassMap.put(sci, new HashSet<Class<?>>());
1681
1682 HandlesTypes ht;
1683 try {
1684 ht = sci.getClass().getAnnotation(HandlesTypes.class);
1685 } catch (Exception e) {
1686 if (log.isDebugEnabled()) {
1687 log.info(sm.getString("contextConfig.sci.debug",
1688 sci.getClass().getName()),
1689 e);
1690 } else {
1691 log.info(sm.getString("contextConfig.sci.info",
1692 sci.getClass().getName()));
1693 }
1694 continue;
1695 }
1696 if (ht == null) {
1697 continue;
1698 }
1699 Class<?>[] types = ht.value();
1700 if (types == null) {
1701 continue;
1702 }
1703
1704 for (Class<?> type : types) {
1705 if (type.isAnnotation()) {
1706 handlesTypesAnnotations = true;
1707 } else {
1708 handlesTypesNonAnnotations = true;
1709 }
1710 Set<ServletContainerInitializer> scis =
1711 typeInitializerMap.get(type);
1712 if (scis == null) {
1713 scis = new HashSet<>();
1714 typeInitializerMap.put(type, scis);
1715 }
1716 scis.add(sci);
1717 }
1718 }
1719 }
1720
1721
1722
1730 protected void processResourceJARs(Set<WebXml> fragments) {
1731 for (WebXml fragment : fragments) {
1732 URL url = fragment.getURL();
1733 try {
1734 if ("jar".equals(url.getProtocol()) || url.toString().endsWith(".jar")) {
1735 try (Jar jar = JarFactory.newInstance(url)) {
1736 jar.nextEntry();
1737 String entryName = jar.getEntryName();
1738 while (entryName != null) {
1739 if (entryName.startsWith("META-INF/resources/")) {
1740 context.getResources().createWebResourceSet(
1741 WebResourceRoot.ResourceSetType.RESOURCE_JAR,
1742 "/", url, "/META-INF/resources");
1743 break;
1744 }
1745 jar.nextEntry();
1746 entryName = jar.getEntryName();
1747 }
1748 }
1749 } else if ("file".equals(url.getProtocol())) {
1750 File file = new File(url.toURI());
1751 File resources = new File(file, "META-INF/resources/");
1752 if (resources.isDirectory()) {
1753 context.getResources().createWebResourceSet(
1754 WebResourceRoot.ResourceSetType.RESOURCE_JAR,
1755 "/", resources.getAbsolutePath(), null, "/");
1756 }
1757 }
1758 } catch (IOException ioe) {
1759 log.error(sm.getString("contextConfig.resourceJarFail", url,
1760 context.getName()));
1761 } catch (URISyntaxException e) {
1762 log.error(sm.getString("contextConfig.resourceJarFail", url,
1763 context.getName()));
1764 }
1765 }
1766 }
1767
1768
1769
1774 protected InputSource getGlobalWebXmlSource() {
1775
1776 if (defaultWebXml == null && context instanceof StandardContext) {
1777 defaultWebXml = ((StandardContext) context).getDefaultWebXml();
1778 }
1779
1780 if (defaultWebXml == null) {
1781 getDefaultWebXml();
1782 }
1783
1784
1785 if (Constants.NoDefaultWebXml.equals(defaultWebXml)) {
1786 return null;
1787 }
1788 return getWebXmlSource(defaultWebXml, true);
1789 }
1790
1791
1792
1797 protected InputSource getHostWebXmlSource() {
1798 File hostConfigBase = getHostConfigBase();
1799 if (hostConfigBase == null)
1800 return null;
1801
1802 return getWebXmlSource(hostConfigBase.getPath(), false);
1803 }
1804
1805
1810 protected InputSource getContextWebXmlSource() {
1811 InputStream stream = null;
1812 InputSource source = null;
1813 URL url = null;
1814
1815 String altDDName = null;
1816
1817
1818 ServletContext servletContext = context.getServletContext();
1819 try {
1820 if (servletContext != null) {
1821 altDDName = (String)servletContext.getAttribute(Globals.ALT_DD_ATTR);
1822 if (altDDName != null) {
1823 try {
1824 stream = new FileInputStream(altDDName);
1825 url = new File(altDDName).toURI().toURL();
1826 } catch (FileNotFoundException e) {
1827 log.error(sm.getString("contextConfig.altDDNotFound",
1828 altDDName));
1829 } catch (MalformedURLException e) {
1830 log.error(sm.getString("contextConfig.applicationUrl"));
1831 }
1832 }
1833 else {
1834 stream = servletContext.getResourceAsStream
1835 (Constants.ApplicationWebXml);
1836 try {
1837 url = servletContext.getResource(
1838 Constants.ApplicationWebXml);
1839 } catch (MalformedURLException e) {
1840 log.error(sm.getString("contextConfig.applicationUrl"));
1841 }
1842 }
1843 }
1844 if (stream == null || url == null) {
1845 if (log.isDebugEnabled()) {
1846 log.debug(sm.getString("contextConfig.applicationMissing") + " " + context);
1847 }
1848 } else {
1849 source = new InputSource(url.toExternalForm());
1850 source.setByteStream(stream);
1851 }
1852 } finally {
1853 if (source == null && stream != null) {
1854 try {
1855 stream.close();
1856 } catch (IOException e) {
1857
1858 }
1859 }
1860 }
1861
1862 return source;
1863 }
1864
1865 public String getConfigBasePath() {
1866 String path = null;
1867 if (context.getParent() instanceof Host) {
1868 Host host = (Host) context.getParent();
1869 if (host.getXmlBase() != null) {
1870 path = host.getXmlBase();
1871 } else {
1872 StringBuilder xmlDir = new StringBuilder("conf");
1873 Container parent = host.getParent();
1874 if (parent instanceof Engine) {
1875 xmlDir.append('/');
1876 xmlDir.append(parent.getName());
1877 }
1878 xmlDir.append('/');
1879 xmlDir.append(host.getName());
1880 path = xmlDir.toString();
1881 }
1882 }
1883 return path;
1884 }
1885
1886
1894 protected InputSource getWebXmlSource(String filename, boolean global) {
1895 ConfigurationSource.Resource webXmlResource = null;
1896 try {
1897 if (global) {
1898 if (Constants.DefaultWebXml.equals(filename)) {
1899 webXmlResource = ConfigFileLoader.getSource().getSharedWebXml();
1900 } else {
1901 webXmlResource = ConfigFileLoader.getSource().getResource(filename);
1902 }
1903 } else {
1904 String hostWebXml = Container.getConfigPath(context, Constants.HostWebXml);
1905 webXmlResource = ConfigFileLoader.getSource().getResource(hostWebXml);
1906 }
1907 } catch (IOException e) {
1908
1909 return null;
1910 }
1911
1912 InputStream stream = null;
1913 InputSource source = null;
1914
1915 try {
1916 stream = webXmlResource.getInputStream();
1917 source = new InputSource(webXmlResource.getURI().toString());
1918 if (stream != null) {
1919 source.setByteStream(stream);
1920 }
1921 } catch (Exception e) {
1922 log.error(sm.getString("contextConfig.defaultError", filename, webXmlResource.getURI()), e);
1923 } finally {
1924 if (source == null && stream != null) {
1925 try {
1926 stream.close();
1927 } catch (IOException e) {
1928
1929 }
1930 }
1931 }
1932
1933 return source;
1934 }
1935
1936
1937
1948 protected Map<String,WebXml> processJarsForWebFragments(WebXml application,
1949 WebXmlParser webXmlParser) {
1950
1951 JarScanner jarScanner = context.getJarScanner();
1952 boolean delegate = false;
1953 if (context instanceof StandardContext) {
1954 delegate = ((StandardContext) context).getDelegate();
1955 }
1956 boolean parseRequired = true;
1957 Set<String> absoluteOrder = application.getAbsoluteOrdering();
1958 if (absoluteOrder != null && absoluteOrder.isEmpty() &&
1959 !context.getXmlValidation()) {
1960
1961
1962 parseRequired = false;
1963 }
1964
1965 FragmentJarScannerCallback callback =
1966 new FragmentJarScannerCallback(webXmlParser, delegate, parseRequired);
1967
1968 jarScanner.scan(JarScanType.PLUGGABILITY,
1969 context.getServletContext(), callback);
1970
1971 if (!callback.isOk()) {
1972 ok = false;
1973 }
1974 return callback.getFragments();
1975 }
1976
1977 protected void processAnnotations(Set<WebXml> fragments,
1978 boolean handlesTypesOnly, Map<String,JavaClassCacheEntry> javaClassCache) {
1979 for(WebXml fragment : fragments) {
1980
1981
1982
1983
1984
1985
1986 boolean htOnly = handlesTypesOnly || !fragment.getWebappJar() ||
1987 fragment.isMetadataComplete();
1988
1989 WebXml annotations = new WebXml();
1990
1991 annotations.setDistributable(true);
1992 URL url = fragment.getURL();
1993 processAnnotationsUrl(url, annotations, htOnly, javaClassCache);
1994 Set<WebXml> set = new HashSet<>();
1995 set.add(annotations);
1996
1997 fragment.merge(set);
1998 }
1999 }
2000
2001 protected void processAnnotationsWebResource(WebResource webResource,
2002 WebXml fragment, boolean handlesTypesOnly,
2003 Map<String,JavaClassCacheEntry> javaClassCache) {
2004
2005 if (webResource.isDirectory()) {
2006 WebResource[] webResources =
2007 webResource.getWebResourceRoot().listResources(
2008 webResource.getWebappPath());
2009 if (webResources.length > 0) {
2010 if (log.isDebugEnabled()) {
2011 log.debug(sm.getString(
2012 "contextConfig.processAnnotationsWebDir.debug",
2013 webResource.getURL()));
2014 }
2015 for (WebResource r : webResources) {
2016 processAnnotationsWebResource(r, fragment, handlesTypesOnly, javaClassCache);
2017 }
2018 }
2019 } else if (webResource.isFile() &&
2020 webResource.getName().endsWith(".class")) {
2021 try (InputStream is = webResource.getInputStream()) {
2022 processAnnotationsStream(is, fragment, handlesTypesOnly, javaClassCache);
2023 } catch (IOException e) {
2024 log.error(sm.getString("contextConfig.inputStreamWebResource",
2025 webResource.getWebappPath()),e);
2026 } catch (ClassFormatException e) {
2027 log.error(sm.getString("contextConfig.inputStreamWebResource",
2028 webResource.getWebappPath()),e);
2029 }
2030 }
2031 }
2032
2033
2034 protected void processAnnotationsUrl(URL url, WebXml fragment,
2035 boolean handlesTypesOnly, Map<String,JavaClassCacheEntry> javaClassCache) {
2036 if (url == null) {
2037
2038 return;
2039 } else if ("jar".equals(url.getProtocol()) || url.toString().endsWith(".jar")) {
2040 processAnnotationsJar(url, fragment, handlesTypesOnly, javaClassCache);
2041 } else if ("file".equals(url.getProtocol())) {
2042 try {
2043 processAnnotationsFile(
2044 new File(url.toURI()), fragment, handlesTypesOnly, javaClassCache);
2045 } catch (URISyntaxException e) {
2046 log.error(sm.getString("contextConfig.fileUrl", url), e);
2047 }
2048 } else {
2049 log.error(sm.getString("contextConfig.unknownUrlProtocol",
2050 url.getProtocol(), url));
2051 }
2052
2053 }
2054
2055
2056 protected void processAnnotationsJar(URL url, WebXml fragment,
2057 boolean handlesTypesOnly, Map<String,JavaClassCacheEntry> javaClassCache) {
2058
2059 try (Jar jar = JarFactory.newInstance(url)) {
2060 if (log.isDebugEnabled()) {
2061 log.debug(sm.getString(
2062 "contextConfig.processAnnotationsJar.debug", url));
2063 }
2064
2065 jar.nextEntry();
2066 String entryName = jar.getEntryName();
2067 while (entryName != null) {
2068 if (entryName.endsWith(".class")) {
2069 try (InputStream is = jar.getEntryInputStream()) {
2070 processAnnotationsStream(is, fragment, handlesTypesOnly, javaClassCache);
2071 } catch (IOException e) {
2072 log.error(sm.getString("contextConfig.inputStreamJar",
2073 entryName, url),e);
2074 } catch (ClassFormatException e) {
2075 log.error(sm.getString("contextConfig.inputStreamJar",
2076 entryName, url),e);
2077 }
2078 }
2079 jar.nextEntry();
2080 entryName = jar.getEntryName();
2081 }
2082 } catch (IOException e) {
2083 log.error(sm.getString("contextConfig.jarFile", url), e);
2084 }
2085 }
2086
2087
2088 protected void processAnnotationsFile(File file, WebXml fragment,
2089 boolean handlesTypesOnly, Map<String,JavaClassCacheEntry> javaClassCache) {
2090
2091 if (file.isDirectory()) {
2092
2093 String[] dirs = file.list();
2094 if (dirs != null) {
2095 if (log.isDebugEnabled()) {
2096 log.debug(sm.getString(
2097 "contextConfig.processAnnotationsDir.debug", file));
2098 }
2099 for (String dir : dirs) {
2100 processAnnotationsFile(
2101 new File(file,dir), fragment, handlesTypesOnly, javaClassCache);
2102 }
2103 }
2104 } else if (file.getName().endsWith(".class") && file.canRead()) {
2105 try (FileInputStream fis = new FileInputStream(file)) {
2106 processAnnotationsStream(fis, fragment, handlesTypesOnly, javaClassCache);
2107 } catch (IOException e) {
2108 log.error(sm.getString("contextConfig.inputStreamFile",
2109 file.getAbsolutePath()),e);
2110 } catch (ClassFormatException e) {
2111 log.error(sm.getString("contextConfig.inputStreamFile",
2112 file.getAbsolutePath()),e);
2113 }
2114 }
2115 }
2116
2117
2118 protected void processAnnotationsStream(InputStream is, WebXml fragment,
2119 boolean handlesTypesOnly, Map<String,JavaClassCacheEntry> javaClassCache)
2120 throws ClassFormatException, IOException {
2121
2122 ClassParser parser = new ClassParser(is);
2123 JavaClass clazz = parser.parse();
2124 checkHandlesTypes(clazz, javaClassCache);
2125
2126 if (handlesTypesOnly) {
2127 return;
2128 }
2129
2130 processClass(fragment, clazz);
2131 }
2132
2133
2134 protected void processClass(WebXml fragment, JavaClass clazz) {
2135 AnnotationEntry[] annotationsEntries = clazz.getAnnotationEntries();
2136 if (annotationsEntries != null) {
2137 String className = clazz.getClassName();
2138 for (AnnotationEntry ae : annotationsEntries) {
2139 String type = ae.getAnnotationType();
2140 if ("Ljavax/servlet/annotation/WebServlet;".equals(type)) {
2141 processAnnotationWebServlet(className, ae, fragment);
2142 }else if ("Ljavax/servlet/annotation/WebFilter;".equals(type)) {
2143 processAnnotationWebFilter(className, ae, fragment);
2144 }else if ("Ljavax/servlet/annotation/WebListener;".equals(type)) {
2145 fragment.addListener(className);
2146 } else {
2147
2148 }
2149 }
2150 }
2151 }
2152
2153
2154
2161 protected void checkHandlesTypes(JavaClass javaClass,
2162 Map<String,JavaClassCacheEntry> javaClassCache) {
2163
2164
2165 if (typeInitializerMap.size() == 0) {
2166 return;
2167 }
2168
2169 if ((javaClass.getAccessFlags() &
2170 org.apache.tomcat.util.bcel.Const.ACC_ANNOTATION) != 0) {
2171
2172 return;
2173 }
2174
2175 String className = javaClass.getClassName();
2176
2177 Class<?> clazz = null;
2178 if (handlesTypesNonAnnotations) {
2179
2180 populateJavaClassCache(className, javaClass, javaClassCache);
2181 JavaClassCacheEntry entry = javaClassCache.get(className);
2182 if (entry.getSciSet() == null) {
2183 try {
2184 populateSCIsForCacheEntry(entry, javaClassCache);
2185 } catch (StackOverflowError soe) {
2186 throw new IllegalStateException(sm.getString(
2187 "contextConfig.annotationsStackOverflow",
2188 context.getName(),
2189 classHierarchyToString(className, entry, javaClassCache)));
2190 }
2191 }
2192 if (!entry.getSciSet().isEmpty()) {
2193
2194 clazz = Introspection.loadClass(context, className);
2195 if (clazz == null) {
2196
2197 return;
2198 }
2199
2200 for (ServletContainerInitializer sci : entry.getSciSet()) {
2201 Set<Class<?>> classes = initializerClassMap.get(sci);
2202 if (classes == null) {
2203 classes = new HashSet<>();
2204 initializerClassMap.put(sci, classes);
2205 }
2206 classes.add(clazz);
2207 }
2208 }
2209 }
2210
2211 if (handlesTypesAnnotations) {
2212 AnnotationEntry[] annotationEntries = javaClass.getAnnotationEntries();
2213 if (annotationEntries != null) {
2214 for (Map.Entry<Class<?>, Set<ServletContainerInitializer>> entry :
2215 typeInitializerMap.entrySet()) {
2216 if (entry.getKey().isAnnotation()) {
2217 String entryClassName = entry.getKey().getName();
2218 for (AnnotationEntry annotationEntry : annotationEntries) {
2219 if (entryClassName.equals(
2220 getClassName(annotationEntry.getAnnotationType()))) {
2221 if (clazz == null) {
2222 clazz = Introspection.loadClass(
2223 context, className);
2224 if (clazz == null) {
2225
2226
2227 return;
2228 }
2229 }
2230 for (ServletContainerInitializer sci : entry.getValue()) {
2231 initializerClassMap.get(sci).add(clazz);
2232 }
2233 break;
2234 }
2235 }
2236 }
2237 }
2238 }
2239 }
2240 }
2241
2242
2243 private String classHierarchyToString(String className,
2244 JavaClassCacheEntry entry, Map<String,JavaClassCacheEntry> javaClassCache) {
2245 JavaClassCacheEntry start = entry;
2246 StringBuilder msg = new StringBuilder(className);
2247 msg.append("->");
2248
2249 String parentName = entry.getSuperclassName();
2250 JavaClassCacheEntry parent = javaClassCache.get(parentName);
2251 int count = 0;
2252
2253 while (count < 100 && parent != null && parent != start) {
2254 msg.append(parentName);
2255 msg.append("->");
2256
2257 count ++;
2258 parentName = parent.getSuperclassName();
2259 parent = javaClassCache.get(parentName);
2260 }
2261
2262 msg.append(parentName);
2263
2264 return msg.toString();
2265 }
2266
2267 private void populateJavaClassCache(String className, JavaClass javaClass,
2268 Map<String,JavaClassCacheEntry> javaClassCache) {
2269 if (javaClassCache.containsKey(className)) {
2270 return;
2271 }
2272
2273
2274 javaClassCache.put(className, new JavaClassCacheEntry(javaClass));
2275
2276 populateJavaClassCache(javaClass.getSuperclassName(), javaClassCache);
2277
2278 for (String interfaceName : javaClass.getInterfaceNames()) {
2279 populateJavaClassCache(interfaceName, javaClassCache);
2280 }
2281 }
2282
2283 private void populateJavaClassCache(String className,
2284 Map<String,JavaClassCacheEntry> javaClassCache) {
2285 if (!javaClassCache.containsKey(className)) {
2286 String name = className.replace('.', '/') + ".class";
2287 try (InputStream is = context.getLoader().getClassLoader().getResourceAsStream(name)) {
2288 if (is == null) {
2289 return;
2290 }
2291 ClassParser parser = new ClassParser(is);
2292 JavaClass clazz = parser.parse();
2293 populateJavaClassCache(clazz.getClassName(), clazz, javaClassCache);
2294 } catch (ClassFormatException e) {
2295 log.debug(sm.getString("contextConfig.invalidSciHandlesTypes",
2296 className), e);
2297 } catch (IOException e) {
2298 log.debug(sm.getString("contextConfig.invalidSciHandlesTypes",
2299 className), e);
2300 }
2301 }
2302 }
2303
2304 private void populateSCIsForCacheEntry(JavaClassCacheEntry cacheEntry,
2305 Map<String,JavaClassCacheEntry> javaClassCache) {
2306 Set<ServletContainerInitializer> result = new HashSet<>();
2307
2308
2309 String superClassName = cacheEntry.getSuperclassName();
2310 JavaClassCacheEntry superClassCacheEntry =
2311 javaClassCache.get(superClassName);
2312
2313
2314 if (cacheEntry.equals(superClassCacheEntry)) {
2315 cacheEntry.setSciSet(EMPTY_SCI_SET);
2316 return;
2317 }
2318
2319
2320 if (superClassCacheEntry != null) {
2321 if (superClassCacheEntry.getSciSet() == null) {
2322 populateSCIsForCacheEntry(superClassCacheEntry, javaClassCache);
2323 }
2324 result.addAll(superClassCacheEntry.getSciSet());
2325 }
2326 result.addAll(getSCIsForClass(superClassName));
2327
2328
2329 for (String interfaceName : cacheEntry.getInterfaceNames()) {
2330 JavaClassCacheEntry interfaceEntry =
2331 javaClassCache.get(interfaceName);
2332
2333
2334
2335 if (interfaceEntry != null) {
2336 if (interfaceEntry.getSciSet() == null) {
2337 populateSCIsForCacheEntry(interfaceEntry, javaClassCache);
2338 }
2339 result.addAll(interfaceEntry.getSciSet());
2340 }
2341 result.addAll(getSCIsForClass(interfaceName));
2342 }
2343
2344 cacheEntry.setSciSet(result.isEmpty() ? EMPTY_SCI_SET : result);
2345 }
2346
2347 private Set<ServletContainerInitializer> getSCIsForClass(String className) {
2348 for (Map.Entry<Class<?>, Set<ServletContainerInitializer>> entry :
2349 typeInitializerMap.entrySet()) {
2350 Class<?> clazz = entry.getKey();
2351 if (!clazz.isAnnotation()) {
2352 if (clazz.getName().equals(className)) {
2353 return entry.getValue();
2354 }
2355 }
2356 }
2357 return EMPTY_SCI_SET;
2358 }
2359
2360 private static final String getClassName(String internalForm) {
2361 if (!internalForm.startsWith("L")) {
2362 return internalForm;
2363 }
2364
2365
2366 return internalForm.substring(1,
2367 internalForm.length() - 1).replace('/', '.');
2368 }
2369
2370 protected void processAnnotationWebServlet(String className,
2371 AnnotationEntry ae, WebXml fragment) {
2372 String servletName = null;
2373
2374 List<ElementValuePair> evps = ae.getElementValuePairs();
2375 for (ElementValuePair evp : evps) {
2376 String name = evp.getNameString();
2377 if ("name".equals(name)) {
2378 servletName = evp.getValue().stringifyValue();
2379 break;
2380 }
2381 }
2382 if (servletName == null) {
2383
2384 servletName = className;
2385 }
2386 ServletDef servletDef = fragment.getServlets().get(servletName);
2387
2388 boolean isWebXMLservletDef;
2389 if (servletDef == null) {
2390 servletDef = new ServletDef();
2391 servletDef.setServletName(servletName);
2392 servletDef.setServletClass(className);
2393 isWebXMLservletDef = false;
2394 } else {
2395 isWebXMLservletDef = true;
2396 }
2397
2398 boolean urlPatternsSet = false;
2399 String[] urlPatterns = null;
2400
2401
2402 for (ElementValuePair evp : evps) {
2403 String name = evp.getNameString();
2404 if ("value".equals(name) || "urlPatterns".equals(name)) {
2405 if (urlPatternsSet) {
2406 throw new IllegalArgumentException(sm.getString(
2407 "contextConfig.urlPatternValue", "WebServlet", className));
2408 }
2409 urlPatternsSet = true;
2410 urlPatterns = processAnnotationsStringArray(evp.getValue());
2411 } else if ("description".equals(name)) {
2412 if (servletDef.getDescription() == null) {
2413 servletDef.setDescription(evp.getValue().stringifyValue());
2414 }
2415 } else if ("displayName".equals(name)) {
2416 if (servletDef.getDisplayName() == null) {
2417 servletDef.setDisplayName(evp.getValue().stringifyValue());
2418 }
2419 } else if ("largeIcon".equals(name)) {
2420 if (servletDef.getLargeIcon() == null) {
2421 servletDef.setLargeIcon(evp.getValue().stringifyValue());
2422 }
2423 } else if ("smallIcon".equals(name)) {
2424 if (servletDef.getSmallIcon() == null) {
2425 servletDef.setSmallIcon(evp.getValue().stringifyValue());
2426 }
2427 } else if ("asyncSupported".equals(name)) {
2428 if (servletDef.getAsyncSupported() == null) {
2429 servletDef.setAsyncSupported(evp.getValue()
2430 .stringifyValue());
2431 }
2432 } else if ("loadOnStartup".equals(name)) {
2433 if (servletDef.getLoadOnStartup() == null) {
2434 servletDef
2435 .setLoadOnStartup(evp.getValue().stringifyValue());
2436 }
2437 } else if ("initParams".equals(name)) {
2438 Map<String, String> initParams = processAnnotationWebInitParams(evp
2439 .getValue());
2440 if (isWebXMLservletDef) {
2441 Map<String, String> webXMLInitParams = servletDef
2442 .getParameterMap();
2443 for (Map.Entry<String, String> entry : initParams
2444 .entrySet()) {
2445 if (webXMLInitParams.get(entry.getKey()) == null) {
2446 servletDef.addInitParameter(entry.getKey(), entry
2447 .getValue());
2448 }
2449 }
2450 } else {
2451 for (Map.Entry<String, String> entry : initParams
2452 .entrySet()) {
2453 servletDef.addInitParameter(entry.getKey(), entry
2454 .getValue());
2455 }
2456 }
2457 }
2458 }
2459 if (!isWebXMLservletDef && urlPatterns != null) {
2460 fragment.addServlet(servletDef);
2461 }
2462 if (urlPatterns != null) {
2463 if (!fragment.getServletMappings().containsValue(servletName)) {
2464 for (String urlPattern : urlPatterns) {
2465 fragment.addServletMapping(urlPattern, servletName);
2466 }
2467 }
2468 }
2469
2470 }
2471
2472
2480 protected void processAnnotationWebFilter(String className,
2481 AnnotationEntry ae, WebXml fragment) {
2482 String filterName = null;
2483
2484 List<ElementValuePair> evps = ae.getElementValuePairs();
2485 for (ElementValuePair evp : evps) {
2486 String name = evp.getNameString();
2487 if ("filterName".equals(name)) {
2488 filterName = evp.getValue().stringifyValue();
2489 break;
2490 }
2491 }
2492 if (filterName == null) {
2493
2494 filterName = className;
2495 }
2496 FilterDef filterDef = fragment.getFilters().get(filterName);
2497 FilterMap filterMap = new FilterMap();
2498
2499 boolean isWebXMLfilterDef;
2500 if (filterDef == null) {
2501 filterDef = new FilterDef();
2502 filterDef.setFilterName(filterName);
2503 filterDef.setFilterClass(className);
2504 isWebXMLfilterDef = false;
2505 } else {
2506 isWebXMLfilterDef = true;
2507 }
2508
2509 boolean urlPatternsSet = false;
2510 boolean servletNamesSet = false;
2511 boolean dispatchTypesSet = false;
2512 String[] urlPatterns = null;
2513
2514 for (ElementValuePair evp : evps) {
2515 String name = evp.getNameString();
2516 if ("value".equals(name) || "urlPatterns".equals(name)) {
2517 if (urlPatternsSet) {
2518 throw new IllegalArgumentException(sm.getString(
2519 "contextConfig.urlPatternValue", "WebFilter", className));
2520 }
2521 urlPatterns = processAnnotationsStringArray(evp.getValue());
2522 urlPatternsSet = urlPatterns.length > 0;
2523 for (String urlPattern : urlPatterns) {
2524
2525 filterMap.addURLPattern(urlPattern);
2526 }
2527 } else if ("servletNames".equals(name)) {
2528 String[] servletNames = processAnnotationsStringArray(evp
2529 .getValue());
2530 servletNamesSet = servletNames.length > 0;
2531 for (String servletName : servletNames) {
2532 filterMap.addServletName(servletName);
2533 }
2534 } else if ("dispatcherTypes".equals(name)) {
2535 String[] dispatcherTypes = processAnnotationsStringArray(evp
2536 .getValue());
2537 dispatchTypesSet = dispatcherTypes.length > 0;
2538 for (String dispatcherType : dispatcherTypes) {
2539 filterMap.setDispatcher(dispatcherType);
2540 }
2541 } else if ("description".equals(name)) {
2542 if (filterDef.getDescription() == null) {
2543 filterDef.setDescription(evp.getValue().stringifyValue());
2544 }
2545 } else if ("displayName".equals(name)) {
2546 if (filterDef.getDisplayName() == null) {
2547 filterDef.setDisplayName(evp.getValue().stringifyValue());
2548 }
2549 } else if ("largeIcon".equals(name)) {
2550 if (filterDef.getLargeIcon() == null) {
2551 filterDef.setLargeIcon(evp.getValue().stringifyValue());
2552 }
2553 } else if ("smallIcon".equals(name)) {
2554 if (filterDef.getSmallIcon() == null) {
2555 filterDef.setSmallIcon(evp.getValue().stringifyValue());
2556 }
2557 } else if ("asyncSupported".equals(name)) {
2558 if (filterDef.getAsyncSupported() == null) {
2559 filterDef
2560 .setAsyncSupported(evp.getValue().stringifyValue());
2561 }
2562 } else if ("initParams".equals(name)) {
2563 Map<String, String> initParams = processAnnotationWebInitParams(evp
2564 .getValue());
2565 if (isWebXMLfilterDef) {
2566 Map<String, String> webXMLInitParams = filterDef
2567 .getParameterMap();
2568 for (Map.Entry<String, String> entry : initParams
2569 .entrySet()) {
2570 if (webXMLInitParams.get(entry.getKey()) == null) {
2571 filterDef.addInitParameter(entry.getKey(), entry
2572 .getValue());
2573 }
2574 }
2575 } else {
2576 for (Map.Entry<String, String> entry : initParams
2577 .entrySet()) {
2578 filterDef.addInitParameter(entry.getKey(), entry
2579 .getValue());
2580 }
2581 }
2582
2583 }
2584 }
2585 if (!isWebXMLfilterDef) {
2586 fragment.addFilter(filterDef);
2587 if (urlPatternsSet || servletNamesSet) {
2588 filterMap.setFilterName(filterName);
2589 fragment.addFilterMapping(filterMap);
2590 }
2591 }
2592 if (urlPatternsSet || dispatchTypesSet) {
2593 Set<FilterMap> fmap = fragment.getFilterMappings();
2594 FilterMap descMap = null;
2595 for (FilterMap map : fmap) {
2596 if (filterName.equals(map.getFilterName())) {
2597 descMap = map;
2598 break;
2599 }
2600 }
2601 if (descMap != null) {
2602 String[] urlsPatterns = descMap.getURLPatterns();
2603 if (urlPatternsSet
2604 && (urlsPatterns == null || urlsPatterns.length == 0)) {
2605 for (String urlPattern : filterMap.getURLPatterns()) {
2606
2607 descMap.addURLPattern(urlPattern);
2608 }
2609 }
2610 String[] dispatcherNames = descMap.getDispatcherNames();
2611 if (dispatchTypesSet
2612 && (dispatcherNames == null || dispatcherNames.length == 0)) {
2613 for (String dis : filterMap.getDispatcherNames()) {
2614 descMap.setDispatcher(dis);
2615 }
2616 }
2617 }
2618 }
2619
2620 }
2621
2622 protected String[] processAnnotationsStringArray(ElementValue ev) {
2623 List<String> values = new ArrayList<>();
2624 if (ev instanceof ArrayElementValue) {
2625 ElementValue[] arrayValues =
2626 ((ArrayElementValue) ev).getElementValuesArray();
2627 for (ElementValue value : arrayValues) {
2628 values.add(value.stringifyValue());
2629 }
2630 } else {
2631 values.add(ev.stringifyValue());
2632 }
2633 String[] result = new String[values.size()];
2634 return values.toArray(result);
2635 }
2636
2637 protected Map<String,String> processAnnotationWebInitParams(
2638 ElementValue ev) {
2639 Map<String, String> result = new HashMap<>();
2640 if (ev instanceof ArrayElementValue) {
2641 ElementValue[] arrayValues =
2642 ((ArrayElementValue) ev).getElementValuesArray();
2643 for (ElementValue value : arrayValues) {
2644 if (value instanceof AnnotationElementValue) {
2645 List<ElementValuePair> evps = ((AnnotationElementValue) value)
2646 .getAnnotationEntry().getElementValuePairs();
2647 String initParamName = null;
2648 String initParamValue = null;
2649 for (ElementValuePair evp : evps) {
2650 if ("name".equals(evp.getNameString())) {
2651 initParamName = evp.getValue().stringifyValue();
2652 } else if ("value".equals(evp.getNameString())) {
2653 initParamValue = evp.getValue().stringifyValue();
2654 } else {
2655
2656 }
2657 }
2658 result.put(initParamName, initParamValue);
2659 }
2660 }
2661 }
2662 return result;
2663 }
2664
2665 private static class DefaultWebXmlCacheEntry {
2666 private final WebXml webXml;
2667 private final long globalTimeStamp;
2668 private final long hostTimeStamp;
2669
2670 public DefaultWebXmlCacheEntry(WebXml webXml, long globalTimeStamp,
2671 long hostTimeStamp) {
2672 this.webXml = webXml;
2673 this.globalTimeStamp = globalTimeStamp;
2674 this.hostTimeStamp = hostTimeStamp;
2675 }
2676
2677 public WebXml getWebXml() {
2678 return webXml;
2679 }
2680
2681 public long getGlobalTimeStamp() {
2682 return globalTimeStamp;
2683 }
2684
2685 public long getHostTimeStamp() {
2686 return hostTimeStamp;
2687 }
2688 }
2689
2690 private static class HostWebXmlCacheCleaner implements LifecycleListener {
2691
2692 @Override
2693 public void lifecycleEvent(LifecycleEvent event) {
2694
2695 if (Lifecycle.AFTER_DESTROY_EVENT.equals(event.getType())) {
2696 Host host = (Host) event.getSource();
2697 hostWebXmlCache.remove(host);
2698 }
2699 }
2700 }
2701
2702 static class JavaClassCacheEntry {
2703 public final String superclassName;
2704
2705 public final String[] interfaceNames;
2706
2707 private Set<ServletContainerInitializer> sciSet = null;
2708
2709 public JavaClassCacheEntry(JavaClass javaClass) {
2710 superclassName = javaClass.getSuperclassName();
2711 interfaceNames = javaClass.getInterfaceNames();
2712 }
2713
2714 public String getSuperclassName() {
2715 return superclassName;
2716 }
2717
2718 public String[] getInterfaceNames() {
2719 return interfaceNames;
2720 }
2721
2722 public Set<ServletContainerInitializer> getSciSet() {
2723 return sciSet;
2724 }
2725
2726 public void setSciSet(Set<ServletContainerInitializer> sciSet) {
2727 this.sciSet = sciSet;
2728 }
2729 }
2730 }
2731