xref: /unit/src/java/nginx/unit/websocket/server/WsSci.java (revision 1157:7ae152bda303)
1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17 package nginx.unit.websocket.server;
18 
19 import java.lang.reflect.Modifier;
20 import java.util.HashSet;
21 import java.util.Set;
22 
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.ContainerProvider;
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 /**
35  * Registers an interest in any class that is annotated with
36  * {@link ServerEndpoint} so that Endpoint can be published via the WebSocket
37  * server.
38  */
39 @HandlesTypes({ServerEndpoint.class, ServerApplicationConfig.class,
40         Endpoint.class})
41 public class WsSci implements ServletContainerInitializer {
42 
43     @Override
onStartup(Set<Class<?>> clazzes, ServletContext ctx)44     public void onStartup(Set<Class<?>> clazzes, ServletContext ctx)
45             throws ServletException {
46 
47         WsServerContainer sc = init(ctx, true);
48 
49         if (clazzes == null || clazzes.size() == 0) {
50             return;
51         }
52 
53         // Group the discovered classes by type
54         Set<ServerApplicationConfig> serverApplicationConfigs = new HashSet<>();
55         Set<Class<? extends Endpoint>> scannedEndpointClazzes = new HashSet<>();
56         Set<Class<?>> scannedPojoEndpoints = new HashSet<>();
57 
58         try {
59             // wsPackage is "javax.websocket."
60             String wsPackage = ContainerProvider.class.getName();
61             wsPackage = wsPackage.substring(0, wsPackage.lastIndexOf('.') + 1);
62             for (Class<?> clazz : clazzes) {
63                 int modifiers = clazz.getModifiers();
64                 if (!Modifier.isPublic(modifiers) ||
65                         Modifier.isAbstract(modifiers)) {
66                     // Non-public or abstract - skip it.
67                     continue;
68                 }
69                 // Protect against scanning the WebSocket API JARs
70                 if (clazz.getName().startsWith(wsPackage)) {
71                     continue;
72                 }
73                 if (ServerApplicationConfig.class.isAssignableFrom(clazz)) {
74                     serverApplicationConfigs.add(
75                             (ServerApplicationConfig) clazz.getConstructor().newInstance());
76                 }
77                 if (Endpoint.class.isAssignableFrom(clazz)) {
78                     @SuppressWarnings("unchecked")
79                     Class<? extends Endpoint> endpoint =
80                             (Class<? extends Endpoint>) clazz;
81                     scannedEndpointClazzes.add(endpoint);
82                 }
83                 if (clazz.isAnnotationPresent(ServerEndpoint.class)) {
84                     scannedPojoEndpoints.add(clazz);
85                 }
86             }
87         } catch (ReflectiveOperationException e) {
88             throw new ServletException(e);
89         }
90 
91         // Filter the results
92         Set<ServerEndpointConfig> filteredEndpointConfigs = new HashSet<>();
93         Set<Class<?>> filteredPojoEndpoints = new HashSet<>();
94 
95         if (serverApplicationConfigs.isEmpty()) {
96             filteredPojoEndpoints.addAll(scannedPojoEndpoints);
97         } else {
98             for (ServerApplicationConfig config : serverApplicationConfigs) {
99                 Set<ServerEndpointConfig> configFilteredEndpoints =
100                         config.getEndpointConfigs(scannedEndpointClazzes);
101                 if (configFilteredEndpoints != null) {
102                     filteredEndpointConfigs.addAll(configFilteredEndpoints);
103                 }
104                 Set<Class<?>> configFilteredPojos =
105                         config.getAnnotatedEndpointClasses(
106                                 scannedPojoEndpoints);
107                 if (configFilteredPojos != null) {
108                     filteredPojoEndpoints.addAll(configFilteredPojos);
109                 }
110             }
111         }
112 
113         try {
114             // Deploy endpoints
115             for (ServerEndpointConfig config : filteredEndpointConfigs) {
116                 sc.addEndpoint(config);
117             }
118             // Deploy POJOs
119             for (Class<?> clazz : filteredPojoEndpoints) {
120                 sc.addEndpoint(clazz);
121             }
122         } catch (DeploymentException e) {
123             throw new ServletException(e);
124         }
125     }
126 
127 
init(ServletContext servletContext, boolean initBySciMechanism)128     static WsServerContainer init(ServletContext servletContext,
129             boolean initBySciMechanism) {
130 
131         WsServerContainer sc = new WsServerContainer(servletContext);
132 
133         servletContext.setAttribute(
134                 Constants.SERVER_CONTAINER_SERVLET_CONTEXT_ATTRIBUTE, sc);
135 
136         servletContext.addListener(new WsSessionListener(sc));
137         // Can't register the ContextListener again if the ContextListener is
138         // calling this method
139         if (initBySciMechanism) {
140             servletContext.addListener(new WsContextListener());
141         }
142 
143         return sc;
144     }
145 }
146