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: [email protected]
For additional commands, e-mail: [email protected]