| // |
| // ======================================================================== |
| // Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // and Apache License v2.0 which accompanies this distribution. |
| // |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // The Apache License v2.0 is available at |
| // http://www.opensource.org/licenses/apache2.0.php |
| // |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| // |
| |
| package org.eclipse.jetty.websocket.jsr356.endpoints; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.Reader; |
| import java.nio.ByteBuffer; |
| import java.util.Map; |
| |
| import javax.websocket.CloseReason; |
| import javax.websocket.Endpoint; |
| import javax.websocket.MessageHandler; |
| import javax.websocket.MessageHandler.Whole; |
| import javax.websocket.PongMessage; |
| |
| import org.eclipse.jetty.util.BufferUtil; |
| import org.eclipse.jetty.util.log.Log; |
| import org.eclipse.jetty.util.log.Logger; |
| import org.eclipse.jetty.websocket.api.WebSocketPolicy; |
| import org.eclipse.jetty.websocket.api.extensions.Frame; |
| import org.eclipse.jetty.websocket.common.message.MessageInputStream; |
| import org.eclipse.jetty.websocket.common.message.MessageReader; |
| import org.eclipse.jetty.websocket.jsr356.JsrPongMessage; |
| import org.eclipse.jetty.websocket.jsr356.JsrSession; |
| import org.eclipse.jetty.websocket.jsr356.MessageHandlerWrapper; |
| import org.eclipse.jetty.websocket.jsr356.MessageType; |
| import org.eclipse.jetty.websocket.jsr356.messages.BinaryPartialMessage; |
| import org.eclipse.jetty.websocket.jsr356.messages.BinaryWholeMessage; |
| import org.eclipse.jetty.websocket.jsr356.messages.TextPartialMessage; |
| import org.eclipse.jetty.websocket.jsr356.messages.TextWholeMessage; |
| |
| /** |
| * EventDriver for websocket that extend from {@link javax.websocket.Endpoint} |
| */ |
| public class JsrEndpointEventDriver extends AbstractJsrEventDriver |
| { |
| private static final Logger LOG = Log.getLogger(JsrEndpointEventDriver.class); |
| |
| private final Endpoint endpoint; |
| private Map<String, String> pathParameters; |
| |
| public JsrEndpointEventDriver(WebSocketPolicy policy, EndpointInstance endpointInstance) |
| { |
| super(policy,endpointInstance); |
| this.endpoint = (Endpoint)endpointInstance.getEndpoint(); |
| } |
| |
| @Override |
| public void init(JsrSession jsrsession) |
| { |
| jsrsession.setPathParameters(pathParameters); |
| } |
| |
| @Override |
| public void onBinaryFrame(ByteBuffer buffer, boolean fin) throws IOException |
| { |
| if (activeMessage == null) |
| { |
| final MessageHandlerWrapper wrapper = jsrsession.getMessageHandlerWrapper(MessageType.BINARY); |
| if (wrapper == null) |
| { |
| LOG.debug("No BINARY MessageHandler declared"); |
| return; |
| } |
| if (wrapper.wantsPartialMessages()) |
| { |
| activeMessage = new BinaryPartialMessage(wrapper); |
| } |
| else if (wrapper.wantsStreams()) |
| { |
| final MessageInputStream stream = new MessageInputStream(); |
| activeMessage = stream; |
| dispatch(new Runnable() |
| { |
| @SuppressWarnings("unchecked") |
| @Override |
| public void run() |
| { |
| MessageHandler.Whole<InputStream> handler = (Whole<InputStream>)wrapper.getHandler(); |
| handler.onMessage(stream); |
| } |
| }); |
| } |
| else |
| { |
| activeMessage = new BinaryWholeMessage(this,wrapper); |
| } |
| } |
| |
| activeMessage.appendFrame(buffer,fin); |
| |
| if (fin) |
| { |
| activeMessage.messageComplete(); |
| activeMessage = null; |
| } |
| } |
| |
| @Override |
| public void onBinaryMessage(byte[] data) |
| { |
| /* Ignored, handled by BinaryWholeMessage */ |
| } |
| |
| @Override |
| protected void onClose(CloseReason closereason) |
| { |
| endpoint.onClose(this.jsrsession,closereason); |
| } |
| |
| @Override |
| public void onConnect() |
| { |
| LOG.debug("onConnect({}, {})",jsrsession,config); |
| try |
| { |
| endpoint.onOpen(jsrsession,config); |
| } |
| catch (Throwable t) |
| { |
| LOG.warn("Uncaught exception",t); |
| } |
| } |
| |
| @Override |
| public void onError(Throwable cause) |
| { |
| endpoint.onError(jsrsession,cause); |
| } |
| |
| @Override |
| public void onFrame(Frame frame) |
| { |
| /* Ignored, not supported by JSR-356 */ |
| } |
| |
| @Override |
| public void onInputStream(InputStream stream) |
| { |
| /* Ignored, handled by BinaryStreamMessage */ |
| } |
| |
| @Override |
| public void onReader(Reader reader) |
| { |
| /* Ignored, handled by TextStreamMessage */ |
| } |
| |
| @Override |
| public void onTextFrame(ByteBuffer buffer, boolean fin) throws IOException |
| { |
| if (activeMessage == null) |
| { |
| final MessageHandlerWrapper wrapper = jsrsession.getMessageHandlerWrapper(MessageType.TEXT); |
| if (wrapper == null) |
| { |
| LOG.debug("No TEXT MessageHandler declared"); |
| return; |
| } |
| if (wrapper.wantsPartialMessages()) |
| { |
| activeMessage = new TextPartialMessage(wrapper); |
| } |
| else if (wrapper.wantsStreams()) |
| { |
| final MessageReader stream = new MessageReader(new MessageInputStream()); |
| activeMessage = stream; |
| |
| dispatch(new Runnable() |
| { |
| @SuppressWarnings("unchecked") |
| @Override |
| public void run() |
| { |
| MessageHandler.Whole<Reader> handler = (Whole<Reader>)wrapper.getHandler(); |
| handler.onMessage(stream); |
| } |
| }); |
| } |
| else |
| { |
| activeMessage = new TextWholeMessage(this,wrapper); |
| } |
| } |
| |
| activeMessage.appendFrame(buffer,fin); |
| |
| if (fin) |
| { |
| activeMessage.messageComplete(); |
| activeMessage = null; |
| } |
| } |
| |
| @Override |
| public void onTextMessage(String message) |
| { |
| /* Ignored, handled by TextWholeMessage */ |
| } |
| |
| @Override |
| public void onPing(ByteBuffer buffer) |
| { |
| onPongMessage(buffer); |
| } |
| |
| @Override |
| public void onPong(ByteBuffer buffer) |
| { |
| onPongMessage(buffer); |
| } |
| |
| private void onPongMessage(ByteBuffer buffer) |
| { |
| final MessageHandlerWrapper wrapper = jsrsession.getMessageHandlerWrapper(MessageType.PONG); |
| if (wrapper == null) |
| { |
| LOG.debug("No PONG MessageHandler declared"); |
| return; |
| } |
| |
| ByteBuffer pongBuf = ByteBuffer.allocate(buffer.remaining()); |
| BufferUtil.put(buffer,pongBuf); |
| BufferUtil.flipToFlush(pongBuf,0); |
| |
| @SuppressWarnings("unchecked") |
| Whole<PongMessage> pongHandler = (Whole<PongMessage>)wrapper.getHandler(); |
| pongHandler.onMessage(new JsrPongMessage(pongBuf)); |
| } |
| |
| @Override |
| public void setPathParameters(Map<String, String> pathParameters) |
| { |
| this.pathParameters = pathParameters; |
| } |
| |
| @Override |
| public String toString() |
| { |
| return String.format("%s[%s]",JsrEndpointEventDriver.class.getSimpleName(),endpoint.getClass().getName()); |
| } |
| } |