Author: markt Date: Tue Dec 11 14:37:37 2012 New Revision: 1420198 URL: http://svn.apache.org/viewvc?rev=1420198&view=rev Log: WebSocket 1.0 implementation part 10 of many WsSession only needs to support one message handler of each type so store each individually rather than in a HashSet. Add the handling for Ping and Close control messages to WsFrame.
Added: tomcat/trunk/java/org/apache/tomcat/websocket/WsPingMessage.java (with props) Modified: tomcat/trunk/java/org/apache/tomcat/websocket/Constants.java tomcat/trunk/java/org/apache/tomcat/websocket/WsFrame.java tomcat/trunk/java/org/apache/tomcat/websocket/WsProtocolHandler.java tomcat/trunk/java/org/apache/tomcat/websocket/WsSession.java Modified: tomcat/trunk/java/org/apache/tomcat/websocket/Constants.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/Constants.java?rev=1420198&r1=1420197&r2=1420198&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/websocket/Constants.java (original) +++ tomcat/trunk/java/org/apache/tomcat/websocket/Constants.java Tue Dec 11 14:37:37 2012 @@ -25,6 +25,14 @@ public class Constants { protected static final String SERVLET_NAME = WsServlet.class.getName(); + // OP Codes + public static final byte OPCODE_CONTINUATION = 0x00; + public static final byte OPCODE_TEXT = 0x01; + public static final byte OPCODE_BINARY = 0x02; + public static final byte OPCODE_CLOSE = 0x08; + public static final byte OPCODE_PING = 0x09; + public static final byte OPCODE_PONG = 0x0A; + private Constants() { // Hide default constructor } Modified: tomcat/trunk/java/org/apache/tomcat/websocket/WsFrame.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/WsFrame.java?rev=1420198&r1=1420197&r2=1420198&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/websocket/WsFrame.java (original) +++ tomcat/trunk/java/org/apache/tomcat/websocket/WsFrame.java Tue Dec 11 14:37:37 2012 @@ -18,6 +18,7 @@ package org.apache.tomcat.websocket; import java.io.EOFException; import java.io.IOException; +import java.nio.ByteBuffer; import java.nio.charset.Charset; import javax.servlet.ServletInputStream; @@ -91,6 +92,10 @@ public class WsFrame { } + /** + * @return <code>true</code> if sufficient data was present to process all + * of the initial header + */ private boolean processInitialHeader() throws IOException { // Need at least two bytes of data to do this if (pos < 2) { @@ -115,6 +120,10 @@ public class WsFrame { } + /** + * @return <code>true</code> if sufficient data was present to complete the + * processing of the header + */ private boolean processRemainingHeader() throws IOException { // Initial 2 bytes already read + 4 for the mask headerLength = 6; @@ -155,8 +164,26 @@ public class WsFrame { } - private boolean processData() { - if (pos < (headerLength + payloadLength)) { + private boolean processData() throws IOException { + if (isControl()) { + if (!isPayloadComplete()) { + return false; + } + if (opCode == Constants.OPCODE_CLOSE) { + wsSession.close(); + } else if (opCode == Constants.OPCODE_PING) { + wsSession.getPingMessageHandler().onMessage( + new WsPingMessage(getPayload())); + } else if (opCode == Constants.OPCODE_PONG) { + // TODO + // Validate the PONG? + } else { + // TODO i18n + throw new UnsupportedOperationException(); + } + return true; + } + if (isPayloadComplete()) { // TODO Check if partial messages supported if (inputBuffer.length - pos > 0) { return false; @@ -184,6 +211,24 @@ public class WsFrame { } + private boolean isPayloadComplete() { + return pos < (headerLength + payloadLength); + } + + private ByteBuffer getPayload() { + ByteBuffer result; + if (isPayloadComplete()) { + result = ByteBuffer.allocate((int) payloadLength); + System.arraycopy(inputBuffer, headerLength, result.array(), 0, + (int) payloadLength); + } else { + // TODO Handle partial payloads + result = null; + } + + return result; + } + protected static long byteArrayToLong(byte[] b, int start, int len) throws IOException { Added: tomcat/trunk/java/org/apache/tomcat/websocket/WsPingMessage.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/WsPingMessage.java?rev=1420198&view=auto ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/websocket/WsPingMessage.java (added) +++ tomcat/trunk/java/org/apache/tomcat/websocket/WsPingMessage.java Tue Dec 11 14:37:37 2012 @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.websocket; + +import java.nio.ByteBuffer; + +import javax.websocket.PingMessage; + +public class WsPingMessage implements PingMessage { + + private final ByteBuffer applicationData; + + public WsPingMessage(ByteBuffer applicationData) { + this.applicationData = applicationData; + } + + @Override + public ByteBuffer getApplicationData() { + return applicationData; + } +} Propchange: tomcat/trunk/java/org/apache/tomcat/websocket/WsPingMessage.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: tomcat/trunk/java/org/apache/tomcat/websocket/WsProtocolHandler.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/WsProtocolHandler.java?rev=1420198&r1=1420197&r2=1420198&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/websocket/WsProtocolHandler.java (original) +++ tomcat/trunk/java/org/apache/tomcat/websocket/WsProtocolHandler.java Tue Dec 11 14:37:37 2012 @@ -38,7 +38,7 @@ public class WsProtocolHandler implement public WsProtocolHandler(Endpoint ep) { this.ep = ep; applicationClassLoader = Thread.currentThread().getContextClassLoader(); - wsSession = new WsSession(); + wsSession = new WsSession(ep); } @Override Modified: tomcat/trunk/java/org/apache/tomcat/websocket/WsSession.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/WsSession.java?rev=1420198&r1=1420197&r2=1420198&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/websocket/WsSession.java (original) +++ tomcat/trunk/java/org/apache/tomcat/websocket/WsSession.java Tue Dec 11 14:37:37 2012 @@ -17,8 +17,10 @@ package org.apache.tomcat.websocket; import java.io.IOException; +import java.lang.reflect.Type; import java.net.URI; -import java.util.LinkedHashSet; +import java.nio.ByteBuffer; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -26,13 +28,24 @@ import java.util.Set; import javax.websocket.ClientContainer; import javax.websocket.CloseReason; import javax.websocket.CloseReason.CloseCodes; +import javax.websocket.Endpoint; import javax.websocket.MessageHandler; +import javax.websocket.PingMessage; import javax.websocket.RemoteEndpoint; import javax.websocket.Session; public class WsSession implements Session { - private final Set<MessageHandler> messageHandlers = new LinkedHashSet<>(); + private MessageHandler textMessageHandler = null; + private MessageHandler binaryMessageHandler = null; + private MessageHandler.Basic<PingMessage> pingMessageHandler = + new DefaultPingMessageHandler(this); + + private final Endpoint localEndpoint; + + public WsSession(Endpoint localEndpoint) { + this.localEndpoint = localEndpoint; + } @Override public ClientContainer getContainer() { @@ -40,19 +53,59 @@ public class WsSession implements Sessio return null; } + @SuppressWarnings("unchecked") @Override public void addMessageHandler(MessageHandler listener) { - messageHandlers.add(listener); + Type[] types = listener.getClass().getGenericInterfaces(); + if (types.length != 1) { + // TODO i18n + throw new IllegalArgumentException(); + } + if (types[0].getClass().equals(String.class)) { + textMessageHandler = listener; + } else if (types[0].getClass().equals(ByteBuffer.class)){ + binaryMessageHandler = listener; + } else if (types[0].getClass().equals(PingMessage.class)){ + if (listener instanceof MessageHandler.Basic<?>) { + pingMessageHandler = (MessageHandler.Basic<PingMessage>) listener; + } else { + // TODO i18n + throw new IllegalArgumentException(); + } + } else { + // TODO i18n + throw new IllegalArgumentException(); + } } @Override public Set<MessageHandler> getMessageHandlers() { - return messageHandlers; + Set<MessageHandler> result = new HashSet<>(); + if (binaryMessageHandler != null) { + result.add(binaryMessageHandler); + } + if (textMessageHandler != null) { + result.add(textMessageHandler); + } + if (pingMessageHandler != null) { + result.add(pingMessageHandler); + } + return result; } @Override public void removeMessageHandler(MessageHandler listener) { - messageHandlers.remove(listener); + if (listener == null) { + return; + } + if (listener.equals(textMessageHandler)) { + textMessageHandler = null; + } else if (listener.equals(binaryMessageHandler)) { + binaryMessageHandler = null; + } else if (listener.equals(pingMessageHandler)) { + pingMessageHandler = null; + } + // TODO Ignore? ISE? } @Override @@ -128,8 +181,8 @@ public class WsSession implements Sessio @Override public void close(CloseReason closeStatus) throws IOException { - // TODO Auto-generated method stub - + // TODO Send the close message to the remote endpoint + localEndpoint.onClose(closeStatus); } @Override @@ -161,4 +214,36 @@ public class WsSession implements Sessio // TODO Auto-generated method stub return null; } + + + public MessageHandler getTextMessageHandler() { + return textMessageHandler; + } + + public MessageHandler getBinaryMessageHandler() { + return binaryMessageHandler; + } + + public MessageHandler.Basic<PingMessage> getPingMessageHandler() { + return pingMessageHandler; + } + + + private static class DefaultPingMessageHandler + implements MessageHandler.Basic<PingMessage>{ + + private final WsSession wsSession; + + private DefaultPingMessageHandler(WsSession wsSession) { + this.wsSession = wsSession; + } + + @Override + public void onMessage(PingMessage message) { + RemoteEndpoint remoteEndpoint = wsSession.getRemote(); + if (remoteEndpoint != null) { + remoteEndpoint.sendPong(message.getApplicationData()); + } + } + } } --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org