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
24 import javax.servlet.ServletContainerInitializer;
25 import javax.servlet.ServletContext;
26 import javax.servlet.ServletException;
27 import javax.servlet.annotation.HandlesTypes;
28 import javax.websocket.DeploymentException;
29 import javax.websocket.Endpoint;
30 import javax.websocket.server.ServerApplicationConfig;
31 import javax.websocket.server.ServerEndpoint;
32 import javax.websocket.server.ServerEndpointConfig;
33
34 import org.eclipse.jetty.server.handler.ContextHandler;
35 import org.eclipse.jetty.servlet.ServletContextHandler;
36 import org.eclipse.jetty.util.TypeUtil;
37 import org.eclipse.jetty.util.log.Log;
38 import org.eclipse.jetty.util.log.Logger;
39 import org.eclipse.jetty.websocket.jsr356.server.ServerContainer;
40 import org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter;
41
42 @HandlesTypes(
43 { ServerApplicationConfig.class, ServerEndpoint.class, Endpoint.class })
44 public class WebSocketServerContainerInitializer implements ServletContainerInitializer
45 {
46 public static final String ENABLE_KEY = "org.eclipse.jetty.websocket.jsr356";
47 private static final Logger LOG = Log.getLogger(WebSocketServerContainerInitializer.class);
48
49
50 public static ServerContainer configureContext(ServletContextHandler context)
51 {
52
53 WebSocketUpgradeFilter filter = WebSocketUpgradeFilter.configureContext(context);
54
55
56 context.setAttribute(WebSocketUpgradeFilter.class.getName(),filter);
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 @Override
69 public void onStartup(Set<Class<?>> c, ServletContext context) throws ServletException
70 {
71 Object enable = context.getAttribute(ENABLE_KEY);
72
73
74 if (TypeUtil.isFalse(enable))
75 {
76 if (c.isEmpty())
77 LOG.debug("JSR-356 support disabled via attribute on context {} - {}",context.getContextPath(),context);
78 else
79 LOG.warn("JSR-356 support disabled via attribute on context {} - {}",context.getContextPath(),context);
80 return;
81 }
82
83
84 if (!TypeUtil.isTrue(enable) && c.isEmpty())
85 {
86 LOG.debug("No JSR-356 annotations or interfaces discovered. JSR-356 support disabled",context.getContextPath(),context);
87 return;
88 }
89
90 ContextHandler handler = ContextHandler.getContextHandler(context);
91
92 if (handler == null)
93 {
94 throw new ServletException("Not running on Jetty, JSR-356 support disabled");
95 }
96
97 if (!(handler instanceof ServletContextHandler))
98 {
99 throw new ServletException("Not running in Jetty ServletContextHandler, JSR-356 support disabled");
100 }
101
102 ServletContextHandler jettyContext = (ServletContextHandler)handler;
103
104
105 ServerContainer jettyContainer = configureContext(jettyContext);
106
107
108 context.setAttribute(javax.websocket.server.ServerContainer.class.getName(),jettyContainer);
109
110 LOG.debug("Found {} classes",c.size());
111
112
113 Set<Class<? extends Endpoint>> discoveredExtendedEndpoints = new HashSet<>();
114 Set<Class<?>> discoveredAnnotatedEndpoints = new HashSet<>();
115 Set<Class<? extends ServerApplicationConfig>> serverAppConfigs = new HashSet<>();
116
117 filterClasses(c,discoveredExtendedEndpoints,discoveredAnnotatedEndpoints,serverAppConfigs);
118
119 LOG.debug("Discovered {} extends Endpoint classes",discoveredExtendedEndpoints.size());
120 LOG.debug("Discovered {} @ServerEndpoint classes",discoveredAnnotatedEndpoints.size());
121 LOG.debug("Discovered {} ServerApplicationConfig classes",serverAppConfigs.size());
122
123
124 boolean wasFiltered = false;
125 Set<ServerEndpointConfig> deployableExtendedEndpointConfigs = new HashSet<>();
126 Set<Class<?>> deployableAnnotatedEndpoints = new HashSet<>();
127
128 for (Class<? extends ServerApplicationConfig> clazz : serverAppConfigs)
129 {
130 LOG.debug("Found ServerApplicationConfig: {}",clazz);
131 try
132 {
133 ServerApplicationConfig config = clazz.newInstance();
134
135 Set<ServerEndpointConfig> seconfigs = config.getEndpointConfigs(discoveredExtendedEndpoints);
136 if (seconfigs != null)
137 {
138 wasFiltered = true;
139 deployableExtendedEndpointConfigs.addAll(seconfigs);
140 }
141
142 Set<Class<?>> annotatedClasses = config.getAnnotatedEndpointClasses(discoveredAnnotatedEndpoints);
143 if (annotatedClasses != null)
144 {
145 wasFiltered = true;
146 deployableAnnotatedEndpoints.addAll(annotatedClasses);
147 }
148 }
149 catch (InstantiationException | IllegalAccessException e)
150 {
151 throw new ServletException("Unable to instantiate: " + clazz.getName(),e);
152 }
153 }
154
155
156 if (!wasFiltered)
157 {
158 deployableAnnotatedEndpoints.addAll(discoveredAnnotatedEndpoints);
159
160 deployableExtendedEndpointConfigs = new HashSet<>();
161 }
162
163
164 LOG.debug("Deploying {} ServerEndpointConfig(s)",deployableExtendedEndpointConfigs.size());
165 for (ServerEndpointConfig config : deployableExtendedEndpointConfigs)
166 {
167 try
168 {
169 jettyContainer.addEndpoint(config);
170 }
171 catch (DeploymentException e)
172 {
173 throw new ServletException(e);
174 }
175 }
176
177 LOG.debug("Deploying {} @ServerEndpoint(s)",deployableAnnotatedEndpoints.size());
178 for (Class<?> annotatedClass : deployableAnnotatedEndpoints)
179 {
180 try
181 {
182 jettyContainer.addEndpoint(annotatedClass);
183 }
184 catch (DeploymentException e)
185 {
186 throw new ServletException(e);
187 }
188 }
189 }
190
191 @SuppressWarnings("unchecked")
192 private void filterClasses(Set<Class<?>> c, Set<Class<? extends Endpoint>> discoveredExtendedEndpoints, Set<Class<?>> discoveredAnnotatedEndpoints,
193 Set<Class<? extends ServerApplicationConfig>> serverAppConfigs)
194 {
195 for (Class<?> clazz : c)
196 {
197 if (ServerApplicationConfig.class.isAssignableFrom(clazz))
198 {
199 serverAppConfigs.add((Class<? extends ServerApplicationConfig>)clazz);
200 }
201
202 if (Endpoint.class.isAssignableFrom(clazz))
203 {
204 discoveredExtendedEndpoints.add((Class<? extends Endpoint>)clazz);
205 }
206
207 ServerEndpoint endpoint = clazz.getAnnotation(ServerEndpoint.class);
208
209 if (endpoint != null)
210 {
211 discoveredAnnotatedEndpoints.add(clazz);
212 }
213 }
214 }
215 }