View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2015 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.common.events;
20  
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.io.Reader;
24  import java.nio.ByteBuffer;
25  
26  import org.eclipse.jetty.websocket.api.BatchMode;
27  import org.eclipse.jetty.websocket.api.WebSocketPolicy;
28  import org.eclipse.jetty.websocket.api.annotations.WebSocket;
29  import org.eclipse.jetty.websocket.api.extensions.Frame;
30  import org.eclipse.jetty.websocket.common.CloseInfo;
31  import org.eclipse.jetty.websocket.common.message.MessageAppender;
32  import org.eclipse.jetty.websocket.common.message.MessageInputStream;
33  import org.eclipse.jetty.websocket.common.message.MessageReader;
34  import org.eclipse.jetty.websocket.common.message.SimpleBinaryMessage;
35  import org.eclipse.jetty.websocket.common.message.SimpleTextMessage;
36  
37  /**
38   * Handler for Annotated User WebSocket objects.
39   */
40  public class JettyAnnotatedEventDriver extends AbstractEventDriver
41  {
42      private final JettyAnnotatedMetadata events;
43      private boolean hasCloseBeenCalled = false;
44      private BatchMode batchMode;
45  
46      public JettyAnnotatedEventDriver(WebSocketPolicy policy, Object websocket, JettyAnnotatedMetadata events)
47      {
48          super(policy,websocket);
49          this.events = events;
50  
51          WebSocket anno = websocket.getClass().getAnnotation(WebSocket.class);
52          // Setup the policy
53          if (anno.maxTextMessageSize() > 0)
54          {
55              this.policy.setMaxTextMessageSize(anno.maxTextMessageSize());
56          }
57          if (anno.maxBinaryMessageSize() > 0)
58          {
59              this.policy.setMaxBinaryMessageSize(anno.maxBinaryMessageSize());
60          }
61          if (anno.inputBufferSize() > 0)
62          {
63              this.policy.setInputBufferSize(anno.inputBufferSize());
64          }
65          if (anno.maxIdleTime() > 0)
66          {
67              this.policy.setIdleTimeout(anno.maxIdleTime());
68          }
69          this.batchMode = anno.batchMode();
70      }
71      
72      @Override
73      public BatchMode getBatchMode()
74      {
75          return this.batchMode;
76      }
77  
78      @Override
79      public void onBinaryFrame(ByteBuffer buffer, boolean fin) throws IOException
80      {
81          if (events.onBinary == null)
82          {
83              // not interested in binary events
84              return;
85          }
86  
87          if (activeMessage == null)
88          {
89              if (events.onBinary.isStreaming())
90              {
91                  activeMessage = new MessageInputStream();
92                  final MessageAppender msg = activeMessage;
93                  dispatch(new Runnable()
94                  {
95                      @Override
96                      public void run()
97                      {
98                          try
99                          {
100                             events.onBinary.call(websocket,session,msg);
101                         }
102                         catch (Throwable t)
103                         {
104                             // dispatched calls need to be reported
105                             onError(t);
106                         }
107                     }
108                 });
109             }
110             else
111             {
112                 activeMessage = new SimpleBinaryMessage(this);
113             }
114         }
115 
116         appendMessage(buffer,fin);
117     }
118 
119     @Override
120     public void onBinaryMessage(byte[] data)
121     {
122         if (events.onBinary != null)
123         {
124             events.onBinary.call(websocket,session,data,0,data.length);
125         }
126     }
127 
128     @Override
129     public void onClose(CloseInfo close)
130     {
131         if (hasCloseBeenCalled)
132         {
133             // avoid duplicate close events (possible when using harsh Session.disconnect())
134             return;
135         }
136         hasCloseBeenCalled = true;
137         if (events.onClose != null)
138         {
139             events.onClose.call(websocket,session,close.getStatusCode(),close.getReason());
140         }
141     }
142 
143     @Override
144     public void onConnect()
145     {
146         if (events.onConnect != null)
147         {
148             events.onConnect.call(websocket,session);
149         }
150     }
151 
152     @Override
153     public void onError(Throwable cause)
154     {
155         if (events.onError != null)
156         {
157             events.onError.call(websocket,session,cause);
158         }
159     }
160 
161     @Override
162     public void onFrame(Frame frame)
163     {
164         if (events.onFrame != null)
165         {
166             events.onFrame.call(websocket,session,frame);
167         }
168     }
169 
170     @Override
171     public void onInputStream(InputStream stream)
172     {
173         if (events.onBinary != null)
174         {
175             events.onBinary.call(websocket,session,stream);
176         }
177     }
178 
179     @Override
180     public void onReader(Reader reader)
181     {
182         if (events.onText != null)
183         {
184             events.onText.call(websocket,session,reader);
185         }
186     }
187 
188     @Override
189     public void onTextFrame(ByteBuffer buffer, boolean fin) throws IOException
190     {
191         if (events.onText == null)
192         {
193             // not interested in text events
194             return;
195         }
196 
197         if (activeMessage == null)
198         {
199             if (events.onText.isStreaming())
200             {
201                 activeMessage = new MessageReader(new MessageInputStream());
202                 final MessageAppender msg = activeMessage;
203                 dispatch(new Runnable()
204                 {
205                     @Override
206                     public void run()
207                     {
208                         try
209                         {
210                             events.onText.call(websocket,session,msg);
211                         }
212                         catch (Throwable t)
213                         {
214                             // dispatched calls need to be reported
215                             onError(t);
216                         }
217                     }
218                 });
219             }
220             else
221             {
222                 activeMessage = new SimpleTextMessage(this);
223             }
224         }
225 
226         appendMessage(buffer,fin);
227     }
228 
229     @Override
230     public void onTextMessage(String message)
231     {
232         if (events.onText != null)
233         {
234             events.onText.call(websocket,session,message);
235         }
236     }
237 
238     @Override
239     public String toString()
240     {
241         return String.format("%s[%s]", this.getClass().getSimpleName(), websocket);
242     }
243 }