1 /*
2  * JBoss, Home of Professional Open Source.
3  * Copyright 2014 Red Hat, Inc., and individual contributors
4  * as indicated by the @author tags.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  */

18
19 package io.undertow.servlet.api;
20
21 import java.io.File;
22 import java.nio.file.Path;
23 import java.nio.file.Paths;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collection;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Locale;
31 import java.util.Map;
32 import java.util.Set;
33 import java.util.concurrent.ConcurrentMap;
34 import java.util.concurrent.Executor;
35
36 import javax.servlet.DispatcherType;
37 import javax.servlet.MultipartConfigElement;
38 import javax.servlet.ServletContextListener;
39 import javax.servlet.descriptor.JspConfigDescriptor;
40
41 import io.undertow.security.api.AuthenticationMechanism;
42 import io.undertow.security.api.AuthenticationMechanismFactory;
43 import io.undertow.security.api.AuthenticationMode;
44 import io.undertow.security.api.NotificationReceiver;
45 import io.undertow.security.api.SecurityContextFactory;
46 import io.undertow.security.idm.IdentityManager;
47 import io.undertow.server.HandlerWrapper;
48 import io.undertow.server.handlers.resource.ResourceManager;
49 import io.undertow.server.session.SecureRandomSessionIdGenerator;
50 import io.undertow.server.session.SessionIdGenerator;
51 import io.undertow.server.session.SessionListener;
52 import io.undertow.servlet.ServletExtension;
53 import io.undertow.servlet.UndertowServletMessages;
54 import io.undertow.servlet.core.DefaultAuthorizationManager;
55 import io.undertow.servlet.core.InMemorySessionManagerFactory;
56 import io.undertow.servlet.util.DefaultClassIntrospector;
57 import io.undertow.util.ImmediateAuthenticationMechanismFactory;
58
59 /**
60  * Represents a servlet deployment.
61  *
62  * @author Stuart Douglas
63  */

64 public class DeploymentInfo implements Cloneable {
65
66     private String deploymentName;
67     private String displayName;
68     private String contextPath;
69     private ClassLoader classLoader;
70     private ResourceManager resourceManager = ResourceManager.EMPTY_RESOURCE_MANAGER;
71     private ClassIntrospecter classIntrospecter = DefaultClassIntrospector.INSTANCE;
72     private int majorVersion = 4;
73     private int minorVersion = 0;
74     private int containerMajorVersion = 4;
75     private int containerMinorVersion = 0;
76     private Executor executor;
77     private Executor asyncExecutor;
78     private Path tempDir;
79     private JspConfigDescriptor jspConfigDescriptor;
80     private DefaultServletConfig defaultServletConfig;
81     private SessionManagerFactory sessionManagerFactory = new InMemorySessionManagerFactory();
82     private LoginConfig loginConfig;
83     private IdentityManager identityManager;
84     private ConfidentialPortManager confidentialPortManager;
85     private boolean allowNonStandardWrappers = false;
86     private int defaultSessionTimeout = 60 * 30;
87     private ConcurrentMap<String, Object> servletContextAttributeBackingMap;
88     private ServletSessionConfig servletSessionConfig;
89     private String hostName = "localhost";
90     private boolean denyUncoveredHttpMethods = false;
91     private ServletStackTraces servletStackTraces = ServletStackTraces.LOCAL_ONLY;
92     private boolean invalidateSessionOnLogout = false;
93     private int defaultCookieVersion = 0;
94     private SessionPersistenceManager sessionPersistenceManager;
95     private String defaultEncoding;
96     private String defaultRequestEncoding;
97     private String defaultResponseEncoding;
98     private String urlEncoding = null;
99     private boolean ignoreFlush = false;
100     private AuthorizationManager authorizationManager = DefaultAuthorizationManager.INSTANCE;
101     private AuthenticationMechanism jaspiAuthenticationMechanism;
102     private SecurityContextFactory securityContextFactory;
103     private String serverName = "Undertow";
104     private MetricsCollector metricsCollector = null;
105     private SessionConfigWrapper sessionConfigWrapper = null;
106     private boolean eagerFilterInit = false;
107     private boolean disableCachingForSecuredPages = true;
108     private boolean escapeErrorMessage = true;
109     private boolean sendCustomReasonPhraseOnError = false;
110     private boolean useCachedAuthenticationMechanism = true;
111     private boolean preservePathOnForward = true;
112     private AuthenticationMode authenticationMode = AuthenticationMode.PRO_ACTIVE;
113     private ExceptionHandler exceptionHandler;
114     private final Map<String, ServletInfo> servlets = new HashMap<>();
115     private final Map<String, FilterInfo> filters = new HashMap<>();
116     private final List<FilterMappingInfo> filterServletNameMappings = new ArrayList<>();
117     private final List<FilterMappingInfo> filterUrlMappings = new ArrayList<>();
118     private final List<ListenerInfo> listeners = new ArrayList<>();
119     private final List<ServletContainerInitializerInfo> servletContainerInitializers = new ArrayList<>();
120     private final List<ThreadSetupHandler> threadSetupActions = new ArrayList<>();
121     private final Map<String, String> initParameters = new HashMap<>();
122     private final Map<String, Object> servletContextAttributes = new HashMap<>();
123     private final Map<String, String> localeCharsetMapping = new HashMap<>();
124     private final List<String> welcomePages = new ArrayList<>();
125     private final List<ErrorPage> errorPages = new ArrayList<>();
126     private final List<MimeMapping> mimeMappings = new ArrayList<>();
127     private final List<SecurityConstraint> securityConstraints = new ArrayList<>();
128     private final Set<String> securityRoles = new HashSet<>();
129     private final List<NotificationReceiver> notificationReceivers = new ArrayList<>();
130     private final Map<String, AuthenticationMechanismFactory> authenticationMechanisms = new HashMap<>();
131     private final List<LifecycleInterceptor> lifecycleInterceptors = new ArrayList<>();
132     private final List<SessionListener> sessionListeners = new ArrayList<>();
133
134     /**
135      * additional servlet extensions
136      */

137     private final List<ServletExtension> servletExtensions = new ArrayList<>();
138
139     /**
140      * map of additional roles that should be applied to the given principal.
141      */

142     private final Map<String, Set<String>> principalVersusRolesMap = new HashMap<>();
143
144     /**
145      * Wrappers that are applied before the servlet initial handler, and before any servlet related object have been
146      * created. If a wrapper wants to bypass servlet entirely it should register itself here.
147      */

148     private final List<HandlerWrapper> initialHandlerChainWrappers = new ArrayList<>();
149
150     /**
151      * Handler chain wrappers that are applied outside all other handlers, including security but after the initial
152      * servlet handler.
153      */

154     private final List<HandlerWrapper> outerHandlerChainWrappers = new ArrayList<>();
155
156     /**
157      * Handler chain wrappers that are applied just before the servlet request is dispatched. At this point the security
158      * handlers have run, and any security information is attached to the request.
159      */

160     private final List<HandlerWrapper> innerHandlerChainWrappers = new ArrayList<>();
161
162     /**
163      * A handler chain wrapper to wrap the initial stages of the security handlers, if this is set it is assumed it
164      * is taking over the responsibility of setting the {@link io.undertow.security.api.SecurityContext} that can handle authentication and the
165      * remaining Undertow handlers specific to authentication will be skipped.
166      */

167     private HandlerWrapper initialSecurityWrapper = null;
168
169     /**
170      * Handler chain wrappers that are applied just before the authentication mechanism is called. Theses handlers are
171      * always called, even if authentication is not required
172      */

173     private final List<HandlerWrapper> securityWrappers = new ArrayList<>();
174
175     /**
176      * Multipart config that will be applied to all servlets that do not have an explicit config
177      */

178     private MultipartConfigElement defaultMultipartConfig;
179
180     /**
181      * Cache of common content types, to prevent allocations when parsing the charset
182      */

183     private int contentTypeCacheSize = 100;
184
185     private boolean changeSessionIdOnLogin = true;
186
187     private SessionIdGenerator sessionIdGenerator = new SecureRandomSessionIdGenerator();
188
189     /**
190      * Config for the {@link io.undertow.servlet.handlers.CrawlerSessionManagerHandler}
191      */

192     private CrawlerSessionManagerConfig crawlerSessionManagerConfig;
193
194     private boolean securityDisabled;
195
196     private boolean checkOtherSessionManagers = true;
197
198     private final List<ServletContextListener> deploymentCompleteListeners = new ArrayList<>();
199
200     /**
201      * A map of content encoding to file extension for pre compressed resource (e.g. gzip -> .gz)
202      */

203     private final Map<String, String> preCompressedResources = new HashMap<>();
204
205     public void validate() {
206         if (deploymentName == null) {
207             throw UndertowServletMessages.MESSAGES.paramCannotBeNull("deploymentName");
208         }
209         if (contextPath == null) {
210             throw UndertowServletMessages.MESSAGES.paramCannotBeNull("contextName");
211         }
212         if (classLoader == null) {
213             throw UndertowServletMessages.MESSAGES.paramCannotBeNull("classLoader");
214         }
215         if (resourceManager == null) {
216             throw UndertowServletMessages.MESSAGES.paramCannotBeNull("resourceManager");
217         }
218         if (classIntrospecter == null) {
219             throw UndertowServletMessages.MESSAGES.paramCannotBeNull("classIntrospecter");
220         }
221
222         for (final ServletInfo servlet : this.servlets.values()) {
223             servlet.validate();
224         }
225         for (final FilterInfo filter : this.filters.values()) {
226             filter.validate();
227         }
228         for (FilterMappingInfo mapping : this.filterServletNameMappings) {
229             if (!this.filters.containsKey(mapping.getFilterName())) {
230                 throw UndertowServletMessages.MESSAGES.filterNotFound(mapping.getFilterName(), mapping.getMappingType() + " - " + mapping.getMapping());
231             }
232         }
233         for (FilterMappingInfo mapping : this.filterUrlMappings) {
234             if (!this.filters.containsKey(mapping.getFilterName())) {
235                 throw UndertowServletMessages.MESSAGES.filterNotFound(mapping.getFilterName(), mapping.getMappingType() + " - " + mapping.getMapping());
236             }
237         }
238     }
239
240     public String getDeploymentName() {
241         return deploymentName;
242     }
243
244     public DeploymentInfo setDeploymentName(final String deploymentName) {
245         this.deploymentName = deploymentName;
246         return this;
247     }
248
249     public String getDisplayName() {
250         return displayName;
251     }
252
253     public DeploymentInfo setDisplayName(final String displayName) {
254         this.displayName = displayName;
255         return this;
256     }
257
258     public String getContextPath() {
259         return contextPath;
260     }
261
262     public DeploymentInfo setContextPath(final String contextPath) {
263         if(contextPath != null && contextPath.isEmpty()) {
264             this.contextPath = "/"//we represent the root context as / instead of "", but both work
265         } else {
266             this.contextPath = contextPath;
267         }
268         return this;
269     }
270
271     public ClassLoader getClassLoader() {
272         return classLoader;
273     }
274
275     public DeploymentInfo setClassLoader(final ClassLoader classLoader) {
276         this.classLoader = classLoader;
277         return this;
278     }
279
280     public ResourceManager getResourceManager() {
281         return resourceManager;
282     }
283
284     public DeploymentInfo setResourceManager(final ResourceManager resourceManager) {
285         this.resourceManager = resourceManager;
286         return this;
287     }
288
289     public ClassIntrospecter getClassIntrospecter() {
290         return classIntrospecter;
291     }
292
293     public DeploymentInfo setClassIntrospecter(final ClassIntrospecter classIntrospecter) {
294         this.classIntrospecter = classIntrospecter;
295         return this;
296     }
297
298     public boolean isAllowNonStandardWrappers() {
299         return allowNonStandardWrappers;
300     }
301
302     public DeploymentInfo setAllowNonStandardWrappers(final boolean allowNonStandardWrappers) {
303         this.allowNonStandardWrappers = allowNonStandardWrappers;
304         return this;
305     }
306
307     public int getDefaultSessionTimeout() {
308         return defaultSessionTimeout;
309     }
310
311     /**
312      * @param defaultSessionTimeout The default session timeout, in seconds
313      */

314     public DeploymentInfo setDefaultSessionTimeout(final int defaultSessionTimeout) {
315         this.defaultSessionTimeout = defaultSessionTimeout;
316         return this;
317     }
318
319     public String getDefaultEncoding() {
320         return defaultEncoding;
321     }
322
323     /**
324      * Sets the default encoding that will be used for servlet responses
325      *
326      * @param defaultEncoding The default encoding
327      */

328     public DeploymentInfo setDefaultEncoding(String defaultEncoding) {
329         this.defaultEncoding = defaultEncoding;
330         return this;
331     }
332
333     public String getUrlEncoding() {
334         return urlEncoding;
335     }
336
337     /**
338      * Sets the URL encoding. This will only take effect if the {@link io.undertow.UndertowOptions#DECODE_URL}
339      * parameter has been set to false. This allows multiple deployments in the same server to use a different URL encoding
340      *
341      * @param urlEncoding The encoding to use
342      */

343     public DeploymentInfo setUrlEncoding(String urlEncoding) {
344         this.urlEncoding = urlEncoding;
345         return this;
346     }
347
348     public DeploymentInfo addServlet(final ServletInfo servlet) {
349         servlets.put(servlet.getName(), servlet);
350         return this;
351     }
352
353     public DeploymentInfo addServlets(final ServletInfo... servlets) {
354         for (final ServletInfo servlet : servlets) {
355             addServlet(servlet);
356         }
357         return this;
358     }
359
360     public DeploymentInfo addServlets(final Collection<ServletInfo> servlets) {
361         for (final ServletInfo servlet : servlets) {
362             addServlet(servlet);
363         }
364         return this;
365     }
366
367     public Map<String, ServletInfo> getServlets() {
368         return servlets;
369     }
370
371
372     public DeploymentInfo addFilter(final FilterInfo filter) {
373         filters.put(filter.getName(), filter);
374         return this;
375     }
376
377     public DeploymentInfo addFilters(final FilterInfo... filters) {
378         for (final FilterInfo filter : filters) {
379             addFilter(filter);
380         }
381         return this;
382     }
383
384     public DeploymentInfo addFilters(final Collection<FilterInfo> filters) {
385         for (final FilterInfo filter : filters) {
386             addFilter(filter);
387         }
388         return this;
389     }
390
391     public Map<String, FilterInfo> getFilters() {
392         return filters;
393     }
394
395     public DeploymentInfo addFilterUrlMapping(final String filterName, final String mapping, DispatcherType dispatcher) {
396         filterUrlMappings.add(new FilterMappingInfo(filterName, FilterMappingInfo.MappingType.URL, mapping, dispatcher));
397         return this;
398     }
399
400     public DeploymentInfo addFilterServletNameMapping(final String filterName, final String mapping, DispatcherType dispatcher) {
401         filterServletNameMappings.add(new FilterMappingInfo(filterName, FilterMappingInfo.MappingType.SERVLET, mapping, dispatcher));
402         return this;
403     }
404
405     public DeploymentInfo insertFilterUrlMapping(final int pos, final String filterName, final String mapping, DispatcherType dispatcher) {
406         filterUrlMappings.add(pos, new FilterMappingInfo(filterName, FilterMappingInfo.MappingType.URL, mapping, dispatcher));
407         return this;
408     }
409
410     public DeploymentInfo insertFilterServletNameMapping(final int pos, final String filterName, final String mapping, DispatcherType dispatcher) {
411         filterServletNameMappings.add(pos, new FilterMappingInfo(filterName, FilterMappingInfo.MappingType.SERVLET, mapping, dispatcher));
412         return this;
413     }
414
415     public List<FilterMappingInfo> getFilterMappings() {
416         final ArrayList<FilterMappingInfo> ret = new ArrayList<>(filterUrlMappings);
417         ret.addAll(filterServletNameMappings);
418         return ret;
419     }
420
421
422     public DeploymentInfo addListener(final ListenerInfo listener) {
423         listeners.add(listener);
424         return this;
425     }
426
427     public DeploymentInfo addListeners(final ListenerInfo... listeners) {
428         this.listeners.addAll(Arrays.asList(listeners));
429         return this;
430     }
431
432     public DeploymentInfo addListeners(final Collection<ListenerInfo> listeners) {
433         this.listeners.addAll(listeners);
434         return this;
435     }
436
437     public List<ListenerInfo> getListeners() {
438         return listeners;
439     }
440
441     public int getMajorVersion() {
442         return majorVersion;
443     }
444
445     public DeploymentInfo setMajorVersion(final int majorVersion) {
446         this.majorVersion = majorVersion;
447         return this;
448     }
449
450     public int getMinorVersion() {
451         return minorVersion;
452     }
453
454     public DeploymentInfo setMinorVersion(final int minorVersion) {
455         this.minorVersion = minorVersion;
456         return this;
457     }
458
459     public DeploymentInfo addServletContainerInitializer(final ServletContainerInitializerInfo servletContainerInitializer) {
460         servletContainerInitializers.add(servletContainerInitializer);
461         return this;
462     }
463
464     @Deprecated // UNDERTOW-1375 Method name is misspelled
465     public DeploymentInfo addServletContainerInitalizer(final ServletContainerInitializerInfo servletContainerInitializer) {
466         return addServletContainerInitializer(servletContainerInitializer);
467     }
468
469     public DeploymentInfo addServletContainerInitializers(final ServletContainerInitializerInfo... servletContainerInitializer) {
470         servletContainerInitializers.addAll(Arrays.asList(servletContainerInitializer));
471         return this;
472     }
473
474     @Deprecated // UNDERTOW-1375 Method name is misspelled
475     public DeploymentInfo addServletContainerInitalizers(final ServletContainerInitializerInfo... servletContainerInitializer) {
476         return addServletContainerInitializers(servletContainerInitializer);
477     }
478
479     public DeploymentInfo addServletContainerInitializers(final List<ServletContainerInitializerInfo> servletContainerInitializer) {
480         servletContainerInitializers.addAll(servletContainerInitializer);
481         return this;
482     }
483
484     @Deprecated // UNDERTOW-1375 Method name is misspelled
485     public DeploymentInfo addServletContainerInitalizers(final List<ServletContainerInitializerInfo> servletContainerInitializers) {
486         return addServletContainerInitializers(servletContainerInitializers);
487     }
488
489     public List<ServletContainerInitializerInfo> getServletContainerInitializers() {
490         return servletContainerInitializers;
491     }
492
493     @Deprecated
494     public DeploymentInfo addThreadSetupAction(final ThreadSetupAction action) {
495         threadSetupActions.add(new LegacyThreadSetupActionWrapper(action));
496         return this;
497     }
498
499     public DeploymentInfo addThreadSetupAction(final ThreadSetupHandler action) {
500         threadSetupActions.add(action);
501         return this;
502     }
503
504     public List<ThreadSetupHandler> getThreadSetupActions() {
505         return threadSetupActions;
506     }
507
508     public boolean isEagerFilterInit() {
509         return eagerFilterInit;
510     }
511
512     public DeploymentInfo setEagerFilterInit(boolean eagerFilterInit) {
513         this.eagerFilterInit = eagerFilterInit;
514         return this;
515     }
516
517     public DeploymentInfo addInitParameter(final String name, final String value) {
518         initParameters.put(name, value);
519         return this;
520     }
521
522     public Map<String, String> getInitParameters() {
523         return initParameters;
524     }
525
526     public DeploymentInfo addServletContextAttribute(final String name, final Object value) {
527         servletContextAttributes.put(name, value);
528         return this;
529     }
530
531     public Map<String, Object> getServletContextAttributes() {
532         return servletContextAttributes;
533     }
534
535     public DeploymentInfo addWelcomePage(final String welcomePage) {
536         this.welcomePages.add(welcomePage);
537         return this;
538     }
539
540     public DeploymentInfo addWelcomePages(final String... welcomePages) {
541         this.welcomePages.addAll(Arrays.asList(welcomePages));
542         return this;
543     }
544
545     public DeploymentInfo addWelcomePages(final Collection<String> welcomePages) {
546         this.welcomePages.addAll(welcomePages);
547         return this;
548     }
549
550     public List<String> getWelcomePages() {
551         return welcomePages;
552     }
553
554     public DeploymentInfo addErrorPage(final ErrorPage errorPage) {
555         this.errorPages.add(errorPage);
556         return this;
557     }
558
559     public DeploymentInfo addErrorPages(final ErrorPage... errorPages) {
560         this.errorPages.addAll(Arrays.asList(errorPages));
561         return this;
562     }
563
564     public DeploymentInfo addErrorPages(final Collection<ErrorPage> errorPages) {
565         this.errorPages.addAll(errorPages);
566         return this;
567     }
568
569     public List<ErrorPage> getErrorPages() {
570         return errorPages;
571     }
572
573     public DeploymentInfo addMimeMapping(final MimeMapping mimeMappings) {
574         this.mimeMappings.add(mimeMappings);
575         return this;
576     }
577
578     public DeploymentInfo addMimeMappings(final MimeMapping... mimeMappings) {
579         this.mimeMappings.addAll(Arrays.asList(mimeMappings));
580         return this;
581     }
582
583     public DeploymentInfo addMimeMappings(final Collection<MimeMapping> mimeMappings) {
584         this.mimeMappings.addAll(mimeMappings);
585         return this;
586     }
587
588     public List<MimeMapping> getMimeMappings() {
589         return mimeMappings;
590     }
591
592
593     public DeploymentInfo addSecurityConstraint(final SecurityConstraint securityConstraint) {
594         this.securityConstraints.add(securityConstraint);
595         return this;
596     }
597
598     public DeploymentInfo addSecurityConstraints(final SecurityConstraint... securityConstraints) {
599         this.securityConstraints.addAll(Arrays.asList(securityConstraints));
600         return this;
601     }
602
603     public DeploymentInfo addSecurityConstraints(final Collection<SecurityConstraint> securityConstraints) {
604         this.securityConstraints.addAll(securityConstraints);
605         return this;
606     }
607
608     public List<SecurityConstraint> getSecurityConstraints() {
609         return securityConstraints;
610     }
611
612     public Executor getExecutor() {
613         return executor;
614     }
615
616     /**
617      * Sets the executor that will be used to run servlet invocations. If this is null then the XNIO worker pool will be
618      * used.
619      * <p>
620      * Individual servlets may use a different executor
621      * <p>
622      * If this is null then the current executor is used, which is generally the XNIO worker pool
623      *
624      * @param executor The executor
625      * @see ServletInfo#executor
626      */

627     public DeploymentInfo setExecutor(final Executor executor) {
628         this.executor = executor;
629         return this;
630     }
631
632     public Executor getAsyncExecutor() {
633         return asyncExecutor;
634     }
635
636     /**
637      * Sets the executor that is used to run async tasks.
638      * <p>
639      * If this is null then {@link #executor} is used, if this is also null then the default is used
640      *
641      * @param asyncExecutor The executor
642      */

643     public DeploymentInfo setAsyncExecutor(final Executor asyncExecutor) {
644         this.asyncExecutor = asyncExecutor;
645         return this;
646     }
647
648     public File getTempDir() {
649         if(tempDir == null) {
650             return null;
651         }
652         return tempDir.toFile();
653     }
654
655     public Path getTempPath() {
656         return tempDir;
657     }
658
659     /**
660      * @return Returns the {@link #getTempDir() temp directory path} if it's
661      * not nullelse returns the system level temporary directory path
662      * pointed to by the Java system property {@code java.io.tmpdir}
663      */

664     public Path requireTempPath() {
665         if (tempDir != null) {
666             return tempDir;
667         }
668         return Paths.get(SecurityActions.getSystemProperty("java.io.tmpdir"));
669     }
670
671     public DeploymentInfo setTempDir(final File tempDir) {
672         this.tempDir = tempDir != null ? tempDir.toPath() : null;
673         return this;
674     }
675
676     public DeploymentInfo setTempDir(final Path tempDir) {
677         this.tempDir = tempDir;
678         return this;
679     }
680
681     public boolean isIgnoreFlush() {
682         return ignoreFlush;
683     }
684
685     public DeploymentInfo setIgnoreFlush(boolean ignoreFlush) {
686         this.ignoreFlush = ignoreFlush;
687         return this;
688     }
689
690     public JspConfigDescriptor getJspConfigDescriptor() {
691         return jspConfigDescriptor;
692     }
693
694     public DeploymentInfo setJspConfigDescriptor(JspConfigDescriptor jspConfigDescriptor) {
695         this.jspConfigDescriptor = jspConfigDescriptor;
696         return this;
697     }
698
699     public DefaultServletConfig getDefaultServletConfig() {
700         return defaultServletConfig;
701     }
702
703     public DeploymentInfo setDefaultServletConfig(final DefaultServletConfig defaultServletConfig) {
704         this.defaultServletConfig = defaultServletConfig;
705         return this;
706     }
707
708     public DeploymentInfo addLocaleCharsetMapping(final String locale, final String charset) {
709         localeCharsetMapping.put(locale, charset);
710         return this;
711     }
712
713     public Map<String, String> getLocaleCharsetMapping() {
714         return localeCharsetMapping;
715     }
716
717     public SessionManagerFactory getSessionManagerFactory() {
718         return sessionManagerFactory;
719     }
720
721     public DeploymentInfo setSessionManagerFactory(final SessionManagerFactory sessionManagerFactory) {
722         this.sessionManagerFactory = sessionManagerFactory;
723         return this;
724     }
725
726     public LoginConfig getLoginConfig() {
727         return loginConfig;
728     }
729
730     public DeploymentInfo setLoginConfig(LoginConfig loginConfig) {
731         this.loginConfig = loginConfig;
732         return this;
733     }
734
735     public IdentityManager getIdentityManager() {
736         return identityManager;
737     }
738
739     public DeploymentInfo setIdentityManager(IdentityManager identityManager) {
740         this.identityManager = identityManager;
741         return this;
742     }
743
744     public ConfidentialPortManager getConfidentialPortManager() {
745         return confidentialPortManager;
746     }
747
748     public DeploymentInfo setConfidentialPortManager(ConfidentialPortManager confidentialPortManager) {
749         this.confidentialPortManager = confidentialPortManager;
750         return this;
751     }
752
753     public DeploymentInfo addSecurityRole(final String role) {
754         this.securityRoles.add(role);
755         return this;
756     }
757
758     public DeploymentInfo addSecurityRoles(final String... roles) {
759         this.securityRoles.addAll(Arrays.asList(roles));
760         return this;
761     }
762
763     public DeploymentInfo addSecurityRoles(final Collection<String> roles) {
764         this.securityRoles.addAll(roles);
765         return this;
766     }
767
768     public Set<String> getSecurityRoles() {
769         return securityRoles;
770     }
771
772     /**
773      * Adds an outer handler wrapper. This handler will be run after the servlet initial handler,
774      * but before any other handlers. These are only run on REQUEST invocations, they
775      * are not invoked on a FORWARD or INCLUDE.
776      *
777      * @param wrapper The wrapper
778      */

779     public DeploymentInfo addOuterHandlerChainWrapper(final HandlerWrapper wrapper) {
780         outerHandlerChainWrappers.add(wrapper);
781         return this;
782     }
783
784     public List<HandlerWrapper> getOuterHandlerChainWrappers() {
785         return outerHandlerChainWrappers;
786     }
787
788     /**
789      * Adds an inner handler chain wrapper. This handler will be run after the security handler,
790      * but before any other servlet handlers, and will be run for every request
791      *
792      * @param wrapper The wrapper
793      */

794     public DeploymentInfo addInnerHandlerChainWrapper(final HandlerWrapper wrapper) {
795         innerHandlerChainWrappers.add(wrapper);
796         return this;
797     }
798
799     public List<HandlerWrapper> getInnerHandlerChainWrappers() {
800         return innerHandlerChainWrappers;
801     }
802
803     public DeploymentInfo addInitialHandlerChainWrapper(final HandlerWrapper wrapper) {
804         initialHandlerChainWrappers.add(wrapper);
805         return this;
806     }
807
808     public List<HandlerWrapper> getInitialHandlerChainWrappers() {
809         return initialHandlerChainWrappers;
810     }
811
812
813     /**
814      * Sets the initial handler wrapper that will take over responsibility for establishing
815      * a security context that will handle authentication for the request.
816      *
817      * Undertow specific authentication mechanisms will not be installed but Undertow handlers will
818      * still make the decision as to if authentication is required and will subsequently
819      * call {@link io.undertow.security.api.SecurityContext#authenticate()} as required.
820      *
821      * @param wrapper the {@link HandlerWrapper} to handle the initial security context installation.
822      * @return {@code this} to allow chaining.
823      */

824     public DeploymentInfo setInitialSecurityWrapper(final HandlerWrapper wrapper) {
825         this.initialSecurityWrapper = wrapper;
826
827         return this;
828     }
829
830     public HandlerWrapper getInitialSecurityWrapper() {
831         return initialSecurityWrapper;
832     }
833
834     /**
835      * Adds a security handler. These are invoked before the authentication mechanism, and are always invoked
836      * even if authentication is not required.
837      * @param wrapper
838      * @return
839      */

840     public DeploymentInfo addSecurityWrapper(final HandlerWrapper wrapper) {
841         securityWrappers.add(wrapper);
842         return this;
843     }
844
845     public List<HandlerWrapper> getSecurityWrappers() {
846         return securityWrappers;
847     }
848
849     public DeploymentInfo addNotificationReceiver(final NotificationReceiver notificationReceiver) {
850         this.notificationReceivers.add(notificationReceiver);
851         return this;
852     }
853
854     public DeploymentInfo addNotificactionReceivers(final NotificationReceiver... notificationReceivers) {
855         this.notificationReceivers.addAll(Arrays.asList(notificationReceivers));
856         return this;
857     }
858
859     public DeploymentInfo addNotificationReceivers(final Collection<NotificationReceiver> notificationReceivers) {
860         this.notificationReceivers.addAll(notificationReceivers);
861         return this;
862     }
863
864     public List<NotificationReceiver> getNotificationReceivers() {
865         return notificationReceivers;
866     }
867
868     public ConcurrentMap<String, Object> getServletContextAttributeBackingMap() {
869         return servletContextAttributeBackingMap;
870     }
871
872     /**
873      * Sets the map that will be used by the ServletContext implementation to store attributes.
874      * <p>
875      * This should usuablly be null, in which case Undertow will create a new map. This is only
876      * used in situations where you want multiple deployments to share the same servlet context
877      * attributes.
878      *
879      * @param servletContextAttributeBackingMap
880      *         The backing map
881      */

882     public DeploymentInfo setServletContextAttributeBackingMap(final ConcurrentMap<String, Object> servletContextAttributeBackingMap) {
883         this.servletContextAttributeBackingMap = servletContextAttributeBackingMap;
884         return this;
885     }
886
887     public ServletSessionConfig getServletSessionConfig() {
888         return servletSessionConfig;
889     }
890
891     public DeploymentInfo setServletSessionConfig(final ServletSessionConfig servletSessionConfig) {
892         this.servletSessionConfig = servletSessionConfig;
893         return this;
894     }
895
896     /**
897      * @return the host name
898      */

899     public String getHostName() {
900         return hostName;
901     }
902
903     public DeploymentInfo setHostName(final String hostName) {
904         this.hostName = hostName;
905         return this;
906     }
907
908     public boolean isDenyUncoveredHttpMethods() {
909         return denyUncoveredHttpMethods;
910     }
911
912     public DeploymentInfo setDenyUncoveredHttpMethods(final boolean denyUncoveredHttpMethods) {
913         this.denyUncoveredHttpMethods = denyUncoveredHttpMethods;
914         return this;
915     }
916
917     public ServletStackTraces getServletStackTraces() {
918         return servletStackTraces;
919     }
920
921     public DeploymentInfo setServletStackTraces(ServletStackTraces servletStackTraces) {
922         this.servletStackTraces = servletStackTraces;
923         return this;
924     }
925
926     public boolean isInvalidateSessionOnLogout() {
927         return invalidateSessionOnLogout;
928     }
929
930     public DeploymentInfo setInvalidateSessionOnLogout(boolean invalidateSessionOnLogout) {
931         this.invalidateSessionOnLogout = invalidateSessionOnLogout;
932         return this;
933     }
934
935     public int getDefaultCookieVersion() {
936         return defaultCookieVersion;
937     }
938
939     public DeploymentInfo setDefaultCookieVersion(int defaultCookieVersion) {
940         this.defaultCookieVersion = defaultCookieVersion;
941         return this;
942     }
943
944     public SessionPersistenceManager getSessionPersistenceManager() {
945         return sessionPersistenceManager;
946     }
947
948     public DeploymentInfo setSessionPersistenceManager(SessionPersistenceManager sessionPersistenceManager) {
949         this.sessionPersistenceManager = sessionPersistenceManager;
950         return this;
951     }
952
953     public AuthorizationManager getAuthorizationManager() {
954         return authorizationManager;
955     }
956
957     public DeploymentInfo setAuthorizationManager(AuthorizationManager authorizationManager) {
958         this.authorizationManager = authorizationManager;
959         return this;
960     }
961
962     public DeploymentInfo addPrincipalVsRoleMapping(final String principal, final String mapping) {
963         Set<String> set = principalVersusRolesMap.get(principal);
964         if (set == null) {
965             principalVersusRolesMap.put(principal, set = new HashSet<>());
966         }
967         set.add(mapping);
968         return this;
969     }
970
971     public DeploymentInfo addPrincipalVsRoleMappings(final String principal, final String... mappings) {
972         Set<String> set = principalVersusRolesMap.get(principal);
973         if (set == null) {
974             principalVersusRolesMap.put(principal, set = new HashSet<>());
975         }
976         set.addAll(Arrays.asList(mappings));
977         return this;
978     }
979
980     public DeploymentInfo addPrincipalVsRoleMappings(final String principal, final Collection<String> mappings) {
981         Set<String> set = principalVersusRolesMap.get(principal);
982         if (set == null) {
983             principalVersusRolesMap.put(principal, set = new HashSet<>());
984         }
985         set.addAll(mappings);
986         return this;
987     }
988
989     public Map<String, Set<String>> getPrincipalVersusRolesMap() {
990         return principalVersusRolesMap;
991     }
992
993     /**
994      * Removes all configured authentication mechanisms from the deployment.
995      *
996      * @return this deployment info
997      */

998     public DeploymentInfo clearLoginMethods() {
999         if(loginConfig != null) {
1000             loginConfig.getAuthMethods().clear();
1001         }
1002         return this;
1003     }
1004
1005     /**
1006      * Adds an authentication mechanism directly to the deployment. This mechanism will be first in the list.
1007      *
1008      * In general you should just use {@link #addAuthenticationMechanism(String, io.undertow.security.api.AuthenticationMechanismFactory)}
1009      * and allow the user to configure the methods they want by name.
1010      *
1011      * This method is essentially a convenience method, if is the same as registering a factory under the provided name that returns
1012      * and authentication mechanism, and then adding it to the login config list.
1013      *
1014      * If you want your mechanism to be the only one in the deployment you should first invoke {@link #clearLoginMethods()}.
1015      *
1016      * @param name The authentication mechanism name
1017      * @param mechanism The mechanism
1018      * @return this deployment info
1019      */

1020     public DeploymentInfo addFirstAuthenticationMechanism(final String name, final AuthenticationMechanism mechanism) {
1021         authenticationMechanisms.put(name, new ImmediateAuthenticationMechanismFactory(mechanism));
1022         if(loginConfig == null) {
1023             loginConfig = new LoginConfig(null);
1024         }
1025         loginConfig.addFirstAuthMethod(new AuthMethodConfig(name));
1026         return this;
1027     }
1028
1029     /**
1030      * Adds an authentication mechanism directly to the deployment. This mechanism will be last in the list.
1031      *
1032      * In general you should just use {@link #addAuthenticationMechanism(String, io.undertow.security.api.AuthenticationMechanismFactory)}
1033      * and allow the user to configure the methods they want by name.
1034      *
1035      * This method is essentially a convenience method, if is the same as registering a factory under the provided name that returns
1036      * and authentication mechanism, and then adding it to the login config list.
1037      *
1038      * If you want your mechanism to be the only one in the deployment you should first invoke {@link #clearLoginMethods()}.
1039      *
1040      * @param name The authentication mechanism name
1041      * @param mechanism The mechanism
1042      * @return
1043      */

1044     public DeploymentInfo addLastAuthenticationMechanism(final String name, final AuthenticationMechanism mechanism) {
1045         authenticationMechanisms.put(name, new ImmediateAuthenticationMechanismFactory(mechanism));
1046         if(loginConfig == null) {
1047             loginConfig = new LoginConfig(null);
1048         }
1049         loginConfig.addLastAuthMethod(new AuthMethodConfig(name));
1050         return this;
1051     }
1052
1053     /**
1054      * Adds an authentication mechanism. The name is case insenstive, and will be converted to uppercase internally.
1055      *
1056      * @param name    The name
1057      * @param factory The factory
1058      * @return
1059      */

1060     public DeploymentInfo addAuthenticationMechanism(final String name, final AuthenticationMechanismFactory factory) {
1061         authenticationMechanisms.put(name.toUpperCase(Locale.US), factory);
1062         return this;
1063     }
1064
1065     public Map<String, AuthenticationMechanismFactory> getAuthenticationMechanisms() {
1066         return authenticationMechanisms;
1067     }
1068
1069     /**
1070      * Returns true if the specified mechanism is present in the login config
1071      * @param mechanismName The mechanism name
1072      * @return true if the mechanism is enabled
1073      */

1074     public boolean isAuthenticationMechanismPresent(final String mechanismName) {
1075         if(loginConfig != null) {
1076             for(AuthMethodConfig method : loginConfig.getAuthMethods()) {
1077                 if(method.getName().equalsIgnoreCase(mechanismName)) {
1078                     return true;
1079                 }
1080             }
1081         }
1082         return false;
1083     }
1084
1085     /**
1086      * Adds an additional servlet extension to the deployment. Servlet extensions are generally discovered
1087      * using META-INF/services entries, however this may not be practical in all environments.
1088      * @param servletExtension The servlet extension
1089      * @return this
1090      */

1091     public DeploymentInfo addServletExtension(final ServletExtension servletExtension) {
1092         this.servletExtensions.add(servletExtension);
1093         return this;
1094     }
1095
1096     public List<ServletExtension> getServletExtensions() {
1097         return servletExtensions;
1098     }
1099
1100     public AuthenticationMechanism getJaspiAuthenticationMechanism() {
1101         return jaspiAuthenticationMechanism;
1102     }
1103
1104     public DeploymentInfo setJaspiAuthenticationMechanism(AuthenticationMechanism jaspiAuthenticationMechanism) {
1105         this.jaspiAuthenticationMechanism = jaspiAuthenticationMechanism;
1106         return this;
1107     }
1108
1109     public SecurityContextFactory getSecurityContextFactory() {
1110         return this.securityContextFactory;
1111     }
1112
1113     public DeploymentInfo setSecurityContextFactory(final SecurityContextFactory securityContextFactory) {
1114         this.securityContextFactory = securityContextFactory;
1115         return this;
1116     }
1117
1118     public String getServerName() {
1119         return serverName;
1120     }
1121
1122     public DeploymentInfo setServerName(String serverName) {
1123         this.serverName = serverName;
1124         return this;
1125     }
1126
1127     public DeploymentInfo setMetricsCollector(MetricsCollector metricsCollector){
1128         this.metricsCollector = metricsCollector;
1129         return this;
1130     }
1131
1132     public MetricsCollector getMetricsCollector() {
1133         return metricsCollector;
1134     }
1135
1136     public SessionConfigWrapper getSessionConfigWrapper() {
1137         return sessionConfigWrapper;
1138     }
1139
1140     public DeploymentInfo setSessionConfigWrapper(SessionConfigWrapper sessionConfigWrapper) {
1141         this.sessionConfigWrapper = sessionConfigWrapper;
1142         return this;
1143     }
1144
1145     public boolean isDisableCachingForSecuredPages() {
1146         return disableCachingForSecuredPages;
1147     }
1148
1149     public DeploymentInfo setDisableCachingForSecuredPages(boolean disableCachingForSecuredPages) {
1150         this.disableCachingForSecuredPages = disableCachingForSecuredPages;
1151         return this;
1152     }
1153
1154     public DeploymentInfo addLifecycleInterceptor(final LifecycleInterceptor interceptor) {
1155         lifecycleInterceptors.add(interceptor);
1156         return this;
1157     }
1158
1159     public List<LifecycleInterceptor> getLifecycleInterceptors() {
1160         return lifecycleInterceptors;
1161     }
1162
1163     /**
1164      * Returns the exception handler that is used by this deployment. By default this will simply
1165      * log unhandled exceptions
1166      */

1167     public ExceptionHandler getExceptionHandler() {
1168         return exceptionHandler;
1169     }
1170
1171     /**
1172      * Sets the default exception handler for this deployment
1173      * @param exceptionHandler The exception handler
1174      * @return
1175      */

1176     public DeploymentInfo setExceptionHandler(ExceptionHandler exceptionHandler) {
1177         this.exceptionHandler = exceptionHandler;
1178         return this;
1179     }
1180
1181     public boolean isEscapeErrorMessage() {
1182         return escapeErrorMessage;
1183     }
1184
1185     /**
1186      * Set if if the message passed to {@link javax.servlet.http.HttpServletResponse#sendError(int, String)} should be escaped.
1187      *
1188      * If this is false applications must be careful not to use user provided data (such as the URI) in the message
1189      *
1190      * @param escapeErrorMessage If the error message should be escaped
1191      */

1192     public DeploymentInfo setEscapeErrorMessage(boolean escapeErrorMessage) {
1193         this.escapeErrorMessage = escapeErrorMessage;
1194         return this;
1195     }
1196
1197
1198     public DeploymentInfo addSessionListener(SessionListener sessionListener) {
1199         this.sessionListeners.add(sessionListener);
1200         return this;
1201     }
1202
1203     public List<SessionListener> getSessionListeners() {
1204         return sessionListeners;
1205     }
1206
1207     public AuthenticationMode getAuthenticationMode() {
1208         return authenticationMode;
1209     }
1210
1211     /**
1212      * Sets if this deployment should use pro-active authentication and always authenticate if the credentials are present
1213      * or constraint driven auth which will only call the authentication mechanisms for protected resources.
1214      *
1215      * Pro active auth means that requests for unprotected resources will still be associated with a user, which may be
1216      * useful for access logging.
1217      *
1218      *
1219      * @param authenticationMode The authentication mode to use
1220      * @return
1221      */

1222     public DeploymentInfo setAuthenticationMode(AuthenticationMode authenticationMode) {
1223         this.authenticationMode = authenticationMode;
1224         return this;
1225     }
1226
1227     public MultipartConfigElement getDefaultMultipartConfig() {
1228         return defaultMultipartConfig;
1229     }
1230
1231     public DeploymentInfo setDefaultMultipartConfig(MultipartConfigElement defaultMultipartConfig) {
1232         this.defaultMultipartConfig = defaultMultipartConfig;
1233         return this;
1234     }
1235
1236     public int getContentTypeCacheSize() {
1237         return contentTypeCacheSize;
1238     }
1239
1240     public DeploymentInfo setContentTypeCacheSize(int contentTypeCacheSize) {
1241         this.contentTypeCacheSize = contentTypeCacheSize;
1242         return this;
1243     }
1244
1245     public SessionIdGenerator getSessionIdGenerator() {
1246         return sessionIdGenerator;
1247     }
1248
1249     public DeploymentInfo setSessionIdGenerator(SessionIdGenerator sessionIdGenerator) {
1250         this.sessionIdGenerator = sessionIdGenerator;
1251         return this;
1252     }
1253
1254
1255     public boolean isSendCustomReasonPhraseOnError() {
1256         return sendCustomReasonPhraseOnError;
1257     }
1258
1259     public CrawlerSessionManagerConfig getCrawlerSessionManagerConfig() {
1260         return crawlerSessionManagerConfig;
1261     }
1262
1263     public DeploymentInfo setCrawlerSessionManagerConfig(CrawlerSessionManagerConfig crawlerSessionManagerConfig) {
1264         this.crawlerSessionManagerConfig = crawlerSessionManagerConfig;
1265         return this;
1266     }
1267
1268     /**
1269      * If this is true then the message parameter of {@link javax.servlet.http.HttpServletResponse#sendError(int, String)} and
1270      * {@link javax.servlet.http.HttpServletResponse#setStatus(int, String)} will be used as the HTTP reason phrase in
1271      * the response.
1272      *
1273      * @param sendCustomReasonPhraseOnError If the parameter to sendError should be used as a HTTP reason phrase
1274      * @return this
1275      */

1276     public DeploymentInfo setSendCustomReasonPhraseOnError(boolean sendCustomReasonPhraseOnError) {
1277         this.sendCustomReasonPhraseOnError = sendCustomReasonPhraseOnError;
1278         return this;
1279     }
1280
1281     public boolean isChangeSessionIdOnLogin() {
1282         return changeSessionIdOnLogin;
1283     }
1284
1285     public DeploymentInfo setChangeSessionIdOnLogin(boolean changeSessionIdOnLogin) {
1286         this.changeSessionIdOnLogin = changeSessionIdOnLogin;
1287         return this;
1288     }
1289
1290     public boolean isUseCachedAuthenticationMechanism() {
1291         return useCachedAuthenticationMechanism;
1292     }
1293
1294     /**
1295      * If this is set to false the the cached authenticated session mechanism won't be installed. If you want FORM and
1296      * other auth methods that require caching to work then you need to install another caching based auth method (such
1297      * as SSO).
1298      * @param useCachedAuthenticationMechanism If Undertow should use its internal authentication cache mechanism
1299      * @return this
1300      */

1301     public DeploymentInfo setUseCachedAuthenticationMechanism(boolean useCachedAuthenticationMechanism) {
1302         this.useCachedAuthenticationMechanism = useCachedAuthenticationMechanism;
1303         return this;
1304     }
1305
1306     public boolean isSecurityDisabled() {
1307         return securityDisabled;
1308     }
1309
1310     public DeploymentInfo setSecurityDisabled(boolean securityDisabled) {
1311         this.securityDisabled = securityDisabled;
1312         return this;
1313     }
1314
1315
1316     public boolean isCheckOtherSessionManagers() {
1317         return checkOtherSessionManagers;
1318     }
1319
1320     /**
1321      * If this is true then when an existing invalid session id is found all other deployments in the container will have their
1322      * session managers checked to see if it represents a valid session. If it does then the session id will be re-used.
1323      */

1324     public DeploymentInfo setCheckOtherSessionManagers(boolean checkOtherSessionManagers) {
1325         this.checkOtherSessionManagers = checkOtherSessionManagers;
1326         return this;
1327     }
1328
1329     public String getDefaultRequestEncoding() {
1330         return defaultRequestEncoding;
1331     }
1332
1333     public DeploymentInfo setDefaultRequestEncoding(String defaultRequestEncoding) {
1334         this.defaultRequestEncoding = defaultRequestEncoding;
1335         return this;
1336     }
1337
1338     public String getDefaultResponseEncoding() {
1339         return defaultResponseEncoding;
1340     }
1341
1342     public DeploymentInfo setDefaultResponseEncoding(String defaultResponseEncoding) {
1343         this.defaultResponseEncoding = defaultResponseEncoding;
1344         return this;
1345     }
1346
1347     /**
1348      * Adds a pre compressed resource encoding and maps it to a file extension
1349      *
1350      *
1351      * @param encoding The content encoding
1352      * @param extension The file extension
1353      * @return this builder
1354      */

1355     public DeploymentInfo addPreCompressedResourceEncoding(String encoding, String extension) {
1356        preCompressedResources.put(encoding, extension);
1357        return this;
1358     }
1359
1360     public Map<String, String> getPreCompressedResources() {
1361         return preCompressedResources;
1362     }
1363
1364     public int getContainerMajorVersion() {
1365         return containerMajorVersion;
1366     }
1367
1368     public DeploymentInfo setContainerMajorVersion(int containerMajorVersion) {
1369         this.containerMajorVersion = containerMajorVersion;
1370         return this;
1371     }
1372
1373     public int getContainerMinorVersion() {
1374         return containerMinorVersion;
1375     }
1376
1377     public DeploymentInfo setContainerMinorVersion(int containerMinorVersion) {
1378         this.containerMinorVersion = containerMinorVersion;
1379         return this;
1380     }
1381
1382     public boolean isPreservePathOnForward() {
1383         return preservePathOnForward;
1384     }
1385
1386     public void setPreservePathOnForward(boolean preservePathOnForward) {
1387         this.preservePathOnForward = preservePathOnForward;
1388     }
1389
1390     /**
1391      * Add's a listener that is only invoked once all other deployment steps have been completed
1392      *
1393      * The listeners <code>contextDestroyed</code> method will be called after all undeployment steps are undertaken
1394      *
1395      * @param servletContextListener
1396      * @return
1397      */

1398     public DeploymentInfo addDeploymentCompleteListener(ServletContextListener servletContextListener) {
1399         deploymentCompleteListeners.add(servletContextListener);
1400         return this;
1401     }
1402
1403     public List<ServletContextListener> getDeploymentCompleteListeners() {
1404         return deploymentCompleteListeners;
1405     }
1406
1407     @Override
1408     public DeploymentInfo clone() {
1409         final DeploymentInfo info = new DeploymentInfo()
1410                 .setClassLoader(classLoader)
1411                 .setContextPath(contextPath)
1412                 .setResourceManager(resourceManager)
1413                 .setMajorVersion(majorVersion)
1414                 .setMinorVersion(minorVersion)
1415                 .setDeploymentName(deploymentName)
1416                 .setClassIntrospecter(classIntrospecter);
1417
1418         for (Map.Entry<String, ServletInfo> e : servlets.entrySet()) {
1419             info.addServlet(e.getValue().clone());
1420         }
1421
1422         for (Map.Entry<String, FilterInfo> e : filters.entrySet()) {
1423             info.addFilter(e.getValue().clone());
1424         }
1425         info.displayName = displayName;
1426         info.filterUrlMappings.addAll(filterUrlMappings);
1427         info.filterServletNameMappings.addAll(filterServletNameMappings);
1428         info.listeners.addAll(listeners);
1429         info.servletContainerInitializers.addAll(servletContainerInitializers);
1430         info.threadSetupActions.addAll(threadSetupActions);
1431         info.initParameters.putAll(initParameters);
1432         info.servletContextAttributes.putAll(servletContextAttributes);
1433         info.welcomePages.addAll(welcomePages);
1434         info.errorPages.addAll(errorPages);
1435         info.mimeMappings.addAll(mimeMappings);
1436         info.executor = executor;
1437         info.asyncExecutor = asyncExecutor;
1438         info.tempDir = tempDir;
1439         info.jspConfigDescriptor = jspConfigDescriptor;
1440         info.defaultServletConfig = defaultServletConfig;
1441         info.localeCharsetMapping.putAll(localeCharsetMapping);
1442         info.sessionManagerFactory = sessionManagerFactory;
1443         if (loginConfig != null) {
1444             info.loginConfig = loginConfig.clone();
1445         }
1446         info.identityManager = identityManager;
1447         info.confidentialPortManager = confidentialPortManager;
1448         info.defaultEncoding = defaultEncoding;
1449         info.urlEncoding = urlEncoding;
1450         info.securityConstraints.addAll(securityConstraints);
1451         info.outerHandlerChainWrappers.addAll(outerHandlerChainWrappers);
1452         info.innerHandlerChainWrappers.addAll(innerHandlerChainWrappers);
1453         info.initialSecurityWrapper = initialSecurityWrapper;
1454         info.securityWrappers.addAll(securityWrappers);
1455         info.initialHandlerChainWrappers.addAll(initialHandlerChainWrappers);
1456         info.securityRoles.addAll(securityRoles);
1457         info.notificationReceivers.addAll(notificationReceivers);
1458         info.allowNonStandardWrappers = allowNonStandardWrappers;
1459         info.defaultSessionTimeout = defaultSessionTimeout;
1460         info.servletContextAttributeBackingMap = servletContextAttributeBackingMap;
1461         info.servletSessionConfig = servletSessionConfig;
1462         info.hostName = hostName;
1463         info.denyUncoveredHttpMethods = denyUncoveredHttpMethods;
1464         info.servletStackTraces = servletStackTraces;
1465         info.invalidateSessionOnLogout = invalidateSessionOnLogout;
1466         info.defaultCookieVersion = defaultCookieVersion;
1467         info.sessionPersistenceManager = sessionPersistenceManager;
1468         for (Map.Entry<String, Set<String>> e : principalVersusRolesMap.entrySet()) {
1469             info.principalVersusRolesMap.put(e.getKey(), new HashSet<>(e.getValue()));
1470         }
1471         info.ignoreFlush = ignoreFlush;
1472         info.authorizationManager = authorizationManager;
1473         info.authenticationMechanisms.putAll(authenticationMechanisms);
1474         info.servletExtensions.addAll(servletExtensions);
1475         info.jaspiAuthenticationMechanism = jaspiAuthenticationMechanism;
1476         info.securityContextFactory = securityContextFactory;
1477         info.serverName = serverName;
1478         info.metricsCollector = metricsCollector;
1479         info.sessionConfigWrapper = sessionConfigWrapper;
1480         info.eagerFilterInit = eagerFilterInit;
1481         info.disableCachingForSecuredPages = disableCachingForSecuredPages;
1482         info.exceptionHandler = exceptionHandler;
1483         info.escapeErrorMessage = escapeErrorMessage;
1484         info.sessionListeners.addAll(sessionListeners);
1485         info.lifecycleInterceptors.addAll(lifecycleInterceptors);
1486         info.authenticationMode = authenticationMode;
1487         info.defaultMultipartConfig = defaultMultipartConfig;
1488         info.contentTypeCacheSize = contentTypeCacheSize;
1489         info.sessionIdGenerator = sessionIdGenerator;
1490         info.sendCustomReasonPhraseOnError = sendCustomReasonPhraseOnError;
1491         info.changeSessionIdOnLogin = changeSessionIdOnLogin;
1492         info.crawlerSessionManagerConfig = crawlerSessionManagerConfig;
1493         info.securityDisabled = securityDisabled;
1494         info.useCachedAuthenticationMechanism = useCachedAuthenticationMechanism;
1495         info.checkOtherSessionManagers = checkOtherSessionManagers;
1496         info.defaultRequestEncoding = defaultRequestEncoding;
1497         info.defaultResponseEncoding = defaultResponseEncoding;
1498         info.preCompressedResources.putAll(preCompressedResources);
1499         info.containerMajorVersion = containerMajorVersion;
1500         info.containerMinorVersion = containerMinorVersion;
1501         info.deploymentCompleteListeners.addAll(deploymentCompleteListeners);
1502         info.preservePathOnForward = preservePathOnForward;
1503         return info;
1504     }
1505
1506
1507 }
1508