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