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.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 public static boolean isJSR356EnabledOnContext(ServletContext context)
49 {
50 Object enable = context.getAttribute(ENABLE_KEY);
51 if (enable instanceof Boolean)
52 {
53 return ((Boolean)enable).booleanValue();
54 }
55
56 return true;
57 }
58
59 public static ServerContainer configureContext(ServletContextHandler context)
60 {
61
62 WebSocketUpgradeFilter filter = WebSocketUpgradeFilter.configureContext(context);
63
64
65 context.setAttribute(WebSocketUpgradeFilter.class.getName(),filter);
66
67
68 ServerContainer jettyContainer = new ServerContainer(filter,filter.getFactory(),context.getServer().getThreadPool());
69 context.addBean(jettyContainer);
70
71
72 context.setAttribute(javax.websocket.server.ServerContainer.class.getName(),jettyContainer);
73
74 return jettyContainer;
75 }
76
77 @Override
78 public void onStartup(Set<Class<?>> c, ServletContext context) throws ServletException
79 {
80 if (!isJSR356EnabledOnContext(context))
81 {
82 LOG.info("JSR-356 support disabled via attribute on context {} - {}",context.getContextPath(),context);
83 return;
84 }
85
86 ContextHandler handler = ContextHandler.getContextHandler(context);
87
88 if (handler == null)
89 {
90 throw new ServletException("Not running on Jetty, JSR support disabled");
91 }
92
93 if (!(handler instanceof ServletContextHandler))
94 {
95 throw new ServletException("Not running in Jetty ServletContextHandler, JSR support disabled");
96 }
97
98 ServletContextHandler jettyContext = (ServletContextHandler)handler;
99
100
101 ServerContainer jettyContainer = configureContext(jettyContext);
102
103
104 context.setAttribute(javax.websocket.server.ServerContainer.class.getName(),jettyContainer);
105
106 LOG.debug("Found {} classes",c.size());
107
108
109 Set<Class<? extends Endpoint>> discoveredExtendedEndpoints = new HashSet<>();
110 Set<Class<?>> discoveredAnnotatedEndpoints = new HashSet<>();
111 Set<Class<? extends ServerApplicationConfig>> serverAppConfigs = new HashSet<>();
112
113 filterClasses(c,discoveredExtendedEndpoints,discoveredAnnotatedEndpoints,serverAppConfigs);
114
115 LOG.debug("Discovered {} extends Endpoint classes",discoveredExtendedEndpoints.size());
116 LOG.debug("Discovered {} @ServerEndpoint classes",discoveredAnnotatedEndpoints.size());
117 LOG.debug("Discovered {} ServerApplicationConfig classes",serverAppConfigs.size());
118
119
120 boolean wasFiltered = false;
121 Set<ServerEndpointConfig> deployableExtendedEndpointConfigs = new HashSet<>();
122 Set<Class<?>> deployableAnnotatedEndpoints = new HashSet<>();
123
124 for (Class<? extends ServerApplicationConfig> clazz : serverAppConfigs)
125 {
126 LOG.debug("Found ServerApplicationConfig: {}",clazz);
127 try
128 {
129 ServerApplicationConfig config = (ServerApplicationConfig)clazz.newInstance();
130
131 Set<ServerEndpointConfig> seconfigs = config.getEndpointConfigs(discoveredExtendedEndpoints);
132 if (seconfigs != null)
133 {
134 wasFiltered = true;
135 deployableExtendedEndpointConfigs.addAll(seconfigs);
136 }
137
138 Set<Class<?>> annotatedClasses = config.getAnnotatedEndpointClasses(discoveredAnnotatedEndpoints);
139 if (annotatedClasses != null)
140 {
141 wasFiltered = true;
142 deployableAnnotatedEndpoints.addAll(annotatedClasses);
143 }
144 }
145 catch (InstantiationException | IllegalAccessException e)
146 {
147 throw new ServletException("Unable to instantiate: " + clazz.getName(),e);
148 }
149 }
150
151
152 if (!wasFiltered)
153 {
154 deployableAnnotatedEndpoints.addAll(discoveredAnnotatedEndpoints);
155
156 deployableExtendedEndpointConfigs = new HashSet<>();
157 }
158
159
160 LOG.debug("Deploying {} ServerEndpointConfig(s)",deployableExtendedEndpointConfigs.size());
161 for (ServerEndpointConfig config : deployableExtendedEndpointConfigs)
162 {
163 try
164 {
165 jettyContainer.addEndpoint(config);
166 }
167 catch (DeploymentException e)
168 {
169 throw new ServletException(e);
170 }
171 }
172
173 LOG.debug("Deploying {} @ServerEndpoint(s)",deployableAnnotatedEndpoints.size());
174 for (Class<?> annotatedClass : deployableAnnotatedEndpoints)
175 {
176 try
177 {
178 jettyContainer.addEndpoint(annotatedClass);
179 }
180 catch (DeploymentException e)
181 {
182 throw new ServletException(e);
183 }
184 }
185 }
186
187 @SuppressWarnings("unchecked")
188 private void filterClasses(Set<Class<?>> c, Set<Class<? extends Endpoint>> discoveredExtendedEndpoints, Set<Class<?>> discoveredAnnotatedEndpoints,
189 Set<Class<? extends ServerApplicationConfig>> serverAppConfigs)
190 {
191 for (Class<?> clazz : c)
192 {
193 if (ServerApplicationConfig.class.isAssignableFrom(clazz))
194 {
195 serverAppConfigs.add((Class<? extends ServerApplicationConfig>)clazz);
196 }
197
198 if (Endpoint.class.isAssignableFrom(clazz))
199 {
200 discoveredExtendedEndpoints.add((Class<? extends Endpoint>)clazz);
201 }
202
203 ServerEndpoint endpoint = clazz.getAnnotation(ServerEndpoint.class);
204
205 if (endpoint != null)
206 {
207 discoveredAnnotatedEndpoints.add(clazz);
208 }
209 }
210 }
211 }