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