View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.websocket.jsr356.server;
20  
21  import java.util.ArrayList;
22  import java.util.List;
23  import java.util.concurrent.Executor;
24  
25  import javax.websocket.DeploymentException;
26  import javax.websocket.Endpoint;
27  import javax.websocket.server.ServerEndpoint;
28  import javax.websocket.server.ServerEndpointConfig;
29  
30  import org.eclipse.jetty.util.log.Log;
31  import org.eclipse.jetty.util.log.Logger;
32  import org.eclipse.jetty.websocket.common.events.EventDriverFactory;
33  import org.eclipse.jetty.websocket.jsr356.ClientContainer;
34  import org.eclipse.jetty.websocket.jsr356.JsrSessionFactory;
35  import org.eclipse.jetty.websocket.jsr356.annotations.AnnotatedEndpointScanner;
36  import org.eclipse.jetty.websocket.jsr356.endpoints.EndpointInstance;
37  import org.eclipse.jetty.websocket.jsr356.metadata.EndpointMetadata;
38  import org.eclipse.jetty.websocket.jsr356.server.pathmap.WebSocketPathSpec;
39  import org.eclipse.jetty.websocket.server.MappedWebSocketCreator;
40  import org.eclipse.jetty.websocket.server.WebSocketServerFactory;
41  
42  public class ServerContainer extends ClientContainer implements javax.websocket.server.ServerContainer
43  {
44      private static final Logger LOG = Log.getLogger(ServerContainer.class);
45  
46      private final MappedWebSocketCreator mappedCreator;
47      private final WebSocketServerFactory webSocketServerFactory;
48      private List<Class<?>> deferredEndpointClasses;
49      private List<ServerEndpointConfig> deferredEndpointConfigs;
50  
51      public ServerContainer(MappedWebSocketCreator creator, WebSocketServerFactory factory, Executor executor)
52      {
53          super(factory);
54          this.mappedCreator = creator;
55          this.webSocketServerFactory = factory;
56          EventDriverFactory eventDriverFactory = this.webSocketServerFactory.getEventDriverFactory();
57          eventDriverFactory.addImplementation(new JsrServerEndpointImpl());
58          eventDriverFactory.addImplementation(new JsrServerExtendsEndpointImpl());
59          this.webSocketServerFactory.addSessionFactory(new JsrSessionFactory(this,this));
60          addBean(webSocketServerFactory);
61      }
62      
63      public EndpointInstance newClientEndpointInstance(Object endpoint, ServerEndpointConfig config, String path)
64      {
65          EndpointMetadata metadata = getClientEndpointMetadata(endpoint.getClass(),config);
66          ServerEndpointConfig cec = config;
67          if (config == null)
68          {
69              if (metadata instanceof AnnotatedServerEndpointMetadata)
70              {
71                  cec = ((AnnotatedServerEndpointMetadata)metadata).getConfig();
72              }
73              else
74              {
75                  cec = new BasicServerEndpointConfig(this,endpoint.getClass(),path);
76              }
77          }
78          return new EndpointInstance(endpoint,cec,metadata);
79      }
80  
81      @Override
82      public void addEndpoint(Class<?> endpointClass) throws DeploymentException
83      {
84          if (isStarted() || isStarting())
85          {
86              ServerEndpointMetadata metadata = getServerEndpointMetadata(endpointClass,null);
87              addEndpoint(metadata);
88          }
89          else
90          {
91              if (deferredEndpointClasses == null)
92              {
93                  deferredEndpointClasses = new ArrayList<Class<?>>();
94              }
95              deferredEndpointClasses.add(endpointClass);
96          }
97      }
98  
99      private void addEndpoint(ServerEndpointMetadata metadata) throws DeploymentException
100     {
101         JsrCreator creator = new JsrCreator(this,metadata,webSocketServerFactory.getExtensionFactory());
102         mappedCreator.addMapping(new WebSocketPathSpec(metadata.getPath()),creator);
103     }
104 
105     @Override
106     public void addEndpoint(ServerEndpointConfig config) throws DeploymentException
107     {
108         if (isStarted() || isStarting())
109         {
110             if (LOG.isDebugEnabled())
111             {
112                 LOG.debug("addEndpoint({}) path={} endpoint={}",config,config.getPath(),config.getEndpointClass());
113             }
114             ServerEndpointMetadata metadata = getServerEndpointMetadata(config.getEndpointClass(),config);
115             addEndpoint(metadata);
116         }
117         else
118         {
119             if (deferredEndpointConfigs == null)
120             {
121                 deferredEndpointConfigs = new ArrayList<ServerEndpointConfig>();
122             }
123             deferredEndpointConfigs.add(config);
124         }
125     }
126     
127     @Override
128     protected void doStart() throws Exception
129     {
130         // Proceed with Normal Startup
131         super.doStart();
132         
133         // Process Deferred Endpoints
134         if (deferredEndpointClasses != null)
135         {
136             for (Class<?> endpointClass : deferredEndpointClasses)
137             {
138                 addEndpoint(endpointClass);
139             }
140             deferredEndpointClasses.clear();
141         }
142         
143         if (deferredEndpointConfigs != null)
144         {
145             for (ServerEndpointConfig config : deferredEndpointConfigs)
146             {
147                 addEndpoint(config);
148             }
149             deferredEndpointConfigs.clear();
150         }
151     }
152 
153     public ServerEndpointMetadata getServerEndpointMetadata(final Class<?> endpoint, final ServerEndpointConfig config) throws DeploymentException
154     {
155         ServerEndpointMetadata metadata = null;
156 
157         ServerEndpoint anno = endpoint.getAnnotation(ServerEndpoint.class);
158         if (anno != null)
159         {
160             // Annotated takes precedence here
161             AnnotatedServerEndpointMetadata ametadata = new AnnotatedServerEndpointMetadata(this,endpoint,config);
162             AnnotatedEndpointScanner<ServerEndpoint, ServerEndpointConfig> scanner = new AnnotatedEndpointScanner<>(ametadata);
163             metadata = ametadata;
164             scanner.scan();
165         }
166         else if (Endpoint.class.isAssignableFrom(endpoint))
167         {
168             // extends Endpoint
169             @SuppressWarnings("unchecked")
170             Class<? extends Endpoint> eendpoint = (Class<? extends Endpoint>)endpoint;
171             metadata = new SimpleServerEndpointMetadata(eendpoint,config);
172         }
173         else
174         {
175             StringBuilder err = new StringBuilder();
176             err.append("Not a recognized websocket [");
177             err.append(endpoint.getName());
178             err.append("] does not extend @").append(ServerEndpoint.class.getName());
179             err.append(" or extend from ").append(Endpoint.class.getName());
180             throw new DeploymentException("Unable to identify as valid Endpoint: " + endpoint);
181         }
182 
183         return metadata;
184     }
185 
186     @Override
187     public long getDefaultAsyncSendTimeout()
188     {
189         return webSocketServerFactory.getPolicy().getAsyncWriteTimeout();
190     }
191 
192     @Override
193     public int getDefaultMaxBinaryMessageBufferSize()
194     {
195         return webSocketServerFactory.getPolicy().getMaxBinaryMessageSize();
196     }
197 
198     @Override
199     public long getDefaultMaxSessionIdleTimeout()
200     {
201         return webSocketServerFactory.getPolicy().getIdleTimeout();
202     }
203 
204     @Override
205     public int getDefaultMaxTextMessageBufferSize()
206     {
207         return webSocketServerFactory.getPolicy().getMaxTextMessageSize();
208     }
209 
210     @Override
211     public void setAsyncSendTimeout(long ms)
212     {
213         super.setAsyncSendTimeout(ms);
214         webSocketServerFactory.getPolicy().setAsyncWriteTimeout(ms);
215     }
216 
217     @Override
218     public void setDefaultMaxBinaryMessageBufferSize(int max)
219     {
220         super.setDefaultMaxBinaryMessageBufferSize(max);
221         // overall message limit (used in non-streaming)
222         webSocketServerFactory.getPolicy().setMaxBinaryMessageSize(max);
223         // incoming streaming buffer size
224         webSocketServerFactory.getPolicy().setMaxBinaryMessageBufferSize(max);
225     }
226 
227     @Override
228     public void setDefaultMaxSessionIdleTimeout(long ms)
229     {
230         super.setDefaultMaxSessionIdleTimeout(ms);
231         webSocketServerFactory.getPolicy().setIdleTimeout(ms);
232     }
233 
234     @Override
235     public void setDefaultMaxTextMessageBufferSize(int max)
236     {
237         super.setDefaultMaxTextMessageBufferSize(max);
238         // overall message limit (used in non-streaming)
239         webSocketServerFactory.getPolicy().setMaxTextMessageSize(max);
240         // incoming streaming buffer size
241         webSocketServerFactory.getPolicy().setMaxTextMessageBufferSize(max);
242     }
243 }