You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2012/12/21 22:04:07 UTC

svn commit: r1425145 - in /tomcat/trunk: java/javax/websocket/ java/org/apache/tomcat/websocket/ webapps/examples/WEB-INF/classes/websocket/chat/ webapps/examples/WEB-INF/classes/websocket/echo/

Author: markt
Date: Fri Dec 21 21:04:07 2012
New Revision: 1425145

URL: http://svn.apache.org/viewvc?rev=1425145&view=rev
Log:
Improve close behaviour - fixes various issues highlighted by the Autobahn WebSocket test suite

Modified:
    tomcat/trunk/java/javax/websocket/Session.java
    tomcat/trunk/java/org/apache/tomcat/websocket/WsEndpointPojo.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/WsRemoteEndpoint.java
    tomcat/trunk/java/org/apache/tomcat/websocket/WsSession.java
    tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/chat/ChatAnnotation.java
    tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/echo/EchoEndpoint.java

Modified: tomcat/trunk/java/javax/websocket/Session.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/javax/websocket/Session.java?rev=1425145&r1=1425144&r2=1425145&view=diff
==============================================================================
--- tomcat/trunk/java/javax/websocket/Session.java (original)
+++ tomcat/trunk/java/javax/websocket/Session.java Fri Dec 21 21:04:07 2012
@@ -54,8 +54,22 @@ public interface Session {
 
     RemoteEndpoint getRemote();
 
+    /**
+     * Close the connection to the remote end point using the code
+     * {@link javax.websocket.CloseReason.CloseCodes#NORMAL_CLOSURE} and an
+     * empty reason phrase.
+     *
+     * @throws IOException
+     */
     void close() throws IOException;
 
+
+    /**
+     * Close the connection to the remote end point using the specified code
+     * and reason phrase.
+     *
+     * @throws IOException
+     */
     void close(CloseReason closeStatus) throws IOException;
 
     URI getRequestURI();

Modified: tomcat/trunk/java/org/apache/tomcat/websocket/WsEndpointPojo.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/WsEndpointPojo.java?rev=1425145&r1=1425144&r2=1425145&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/WsEndpointPojo.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/WsEndpointPojo.java Fri Dec 21 21:04:07 2012
@@ -16,6 +16,7 @@
  */
 package org.apache.tomcat.websocket;
 
+import java.io.IOException;
 import java.lang.reflect.InvocationTargetException;
 
 import javax.websocket.CloseReason;
@@ -68,7 +69,15 @@ public class WsEndpointPojo extends Endp
 
     @Override
     public void onClose(CloseReason closeReason) {
-        if (methodMapping.getOnClose() != null) {
+        if (methodMapping.getOnClose() == null) {
+            // If the POJO doesn't handle the close, close the connection
+            try {
+                session.close(closeReason);
+            } catch (IOException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        } else {
             try {
                 methodMapping.getOnClose().invoke(pojo,
                         methodMapping.getOnCloseArgs(pathInfo, session));

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=1425145&r1=1425144&r2=1425145&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/WsFrame.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/WsFrame.java Fri Dec 21 21:04:07 2012
@@ -21,6 +21,8 @@ import java.io.IOException;
 import java.nio.ByteBuffer;
 
 import javax.servlet.ServletInputStream;
+import javax.websocket.CloseReason;
+import javax.websocket.CloseReason.CloseCodes;
 import javax.websocket.MessageHandler;
 import javax.websocket.PongMessage;
 
@@ -194,7 +196,19 @@ public class WsFrame {
                 return false;
             }
             if (opCode == Constants.OPCODE_CLOSE) {
-                wsSession.close();
+                messageBuffer.flip();
+                String reason = null;
+                int code = CloseCodes.NO_STATUS_CODE.getCode();
+                if (messageBuffer.remaining() > 1) {
+                    code = messageBuffer.getShort();
+                    if (messageBuffer.remaining() > 0) {
+                         reason = new String(messageBuffer.array(),
+                                messageBuffer.arrayOffset() + messageBuffer.position(),
+                                messageBuffer.remaining(), "UTF8");
+                    }
+                }
+                wsSession.onClose(
+                        new CloseReason(Util.getCloseCode(code), reason));
             } else if (opCode == Constants.OPCODE_PING) {
                 messageBuffer.flip();
                 wsSession.getRemote().sendPong(messageBuffer);

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=1425145&r1=1425144&r2=1425145&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/WsProtocolHandler.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/WsProtocolHandler.java Fri Dec 21 21:04:07 2012
@@ -58,7 +58,8 @@ public class WsProtocolHandler implement
         }
         WsFrame wsFrame = new WsFrame(sis, wsSession);
         sis.setReadListener(new WsReadListener(this, wsFrame, wsSession));
-        WsRemoteEndpoint wsRemoteEndpoint = new WsRemoteEndpoint(sos);
+        WsRemoteEndpoint wsRemoteEndpoint =
+                new WsRemoteEndpoint(wsSession, sos);
         wsSession.setRemote(wsRemoteEndpoint);
         sos.setWriteListener(new WsWriteListener(this, wsRemoteEndpoint));
 
@@ -108,8 +109,10 @@ public class WsProtocolHandler implement
             } catch (IOException e) {
                 if (e instanceof EOFException){
                     try {
-                        wsSession.close(new CloseReason(
-                                CloseCodes.CLOSED_ABNORMALLY, e.getMessage()));
+                        CloseReason cr = new CloseReason(
+                                CloseCodes.CLOSED_ABNORMALLY, e.getMessage());
+                        wsSession.onClose(cr);
+                        wsSession.close(cr);
                     } catch (IOException e1) {
                         // TODO
                     }

Modified: tomcat/trunk/java/org/apache/tomcat/websocket/WsRemoteEndpoint.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/WsRemoteEndpoint.java?rev=1425145&r1=1425144&r2=1425145&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/WsRemoteEndpoint.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/WsRemoteEndpoint.java Fri Dec 21 21:04:07 2012
@@ -37,6 +37,7 @@ import javax.websocket.SendResult;
 public class WsRemoteEndpoint implements RemoteEndpoint {
 
     private final ServletOutputStream sos;
+    private final WsSession wsSession;
     // Max length for outgoing WebSocket frame header is 10 bytes
     private final ByteBuffer header = ByteBuffer.allocate(10);
 
@@ -46,7 +47,8 @@ public class WsRemoteEndpoint implements
     private volatile CyclicBarrier writeBarrier = new CyclicBarrier(2);
 
 
-    public WsRemoteEndpoint(ServletOutputStream sos) {
+    public WsRemoteEndpoint(WsSession wsSession, ServletOutputStream sos) {
+        this.wsSession = wsSession;
         this.sos = sos;
     }
 
@@ -198,7 +200,7 @@ public class WsRemoteEndpoint implements
     }
 
 
-    private void sendMessage(byte opCode, ByteBuffer message,
+    protected void sendMessage(byte opCode, ByteBuffer message,
             boolean isFirstFragment, boolean isLastFragment) {
         // Clear header, ready for new message
         header.clear();
@@ -247,6 +249,15 @@ public class WsRemoteEndpoint implements
             // TODO Auto-generated catch block
             e.printStackTrace();
         }
+
+        if (Constants.OPCODE_CLOSE == opCode) {
+            try {
+                sos.close();
+            } catch (IOException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        }
     }
 
 
@@ -255,15 +266,13 @@ public class WsRemoteEndpoint implements
             try {
                 writeBarrier.await();
             } catch (InterruptedException | BrokenBarrierException e) {
-                // TODO Auto-generated catch block
-                e.printStackTrace();
+                wsSession.getLocalEndpoint().onError(e);
             }
         }
         try {
             sos.write(data.array(), data.arrayOffset(), data.limit());
         } catch (IOException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
+            wsSession.getLocalEndpoint().onError(e);
         }
     }
 }

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=1425145&r1=1425144&r2=1425145&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/WsSession.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/WsSession.java Fri Dec 21 21:04:07 2012
@@ -22,6 +22,7 @@ import java.lang.reflect.Type;
 import java.lang.reflect.TypeVariable;
 import java.net.URI;
 import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -38,14 +39,16 @@ import javax.websocket.Session;
 
 public class WsSession implements Session {
 
+    private static final Charset UTF8 = Charset.forName("UTF8");
+
     private final Endpoint localEndpoint;
-    private RemoteEndpoint remoteEndpoint;
+    private WsRemoteEndpoint wsRemoteEndpoint;
     private MessageHandler textMessageHandler = null;
     private MessageHandler binaryMessageHandler = null;
     private MessageHandler.Basic<PongMessage> pongMessageHandler =
             new DefaultPingMessageHandler(this);
 
-    public WsSession(Endpoint localEndpoint) {
+    protected WsSession(Endpoint localEndpoint) {
         this.localEndpoint = localEndpoint;
     }
 
@@ -194,20 +197,28 @@ public class WsSession implements Sessio
 
     @Override
     public RemoteEndpoint getRemote() {
-        return remoteEndpoint;
+        return wsRemoteEndpoint;
     }
 
 
     @Override
     public void close() throws IOException {
-        close(new CloseReason(CloseCodes.GOING_AWAY, ""));
+        close(new CloseReason(CloseCodes.NORMAL_CLOSURE, ""));
     }
 
 
     @Override
     public void close(CloseReason closeStatus) throws IOException {
         // TODO Send the close message to the remote endpoint
-        localEndpoint.onClose(closeStatus);
+        // 125 is maximum size for the payload of a control message
+        ByteBuffer msg = ByteBuffer.allocate(125);
+        msg.putShort((short) closeStatus.getCloseCode().getCode());
+        String reason = closeStatus.getReasonPhrase();
+        if (reason != null && reason.length() > 0) {
+            msg.put(reason.getBytes(UTF8));
+        }
+        msg.flip();
+        wsRemoteEndpoint.sendMessage(Constants.OPCODE_CLOSE, msg, true, true);
     }
 
 
@@ -246,25 +257,34 @@ public class WsSession implements Sessio
     }
 
 
-    public void setRemote(WsRemoteEndpoint remoteEndpoint) {
-        this.remoteEndpoint = remoteEndpoint;
+    protected void setRemote(WsRemoteEndpoint wsRemoteEndpoint) {
+        this.wsRemoteEndpoint = wsRemoteEndpoint;
     }
 
 
-    public MessageHandler getTextMessageHandler() {
+    protected MessageHandler getTextMessageHandler() {
         return textMessageHandler;
     }
 
 
-    public MessageHandler getBinaryMessageHandler() {
+    protected MessageHandler getBinaryMessageHandler() {
         return binaryMessageHandler;
     }
 
 
-    public MessageHandler.Basic<PongMessage> getPongMessageHandler() {
+    protected MessageHandler.Basic<PongMessage> getPongMessageHandler() {
         return pongMessageHandler;
     }
 
+    protected void onClose(CloseReason closeReason) {
+        localEndpoint.onClose(closeReason);
+    }
+
+
+    protected Endpoint getLocalEndpoint() {
+        return localEndpoint;
+    }
+
 
     // Protected so unit tests can use it
     protected static Class<?> getMessageType(MessageHandler listener) {

Modified: tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/chat/ChatAnnotation.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/chat/ChatAnnotation.java?rev=1425145&r1=1425144&r2=1425145&view=diff
==============================================================================
--- tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/chat/ChatAnnotation.java (original)
+++ tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/chat/ChatAnnotation.java Fri Dec 21 21:04:07 2012
@@ -56,6 +56,12 @@ public class ChatAnnotation {
 
     @WebSocketClose
     public void end() {
+        try {
+            session.close();
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
         connections.remove(this);
         String message = String.format("* %s %s",
                 nickname, "has disconnected.");

Modified: tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/echo/EchoEndpoint.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/echo/EchoEndpoint.java?rev=1425145&r1=1425144&r2=1425145&view=diff
==============================================================================
--- tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/echo/EchoEndpoint.java (original)
+++ tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/echo/EchoEndpoint.java Fri Dec 21 21:04:07 2012
@@ -18,6 +18,8 @@ package websocket.echo;
 
 import java.io.IOException;
 
+import javax.websocket.CloseReason;
+import javax.websocket.CloseReason.CloseCodes;
 import javax.websocket.Endpoint;
 import javax.websocket.MessageHandler;
 import javax.websocket.RemoteEndpoint;
@@ -25,12 +27,25 @@ import javax.websocket.Session;
 
 public class EchoEndpoint extends Endpoint{
 
+    private Session session;
+
     @Override
     public void onOpen(Session session) {
+        this.session = session;
         RemoteEndpoint remoteEndpoint = session.getRemote();
         session.addMessageHandler(new EchoMessageHandler(remoteEndpoint));
     }
 
+    @Override
+    public void onClose(CloseReason closeReason) {
+        try {
+            session.close(new CloseReason(CloseCodes.NORMAL_CLOSURE, null));
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+
     private static class EchoMessageHandler
             implements MessageHandler.Basic<String> {
 



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org