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