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.core;
20
21 import java.nio.charset.Charset;
22 import java.nio.charset.StandardCharsets;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Set;
32 import java.util.concurrent.Executor;
33
34 import io.undertow.security.api.AuthenticationMechanism;
35 import io.undertow.server.HttpHandler;
36 import io.undertow.server.session.SessionManager;
37 import io.undertow.servlet.api.Deployment;
38 import io.undertow.servlet.api.DeploymentInfo;
39 import io.undertow.servlet.api.DeploymentManager;
40 import io.undertow.servlet.api.ServletContainer;
41 import io.undertow.servlet.api.ServletDispatcher;
42 import io.undertow.servlet.api.ServletInfo;
43 import io.undertow.servlet.api.ThreadSetupHandler;
44 import io.undertow.servlet.handlers.ServletInitialHandler;
45 import io.undertow.servlet.handlers.ServletPathMatches;
46 import io.undertow.servlet.spec.ServletContextImpl;
47
48 /**
49  * Class that represents the mutable state associated with a servlet deployment that is built up
50  * during the bootstrap process.
51  * <p>
52  * Classes calling deployment methods during bootstrap must be aware of ordering concerns.
53  *
54  * @author Stuart Douglas
55  */

56 public class DeploymentImpl implements Deployment {
57
58     private final DeploymentManager deploymentManager;
59     private final DeploymentInfo deploymentInfo;
60     private final ServletContainer servletContainer;
61     private final List<Lifecycle> lifecycleObjects = new ArrayList<>();
62     private final ServletPathMatches servletPaths;
63     private final ManagedServlets servlets;
64     private final ManagedFilters filters;
65
66
67     private volatile ApplicationListeners applicationListeners;
68     private volatile ServletContextImpl servletContext;
69     private volatile ServletInitialHandler servletHandler;
70     private volatile HttpHandler initialHandler;
71     private volatile ErrorPages errorPages;
72     private volatile Map<String, String> mimeExtensionMappings;
73     private volatile SessionManager sessionManager;
74     @Deprecated
75     private volatile Charset defaultCharset = StandardCharsets.ISO_8859_1;
76     private volatile Charset defaultRequestCharset = StandardCharsets.ISO_8859_1;
77     private volatile Charset defaultResponseCharset = StandardCharsets.ISO_8859_1;
78
79
80
81     private volatile List<AuthenticationMechanism> authenticationMechanisms;
82     private volatile List<ThreadSetupHandler> threadSetupActions;
83
84     /**
85      * user for {@link #tryAddServletMappings(ServletInfo, String...)}
86      *
87      * https://issues.jboss.org/browse/UNDERTOW-1418
88      */

89     private Set<String> existingUrlPatterns;
90
91     public DeploymentImpl(DeploymentManager deploymentManager, final DeploymentInfo deploymentInfo, ServletContainer servletContainer) {
92         this.deploymentManager = deploymentManager;
93         this.deploymentInfo = deploymentInfo;
94         this.servletContainer = servletContainer;
95         servletPaths = new ServletPathMatches(this);
96         servlets = new ManagedServlets(this, servletPaths);
97         filters = new ManagedFilters(this, servletPaths);
98     }
99
100     @Override
101     public ServletContainer getServletContainer() {
102         return servletContainer;
103     }
104
105     public ManagedServlets getServlets() {
106         return servlets;
107     }
108
109     public ManagedFilters getFilters() {
110         return filters;
111     }
112
113     void setApplicationListeners(final ApplicationListeners applicationListeners) {
114         this.applicationListeners = applicationListeners;
115     }
116
117     void setServletContext(final ServletContextImpl servletContext) {
118         this.servletContext = servletContext;
119     }
120
121     @Override
122     public DeploymentInfo getDeploymentInfo() {
123         return deploymentInfo;
124     }
125
126     @Override
127     public ApplicationListeners getApplicationListeners() {
128         return applicationListeners;
129     }
130
131     @Override
132     public ServletContextImpl getServletContext() {
133         return servletContext;
134     }
135
136     @Override
137     public HttpHandler getHandler() {
138         return initialHandler;
139     }
140
141     public void setInitialHandler(final HttpHandler initialHandler) {
142         this.initialHandler = initialHandler;
143     }
144
145     void setServletHandler(final ServletInitialHandler servletHandler) {
146         this.servletHandler = servletHandler;
147     }
148
149     void addLifecycleObjects(final Collection<Lifecycle> objects) {
150         lifecycleObjects.addAll(objects);
151     }
152
153     void addLifecycleObjects(final Lifecycle... objects) {
154         lifecycleObjects.addAll(Arrays.asList(objects));
155     }
156
157     void setSessionManager(final SessionManager sessionManager) {
158         this.sessionManager = sessionManager;
159     }
160
161     public List<Lifecycle> getLifecycleObjects() {
162         return Collections.unmodifiableList(lifecycleObjects);
163     }
164
165     @Override
166     public ServletPathMatches getServletPaths() {
167         return servletPaths;
168     }
169
170     void setThreadSetupActions(List<ThreadSetupHandler> threadSetupActions) {
171         this.threadSetupActions = threadSetupActions;
172     }
173
174     public <C, T> ThreadSetupHandler.Action<C, T> createThreadSetupAction(ThreadSetupHandler.Action<C, T> target) {
175         ThreadSetupHandler.Action<C, T> ret = target;
176         for(ThreadSetupHandler wrapper : threadSetupActions) {
177             ret = wrapper.create(ret);
178         }
179         return ret;
180     }
181
182     public ErrorPages getErrorPages() {
183         return errorPages;
184     }
185
186     public void setErrorPages(final ErrorPages errorPages) {
187         this.errorPages = errorPages;
188     }
189
190     @Override
191     public Map<String, String> getMimeExtensionMappings() {
192         return mimeExtensionMappings;
193     }
194
195     public void setMimeExtensionMappings(final Map<String, String> mimeExtensionMappings) {
196         this.mimeExtensionMappings = Collections.unmodifiableMap(new HashMap<>(mimeExtensionMappings));
197     }
198
199     @Override
200     public ServletDispatcher getServletDispatcher() {
201         return servletHandler;
202     }
203
204     @Override
205     public SessionManager getSessionManager() {
206         return sessionManager;
207     }
208
209     @Override
210     public Executor getExecutor() {
211         return deploymentInfo.getExecutor();
212     }
213
214     @Override
215     public Executor getAsyncExecutor() {
216         return deploymentInfo.getAsyncExecutor();
217     }
218
219     @Deprecated
220     public Charset getDefaultCharset() {
221         return defaultCharset;
222     }
223
224     @Override
225     public Charset getDefaultRequestCharset() {
226         return defaultRequestCharset;
227     }
228
229     @Override
230     public Charset getDefaultResponseCharset() {
231         return defaultResponseCharset;
232     }
233
234     public void setAuthenticationMechanisms(List<AuthenticationMechanism> authenticationMechanisms) {
235         this.authenticationMechanisms = authenticationMechanisms;
236     }
237
238     @Override
239     public List<AuthenticationMechanism> getAuthenticationMechanisms() {
240         return authenticationMechanisms;
241     }
242
243     @Override
244     public DeploymentManager.State getDeploymentState() {
245         return deploymentManager.getState();
246     }
247
248     @Override
249     public Set<String> tryAddServletMappings(ServletInfo servletInfo, String... urlPatterns) {
250         final Set<String> ret = new HashSet<>();
251         if(existingUrlPatterns == null) {
252             existingUrlPatterns = new HashSet<>();
253             for (ServletInfo s : deploymentInfo.getServlets().values()) {
254                 if (!s.getName().equals(servletInfo.getName())) {
255                     existingUrlPatterns.addAll(s.getMappings());
256                 }
257             }
258         }
259         for (String pattern : urlPatterns) {
260             if (existingUrlPatterns.contains(pattern)) {
261                 ret.add(pattern);
262             }
263         }
264         //only update if no changes have been made
265         if (ret.isEmpty()) {
266             for (String pattern : urlPatterns) {
267                 existingUrlPatterns.add(pattern);
268                 if (!servletInfo.getMappings().contains(pattern)) {
269                     servletInfo.addMapping(pattern);
270                 }
271             }
272         }
273         getServletPaths().invalidate();
274         return ret;
275     }
276
277     @Deprecated
278     public void setDefaultCharset(Charset defaultCharset) {
279         this.defaultCharset = defaultCharset;
280     }
281
282     public void setDefaultRequestCharset(Charset defaultRequestCharset) {
283         this.defaultRequestCharset = defaultRequestCharset;
284     }
285
286     public void setDefaultResponseCharset(Charset defaultResponseCharset) {
287         this.defaultResponseCharset = defaultResponseCharset;
288     }
289
290     void destroy(){
291         getApplicationListeners().contextDestroyed();
292         getApplicationListeners().stop();
293         if (servletContext!=null){
294             servletContext.destroy();
295         }
296         servletContext = null;
297     }
298 }
299