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 2013/01/20 18:54:04 UTC

svn commit: r1435904 - in /tomcat/trunk: java/javax/websocket/ java/org/apache/tomcat/websocket/ java/org/apache/tomcat/websocket/server/ res/META-INF/tomcat-websocket.jar/services/ res/checkstyle/ test/org/apache/tomcat/websocket/ test/org/apache/tomc...

Author: markt
Date: Sun Jan 20 17:54:03 2013
New Revision: 1435904

URL: http://svn.apache.org/viewvc?rev=1435904&view=rev
Log:
Move server side specific code to separate package. Further refactoring is likely to be required as client side code is developed.

Added:
    tomcat/trunk/java/org/apache/tomcat/websocket/WsRemoteEndpointBase.java
      - copied, changed from r1434921, tomcat/trunk/java/org/apache/tomcat/websocket/WsRemoteEndpoint.java
    tomcat/trunk/java/org/apache/tomcat/websocket/server/
    tomcat/trunk/java/org/apache/tomcat/websocket/server/Constants.java   (with props)
    tomcat/trunk/java/org/apache/tomcat/websocket/server/LocalStrings.properties   (with props)
    tomcat/trunk/java/org/apache/tomcat/websocket/server/ServerContainerImpl.java
      - copied, changed from r1434927, tomcat/trunk/java/org/apache/tomcat/websocket/ServerContainerImpl.java
    tomcat/trunk/java/org/apache/tomcat/websocket/server/WsProtocolHandler.java
      - copied, changed from r1434921, tomcat/trunk/java/org/apache/tomcat/websocket/WsProtocolHandler.java
    tomcat/trunk/java/org/apache/tomcat/websocket/server/WsRemoteEndpointServer.java   (with props)
    tomcat/trunk/java/org/apache/tomcat/websocket/server/WsSci.java
      - copied, changed from r1434921, tomcat/trunk/java/org/apache/tomcat/websocket/WsSci.java
    tomcat/trunk/java/org/apache/tomcat/websocket/server/WsServlet.java
      - copied, changed from r1434921, tomcat/trunk/java/org/apache/tomcat/websocket/WsServlet.java
    tomcat/trunk/java/org/apache/tomcat/websocket/server/package-info.java   (with props)
    tomcat/trunk/test/org/apache/tomcat/websocket/TestWsWebSocketContainer.java   (with props)
    tomcat/trunk/test/org/apache/tomcat/websocket/server/
    tomcat/trunk/test/org/apache/tomcat/websocket/server/TestServerContainerImpl.java
      - copied, changed from r1434921, tomcat/trunk/test/org/apache/tomcat/websocket/TestUtil.java
Removed:
    tomcat/trunk/java/org/apache/tomcat/websocket/ServerContainerImpl.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/WsSci.java
    tomcat/trunk/java/org/apache/tomcat/websocket/WsServlet.java
    tomcat/trunk/test/org/apache/tomcat/websocket/TestUtil.java
Modified:
    tomcat/trunk/java/javax/websocket/WebSocketContainer.java
    tomcat/trunk/java/org/apache/tomcat/websocket/Constants.java
    tomcat/trunk/java/org/apache/tomcat/websocket/Util.java
    tomcat/trunk/java/org/apache/tomcat/websocket/WsFrame.java
    tomcat/trunk/java/org/apache/tomcat/websocket/WsSession.java
    tomcat/trunk/res/META-INF/tomcat-websocket.jar/services/javax.servlet.ServletContainerInitializer
    tomcat/trunk/res/checkstyle/org-import-control.xml
    tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/echo/WsConfigListener.java

Modified: tomcat/trunk/java/javax/websocket/WebSocketContainer.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/javax/websocket/WebSocketContainer.java?rev=1435904&r1=1435903&r2=1435904&view=diff
==============================================================================
--- tomcat/trunk/java/javax/websocket/WebSocketContainer.java (original)
+++ tomcat/trunk/java/javax/websocket/WebSocketContainer.java Sun Jan 20 17:54:03 2013
@@ -28,6 +28,21 @@ public interface WebSocketContainer {
     Session connectToServer(Class<?> annotatedEndpointClass, URI path)
             throws DeploymentException;
 
+    /**
+     * Creates a new connection to the WebSocket.
+     *
+     * @param endpoint
+     *            An instance of this class will be created to handle responses
+     *            from the server
+     * @param clientEndpointConfiguration
+     *            Used to configure the new connection
+     * @param path
+     *            The full URL of the WebSocket endpoint to connect to
+     *
+     * @return The WebSocket session for the connection
+     *
+     * @throws DeploymentException  If the connection can not be established
+     */
     Session connectToServer(Class<? extends Endpoint> endpoint,
             ClientEndpointConfiguration clientEndpointConfiguration, URI path)
             throws DeploymentException;

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=1435904&r1=1435903&r2=1435904&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/Constants.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/Constants.java Sun Jan 20 17:54:03 2013
@@ -23,7 +23,6 @@ public class Constants {
 
     protected static final String PACKAGE_NAME =
             Constants.class.getPackage().getName();
-    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;

Modified: tomcat/trunk/java/org/apache/tomcat/websocket/Util.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/Util.java?rev=1435904&r1=1435903&r2=1435904&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/Util.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/Util.java Sun Jan 20 17:54:03 2013
@@ -30,32 +30,6 @@ class Util {
     }
 
 
-    /**
-     * Converts a path defined for a WebSocket endpoint into a path that can be
-     * used as a servlet mapping.
-     *
-     * @param wsPath The WebSocket endpoint path to convert
-     * @return The servlet mapping
-     */
-    static String getServletPath(String wsPath) {
-        int templateStart = wsPath.indexOf('{');
-        if (templateStart == -1) {
-            if (wsPath.charAt(wsPath.length() - 1) == '/') {
-                return wsPath + '*';
-            } else {
-                return wsPath + "/*";
-            }
-        } else {
-            String temp = wsPath.substring(0, templateStart);
-            if (temp.charAt(temp.length() - 1) == '/') {
-                return temp + '*';
-            } else {
-                return temp.substring(0, temp.lastIndexOf('/') + 1) + '*';
-            }
-        }
-    }
-
-
     static CloseCode getCloseCode(int code) {
         if (code > 2999 && code < 5000) {
             return CloseCodes.NORMAL_CLOSURE;

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=1435904&r1=1435903&r2=1435904&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/WsFrame.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/WsFrame.java Sun Jan 20 17:54:03 2013
@@ -83,8 +83,13 @@ public class WsFrame {
         this.sis = sis;
         this.wsSession = wsSession;
 
+        // TODO This needs to work for client and server side code
+        /*
         int readBufferSize =
                 ServerContainerImpl.getServerContainer().getReadBufferSize();
+        */
+        // Temp hack until the above is resolved
+        int readBufferSize = 8192;
 
         inputBuffer = new byte[readBufferSize];
         messageBufferBinary = ByteBuffer.allocate(readBufferSize);

Copied: tomcat/trunk/java/org/apache/tomcat/websocket/WsRemoteEndpointBase.java (from r1434921, tomcat/trunk/java/org/apache/tomcat/websocket/WsRemoteEndpoint.java)
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/WsRemoteEndpointBase.java?p2=tomcat/trunk/java/org/apache/tomcat/websocket/WsRemoteEndpointBase.java&p1=tomcat/trunk/java/org/apache/tomcat/websocket/WsRemoteEndpoint.java&r1=1434921&r2=1435904&rev=1435904&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/WsRemoteEndpoint.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/WsRemoteEndpointBase.java Sun Jan 20 17:54:03 2013
@@ -24,35 +24,21 @@ import java.nio.CharBuffer;
 import java.nio.charset.Charset;
 import java.nio.charset.CharsetEncoder;
 import java.nio.charset.CoderResult;
-import java.util.concurrent.BrokenBarrierException;
-import java.util.concurrent.CyclicBarrier;
 import java.util.concurrent.Future;
 
-import javax.servlet.ServletOutputStream;
 import javax.websocket.EncodeException;
 import javax.websocket.RemoteEndpoint;
 import javax.websocket.SendHandler;
 import javax.websocket.SendResult;
 
-public class WsRemoteEndpoint implements RemoteEndpoint {
+public abstract class WsRemoteEndpointBase implements RemoteEndpoint {
 
-    private final Object messageWriteLock = new Object();
-
-    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);
 
     private final ByteBuffer textToByte = ByteBuffer.allocate(8192);
     private final CharsetEncoder encoder = Charset.forName("UTF8").newEncoder();
     private volatile Boolean isText = null;
-    private volatile CyclicBarrier writeBarrier = new CyclicBarrier(2);
-
-
-    public WsRemoteEndpoint(WsSession wsSession, ServletOutputStream sos) {
-        this.wsSession = wsSession;
-        this.sos = sos;
-    }
 
 
     @Override
@@ -200,14 +186,7 @@ public class WsRemoteEndpoint implements
     }
 
 
-    public void onWritePossible() {
-        try {
-            writeBarrier.await();
-        } catch (InterruptedException | BrokenBarrierException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        }
-    }
+    public abstract void onWritePossible();
 
 
     protected void sendMessage(byte opCode, ByteBuffer message,
@@ -250,50 +229,13 @@ public class WsRemoteEndpoint implements
         }
         header.flip();
 
-        // Could sync on sos but don't as other (user or container) code may
-        // sync on this creating the potential for deadlocks.
-        synchronized (messageWriteLock) {
-            doBlockingWrite(header);
-            doBlockingWrite(message);
-            try {
-                sos.flush();
-            } catch (IOException e) {
-                // 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();
-                }
-            }
-        }
-        if (opCode == Constants.OPCODE_CLOSE) {
-            // Connection is closing - ensure no threads are stuck waiting on
-            // the write barrier
-            writeBarrier.reset();
-        }
-    }
-
 
-    private void doBlockingWrite(ByteBuffer data) {
-        if (!sos.canWrite()) {
-            try {
-                writeBarrier.await();
-            } catch (InterruptedException | BrokenBarrierException e) {
-                wsSession.getLocalEndpoint().onError(wsSession, e);
-            }
-        }
-        try {
-            sos.write(data.array(), data.arrayOffset(), data.limit());
-        } catch (IOException e) {
-            wsSession.getLocalEndpoint().onError(wsSession, e);
-        }
+        writeMessage(opCode, header, message);
     }
 
+    protected abstract void writeMessage(int opCode, ByteBuffer header,
+            ByteBuffer message);
+
 
     @Override
     public void setBatchingAllowed(boolean batchingAllowed) {

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=1435904&r1=1435903&r2=1435904&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/WsSession.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/WsSession.java Sun Jan 20 17:54:03 2013
@@ -43,12 +43,12 @@ public class WsSession implements Sessio
     private static final Charset UTF8 = Charset.forName("UTF8");
 
     private final Endpoint localEndpoint;
-    private WsRemoteEndpoint wsRemoteEndpoint;
+    private WsRemoteEndpointBase wsRemoteEndpoint;
     private MessageHandler textMessageHandler = null;
     private MessageHandler binaryMessageHandler = null;
     private MessageHandler.Basic<PongMessage> pongMessageHandler = null;
 
-    protected WsSession(Endpoint localEndpoint) {
+    public WsSession(Endpoint localEndpoint) {
         this.localEndpoint = localEndpoint;
     }
 
@@ -250,7 +250,7 @@ public class WsSession implements Sessio
     }
 
 
-    protected void setRemote(WsRemoteEndpoint wsRemoteEndpoint) {
+    public void setRemote(WsRemoteEndpointBase wsRemoteEndpoint) {
         this.wsRemoteEndpoint = wsRemoteEndpoint;
     }
 
@@ -269,12 +269,12 @@ public class WsSession implements Sessio
         return pongMessageHandler;
     }
 
-    protected void onClose(CloseReason closeReason) {
+    public void onClose(CloseReason closeReason) {
         localEndpoint.onClose(this, closeReason);
     }
 
 
-    protected Endpoint getLocalEndpoint() {
+    public Endpoint getLocalEndpoint() {
         return localEndpoint;
     }
 

Added: tomcat/trunk/java/org/apache/tomcat/websocket/server/Constants.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/server/Constants.java?rev=1435904&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/server/Constants.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/server/Constants.java Sun Jan 20 17:54:03 2013
@@ -0,0 +1,31 @@
+/*
+ * 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.server;
+
+/**
+ * Internal implementation constants.
+ */
+public class Constants {
+
+    protected static final String PACKAGE_NAME =
+            Constants.class.getPackage().getName();
+    protected static final String SERVLET_NAME = WsServlet.class.getName();
+
+    private Constants() {
+        // Hide default constructor
+    }
+}

Propchange: tomcat/trunk/java/org/apache/tomcat/websocket/server/Constants.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tomcat/trunk/java/org/apache/tomcat/websocket/server/LocalStrings.properties
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/server/LocalStrings.properties?rev=1435904&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/server/LocalStrings.properties (added)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/server/LocalStrings.properties Sun Jan 20 17:54:03 2013
@@ -0,0 +1,37 @@
+# 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.
+sci.newInstance.fail=Failed to create an Endpoint instance of type [{0}]
+serverContainer.endpointDeploy=Endpoint class [{0}] deploying to path [{1}] in ServletContext [{2}]
+serverContainer.missingEndpoint=An Endpoint instance has been request for path [{0}] but no matching Endpoint class was found
+serverContainer.pojoDeploy=POJO class [{0}] deploying to path [{1}] in ServletContext [{2}]
+serverContainer.servletContextMismatch=Attempted to register a POJO annotated for WebSocket at path [{0}] in the ServletContext with context path [{1}] when the WebSocket ServerContainer is allocated to the ServletContext with context path [{2}]
+serverContainer.servletContextMissing=No ServletContext was specified
+uriTemplate.noMatch=The input template [{0}] generated the pattern [{1}] which did not match the supplied pathInfo [{2}]
+# Note the wsFrame.* messages are used as close reasons in WebSocket control
+# frames and therefore must be 123 bytes (not characters) or less in length.
+# Messages are encoded using UTF-8 where a single character may be encoded in
+# as many as 4 bytes.
+wsFrame.byteToLongFail=Too many bytes ([{0}]) were provided to be converted into a long
+wsFrame.controlFragmented=A fragmented control frame was received but control frames may not be fragmented
+wsFrame.controlPayloadTooBig=A control frame was sent with a payload of size [{0}] which is larger than the maximum permitted of 125 bytes
+wsFrame.controlNoFin=A control frame was sent that did not have the fin bit set. Control frames are not permitted to use continuation frames.
+wsFrame.invalidOpCode= A WebSocket frame was sent with an unrecognised opCode of [{0}]
+wsFrame.invalidUtf8=A WebSocket text frame was received that could not be decoded to UTF-8 because it contained invalid byte sequences
+wsFrame.invalidUtf8Close=A WebSocket close frame was received with a close reason that contained invalid UTF-8 byte sequences
+wsFrame.noContinuation=A new message was started when a continuation frame was expected
+wsFrame.notMasked=The client frame was not masked but all client frames must be masked
+wsFrame.oneByteCloseCode=The client sent a close frame with a single byte payload which is not valid
+wsFrame.textMessageTooBig=The decoded text message was too big for the output buffer and the endpoint does not support partial messages
+wsFrame.wrongRsv=The client frame set the reserved bits to [{0}] which was not supported by this endpoint
\ No newline at end of file

Propchange: tomcat/trunk/java/org/apache/tomcat/websocket/server/LocalStrings.properties
------------------------------------------------------------------------------
    svn:eol-style = native

Copied: tomcat/trunk/java/org/apache/tomcat/websocket/server/ServerContainerImpl.java (from r1434927, tomcat/trunk/java/org/apache/tomcat/websocket/ServerContainerImpl.java)
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/server/ServerContainerImpl.java?p2=tomcat/trunk/java/org/apache/tomcat/websocket/server/ServerContainerImpl.java&p1=tomcat/trunk/java/org/apache/tomcat/websocket/ServerContainerImpl.java&r1=1434927&r2=1435904&rev=1435904&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/ServerContainerImpl.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/server/ServerContainerImpl.java Sun Jan 20 17:54:03 2013
@@ -14,7 +14,7 @@
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
-package org.apache.tomcat.websocket;
+package org.apache.tomcat.websocket.server;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
@@ -31,6 +31,7 @@ import javax.websocket.server.ServerEndp
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 import org.apache.tomcat.util.res.StringManager;
+import org.apache.tomcat.websocket.WsWebSocketContainer;
 import org.apache.tomcat.websocket.pojo.PojoEndpointConfiguration;
 import org.apache.tomcat.websocket.pojo.PojoMethodMapping;
 
@@ -111,7 +112,7 @@ public class ServerContainerImpl extends
             throw new DeploymentException(sm.getString("sci.newInstance.fail",
                     endpointClass.getName()), e);
         }
-        String servletPath = Util.getServletPath(path);
+        String servletPath = getServletPath(path);
         if (log.isDebugEnabled()) {
             log.debug(sm.getString("serverContainer.endpointDeploy",
                     endpointClass.getName(), path,
@@ -150,7 +151,7 @@ public class ServerContainerImpl extends
             log.debug(sm.getString("serverContainer.pojoDeploy",
                     pojo.getName(), wsPath, servletContext.getContextPath()));
         }
-        String servletPath = Util.getServletPath(wsPath);
+        String servletPath = getServletPath(wsPath);
         // Remove the trailing /* before adding it to the map
         pojoMap.put(servletPath.substring(0, servletPath.length() - 2), pojo);
         pojoMethodMap.put(pojo,
@@ -201,4 +202,30 @@ public class ServerContainerImpl extends
     public void setReadBufferSize(int readBufferSize) {
         this.readBufferSize = readBufferSize;
     }
+
+
+    /**
+     * Converts a path defined for a WebSocket endpoint into a path that can be
+     * used as a servlet mapping.
+     *
+     * @param wsPath The WebSocket endpoint path to convert
+     * @return The servlet mapping
+     */
+    static String getServletPath(String wsPath) {
+        int templateStart = wsPath.indexOf('{');
+        if (templateStart == -1) {
+            if (wsPath.charAt(wsPath.length() - 1) == '/') {
+                return wsPath + '*';
+            } else {
+                return wsPath + "/*";
+            }
+        } else {
+            String temp = wsPath.substring(0, templateStart);
+            if (temp.charAt(temp.length() - 1) == '/') {
+                return temp + '*';
+            } else {
+                return temp.substring(0, temp.lastIndexOf('/') + 1) + '*';
+            }
+        }
+    }
 }

Copied: tomcat/trunk/java/org/apache/tomcat/websocket/server/WsProtocolHandler.java (from r1434921, tomcat/trunk/java/org/apache/tomcat/websocket/WsProtocolHandler.java)
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/server/WsProtocolHandler.java?p2=tomcat/trunk/java/org/apache/tomcat/websocket/server/WsProtocolHandler.java&p1=tomcat/trunk/java/org/apache/tomcat/websocket/WsProtocolHandler.java&r1=1434921&r2=1435904&rev=1435904&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/WsProtocolHandler.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/server/WsProtocolHandler.java Sun Jan 20 17:54:03 2013
@@ -14,7 +14,7 @@
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
-package org.apache.tomcat.websocket;
+package org.apache.tomcat.websocket.server;
 
 import java.io.EOFException;
 import java.io.IOException;
@@ -30,6 +30,10 @@ import javax.websocket.CloseReason.Close
 import javax.websocket.Endpoint;
 import javax.websocket.EndpointConfiguration;
 
+import org.apache.tomcat.websocket.WsFrame;
+import org.apache.tomcat.websocket.WsIOException;
+import org.apache.tomcat.websocket.WsSession;
+
 /**
  * Servlet 3.1 HTTP upgrade handler for WebSocket connections.
  */
@@ -69,10 +73,11 @@ public class WsProtocolHandler implement
         try {
             WsFrame wsFrame = new WsFrame(sis, wsSession);
             sis.setReadListener(new WsReadListener(this, wsFrame, wsSession));
-            WsRemoteEndpoint wsRemoteEndpoint =
-                    new WsRemoteEndpoint(wsSession, sos);
-            wsSession.setRemote(wsRemoteEndpoint);
-            sos.setWriteListener(new WsWriteListener(this, wsRemoteEndpoint));
+            WsRemoteEndpointServer wsRemoteEndpointServer =
+                    new WsRemoteEndpointServer(wsSession, sos);
+            wsSession.setRemote(wsRemoteEndpointServer);
+            sos.setWriteListener(
+                    new WsWriteListener(this, wsRemoteEndpointServer));
             ep.onOpen(wsSession, endpointConfig);
         } finally {
             t.setContextClassLoader(cl);
@@ -150,18 +155,18 @@ public class WsProtocolHandler implement
     private static class WsWriteListener implements WriteListener {
 
         private final WsProtocolHandler wsProtocolHandler;
-        private final WsRemoteEndpoint wsRemoteEndpoint;
+        private final WsRemoteEndpointServer wsRemoteEndpointServer;
 
         private WsWriteListener(WsProtocolHandler wsProtocolHandler,
-                WsRemoteEndpoint wsRemoteEndpoint) {
+                WsRemoteEndpointServer wsRemoteEndpointServer) {
             this.wsProtocolHandler = wsProtocolHandler;
-            this.wsRemoteEndpoint = wsRemoteEndpoint;
+            this.wsRemoteEndpointServer = wsRemoteEndpointServer;
         }
 
 
         @Override
         public void onWritePossible() {
-            wsRemoteEndpoint.onWritePossible();
+            wsRemoteEndpointServer.onWritePossible();
         }
 
 

Added: tomcat/trunk/java/org/apache/tomcat/websocket/server/WsRemoteEndpointServer.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/server/WsRemoteEndpointServer.java?rev=1435904&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/server/WsRemoteEndpointServer.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/server/WsRemoteEndpointServer.java Sun Jan 20 17:54:03 2013
@@ -0,0 +1,108 @@
+/*
+ * 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.server;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CyclicBarrier;
+
+import javax.servlet.ServletOutputStream;
+
+import org.apache.tomcat.websocket.Constants;
+import org.apache.tomcat.websocket.WsRemoteEndpointBase;
+import org.apache.tomcat.websocket.WsSession;
+
+/**
+ * This is the server side {@link RemoteEndpoint} implementation - i.e. what the
+ * server uses to send data to the client. Communication is over a
+ * {@link ServletOutputStream}.
+ */
+public class WsRemoteEndpointServer extends WsRemoteEndpointBase {
+
+    private final WsSession wsSession;
+    private final ServletOutputStream sos;
+    private final Object messageWriteLock = new Object();
+
+    private volatile CyclicBarrier writeBarrier = new CyclicBarrier(2);
+
+
+    public WsRemoteEndpointServer(WsSession wsSession,
+            ServletOutputStream sos) {
+        this.wsSession = wsSession;
+        this.sos = sos;
+    }
+
+
+    @Override
+    public void onWritePossible() {
+        try {
+            writeBarrier.await();
+        } catch (InterruptedException | BrokenBarrierException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+
+
+    @Override
+    protected void writeMessage(int opCode, ByteBuffer header,
+            ByteBuffer message) {
+        // Could sync on sos but don't as other (user or container) code may
+        // sync on this creating the potential for deadlocks.
+        synchronized (messageWriteLock) {
+            doBlockingWrite(header);
+            doBlockingWrite(message);
+            try {
+                sos.flush();
+            } catch (IOException e) {
+                // 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();
+                }
+            }
+        }
+        if (opCode == Constants.OPCODE_CLOSE) {
+            // Connection is closing - ensure no threads are stuck waiting on
+            // the write barrier
+            writeBarrier.reset();
+        }
+    }
+
+
+    private void doBlockingWrite(ByteBuffer data) {
+        if (!sos.canWrite()) {
+            try {
+                writeBarrier.await();
+            } catch (InterruptedException | BrokenBarrierException e) {
+                wsSession.getLocalEndpoint().onError(wsSession, e);
+            }
+        }
+        try {
+            sos.write(data.array(), data.arrayOffset(), data.limit());
+        } catch (IOException e) {
+            wsSession.getLocalEndpoint().onError(wsSession, e);
+        }
+    }
+}

Propchange: tomcat/trunk/java/org/apache/tomcat/websocket/server/WsRemoteEndpointServer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Copied: tomcat/trunk/java/org/apache/tomcat/websocket/server/WsSci.java (from r1434921, tomcat/trunk/java/org/apache/tomcat/websocket/WsSci.java)
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/server/WsSci.java?p2=tomcat/trunk/java/org/apache/tomcat/websocket/server/WsSci.java&p1=tomcat/trunk/java/org/apache/tomcat/websocket/WsSci.java&r1=1434921&r2=1435904&rev=1435904&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/WsSci.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/server/WsSci.java Sun Jan 20 17:54:03 2013
@@ -14,7 +14,7 @@
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
-package org.apache.tomcat.websocket;
+package org.apache.tomcat.websocket.server;
 
 import java.util.Set;
 
@@ -24,6 +24,7 @@ import javax.servlet.ServletException;
 import javax.servlet.annotation.HandlesTypes;
 import javax.websocket.server.WebSocketEndpoint;
 
+
 /**
  * Registers an interest in any class that is annotated with
  * {@link WebSocketEndpoint} so that Endpoint can be published via the WebSocket

Copied: tomcat/trunk/java/org/apache/tomcat/websocket/server/WsServlet.java (from r1434921, tomcat/trunk/java/org/apache/tomcat/websocket/WsServlet.java)
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/server/WsServlet.java?p2=tomcat/trunk/java/org/apache/tomcat/websocket/server/WsServlet.java&p1=tomcat/trunk/java/org/apache/tomcat/websocket/WsServlet.java&r1=1434921&r2=1435904&rev=1435904&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/WsServlet.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/server/WsServlet.java Sun Jan 20 17:54:03 2013
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.tomcat.websocket;
+package org.apache.tomcat.websocket.server;
 
 import java.io.IOException;
 import java.nio.charset.Charset;
@@ -38,6 +38,7 @@ import javax.websocket.Extension;
 import javax.websocket.server.ServerEndpointConfiguration;
 import javax.xml.bind.DatatypeConverter;
 
+
 /**
  * Handles the initial HTTP connection for WebSocket connections.
  */

Added: tomcat/trunk/java/org/apache/tomcat/websocket/server/package-info.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/server/package-info.java?rev=1435904&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/server/package-info.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/server/package-info.java Sun Jan 20 17:54:03 2013
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+/**
+ * Server-side specific implementation classes. These are in a separate package
+ * to make packaging a pure client JAR simpler.
+ */
+package org.apache.tomcat.websocket.server;
\ No newline at end of file

Propchange: tomcat/trunk/java/org/apache/tomcat/websocket/server/package-info.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/trunk/res/META-INF/tomcat-websocket.jar/services/javax.servlet.ServletContainerInitializer
URL: http://svn.apache.org/viewvc/tomcat/trunk/res/META-INF/tomcat-websocket.jar/services/javax.servlet.ServletContainerInitializer?rev=1435904&r1=1435903&r2=1435904&view=diff
==============================================================================
--- tomcat/trunk/res/META-INF/tomcat-websocket.jar/services/javax.servlet.ServletContainerInitializer (original)
+++ tomcat/trunk/res/META-INF/tomcat-websocket.jar/services/javax.servlet.ServletContainerInitializer Sun Jan 20 17:54:03 2013
@@ -1 +1 @@
-org.apache.tomcat.websocket.WsSci
+org.apache.tomcat.websocket.server.WsSci

Modified: tomcat/trunk/res/checkstyle/org-import-control.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/res/checkstyle/org-import-control.xml?rev=1435904&r1=1435903&r2=1435904&view=diff
==============================================================================
--- tomcat/trunk/res/checkstyle/org-import-control.xml (original)
+++ tomcat/trunk/res/checkstyle/org-import-control.xml Sun Jan 20 17:54:03 2013
@@ -138,12 +138,16 @@
       </subpackage>
     </subpackage>
     <subpackage name="websocket">
-      <allow pkg="javax.servlet"/>
       <allow pkg="javax.websocket"/>
       <allow pkg="org.apache.juli"/>
       <allow pkg="org.apache.tomcat.util"/>
       <!-- Ideally want to remove this -->
       <allow pkg="org.apache.tomcat.websocket.pojo"/>
+      <disallow pkg="javax.servlet"/>
+      <subpackage name="server">
+        <allow pkg="javax.servlet"/>
+        <allow pkg="org.apache.tomcat.websocket"/>
+      </subpackage>
     </subpackage>
   </subpackage>
 </import-control>
\ No newline at end of file

Added: tomcat/trunk/test/org/apache/tomcat/websocket/TestWsWebSocketContainer.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/websocket/TestWsWebSocketContainer.java?rev=1435904&view=auto
==============================================================================
--- tomcat/trunk/test/org/apache/tomcat/websocket/TestWsWebSocketContainer.java (added)
+++ tomcat/trunk/test/org/apache/tomcat/websocket/TestWsWebSocketContainer.java Sun Jan 20 17:54:03 2013
@@ -0,0 +1,109 @@
+/*
+ * 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.io.File;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.websocket.ContainerProvider;
+import javax.websocket.DefaultClientConfiguration;
+import javax.websocket.Endpoint;
+import javax.websocket.EndpointConfiguration;
+import javax.websocket.MessageHandler;
+import javax.websocket.Session;
+import javax.websocket.WebSocketContainer;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.apache.catalina.startup.Tomcat;
+import org.apache.catalina.startup.TomcatBaseTest;
+
+public class TestWsWebSocketContainer extends TomcatBaseTest {
+
+    private static final String MESSAGE_STRING_1 = "qwerty";
+
+    @Test
+    public void testConnectToServerEndpoint() throws Exception {
+        // Examples app includes WebSocket Echo endpoint
+        Tomcat tomcat = getTomcatInstance();
+        File appDir = new File(getBuildDirectory(), "webapps/examples");
+        tomcat.addWebapp(null, "/examples", appDir.getAbsolutePath());
+
+        tomcat.start();
+
+        WebSocketContainer wsContainer = ContainerProvider.getClientContainer();
+        Session wsSession = wsContainer.connectToServer(TesterEndpoint.class,
+                new DefaultClientConfiguration(), new URI("http://localhost:" +
+                        getPort() + "/examples/echoAnnotation"));
+        TesterMessageHandlerString handler = new TesterMessageHandlerString(1);
+        wsSession.addMessageHandler(handler);
+        wsSession.getRemote().sendString(MESSAGE_STRING_1);
+
+        boolean latchResult = handler.getLatch().await(10, TimeUnit.SECONDS);
+
+        Assert.assertTrue(latchResult);
+
+        List<String> messages = handler.getMessages();
+        Assert.assertEquals(1, messages.size());
+        Assert.assertEquals(MESSAGE_STRING_1, messages.get(0));
+    }
+
+    private static class TesterMessageHandlerString
+            implements MessageHandler.Basic<String> {
+
+        private final CountDownLatch latch;
+
+        private List<String> messages = new ArrayList<>();
+
+        public TesterMessageHandlerString(int latchCount) {
+            if (latchCount > 0) {
+                latch = new CountDownLatch(latchCount);
+            } else {
+                latch = null;
+            }
+        }
+
+        public List<String> getMessages() {
+            return messages;
+        }
+
+        public CountDownLatch getLatch() {
+            return latch;
+        }
+
+        @Override
+        public void onMessage(String message) {
+            if (latch != null) {
+                latch.countDown();
+            }
+            messages.add(message);
+        }
+    }
+
+    private static class TesterEndpoint extends Endpoint {
+
+        @Override
+        public void onOpen(Session session, EndpointConfiguration config) {
+            // TODO Auto-generated method stub
+        }
+    }
+}

Propchange: tomcat/trunk/test/org/apache/tomcat/websocket/TestWsWebSocketContainer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Copied: tomcat/trunk/test/org/apache/tomcat/websocket/server/TestServerContainerImpl.java (from r1434921, tomcat/trunk/test/org/apache/tomcat/websocket/TestUtil.java)
URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/websocket/server/TestServerContainerImpl.java?p2=tomcat/trunk/test/org/apache/tomcat/websocket/server/TestServerContainerImpl.java&p1=tomcat/trunk/test/org/apache/tomcat/websocket/TestUtil.java&r1=1434921&r2=1435904&rev=1435904&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/tomcat/websocket/TestUtil.java (original)
+++ tomcat/trunk/test/org/apache/tomcat/websocket/server/TestServerContainerImpl.java Sun Jan 20 17:54:03 2013
@@ -14,30 +14,30 @@
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
-package org.apache.tomcat.websocket;
+package org.apache.tomcat.websocket.server;
 
 import org.junit.Assert;
 import org.junit.Test;
 
-public class TestUtil {
+public class TestServerContainerImpl {
 
     @Test
     public void testGetServletMappingPath() throws Exception {
         Assert.assertEquals("/foo/*",
-                Util.getServletPath("/foo"));
+                ServerContainerImpl.getServletPath("/foo"));
         Assert.assertEquals("/foo/*",
-                Util.getServletPath("/foo/"));
+                ServerContainerImpl.getServletPath("/foo/"));
         Assert.assertEquals("/foo/bar/*",
-                Util.getServletPath("/foo/bar"));
+                ServerContainerImpl.getServletPath("/foo/bar"));
         Assert.assertEquals("/foo/bar/*",
-                Util.getServletPath("/foo/bar/"));
+                ServerContainerImpl.getServletPath("/foo/bar/"));
         Assert.assertEquals("/foo/*",
-                Util.getServletPath("/foo/{bar}"));
+                ServerContainerImpl.getServletPath("/foo/{bar}"));
         Assert.assertEquals("/foo/*",
-                Util.getServletPath("/foo/{bar}/"));
+                ServerContainerImpl.getServletPath("/foo/{bar}/"));
         Assert.assertEquals("/foo/*",
-                Util.getServletPath("/foo/x{bar}"));
+                ServerContainerImpl.getServletPath("/foo/x{bar}"));
         Assert.assertEquals("/foo/*",
-                Util.getServletPath("/foo/x{bar}/"));
+                ServerContainerImpl.getServletPath("/foo/x{bar}/"));
     }
 }

Modified: tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/echo/WsConfigListener.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/echo/WsConfigListener.java?rev=1435904&r1=1435903&r2=1435904&view=diff
==============================================================================
--- tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/echo/WsConfigListener.java (original)
+++ tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/echo/WsConfigListener.java Sun Jan 20 17:54:03 2013
@@ -23,7 +23,7 @@ import javax.servlet.annotation.WebListe
 import javax.websocket.DeploymentException;
 import javax.websocket.server.DefaultServerConfiguration;
 
-import org.apache.tomcat.websocket.ServerContainerImpl;
+import org.apache.tomcat.websocket.server.ServerContainerImpl;
 
 @WebListener
 public class WsConfigListener implements ServletContextListener {



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