View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2014 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.endpoints;
20  
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.io.Reader;
24  import java.nio.ByteBuffer;
25  import java.util.Map;
26  
27  import javax.websocket.CloseReason;
28  import javax.websocket.Endpoint;
29  import javax.websocket.MessageHandler;
30  import javax.websocket.MessageHandler.Whole;
31  import javax.websocket.PongMessage;
32  
33  import org.eclipse.jetty.util.BufferUtil;
34  import org.eclipse.jetty.util.log.Log;
35  import org.eclipse.jetty.util.log.Logger;
36  import org.eclipse.jetty.websocket.api.WebSocketPolicy;
37  import org.eclipse.jetty.websocket.api.extensions.Frame;
38  import org.eclipse.jetty.websocket.common.message.MessageInputStream;
39  import org.eclipse.jetty.websocket.common.message.MessageReader;
40  import org.eclipse.jetty.websocket.jsr356.JsrPongMessage;
41  import org.eclipse.jetty.websocket.jsr356.JsrSession;
42  import org.eclipse.jetty.websocket.jsr356.MessageHandlerWrapper;
43  import org.eclipse.jetty.websocket.jsr356.MessageType;
44  import org.eclipse.jetty.websocket.jsr356.messages.BinaryPartialMessage;
45  import org.eclipse.jetty.websocket.jsr356.messages.BinaryWholeMessage;
46  import org.eclipse.jetty.websocket.jsr356.messages.TextPartialMessage;
47  import org.eclipse.jetty.websocket.jsr356.messages.TextWholeMessage;
48  
49  /**
50   * EventDriver for websocket that extend from {@link javax.websocket.Endpoint}
51   */
52  public class JsrEndpointEventDriver extends AbstractJsrEventDriver
53  {
54      private static final Logger LOG = Log.getLogger(JsrEndpointEventDriver.class);
55  
56      private final Endpoint endpoint;
57      private Map<String, String> pathParameters;
58  
59      public JsrEndpointEventDriver(WebSocketPolicy policy, EndpointInstance endpointInstance)
60      {
61          super(policy,endpointInstance);
62          this.endpoint = (Endpoint)endpointInstance.getEndpoint();
63      }
64  
65      @Override
66      public void init(JsrSession jsrsession)
67      {
68          jsrsession.setPathParameters(pathParameters);
69      }
70  
71      @Override
72      public void onBinaryFrame(ByteBuffer buffer, boolean fin) throws IOException
73      {
74          if (activeMessage == null)
75          {
76              final MessageHandlerWrapper wrapper = jsrsession.getMessageHandlerWrapper(MessageType.BINARY);
77              if (wrapper == null)
78              {
79                  LOG.debug("No BINARY MessageHandler declared");
80                  return;
81              }
82              if (wrapper.wantsPartialMessages())
83              {
84                  activeMessage = new BinaryPartialMessage(wrapper);
85              }
86              else if (wrapper.wantsStreams())
87              {
88                  final MessageInputStream stream = new MessageInputStream();
89                  activeMessage = stream;
90                  dispatch(new Runnable()
91                  {
92                      @SuppressWarnings("unchecked")
93                      @Override
94                      public void run()
95                      {
96                          MessageHandler.Whole<InputStream> handler = (Whole<InputStream>)wrapper.getHandler();
97                          handler.onMessage(stream);
98                      }
99                  });
100             }
101             else
102             {
103                 activeMessage = new BinaryWholeMessage(this,wrapper);
104             }
105         }
106 
107         activeMessage.appendFrame(buffer,fin);
108 
109         if (fin)
110         {
111             activeMessage.messageComplete();
112             activeMessage = null;
113         }
114     }
115 
116     @Override
117     public void onBinaryMessage(byte[] data)
118     {
119         /* Ignored, handled by BinaryWholeMessage */
120     }
121 
122     @Override
123     protected void onClose(CloseReason closereason)
124     {
125         endpoint.onClose(this.jsrsession,closereason);
126     }
127 
128     @Override
129     public void onConnect()
130     {
131         LOG.debug("onConnect({}, {})",jsrsession,config);
132         try
133         {
134             endpoint.onOpen(jsrsession,config);
135         }
136         catch (Throwable t)
137         {
138             LOG.warn("Uncaught exception",t);
139         }
140     }
141 
142     @Override
143     public void onError(Throwable cause)
144     {
145         endpoint.onError(jsrsession,cause);
146     }
147 
148     @Override
149     public void onFrame(Frame frame)
150     {
151         /* Ignored, not supported by JSR-356 */
152     }
153 
154     @Override
155     public void onInputStream(InputStream stream)
156     {
157         /* Ignored, handled by BinaryStreamMessage */
158     }
159 
160     @Override
161     public void onReader(Reader reader)
162     {
163         /* Ignored, handled by TextStreamMessage */
164     }
165 
166     @Override
167     public void onTextFrame(ByteBuffer buffer, boolean fin) throws IOException
168     {
169         if (activeMessage == null)
170         {
171             final MessageHandlerWrapper wrapper = jsrsession.getMessageHandlerWrapper(MessageType.TEXT);
172             if (wrapper == null)
173             {
174                 LOG.debug("No TEXT MessageHandler declared");
175                 return;
176             }
177             if (wrapper.wantsPartialMessages())
178             {
179                 activeMessage = new TextPartialMessage(wrapper);
180             }
181             else if (wrapper.wantsStreams())
182             {
183                 final MessageReader stream = new MessageReader(new MessageInputStream());
184                 activeMessage = stream;
185 
186                 dispatch(new Runnable()
187                 {
188                     @SuppressWarnings("unchecked")
189                     @Override
190                     public void run()
191                     {
192                         MessageHandler.Whole<Reader> handler = (Whole<Reader>)wrapper.getHandler();
193                         handler.onMessage(stream);
194                     }
195                 });
196             }
197             else
198             {
199                 activeMessage = new TextWholeMessage(this,wrapper);
200             }
201         }
202 
203         activeMessage.appendFrame(buffer,fin);
204 
205         if (fin)
206         {
207             activeMessage.messageComplete();
208             activeMessage = null;
209         }
210     }
211 
212     @Override
213     public void onTextMessage(String message)
214     {
215         /* Ignored, handled by TextWholeMessage */
216     }
217     
218     @Override
219     public void onPing(ByteBuffer buffer)
220     {
221         onPongMessage(buffer);
222     }
223 
224     @Override
225     public void onPong(ByteBuffer buffer)
226     {
227         onPongMessage(buffer);
228     }
229 
230     private void onPongMessage(ByteBuffer buffer)
231     {
232         final MessageHandlerWrapper wrapper = jsrsession.getMessageHandlerWrapper(MessageType.PONG);
233         if (wrapper == null)
234         {
235             LOG.debug("No PONG MessageHandler declared");
236             return;
237         }
238 
239         ByteBuffer pongBuf = ByteBuffer.allocate(buffer.remaining());
240         BufferUtil.put(buffer,pongBuf);
241         BufferUtil.flipToFlush(pongBuf,0);
242         
243         @SuppressWarnings("unchecked")
244         Whole<PongMessage> pongHandler = (Whole<PongMessage>)wrapper.getHandler();
245         pongHandler.onMessage(new JsrPongMessage(pongBuf));
246     }
247     
248     @Override
249     public void setPathParameters(Map<String, String> pathParameters)
250     {
251         this.pathParameters = pathParameters;
252     }
253 
254     @Override
255     public String toString()
256     {
257         return String.format("%s[%s]",JsrEndpointEventDriver.class.getSimpleName(),endpoint.getClass().getName());
258     }
259 }