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