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/15 20:55:09 UTC

svn commit: r1422332 - in /tomcat/trunk: java/org/apache/tomcat/websocket/WsSession.java test/org/apache/tomcat/websocket/TestWsSession.java

Author: markt
Date: Sat Dec 15 19:55:08 2012
New Revision: 1422332

URL: http://svn.apache.org/viewvc?rev=1422332&view=rev
Log:
WebSocket 1.0 implementation part 16 of many
Re-write the code that identifies the type that a MessaheHandler is associated with. Doing it correctly is non-trivial. Includes a test case.

Added:
    tomcat/trunk/test/org/apache/tomcat/websocket/TestWsSession.java   (with props)
Modified:
    tomcat/trunk/java/org/apache/tomcat/websocket/WsSession.java

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=1422332&r1=1422331&r2=1422332&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/WsSession.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/WsSession.java Sat Dec 15 19:55:08 2012
@@ -19,6 +19,7 @@ package org.apache.tomcat.websocket;
 import java.io.IOException;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
 import java.net.URI;
 import java.nio.ByteBuffer;
 import java.util.HashSet;
@@ -59,24 +60,21 @@ public class WsSession implements Sessio
     @SuppressWarnings("unchecked")
     @Override
     public void addMessageHandler(MessageHandler listener) {
-        Type[] types = ((ParameterizedType) listener.getClass().getGenericSuperclass()).getActualTypeArguments();
-        if (types.length != 1) {
-            // TODO i18n
-            throw new IllegalArgumentException();
-        }
-        if (types[0].equals(String.class)) {
+        Type t = getMessageType(listener);
+
+        if (t.equals(String.class)) {
             if (textMessageHandler != null) {
                 // TODO i18n
                 throw new IllegalStateException();
             }
             textMessageHandler = listener;
-        } else if (types[0].equals(ByteBuffer.class)) {
+        } else if (t.equals(ByteBuffer.class)) {
             if (binaryMessageHandler != null) {
                 // TODO i18n
                 throw new IllegalStateException();
             }
             binaryMessageHandler = listener;
-        } else if (types[0].equals(PongMessage.class)) {
+        } else if (t.equals(PongMessage.class)) {
             if (pongMessageHandler != null) {
                 // TODO i18n
                 throw new IllegalStateException();
@@ -267,6 +265,79 @@ public class WsSession implements Sessio
         return pongMessageHandler;
     }
 
+
+    // Protected so unit tests can use it
+    protected static Class<?> getMessageType(MessageHandler listener) {
+        return (Class<?>) getMessageType(listener.getClass());
+    }
+
+
+    private static Object getMessageType(Class<? extends MessageHandler> clazz) {
+
+        // Look to see if this class implements the generic MessageHandler<>
+        // interface
+
+        // Get all the interfaces
+        Type[] interfaces = clazz.getGenericInterfaces();
+        for (Type iface : interfaces) {
+            // Only need to check interfaces that use generics
+            if (iface instanceof ParameterizedType) {
+                ParameterizedType pi = (ParameterizedType) iface;
+                // Look for the MessageHandler<> interface
+                if (pi.getRawType().equals(MessageHandler.Basic.class)
+                        || pi.getRawType().equals(MessageHandler.Async.class)) {
+                    // Whichever interface it is, there is only one generic
+                    // type.
+                    return getTypeParameter(
+                            clazz, pi.getActualTypeArguments()[0]);
+                }
+            }
+        }
+
+        // Interface not found on this class. Look at the superclass.
+        Class<? extends MessageHandler> superClazz =
+                (Class<? extends MessageHandler>) clazz.getSuperclass();
+
+        Object result = getMessageType(superClazz);
+        if (result instanceof Class<?>) {
+            // Superclass implements interface and defines explicit type for
+            // MessageHandler<>
+            return result;
+        } else if (result instanceof Integer) {
+            // Superclass implements interface and defines unknown type for
+            // MessageHandler<>
+            // Map that unknown type to the generic types defined in this class
+            ParameterizedType superClassType =
+                    (ParameterizedType) clazz.getGenericSuperclass();
+            return getTypeParameter(clazz,
+                    superClassType.getActualTypeArguments()[
+                            ((Integer) result).intValue()]);
+        } else {
+            // TODO: Something went wrong. Log an error.
+            return null;
+        }
+    }
+
+
+    /*
+     * For a generic parameter, return either the Class used or if the type
+     * is unknown, the index for the type in definition of the class
+     */
+    private static Object getTypeParameter(Class<?> clazz, Type argType) {
+        if (argType instanceof Class<?>) {
+            return argType;
+        } else {
+            TypeVariable<?>[] tvs = clazz.getTypeParameters();
+            for (int i = 0; i < tvs.length; i++) {
+                if (tvs[i].equals(argType)) {
+                    return Integer.valueOf(i);
+                }
+            }
+            return null;
+        }
+    }
+
+
     private static class DefaultPingMessageHandler implements
             MessageHandler.Basic<PongMessage> {
 

Added: tomcat/trunk/test/org/apache/tomcat/websocket/TestWsSession.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/websocket/TestWsSession.java?rev=1422332&view=auto
==============================================================================
--- tomcat/trunk/test/org/apache/tomcat/websocket/TestWsSession.java (added)
+++ tomcat/trunk/test/org/apache/tomcat/websocket/TestWsSession.java Sat Dec 15 19:55:08 2012
@@ -0,0 +1,135 @@
+/*
+ * 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 javax.websocket.MessageHandler;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestWsSession {
+
+    @Test
+    public void testGetMessageTypeSimple() {
+        Assert.assertEquals(
+                String.class, WsSession.getMessageType(new Simple()));
+    }
+
+
+    @Test
+    public void testGetMessageTypeSubclass() {
+        Assert.assertEquals(String.class,
+                WsSession.getMessageType(new SubSimple()));
+    }
+
+
+    @Test
+    public void testGetMessageTypeGenericSubclass() {
+        Assert.assertEquals(String.class,
+                WsSession.getMessageType(new GenericSub()));
+    }
+
+
+    @Test
+    public void testGetMessageTypeGenericMultipleSubclass() {
+        Assert.assertEquals(String.class,
+                WsSession.getMessageType(new GenericMultipleSubSub()));
+    }
+
+
+    @Test
+    public void testGetMessageTypeGenericMultipleSubclassSwap() {
+        Assert.assertEquals(String.class,
+                WsSession.getMessageType(new GenericMultipleSubSubSwap()));
+    }
+
+
+    private static class Simple implements MessageHandler.Basic<String> {
+        @Override
+        public void onMessage(String message) {
+            // NO-OP
+        }
+    }
+
+
+    private static class SubSimple extends Simple {
+    }
+
+
+    private abstract static class Generic<T>
+            implements MessageHandler.Basic<T> {
+    }
+
+
+    private static class GenericSub extends Generic<String>{
+
+        @Override
+        public void onMessage(String message) {
+            // NO-OP
+        }
+    }
+
+
+    private static interface Foo<T> {
+        void doSomething(T thing);
+    }
+
+
+    private abstract static class GenericMultiple<A,B>
+            implements MessageHandler.Basic<A>, Foo<B> {
+    }
+
+
+    private abstract static class GenericMultipleSub<X,Y>
+            extends GenericMultiple<X,Y> {
+    }
+
+
+    private static class GenericMultipleSubSub
+            extends GenericMultipleSub<String,Boolean> {
+
+        @Override
+        public void onMessage(String message) {
+            // NO-OP
+        }
+
+        @Override
+        public void doSomething(Boolean thing) {
+            // NO-OP
+        }
+    }
+
+
+    private abstract static class GenericMultipleSubSwap<Y,X>
+            extends GenericMultiple<X,Y> {
+    }
+
+
+    private static class GenericMultipleSubSubSwap
+            extends GenericMultipleSubSwap<Boolean,String> {
+
+        @Override
+        public void onMessage(String message) {
+            // NO-OP
+        }
+
+        @Override
+        public void doSomething(Boolean thing) {
+            // NO-OP
+        }
+    }
+}

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



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