View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 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.servlet;
20  
21  import java.io.IOException;
22  import java.util.Iterator;
23  import java.util.ServiceLoader;
24  
25  import javax.servlet.ServletException;
26  import javax.servlet.http.HttpServlet;
27  import javax.servlet.http.HttpServletRequest;
28  import javax.servlet.http.HttpServletResponse;
29  
30  import org.eclipse.jetty.websocket.api.WebSocketBehavior;
31  import org.eclipse.jetty.websocket.api.WebSocketPolicy;
32  import org.eclipse.jetty.websocket.api.annotations.WebSocket;
33  
34  /**
35   * Abstract Servlet used to bridge the Servlet API to the WebSocket API.
36   * <p>
37   * To use this servlet, you will be required to register your websockets with the {@link WebSocketServerFactory} so that it can create your websockets under the
38   * appropriate conditions.
39   * <p>
40   * The most basic implementation would be as follows.
41   * 
42   * <pre>
43   * package my.example;
44   * 
45   * import javax.servlet.http.HttpServletRequest;
46   * import org.eclipse.jetty.websocket.WebSocket;
47   * import org.eclipse.jetty.websocket.server.WebSocketServlet;
48   * 
49   * public class MyEchoServlet extends WebSocketServlet
50   * {
51   *     &#064;Override
52   *     public void registerWebSockets(WebSocketServerFactory factory)
53   *     {
54   *         factory.register(MyEchoSocket.class);
55   *     }
56   * }
57   * </pre>
58   * 
59   * Note: that only request that conforms to a "WebSocket: Upgrade" handshake request will trigger the {@link WebSocketServerFactory} handling of creating
60   * WebSockets.<br>
61   * All other requests are treated as normal servlet requests.
62   * 
63   * <p>
64   * <b>Configuration / Init-Parameters:</b><br>
65   * Note: If you use the {@link WebSocket &#064;WebSocket} annotation, these configuration settings can be specified on a per WebSocket basis, vs a per Servlet
66   * basis.
67   * 
68   * <dl>
69   * <dt>maxIdleTime</dt>
70   * <dd>set the time in ms that a websocket may be idle before closing<br>
71   * 
72   * <dt>maxMessagesSize</dt>
73   * <dd>set the size in bytes that a websocket may be accept before closing<br>
74   * 
75   * <dt>inputBufferSize</dt>
76   * <dd>set the size in bytes of the buffer used to read raw bytes from the network layer<br>
77   * </dl>
78   */
79  @SuppressWarnings("serial")
80  public abstract class WebSocketServlet extends HttpServlet
81  {
82      private WebSocketServletFactory factory;
83  
84      public abstract void configure(WebSocketServletFactory factory);
85  
86      @Override
87      public void destroy()
88      {
89          factory.cleanup();
90      }
91  
92      /**
93       * @see javax.servlet.GenericServlet#init()
94       */
95      @Override
96      public void init() throws ServletException
97      {
98          try
99          {
100             WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
101 
102             String max = getInitParameter("maxIdleTime");
103             if (max != null)
104             {
105                 policy.setIdleTimeout(Long.parseLong(max));
106             }
107 
108             max = getInitParameter("maxMessageSize");
109             if (max != null)
110             {
111                 policy.setMaxMessageSize(Long.parseLong(max));
112             }
113 
114             max = getInitParameter("inputBufferSize");
115             if (max != null)
116             {
117                 policy.setInputBufferSize(Integer.parseInt(max));
118             }
119 
120             WebSocketServletFactory baseFactory;
121             Iterator<WebSocketServletFactory> factories = ServiceLoader.load(WebSocketServletFactory.class).iterator();
122 
123             if (factories.hasNext())
124             {
125                 baseFactory = factories.next();
126             }
127             else
128             {
129                 // Load the default class if ServiceLoader mechanism isn't valid in this environment. (such as OSGi)
130                 ClassLoader loader = Thread.currentThread().getContextClassLoader();
131                 @SuppressWarnings("unchecked")
132                 Class<WebSocketServletFactory> wssf = (Class<WebSocketServletFactory>)loader
133                         .loadClass("org.eclipse.jetty.websocket.server.WebSocketServerFactory");
134                 baseFactory = wssf.newInstance();
135             }
136 
137             factory = baseFactory.createFactory(policy);
138 
139             configure(factory);
140 
141             factory.init();
142         }
143         catch (Exception x)
144         {
145             throw new ServletException(x);
146         }
147     }
148 
149     /**
150      * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
151      */
152     @Override
153     protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
154     {
155         if (factory.isUpgradeRequest(request,response))
156         {
157             // We have an upgrade request
158             if (factory.acceptWebSocket(request,response))
159             {
160                 // We have a socket instance created
161                 return;
162             }
163             // If we reach this point, it means we had an incoming request to upgrade
164             // but it was either not a proper websocket upgrade, or it was possibly rejected
165             // due to incoming request constraints (controlled by WebSocketCreator)
166             if (response.isCommitted())
167             {
168                 // not much we can do at this point.
169                 return;
170             }
171         }
172 
173         // All other processing
174         super.service(request,response);
175     }
176 }