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