1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.websocket.jsr356.server.deploy;
20
21 import java.util.HashSet;
22 import java.util.Set;
23 import javax.servlet.ServletContainerInitializer;
24 import javax.servlet.ServletContext;
25 import javax.servlet.ServletException;
26 import javax.servlet.annotation.HandlesTypes;
27 import javax.websocket.DeploymentException;
28 import javax.websocket.Endpoint;
29 import javax.websocket.server.ServerApplicationConfig;
30 import javax.websocket.server.ServerEndpoint;
31 import javax.websocket.server.ServerEndpointConfig;
32
33 import org.eclipse.jetty.server.handler.ContextHandler;
34 import org.eclipse.jetty.servlet.ServletContextHandler;
35 import org.eclipse.jetty.util.TypeUtil;
36 import org.eclipse.jetty.util.log.Log;
37 import org.eclipse.jetty.util.log.Logger;
38 import org.eclipse.jetty.websocket.jsr356.server.ServerContainer;
39 import org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter;
40
41 @HandlesTypes(
42 { ServerApplicationConfig.class, ServerEndpoint.class, Endpoint.class })
43 public class WebSocketServerContainerInitializer implements ServletContainerInitializer
44 {
45 public static final String ENABLE_KEY = "org.eclipse.jetty.websocket.jsr356";
46 private static final Logger LOG = Log.getLogger(WebSocketServerContainerInitializer.class);
47
48
49
50
51
52
53 public static ServerContainer configureContext(ServletContextHandler context) throws ServletException
54 {
55
56 WebSocketUpgradeFilter filter = WebSocketUpgradeFilter.configureContext(context);
57
58
59 ServerContainer jettyContainer = new ServerContainer(filter,filter.getFactory(),context.getServer().getThreadPool());
60 context.addBean(jettyContainer);
61
62
63 context.setAttribute(javax.websocket.server.ServerContainer.class.getName(),jettyContainer);
64
65 return jettyContainer;
66 }
67
68
69
70
71
72
73 public static ServerContainer configureContext(ServletContext context, ServletContextHandler jettyContext) throws ServletException
74 {
75
76 WebSocketUpgradeFilter filter = WebSocketUpgradeFilter.configureContext(context);
77
78
79 ServerContainer jettyContainer = new ServerContainer(filter,filter.getFactory(),jettyContext.getServer().getThreadPool());
80 jettyContext.addBean(jettyContainer);
81
82
83 context.setAttribute(javax.websocket.server.ServerContainer.class.getName(),jettyContainer);
84
85 return jettyContainer;
86 }
87
88 private boolean isEnabled(Set<Class<?>> c, ServletContext context)
89 {
90
91 String cp = context.getInitParameter(ENABLE_KEY);
92 if(TypeUtil.isTrue(cp))
93 {
94
95 return true;
96 }
97
98 if(TypeUtil.isFalse(cp))
99 {
100
101 LOG.warn("JSR-356 support disabled via parameter on context {} - {}",context.getContextPath(),context);
102 return false;
103 }
104
105
106 Object enable = context.getAttribute(ENABLE_KEY);
107
108 if(TypeUtil.isTrue(enable))
109 {
110
111 return true;
112 }
113
114 if (TypeUtil.isFalse(enable))
115 {
116
117 LOG.warn("JSR-356 support disabled via attribute on context {} - {}",context.getContextPath(),context);
118 return false;
119 }
120
121
122 if (c.isEmpty())
123 {
124 if (LOG.isDebugEnabled())
125 {
126 LOG.debug("No JSR-356 annotations or interfaces discovered. JSR-356 support disabled",context.getContextPath(),context);
127 }
128 return false;
129 }
130
131 return true;
132 }
133
134 @Override
135 public void onStartup(Set<Class<?>> c, ServletContext context) throws ServletException
136 {
137 if(!isEnabled(c,context))
138 {
139 return;
140 }
141
142 ContextHandler handler = ContextHandler.getContextHandler(context);
143
144 if (handler == null)
145 {
146 throw new ServletException("Not running on Jetty, JSR-356 support unavailable");
147 }
148
149 if (!(handler instanceof ServletContextHandler))
150 {
151 throw new ServletException("Not running in Jetty ServletContextHandler, JSR-356 support unavailable");
152 }
153
154 ServletContextHandler jettyContext = (ServletContextHandler)handler;
155
156 ClassLoader old = Thread.currentThread().getContextClassLoader();
157 try
158 {
159 Thread.currentThread().setContextClassLoader(context.getClassLoader());
160
161
162 ServerContainer jettyContainer = configureContext(context,jettyContext);
163
164
165 context.setAttribute(javax.websocket.server.ServerContainer.class.getName(),jettyContainer);
166
167 if (LOG.isDebugEnabled())
168 {
169 LOG.debug("Found {} classes",c.size());
170 }
171
172
173 Set<Class<? extends Endpoint>> discoveredExtendedEndpoints = new HashSet<>();
174 Set<Class<?>> discoveredAnnotatedEndpoints = new HashSet<>();
175 Set<Class<? extends ServerApplicationConfig>> serverAppConfigs = new HashSet<>();
176
177 filterClasses(c,discoveredExtendedEndpoints,discoveredAnnotatedEndpoints,serverAppConfigs);
178
179 if (LOG.isDebugEnabled())
180 {
181 LOG.debug("Discovered {} extends Endpoint classes",discoveredExtendedEndpoints.size());
182 LOG.debug("Discovered {} @ServerEndpoint classes",discoveredAnnotatedEndpoints.size());
183 LOG.debug("Discovered {} ServerApplicationConfig classes",serverAppConfigs.size());
184 }
185
186
187 boolean wasFiltered = false;
188 Set<ServerEndpointConfig> deployableExtendedEndpointConfigs = new HashSet<>();
189 Set<Class<?>> deployableAnnotatedEndpoints = new HashSet<>();
190
191 for (Class<? extends ServerApplicationConfig> clazz : serverAppConfigs)
192 {
193 if (LOG.isDebugEnabled())
194 {
195 LOG.debug("Found ServerApplicationConfig: {}",clazz);
196 }
197 try
198 {
199 ServerApplicationConfig config = clazz.newInstance();
200
201 Set<ServerEndpointConfig> seconfigs = config.getEndpointConfigs(discoveredExtendedEndpoints);
202 if (seconfigs != null)
203 {
204 wasFiltered = true;
205 deployableExtendedEndpointConfigs.addAll(seconfigs);
206 }
207
208 Set<Class<?>> annotatedClasses = config.getAnnotatedEndpointClasses(discoveredAnnotatedEndpoints);
209 if (annotatedClasses != null)
210 {
211 wasFiltered = true;
212 deployableAnnotatedEndpoints.addAll(annotatedClasses);
213 }
214 }
215 catch (InstantiationException | IllegalAccessException e)
216 {
217 throw new ServletException("Unable to instantiate: " + clazz.getName(),e);
218 }
219 }
220
221
222 if (!wasFiltered)
223 {
224 deployableAnnotatedEndpoints.addAll(discoveredAnnotatedEndpoints);
225
226 deployableExtendedEndpointConfigs = new HashSet<>();
227 }
228
229 if (LOG.isDebugEnabled())
230 {
231 LOG.debug("Deploying {} ServerEndpointConfig(s)",deployableExtendedEndpointConfigs.size());
232 }
233
234 for (ServerEndpointConfig config : deployableExtendedEndpointConfigs)
235 {
236 try
237 {
238 jettyContainer.addEndpoint(config);
239 }
240 catch (DeploymentException e)
241 {
242 throw new ServletException(e);
243 }
244 }
245
246 if (LOG.isDebugEnabled())
247 {
248 LOG.debug("Deploying {} @ServerEndpoint(s)",deployableAnnotatedEndpoints.size());
249 }
250 for (Class<?> annotatedClass : deployableAnnotatedEndpoints)
251 {
252 try
253 {
254 jettyContainer.addEndpoint(annotatedClass);
255 }
256 catch (DeploymentException e)
257 {
258 throw new ServletException(e);
259 }
260 }
261 } finally {
262 Thread.currentThread().setContextClassLoader(old);
263 }
264 }
265
266 @SuppressWarnings("unchecked")
267 private void filterClasses(Set<Class<?>> c, Set<Class<? extends Endpoint>> discoveredExtendedEndpoints, Set<Class<?>> discoveredAnnotatedEndpoints,
268 Set<Class<? extends ServerApplicationConfig>> serverAppConfigs)
269 {
270 for (Class<?> clazz : c)
271 {
272 if (ServerApplicationConfig.class.isAssignableFrom(clazz))
273 {
274 serverAppConfigs.add((Class<? extends ServerApplicationConfig>)clazz);
275 }
276
277 if (Endpoint.class.isAssignableFrom(clazz))
278 {
279 discoveredExtendedEndpoints.add((Class<? extends Endpoint>)clazz);
280 }
281
282 ServerEndpoint endpoint = clazz.getAnnotation(ServerEndpoint.class);
283
284 if (endpoint != null)
285 {
286 discoveredAnnotatedEndpoints.add(clazz);
287 }
288 }
289 }
290 }