Author: markt
Date: Wed Jun 26 11:54:31 2013
New Revision: 1496889

URL: http://svn.apache.org/r1496889
Log:
Further refactoring towards a fix for BZ 55143

Modified:
    tomcat/trunk/java/org/apache/tomcat/websocket/LocalStrings.properties
    tomcat/trunk/java/org/apache/tomcat/websocket/Util.java
    tomcat/trunk/java/org/apache/tomcat/websocket/WsSession.java
    
tomcat/trunk/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeBinary.java
    
tomcat/trunk/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeText.java
    tomcat/trunk/java/org/apache/tomcat/websocket/pojo/PojoMethodMapping.java

Modified: tomcat/trunk/java/org/apache/tomcat/websocket/LocalStrings.properties
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/LocalStrings.properties?rev=1496889&r1=1496888&r2=1496889&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/LocalStrings.properties 
(original)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/LocalStrings.properties Wed 
Jun 26 11:54:31 2013
@@ -26,7 +26,9 @@ asyncChannelWrapperSecure.writeFail=Only
 
 backgroundProcessManager.processFailed=A background process failed
 
+util.invalidMessageHandler=The message handler provided does not have an 
onMessage(Object) method
 util.invalidType=Unable to coerce value [{0}] to type [{1}]. That type is not 
supported.
+util.unknownDecoderType=The Decoder type [{0}] is not recognized
 
 # 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.

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=1496889&r1=1496888&r2=1496889&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/Util.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/Util.java Wed Jun 26 11:54:31 
2013
@@ -16,13 +16,16 @@
  */
 package org.apache.tomcat.websocket;
 
+import java.lang.reflect.Method;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 import java.lang.reflect.TypeVariable;
 import java.nio.ByteBuffer;
 import java.security.NoSuchAlgorithmException;
 import java.security.SecureRandom;
+import java.util.ArrayList;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Queue;
 import java.util.Set;
 import java.util.concurrent.ConcurrentLinkedQueue;
@@ -30,11 +33,19 @@ import java.util.concurrent.ConcurrentLi
 import javax.websocket.CloseReason.CloseCode;
 import javax.websocket.CloseReason.CloseCodes;
 import javax.websocket.Decoder;
+import javax.websocket.Decoder.Binary;
+import javax.websocket.Decoder.BinaryStream;
+import javax.websocket.Decoder.Text;
+import javax.websocket.Decoder.TextStream;
+import javax.websocket.DeploymentException;
 import javax.websocket.Encoder;
+import javax.websocket.EndpointConfig;
 import javax.websocket.MessageHandler;
 import javax.websocket.PongMessage;
 
 import org.apache.tomcat.util.res.StringManager;
+import org.apache.tomcat.websocket.pojo.PojoMessageHandlerWholeBinary;
+import org.apache.tomcat.websocket.pojo.PojoMessageHandlerWholeText;
 
 /**
  * Utility class for internal use only within the
@@ -271,40 +282,179 @@ public class Util {
     }
 
 
+    public static List<DecoderEntry> getDecoders(
+            Class<? extends Decoder>[] decoderClazzes)
+                    throws DeploymentException{
+
+        List<DecoderEntry> result = new ArrayList<>();
+        for (Class<? extends Decoder> decoderClazz : decoderClazzes) {
+            // Need to instantiate decoder to ensure it is valid and that
+            // deployment can be failed if it is not
+            @SuppressWarnings("unused")
+            Decoder instance;
+            try {
+                instance = decoderClazz.newInstance();
+            } catch (InstantiationException | IllegalAccessException e) {
+                throw new DeploymentException(
+                        sm.getString("pojoMethodMapping.invalidDecoder",
+                                decoderClazz.getName()), e);
+            }
+            DecoderEntry entry = new DecoderEntry(
+                    Util.getDecoderType(decoderClazz), decoderClazz);
+            result.add(entry);
+        }
+
+        return result;
+    }
+
+
+
     public static Set<MessageHandlerResult> getMessageHandlers(
-            MessageHandler listener) {
+            MessageHandler listener, EndpointConfig endpointConfig) {
 
-        Type t = Util.getMessageType(listener);
+        Class<?> target = Util.getMessageType(listener);
 
         // Will never be more than 2 types
         Set<MessageHandlerResult> results = new HashSet<>(2);
 
         // Simple cases - handlers already accepts one of the types expected by
         // the frame handling code
-        if (String.class.isAssignableFrom((Class<?>) t)) {
+        if (String.class.isAssignableFrom(target)) {
             MessageHandlerResult result =
                     new MessageHandlerResult(listener,
                             MessageHandlerResultType.TEXT);
             results.add(result);
-        } else if (ByteBuffer.class.isAssignableFrom((Class<?>) t)) {
+        } else if (ByteBuffer.class.isAssignableFrom(target)) {
             MessageHandlerResult result =
                     new MessageHandlerResult(listener,
                             MessageHandlerResultType.BINARY);
             results.add(result);
-        } else if (PongMessage.class.isAssignableFrom((Class<?>) t)) {
+        } else if (PongMessage.class.isAssignableFrom(target)) {
             MessageHandlerResult result =
                     new MessageHandlerResult(listener,
                             MessageHandlerResultType.PONG);
             results.add(result);
+            // TODO byte[], Reader, InputStream
         } else {
-            // TODO Decoder handling
+            // More complex case - listener that requires a decoder
+            DecoderMatch decoderMatch;
+            try {
+                decoderMatch = new DecoderMatch(target,
+                        endpointConfig.getDecoders());
+            } catch (DeploymentException e) {
+                throw new IllegalArgumentException(e);
+            }
+            Method m = getOnMessageMethod(listener);
+            if (decoderMatch.getBinaryDecoders().size() > 0) {
+                MessageHandlerResult result = new MessageHandlerResult(
+                        new PojoMessageHandlerWholeBinary(listener, m,
+                                endpointConfig,
+                                decoderMatch.getBinaryDecoders()),
+                        MessageHandlerResultType.BINARY);
+                results.add(result);
+            }
+            if (decoderMatch.getTextDecoders().size() > 0) {
+                MessageHandlerResult result = new MessageHandlerResult(
+                        new PojoMessageHandlerWholeText(listener, m,
+                                endpointConfig, 
decoderMatch.getTextDecoders()),
+                        MessageHandlerResultType.TEXT);
+                results.add(result);
+            }
         }
 
         if (results.size() == 0) {
             throw new IllegalArgumentException(
-                    sm.getString("wsSession.unknownHandler", listener, t));
+                    sm.getString("wsSession.unknownHandler", listener, 
target));
         }
 
         return results;
     }
+
+
+    private static Method getOnMessageMethod(MessageHandler listener) {
+        try {
+            return listener.getClass().getMethod("onMessage", Object.class);
+        } catch (NoSuchMethodException | SecurityException e) {
+            throw new IllegalArgumentException(
+                    sm.getString("util.invalidMessageHandler"), e);
+        }
+    }
+
+    public static class DecoderEntry {
+
+        private final Class<?> clazz;
+        private final Class<? extends Decoder> decoderClazz;
+
+        public DecoderEntry(Class<?> clazz,
+                Class<? extends Decoder> decoderClazz) {
+            this.clazz = clazz;
+            this.decoderClazz = decoderClazz;
+        }
+
+        public Class<?> getClazz() {
+            return clazz;
+        }
+
+        public Class<? extends Decoder> getDecoderClazz() {
+            return decoderClazz;
+        }
+    }
+
+
+    private static class DecoderMatch {
+
+        private final List<Class<? extends Decoder>> textDecoders =
+                new ArrayList<>();
+        private final List<Class<? extends Decoder>> binaryDecoders =
+                new ArrayList<>();
+
+
+        public DecoderMatch(Class<?> target, List<Class<? extends Decoder>> 
decoders)
+                throws DeploymentException {
+            List<DecoderEntry> decoderEntries = getDecoders(
+                    decoders.toArray(new Class[decoders.size()]));
+            for (DecoderEntry decoderEntry : decoderEntries) {
+                if (decoderEntry.getClazz().isAssignableFrom(target)) {
+                    if (Binary.class.isAssignableFrom(
+                            decoderEntry.getDecoderClazz())) {
+                        binaryDecoders.add(decoderEntry.getDecoderClazz());
+                        // willDecode() method means this decoder may or may 
not
+                        // decode a message so need to carry on checking for
+                        // other matches
+                    } else if (BinaryStream.class.isAssignableFrom(
+                            decoderEntry.getDecoderClazz())) {
+                        binaryDecoders.add(decoderEntry.getDecoderClazz());
+                        // Stream decoders have to process the message so no
+                        // more decoders can be matched
+                        break;
+                    } else if (Text.class.isAssignableFrom(
+                            decoderEntry.getDecoderClazz())) {
+                        textDecoders.add(decoderEntry.getDecoderClazz());
+                        // willDecode() method means this decoder may or may 
not
+                        // decode a message so need to carry on checking for
+                        // other matches
+                    } else if (TextStream.class.isAssignableFrom(
+                            decoderEntry.getDecoderClazz())) {
+                        textDecoders.add(decoderEntry.getDecoderClazz());
+                        // Stream decoders have to process the message so no
+                        // more decoders can be matched
+                        break;
+                    } else {
+                        throw new IllegalArgumentException(
+                                sm.getString("util.unknownDecoderType"));
+                    }
+                }
+            }
+        }
+
+
+        public List<Class<? extends Decoder>> getTextDecoders() {
+            return textDecoders;
+        }
+
+
+        public List<Class<? extends Decoder>> getBinaryDecoders() {
+            return binaryDecoders;
+        }
+    }
 }

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=1496889&r1=1496888&r2=1496889&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/WsSession.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/WsSession.java Wed Jun 26 
11:54:31 2013
@@ -64,6 +64,7 @@ public class WsSession implements Sessio
     private final Map<String,List<String>> requestParameterMap;
     private final String queryString;
     private final Principal userPrincipal;
+    private final EndpointConfig endpointConfig;
 
     private final String subProtocol;
     private final Map<String,String> pathParameters;
@@ -132,6 +133,7 @@ public class WsSession implements Sessio
         this.pathParameters = pathParameters;
         this.secure = secure;
         this.wsRemoteEndpoint.setEncoders(endpointConfig);
+        this.endpointConfig = endpointConfig;
 
         this.userProperties.putAll(endpointConfig.getUserProperties());
         this.id = Long.toHexString(ids.getAndIncrement());
@@ -161,7 +163,8 @@ public class WsSession implements Sessio
         // arbitrary objects with MessageHandlers and can wrap MessageHandlers
         // just as easily.
 
-        Set<MessageHandlerResult> mhResults = 
Util.getMessageHandlers(listener);
+        Set<MessageHandlerResult> mhResults =
+                Util.getMessageHandlers(listener, endpointConfig);
 
         for (MessageHandlerResult mhResult : mhResults) {
             switch (mhResult.getType()) {

Modified: 
tomcat/trunk/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeBinary.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeBinary.java?rev=1496889&r1=1496888&r2=1496889&view=diff
==============================================================================
--- 
tomcat/trunk/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeBinary.java
 (original)
+++ 
tomcat/trunk/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeBinary.java
 Wed Jun 26 11:54:31 2013
@@ -28,6 +28,7 @@ import javax.websocket.Decoder;
 import javax.websocket.Decoder.Binary;
 import javax.websocket.Decoder.BinaryStream;
 import javax.websocket.EndpointConfig;
+import javax.websocket.MessageHandler;
 import javax.websocket.Session;
 
 import org.apache.tomcat.util.res.StringManager;
@@ -73,6 +74,25 @@ public class PojoMessageHandlerWholeBina
     }
 
 
+    public PojoMessageHandlerWholeBinary(MessageHandler listener,
+            Method method, EndpointConfig config,
+            List<Class<? extends Decoder>> binaryDecoders) {
+        super(listener, method, null, new Object[1], -1, false, -1);
+
+        try {
+            for (Class<? extends Decoder> decoderClazz : binaryDecoders) {
+                Binary<?> decoder = (Binary<?>) decoderClazz.newInstance();
+                decoder.init(config);
+                decoders.add(decoder);
+            }
+        } catch (IllegalAccessException | InstantiationException e) {
+            throw new IllegalArgumentException(e);
+        }
+
+        this.isForInputStream = false;
+    }
+
+
     @Override
     protected Object decode(ByteBuffer message) throws DecodeException {
         for (Decoder decoder : decoders) {

Modified: 
tomcat/trunk/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeText.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeText.java?rev=1496889&r1=1496888&r2=1496889&view=diff
==============================================================================
--- 
tomcat/trunk/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeText.java
 (original)
+++ 
tomcat/trunk/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeText.java
 Wed Jun 26 11:54:31 2013
@@ -27,6 +27,7 @@ import javax.websocket.Decoder;
 import javax.websocket.Decoder.Text;
 import javax.websocket.Decoder.TextStream;
 import javax.websocket.EndpointConfig;
+import javax.websocket.MessageHandler;
 import javax.websocket.Session;
 
 import org.apache.tomcat.util.res.StringManager;
@@ -81,6 +82,25 @@ public class PojoMessageHandlerWholeText
     }
 
 
+    public PojoMessageHandlerWholeText(MessageHandler listener,
+            Method method, EndpointConfig config,
+            List<Class<? extends Decoder>> textDecoders) {
+        super(listener, method, null, new Object[1], -1, false, -1);
+
+        try {
+            for (Class<? extends Decoder> decoderClazz : textDecoders) {
+                Text<?> decoder = (Text<?>) decoderClazz.newInstance();
+                decoder.init(config);
+                decoders.add(decoder);
+            }
+        } catch (IllegalAccessException | InstantiationException e) {
+            throw new IllegalArgumentException(e);
+        }
+
+        primitiveType = null;
+    }
+
+
     @Override
     protected Object decode(String message) throws DecodeException {
         // Handle primitives

Modified: 
tomcat/trunk/java/org/apache/tomcat/websocket/pojo/PojoMethodMapping.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/pojo/PojoMethodMapping.java?rev=1496889&r1=1496888&r2=1496889&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/pojo/PojoMethodMapping.java 
(original)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/pojo/PojoMethodMapping.java 
Wed Jun 26 11:54:31 2013
@@ -21,7 +21,6 @@ import java.io.Reader;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
 import java.nio.ByteBuffer;
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -46,6 +45,7 @@ import javax.websocket.server.PathParam;
 
 import org.apache.tomcat.util.res.StringManager;
 import org.apache.tomcat.websocket.Util;
+import org.apache.tomcat.websocket.Util.DecoderEntry;
 
 /**
  * For a POJO class annotated with
@@ -74,7 +74,7 @@ public class PojoMethodMapping {
 
         this.wsPath = wsPath;
 
-        List<DecoderEntry> decoders = getDecoders(decoderClazzes);
+        List<DecoderEntry> decoders = Util.getDecoders(decoderClazzes);
         Method open = null;
         Method close = null;
         Method error = null;
@@ -174,32 +174,6 @@ public class PojoMethodMapping {
     }
 
 
-    private static List<DecoderEntry> getDecoders(
-            Class<? extends Decoder>[] decoderClazzes)
-                    throws DeploymentException{
-
-        List<DecoderEntry> result = new ArrayList<>();
-        for (Class<? extends Decoder> decoderClazz : decoderClazzes) {
-            // Need to instantiate decoder to ensure it is valid and that
-            // deployment can be failed if it is not
-            @SuppressWarnings("unused")
-            Decoder instance;
-            try {
-                instance = decoderClazz.newInstance();
-            } catch (InstantiationException | IllegalAccessException e) {
-                throw new DeploymentException(
-                        sm.getString("pojoMethodMapping.invalidDecoder",
-                                decoderClazz.getName()), e);
-            }
-            DecoderEntry entry = new DecoderEntry(
-                    Util.getDecoderType(decoderClazz), decoderClazz);
-            result.add(entry);
-        }
-
-        return result;
-    }
-
-
     private static PojoPathParam[] getPathParams(Method m,
             MethodType methodType) {
         if (m == null) {
@@ -593,27 +567,6 @@ public class PojoMethodMapping {
     }
 
 
-    private static class DecoderEntry {
-
-        private final Class<?> clazz;
-        private final Class<? extends Decoder> decoderClazz;
-
-        public DecoderEntry(Class<?> clazz,
-                Class<? extends Decoder> decoderClazz) {
-            this.clazz = clazz;
-            this.decoderClazz = decoderClazz;
-        }
-
-        public Class<?> getClazz() {
-            return clazz;
-        }
-
-        public Class<? extends Decoder> getDecoderClazz() {
-            return decoderClazz;
-        }
-    }
-
-
     private static enum MethodType {
         ON_OPEN,
         ON_CLOSE,



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

Reply via email to