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 2021/05/05 15:01:49 UTC

[tomcat] branch master updated (0235fd7 -> a23c578)

This is an automated email from the ASF dual-hosted git repository.

markt pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/tomcat.git.


    from 0235fd7  Remove trailing space
     new 56ce1d9  Refactor with a view towards using the InstanceManager with decoders
     new c48f647  Create/destroy Decoders via the InstanceManager (BZ 65262)
     new a23c578  Complete fix for BZ 65262. Encoders and decoders now use InstanceManager

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../tomcat/websocket/LocalStrings.properties       |  1 +
 .../apache/tomcat/websocket/PojoClassHolder.java   |  2 +-
 java/org/apache/tomcat/websocket/PojoHolder.java   |  2 +-
 java/org/apache/tomcat/websocket/Util.java         | 80 ++++++++++++++++------
 .../tomcat/websocket/WsRemoteEndpointImplBase.java | 21 +++++-
 java/org/apache/tomcat/websocket/WsSession.java    |  2 +-
 .../tomcat/websocket/pojo/LocalStrings.properties  |  2 +
 .../tomcat/websocket/pojo/PojoEndpointClient.java  |  9 +++
 .../pojo/PojoMessageHandlerWholeBase.java          | 43 +++++++++++-
 .../pojo/PojoMessageHandlerWholeBinary.java        | 23 ++-----
 .../pojo/PojoMessageHandlerWholeText.java          | 22 ++----
 .../tomcat/websocket/pojo/PojoMethodMapping.java   | 37 ++++++++--
 .../tomcat/websocket/server/WsServerContainer.java | 23 ++++---
 .../tomcat/websocket/TesterWsClientAutobahn.java   |  2 +-
 webapps/docs/changelog.xml                         |  6 +-
 15 files changed, 199 insertions(+), 76 deletions(-)

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


[tomcat] 03/03: Complete fix for BZ 65262. Encoders and decoders now use InstanceManager

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit a23c5788012712609c760a77f9cebfc45aaa29d9
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Wed May 5 15:14:30 2021 +0100

    Complete fix for BZ 65262. Encoders and decoders now use InstanceManager
    
    https://bz.apache.org/bugzilla/show_bug.cgi?id=65262
---
 .../apache/tomcat/websocket/LocalStrings.properties |  1 +
 .../tomcat/websocket/WsRemoteEndpointImplBase.java  | 21 +++++++++++++++++++--
 .../tomcat/websocket/server/WsServerContainer.java  | 21 ++++++++++++++-------
 webapps/docs/changelog.xml                          |  6 +++---
 4 files changed, 37 insertions(+), 12 deletions(-)

diff --git a/java/org/apache/tomcat/websocket/LocalStrings.properties b/java/org/apache/tomcat/websocket/LocalStrings.properties
index 3ee86ae..382cc04 100644
--- a/java/org/apache/tomcat/websocket/LocalStrings.properties
+++ b/java/org/apache/tomcat/websocket/LocalStrings.properties
@@ -92,6 +92,7 @@ wsRemoteEndpoint.closed=Message will not be sent because the WebSocket session h
 wsRemoteEndpoint.closedDuringMessage=The remainder of the message will not be sent because the WebSocket session has been closed
 wsRemoteEndpoint.closedOutputStream=This method may not be called as the OutputStream has been closed
 wsRemoteEndpoint.closedWriter=This method may not be called as the Writer has been closed
+wsRemoteEndpoint.encoderDestoryFailed=Failed to destroy the encoder of type [{0}]
 wsRemoteEndpoint.flushOnCloseFailed=Batched messages still enabled after session has been closed. Unable to flush remaining batched message.
 wsRemoteEndpoint.invalidEncoder=The specified encoder of type [{0}] could not be instantiated
 wsRemoteEndpoint.noEncoder=No encoder specified for object of class [{0}]
diff --git a/java/org/apache/tomcat/websocket/WsRemoteEndpointImplBase.java b/java/org/apache/tomcat/websocket/WsRemoteEndpointImplBase.java
index aaeebd8..cbc1a72 100644
--- a/java/org/apache/tomcat/websocket/WsRemoteEndpointImplBase.java
+++ b/java/org/apache/tomcat/websocket/WsRemoteEndpointImplBase.java
@@ -19,6 +19,7 @@ package org.apache.tomcat.websocket;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.Writer;
+import java.lang.reflect.InvocationTargetException;
 import java.net.SocketTimeoutException;
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
@@ -33,6 +34,8 @@ import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 
+import javax.naming.NamingException;
+
 import jakarta.websocket.CloseReason;
 import jakarta.websocket.CloseReason.CloseCodes;
 import jakarta.websocket.DeploymentException;
@@ -45,6 +48,7 @@ import jakarta.websocket.SendResult;
 
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.InstanceManager;
 import org.apache.tomcat.util.ExceptionUtils;
 import org.apache.tomcat.util.buf.Utf8Encoder;
 import org.apache.tomcat.util.res.StringManager;
@@ -704,10 +708,15 @@ public abstract class WsRemoteEndpointImplBase implements RemoteEndpoint {
         for (Class<? extends Encoder> encoderClazz :
                 endpointConfig.getEncoders()) {
             Encoder instance;
+            InstanceManager instanceManager = wsSession.getInstanceManager();
             try {
-                instance = encoderClazz.getConstructor().newInstance();
+                if (instanceManager == null) {
+                    instance = encoderClazz.getConstructor().newInstance();
+                } else {
+                    instance = (Encoder) instanceManager.newInstance(encoderClazz);
+                }
                 instance.init(endpointConfig);
-            } catch (ReflectiveOperationException e) {
+            } catch (ReflectiveOperationException | NamingException e) {
                 throw new DeploymentException(
                         sm.getString("wsRemoteEndpoint.invalidEncoder",
                                 encoderClazz.getName()), e);
@@ -730,8 +739,16 @@ public abstract class WsRemoteEndpointImplBase implements RemoteEndpoint {
 
 
     public final void close() {
+        InstanceManager instanceManager = wsSession.getInstanceManager();
         for (EncoderEntry entry : encoderEntries) {
             entry.getEncoder().destroy();
+            if (instanceManager != null) {
+                try {
+                    instanceManager.destroyInstance(entry);
+                } catch (IllegalAccessException | InvocationTargetException e) {
+                    log.warn(sm.getString("wsRemoteEndpoint.encoderDestoryFailed", encoder.getClass()), e);
+                }
+            }
         }
         // The transformation handles both input and output. It only needs to be
         // closed once so it is closed here on the output side.
diff --git a/java/org/apache/tomcat/websocket/server/WsServerContainer.java b/java/org/apache/tomcat/websocket/server/WsServerContainer.java
index 96c1422..e269f8b 100644
--- a/java/org/apache/tomcat/websocket/server/WsServerContainer.java
+++ b/java/org/apache/tomcat/websocket/server/WsServerContainer.java
@@ -25,6 +25,8 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentSkipListMap;
 
+import javax.naming.NamingException;
+
 import jakarta.servlet.DispatcherType;
 import jakarta.servlet.FilterRegistration;
 import jakarta.servlet.ServletContext;
@@ -248,7 +250,7 @@ public class WsServerContainer extends WsWebSocketContainer
             String path = annotation.value();
 
             // Validate encoders
-            validateEncoders(annotation.encoders());
+            validateEncoders(annotation.encoders(), getInstanceManager(Thread.currentThread().getContextClassLoader()));
 
             // ServerEndpointConfig
             Class<? extends Configurator> configuratorClazz =
@@ -463,17 +465,22 @@ public class WsServerContainer extends WsWebSocketContainer
     }
 
 
-    private static void validateEncoders(Class<? extends Encoder>[] encoders)
+    private static void validateEncoders(Class<? extends Encoder>[] encoders, InstanceManager instanceManager)
             throws DeploymentException {
 
         for (Class<? extends Encoder> encoder : encoders) {
-            // Need to instantiate decoder to ensure it is valid and that
-            // deployment can be failed if it is not
-            @SuppressWarnings("unused")
+            // Need to instantiate encoder to ensure it is valid and that
+            // deployment can be failed if it is not. The encoder is then
+            // discarded immediately.
             Encoder instance;
             try {
-                encoder.getConstructor().newInstance();
-            } catch(ReflectiveOperationException e) {
+                if (instanceManager == null) {
+                    instance = encoder.getConstructor().newInstance();
+                } else {
+                    instance = (Encoder) instanceManager.newInstance(encoder);
+                    instanceManager.destroyInstance(instance);
+                }
+            } catch(ReflectiveOperationException | NamingException e) {
                 throw new DeploymentException(sm.getString(
                         "serverContainer.encoderFail", encoder.getName()), e);
             }
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 07810c6..f1ca839 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -180,9 +180,9 @@
         simplify the code. (markt)
       </scode>
       <fix>
-        <bug>65262</bug>: Refactor the creation of WebSocket end point instances
-        to be more IoC friendly. Instances are now created via the
-        <code>InstanceManager</code> where possible. (markt)
+        <bug>65262</bug>: Refactor the creation of WebSocket end point, decoder
+        and encoder instances to be more IoC friendly. Instances are now created
+        via the <code>InstanceManager</code> where possible. (markt)
       </fix>
     </changelog>
   </subsection>

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


[tomcat] 02/03: Create/destroy Decoders via the InstanceManager (BZ 65262)

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit c48f647d951f20d5b51a5ad3f3dbd07be05c3e3e
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Wed Apr 28 12:47:31 2021 +0100

    Create/destroy Decoders via the InstanceManager (BZ 65262)
---
 .../apache/tomcat/websocket/PojoClassHolder.java   |  2 +-
 java/org/apache/tomcat/websocket/PojoHolder.java   |  2 +-
 java/org/apache/tomcat/websocket/Util.java         | 80 ++++++++++++++++------
 .../tomcat/websocket/pojo/LocalStrings.properties  |  2 +
 .../tomcat/websocket/pojo/PojoEndpointClient.java  |  9 +++
 .../pojo/PojoMessageHandlerWholeBase.java          | 29 ++++++++
 .../pojo/PojoMessageHandlerWholeBinary.java        | 12 ++--
 .../pojo/PojoMessageHandlerWholeText.java          | 12 ++--
 .../tomcat/websocket/pojo/PojoMethodMapping.java   | 37 ++++++++--
 .../tomcat/websocket/server/WsServerContainer.java |  2 +-
 .../tomcat/websocket/TesterWsClientAutobahn.java   |  2 +-
 11 files changed, 148 insertions(+), 41 deletions(-)

diff --git a/java/org/apache/tomcat/websocket/PojoClassHolder.java b/java/org/apache/tomcat/websocket/PojoClassHolder.java
index e2c1da8..61e338b 100644
--- a/java/org/apache/tomcat/websocket/PojoClassHolder.java
+++ b/java/org/apache/tomcat/websocket/PojoClassHolder.java
@@ -54,7 +54,7 @@ public class PojoClassHolder implements ClientEndpointHolder {
             } else {
                 pojo = instanceManager.newInstance(pojoClazz);
             }
-            return new PojoEndpointClient(pojo, clientEndpointConfig.getDecoders());
+            return new PojoEndpointClient(pojo, clientEndpointConfig.getDecoders(), instanceManager);
         } catch (ReflectiveOperationException | SecurityException | NamingException e) {
             throw new DeploymentException(sm.getString("clientEndpointHolder.instanceCreationFailed"), e);
         }
diff --git a/java/org/apache/tomcat/websocket/PojoHolder.java b/java/org/apache/tomcat/websocket/PojoHolder.java
index 7195944..8ff3f42 100644
--- a/java/org/apache/tomcat/websocket/PojoHolder.java
+++ b/java/org/apache/tomcat/websocket/PojoHolder.java
@@ -55,6 +55,6 @@ public class PojoHolder implements ClientEndpointHolder {
                 throw new DeploymentException(sm.getString("clientEndpointHolder.instanceRegistrationFailed"), e);
             }
         }
-        return new PojoEndpointClient(pojo, clientEndpointConfig.getDecoders());
+        return new PojoEndpointClient(pojo, clientEndpointConfig.getDecoders(), instanceManager);
     }
 }
diff --git a/java/org/apache/tomcat/websocket/Util.java b/java/org/apache/tomcat/websocket/Util.java
index ac8ea2d..6095f54 100644
--- a/java/org/apache/tomcat/websocket/Util.java
+++ b/java/org/apache/tomcat/websocket/Util.java
@@ -33,6 +33,8 @@ import java.util.Queue;
 import java.util.Set;
 import java.util.concurrent.ConcurrentLinkedQueue;
 
+import javax.naming.NamingException;
+
 import jakarta.websocket.CloseReason.CloseCode;
 import jakarta.websocket.CloseReason.CloseCodes;
 import jakarta.websocket.Decoder;
@@ -48,6 +50,7 @@ import jakarta.websocket.MessageHandler;
 import jakarta.websocket.PongMessage;
 import jakarta.websocket.Session;
 
+import org.apache.tomcat.InstanceManager;
 import org.apache.tomcat.util.res.StringManager;
 import org.apache.tomcat.websocket.pojo.PojoMessageHandlerPartialBinary;
 import org.apache.tomcat.websocket.pojo.PojoMessageHandlerWholeBinary;
@@ -330,26 +333,59 @@ public class Util {
     }
 
 
-    public static List<DecoderEntry> getDecoders(
-            List<Class<? extends Decoder>> decoderClazzes)
-                    throws DeploymentException{
+    /**
+     * Build the list of decoder entries from a set of decoder implementations.
+     *
+     * @param decoderClazzes Decoder implementation classes
+     *
+     * @return List of mappings from target type to associated decoder
+     *
+     * @throws DeploymentException If a provided decoder class is not valid
+     *
+     * @deprecated Will be removed in Tomcat 10.1.x.
+     *             Use {@link Util#getDecoders(List, InstanceManager)}
+     */
+    @Deprecated
+    public static List<DecoderEntry> getDecoders(List<Class<? extends Decoder>> decoderClazzes)
+            throws DeploymentException {
+        return getDecoders(decoderClazzes, null);
+    }
+
+
+    /**
+     * Build the list of decoder entries from a set of decoder implementations.
+     *
+     * @param decoderClazzes    Decoder implementation classes
+     * @param instanceManager   Instance manager to use to create Decoder
+     *                              instances
+     *
+     * @return List of mappings from target type to associated decoder
+     *
+     * @throws DeploymentException If a provided decoder class is not valid
+     */
+    public static List<DecoderEntry> getDecoders(List<Class<? extends Decoder>> decoderClazzes,
+            InstanceManager instanceManager) throws DeploymentException{
 
         List<DecoderEntry> result = new ArrayList<>();
         if (decoderClazzes != null) {
             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.getConstructor().newInstance();
-                } catch (ReflectiveOperationException e) {
+                    if (instanceManager == null) {
+                        instance = decoderClazz.getConstructor().newInstance();
+                    } else {
+                        instance = (Decoder) instanceManager.newInstance(decoderClazz);
+                        // Don't need this instance, so destroy it
+                        instanceManager.destroyInstance(instance);
+                    }
+                } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException |
+                        NamingException e) {
                     throw new DeploymentException(
-                            sm.getString("pojoMethodMapping.invalidDecoder",
-                                    decoderClazz.getName()), e);
+                            sm.getString("pojoMethodMapping.invalidDecoder", decoderClazz.getName()), e);
                 }
-                DecoderEntry entry = new DecoderEntry(
-                        Util.getDecoderType(decoderClazz), decoderClazz);
+                DecoderEntry entry = new DecoderEntry(Util.getDecoderType(decoderClazz), decoderClazz);
                 result.add(entry);
             }
         }
@@ -388,8 +424,9 @@ public class Util {
             boolean whole = MessageHandler.Whole.class.isAssignableFrom(listener.getClass());
             MessageHandlerResult result = new MessageHandlerResult(
                     whole ? new PojoMessageHandlerWholeBinary(listener,
-                                    getOnMessageMethod(listener), session,
-                                    endpointConfig, matchDecoders(target, endpointConfig, true),
+                                    getOnMessageMethod(listener), session, endpointConfig,
+                                    matchDecoders(target, endpointConfig, true,
+                                            ((WsSession) session).getInstanceManager()),
                                     new Object[1], 0, true, -1, false, -1) :
                             new PojoMessageHandlerPartialBinary(listener,
                                     getOnMessagePartialMethod(listener), session,
@@ -399,23 +436,24 @@ public class Util {
         } else if (InputStream.class.isAssignableFrom(target)) {
             MessageHandlerResult result = new MessageHandlerResult(
                     new PojoMessageHandlerWholeBinary(listener,
-                            getOnMessageMethod(listener), session,
-                            endpointConfig, matchDecoders(target, endpointConfig, true),
+                            getOnMessageMethod(listener), session, endpointConfig,
+                            matchDecoders(target, endpointConfig, true, ((WsSession) session).getInstanceManager()),
                             new Object[1], 0, true, -1, true, -1),
                     MessageHandlerResultType.BINARY);
             results.add(result);
         } else if (Reader.class.isAssignableFrom(target)) {
             MessageHandlerResult result = new MessageHandlerResult(
                     new PojoMessageHandlerWholeText(listener,
-                            getOnMessageMethod(listener), session,
-                            endpointConfig, matchDecoders(target, endpointConfig, false),
+                            getOnMessageMethod(listener), session, endpointConfig,
+                            matchDecoders(target, endpointConfig, false, ((WsSession) session).getInstanceManager()),
                             new Object[1], 0, true, -1, -1),
                     MessageHandlerResultType.TEXT);
             results.add(result);
         } else {
             // Handler needs wrapping and requires decoder to convert it to one
             // of the types expected by the frame handling code
-            DecoderMatch decoderMatch = matchDecoders(target, endpointConfig);
+            DecoderMatch decoderMatch = matchDecoders(target, endpointConfig,
+                    ((WsSession) session).getInstanceManager());
             Method m = getOnMessageMethod(listener);
             if (decoderMatch.getBinaryDecoders().size() > 0) {
                 MessageHandlerResult result = new MessageHandlerResult(
@@ -446,8 +484,8 @@ public class Util {
     }
 
     private static List<Class<? extends Decoder>> matchDecoders(Class<?> target,
-            EndpointConfig endpointConfig, boolean binary) {
-        DecoderMatch decoderMatch = matchDecoders(target, endpointConfig);
+            EndpointConfig endpointConfig, boolean binary, InstanceManager instanceManager) {
+        DecoderMatch decoderMatch = matchDecoders(target, endpointConfig, instanceManager);
         if (binary) {
             if (decoderMatch.getBinaryDecoders().size() > 0) {
                 return decoderMatch.getBinaryDecoders();
@@ -459,12 +497,12 @@ public class Util {
     }
 
     private static DecoderMatch matchDecoders(Class<?> target,
-            EndpointConfig endpointConfig) {
+            EndpointConfig endpointConfig, InstanceManager instanceManager) {
         DecoderMatch decoderMatch;
         try {
             List<Class<? extends Decoder>> decoders =
                     endpointConfig.getDecoders();
-            List<DecoderEntry> decoderEntries = getDecoders(decoders);
+            List<DecoderEntry> decoderEntries = getDecoders(decoders, instanceManager);
             decoderMatch = new DecoderMatch(target, decoderEntries);
         } catch (DeploymentException e) {
             throw new IllegalArgumentException(e);
diff --git a/java/org/apache/tomcat/websocket/pojo/LocalStrings.properties b/java/org/apache/tomcat/websocket/pojo/LocalStrings.properties
index 50b47c3..afefa8c 100644
--- a/java/org/apache/tomcat/websocket/pojo/LocalStrings.properties
+++ b/java/org/apache/tomcat/websocket/pojo/LocalStrings.properties
@@ -22,6 +22,8 @@ pojoEndpointBase.onOpenFail=Failed to call onOpen method of POJO end point for P
 pojoMessageHandlerWhole.decodeIoFail=IO error while decoding message
 pojoMessageHandlerWhole.maxBufferSize=The maximum supported message size for this implementation is Integer.MAX_VALUE
 
+pojoMessageHandlerWholeBase.decodeDestoryFailed=Failed to destroy the decoder of type [{0}]
+
 pojoMethodMapping.decodePathParamFail=Failed to decode path parameter value [{0}] to expected type [{1}]
 pojoMethodMapping.duplicateAnnotation=Duplicate annotations [{0}] present on class [{1}]
 pojoMethodMapping.duplicateLastParam=Multiple boolean (last) parameters present on the method [{0}] of class [{1}] that was annotated with OnMessage
diff --git a/java/org/apache/tomcat/websocket/pojo/PojoEndpointClient.java b/java/org/apache/tomcat/websocket/pojo/PojoEndpointClient.java
index 66033f3..2aebe00 100644
--- a/java/org/apache/tomcat/websocket/pojo/PojoEndpointClient.java
+++ b/java/org/apache/tomcat/websocket/pojo/PojoEndpointClient.java
@@ -24,6 +24,8 @@ import jakarta.websocket.DeploymentException;
 import jakarta.websocket.EndpointConfig;
 import jakarta.websocket.Session;
 
+import org.apache.tomcat.InstanceManager;
+
 /**
  * Wrapper class for instances of POJOs annotated with
  * {@link jakarta.websocket.ClientEndpoint} so they appear as standard
@@ -31,6 +33,7 @@ import jakarta.websocket.Session;
  */
 public class PojoEndpointClient extends PojoEndpointBase {
 
+    @Deprecated
     public PojoEndpointClient(Object pojo,
             List<Class<? extends Decoder>> decoders) throws DeploymentException {
         super(Collections.<String,String>emptyMap());
@@ -38,6 +41,12 @@ public class PojoEndpointClient extends PojoEndpointBase {
         setMethodMapping(new PojoMethodMapping(pojo.getClass(), decoders, null));
     }
 
+    public PojoEndpointClient(Object pojo, List<Class<? extends Decoder>> decoders, InstanceManager instanceManager) throws DeploymentException {
+        super(Collections.<String,String>emptyMap());
+        setPojo(pojo);
+        setMethodMapping(new PojoMethodMapping(pojo.getClass(), decoders, null, instanceManager));
+    }
+
     @Override
     public void onOpen(Session session, EndpointConfig config) {
         doOnOpen(session, config);
diff --git a/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeBase.java b/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeBase.java
index 90d7398..4fdb87c 100644
--- a/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeBase.java
+++ b/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeBase.java
@@ -21,11 +21,17 @@ import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
 
+import javax.naming.NamingException;
+
 import jakarta.websocket.DecodeException;
 import jakarta.websocket.Decoder;
 import jakarta.websocket.MessageHandler;
 import jakarta.websocket.Session;
 
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.InstanceManager;
+import org.apache.tomcat.util.res.StringManager;
 import org.apache.tomcat.websocket.WsSession;
 
 /**
@@ -37,6 +43,9 @@ import org.apache.tomcat.websocket.WsSession;
 public abstract class PojoMessageHandlerWholeBase<T>
         extends PojoMessageHandlerBase<T> implements MessageHandler.Whole<T> {
 
+    private final Log log = LogFactory.getLog(PojoMessageHandlerWholeBase.class);  // must not be static
+    private static final StringManager sm = StringManager.getManager(PojoMessageHandlerWholeBase.class);
+
     protected final List<Decoder> decoders = new ArrayList<>();
 
     public PojoMessageHandlerWholeBase(Object pojo, Method method,
@@ -47,6 +56,17 @@ public abstract class PojoMessageHandlerWholeBase<T>
     }
 
 
+    protected Decoder createDecoderInstance(Class<? extends Decoder> clazz)
+            throws ReflectiveOperationException, NamingException {
+        InstanceManager instanceManager = ((WsSession) session).getInstanceManager();
+        if (instanceManager == null) {
+            return clazz.getConstructor().newInstance();
+        } else {
+            return (Decoder) instanceManager.newInstance(clazz);
+        }
+    }
+
+
     @Override
     public final void onMessage(T message) {
 
@@ -91,8 +111,17 @@ public abstract class PojoMessageHandlerWholeBase<T>
 
 
     protected void onClose() {
+        InstanceManager instanceManager = ((WsSession) session).getInstanceManager();
+
         for (Decoder decoder : decoders) {
             decoder.destroy();
+            if (instanceManager != null) {
+                try {
+                    instanceManager.destroyInstance(decoder);
+                } catch (IllegalAccessException | InvocationTargetException e) {
+                    log.warn(sm.getString("pojoMessageHandlerWholeBase.decodeDestoryFailed", decoder.getClass()), e);
+                }
+            }
         }
     }
 
diff --git a/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeBinary.java b/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeBinary.java
index 93feeeb..9a7699d 100644
--- a/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeBinary.java
+++ b/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeBinary.java
@@ -22,6 +22,8 @@ import java.lang.reflect.Method;
 import java.nio.ByteBuffer;
 import java.util.List;
 
+import javax.naming.NamingException;
+
 import jakarta.websocket.DecodeException;
 import jakarta.websocket.Decoder;
 import jakarta.websocket.Decoder.Binary;
@@ -63,13 +65,11 @@ public class PojoMessageHandlerWholeBinary
             if (decoderClazzes != null) {
                 for (Class<? extends Decoder> decoderClazz : decoderClazzes) {
                     if (Binary.class.isAssignableFrom(decoderClazz)) {
-                        Binary<?> decoder = (Binary<?>) decoderClazz.getConstructor().newInstance();
+                        Binary<?> decoder = (Binary<?>) createDecoderInstance(decoderClazz);
                         decoder.init(config);
                         decoders.add(decoder);
-                    } else if (BinaryStream.class.isAssignableFrom(
-                            decoderClazz)) {
-                        BinaryStream<?> decoder = (BinaryStream<?>)
-                                decoderClazz.getConstructor().newInstance();
+                    } else if (BinaryStream.class.isAssignableFrom(decoderClazz)) {
+                        BinaryStream<?> decoder = (BinaryStream<?>) createDecoderInstance(decoderClazz);
                         decoder.init(config);
                         decoders.add(decoder);
                     } else {
@@ -77,7 +77,7 @@ public class PojoMessageHandlerWholeBinary
                     }
                 }
             }
-        } catch (ReflectiveOperationException e) {
+        } catch (ReflectiveOperationException | NamingException e) {
             throw new IllegalArgumentException(e);
         }
         this.isForInputStream = isForInputStream;
diff --git a/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeText.java b/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeText.java
index ce12f16..9d2c646 100644
--- a/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeText.java
+++ b/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeText.java
@@ -21,6 +21,8 @@ import java.io.StringReader;
 import java.lang.reflect.Method;
 import java.util.List;
 
+import javax.naming.NamingException;
+
 import jakarta.websocket.DecodeException;
 import jakarta.websocket.Decoder;
 import jakarta.websocket.Decoder.Text;
@@ -73,13 +75,11 @@ public class PojoMessageHandlerWholeText
             if (decoderClazzes != null) {
                 for (Class<? extends Decoder> decoderClazz : decoderClazzes) {
                     if (Text.class.isAssignableFrom(decoderClazz)) {
-                        Text<?> decoder = (Text<?>) decoderClazz.getConstructor().newInstance();
+                        Text<?> decoder = (Text<?>) createDecoderInstance(decoderClazz);
                         decoder.init(config);
                         decoders.add(decoder);
-                    } else if (TextStream.class.isAssignableFrom(
-                            decoderClazz)) {
-                        TextStream<?> decoder =
-                                (TextStream<?>) decoderClazz.getConstructor().newInstance();
+                    } else if (TextStream.class.isAssignableFrom(decoderClazz)) {
+                        TextStream<?> decoder = (TextStream<?>) createDecoderInstance(decoderClazz);
                         decoder.init(config);
                         decoders.add(decoder);
                     } else {
@@ -87,7 +87,7 @@ public class PojoMessageHandlerWholeText
                     }
                 }
             }
-        } catch (ReflectiveOperationException e) {
+        } catch (ReflectiveOperationException | NamingException e) {
             throw new IllegalArgumentException(e);
         }
     }
diff --git a/java/org/apache/tomcat/websocket/pojo/PojoMethodMapping.java b/java/org/apache/tomcat/websocket/pojo/PojoMethodMapping.java
index 4ace70f..ce07c34 100644
--- a/java/org/apache/tomcat/websocket/pojo/PojoMethodMapping.java
+++ b/java/org/apache/tomcat/websocket/pojo/PojoMethodMapping.java
@@ -44,6 +44,7 @@ import jakarta.websocket.PongMessage;
 import jakarta.websocket.Session;
 import jakarta.websocket.server.PathParam;
 
+import org.apache.tomcat.InstanceManager;
 import org.apache.tomcat.util.res.StringManager;
 import org.apache.tomcat.websocket.DecoderEntry;
 import org.apache.tomcat.websocket.Util;
@@ -70,13 +71,41 @@ public class PojoMethodMapping {
     private final String wsPath;
 
 
-    public PojoMethodMapping(Class<?> clazzPojo,
-            List<Class<? extends Decoder>> decoderClazzes, String wsPath)
-                    throws DeploymentException {
+    /**
+     * Create a method mapping for the given POJO
+     *
+     * @param clazzPojo         POJO implementation class
+     * @param decoderClazzes    Set of potential decoder classes
+     * @param wsPath            Path at which the endpoint will be deployed
+     *
+     * @throws DeploymentException If the mapping cannot be completed
+     *
+     * @deprecated Will be removed in Tomcat 10.1.x
+     *             Use (@link {@link #PojoMethodMapping(Class, List, String, InstanceManager)}
+     */
+    @Deprecated
+    public PojoMethodMapping(Class<?> clazzPojo, List<Class<? extends Decoder>> decoderClazzes, String wsPath)
+            throws DeploymentException {
+        this(clazzPojo, decoderClazzes, wsPath, null);
+    }
+
+
+    /**
+     * Create a method mapping for the given POJO
+     *
+     * @param clazzPojo         POJO implementation class
+     * @param decoderClazzes    Set of potential decoder classes
+     * @param wsPath            Path at which the endpoint will be deployed
+     * @param instanceManager   Instance manager to use to create Decoder instances
+     *
+     * @throws DeploymentException If the mapping cannot be completed
+     */
+    public PojoMethodMapping(Class<?> clazzPojo, List<Class<? extends Decoder>> decoderClazzes, String wsPath,
+            InstanceManager instanceManager) throws DeploymentException {
 
         this.wsPath = wsPath;
 
-        List<DecoderEntry> decoders = Util.getDecoders(decoderClazzes);
+        List<DecoderEntry> decoders = Util.getDecoders(decoderClazzes, instanceManager);
         Method open = null;
         Method close = null;
         Method error = null;
diff --git a/java/org/apache/tomcat/websocket/server/WsServerContainer.java b/java/org/apache/tomcat/websocket/server/WsServerContainer.java
index 40d52cc..96c1422 100644
--- a/java/org/apache/tomcat/websocket/server/WsServerContainer.java
+++ b/java/org/apache/tomcat/websocket/server/WsServerContainer.java
@@ -151,7 +151,7 @@ public class WsServerContainer extends WsWebSocketContainer
 
             // Add method mapping to user properties
             PojoMethodMapping methodMapping = new PojoMethodMapping(sec.getEndpointClass(),
-                    sec.getDecoders(), path);
+                    sec.getDecoders(), path, getInstanceManager(Thread.currentThread().getContextClassLoader()));
             if (methodMapping.getOnClose() != null || methodMapping.getOnOpen() != null
                     || methodMapping.getOnError() != null || methodMapping.hasMessageHandlers()) {
                 sec.getUserProperties().put(org.apache.tomcat.websocket.pojo.Constants.POJO_METHOD_MAPPING_KEY,
diff --git a/test/org/apache/tomcat/websocket/TesterWsClientAutobahn.java b/test/org/apache/tomcat/websocket/TesterWsClientAutobahn.java
index 4917004..79c5e2a 100644
--- a/test/org/apache/tomcat/websocket/TesterWsClientAutobahn.java
+++ b/test/org/apache/tomcat/websocket/TesterWsClientAutobahn.java
@@ -99,7 +99,7 @@ public class TesterWsClientAutobahn {
         List<Extension> extensions = new ArrayList<>(1);
         extensions.add(permessageDeflate);
 
-        Endpoint ep = new PojoEndpointClient(testCaseClient, null);
+        Endpoint ep = new PojoEndpointClient(testCaseClient, null, null);
         ClientEndpointConfig.Builder builder = ClientEndpointConfig.Builder.create();
         ClientEndpointConfig config = builder.extensions(extensions).build();
 

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


[tomcat] 01/03: Refactor with a view towards using the InstanceManager with decoders

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 56ce1d9a83c55cf37bbb4ebff7cbd404a54cb00f
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Wed May 5 12:57:56 2021 +0100

    Refactor with a view towards using the InstanceManager with decoders
---
 java/org/apache/tomcat/websocket/WsSession.java            |  2 +-
 .../tomcat/websocket/pojo/PojoMessageHandlerWholeBase.java | 14 +++++++++++++-
 .../websocket/pojo/PojoMessageHandlerWholeBinary.java      | 11 -----------
 .../tomcat/websocket/pojo/PojoMessageHandlerWholeText.java | 10 ----------
 4 files changed, 14 insertions(+), 23 deletions(-)

diff --git a/java/org/apache/tomcat/websocket/WsSession.java b/java/org/apache/tomcat/websocket/WsSession.java
index c91a0f2..0120845 100644
--- a/java/org/apache/tomcat/websocket/WsSession.java
+++ b/java/org/apache/tomcat/websocket/WsSession.java
@@ -750,7 +750,7 @@ public class WsSession implements Session {
 
         // Fire the onClose event
         Throwable throwable = null;
-        InstanceManager instanceManager = webSocketContainer.getInstanceManager(applicationClassLoader);
+        InstanceManager instanceManager = getInstanceManager();
         Thread t = Thread.currentThread();
         ClassLoader cl = t.getContextClassLoader();
         t.setContextClassLoader(applicationClassLoader);
diff --git a/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeBase.java b/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeBase.java
index e973552..90d7398 100644
--- a/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeBase.java
+++ b/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeBase.java
@@ -18,8 +18,11 @@ package org.apache.tomcat.websocket.pojo;
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
 
 import jakarta.websocket.DecodeException;
+import jakarta.websocket.Decoder;
 import jakarta.websocket.MessageHandler;
 import jakarta.websocket.Session;
 
@@ -34,6 +37,8 @@ import org.apache.tomcat.websocket.WsSession;
 public abstract class PojoMessageHandlerWholeBase<T>
         extends PojoMessageHandlerBase<T> implements MessageHandler.Whole<T> {
 
+    protected final List<Decoder> decoders = new ArrayList<>();
+
     public PojoMessageHandlerWholeBase(Object pojo, Method method,
             Session session, Object[] params, int indexPayload,
             boolean convert, int indexSession, long maxMessageSize) {
@@ -84,11 +89,18 @@ public abstract class PojoMessageHandlerWholeBase<T>
         processResult(result);
     }
 
+
+    protected void onClose() {
+        for (Decoder decoder : decoders) {
+            decoder.destroy();
+        }
+    }
+
+
     protected Object convert(T message) {
         return message;
     }
 
 
     protected abstract Object decode(T message) throws DecodeException;
-    protected abstract void onClose();
 }
diff --git a/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeBinary.java b/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeBinary.java
index 07b49ce..93feeeb 100644
--- a/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeBinary.java
+++ b/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeBinary.java
@@ -20,7 +20,6 @@ import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.lang.reflect.Method;
 import java.nio.ByteBuffer;
-import java.util.ArrayList;
 import java.util.List;
 
 import jakarta.websocket.DecodeException;
@@ -41,8 +40,6 @@ public class PojoMessageHandlerWholeBinary
     private static final StringManager sm =
             StringManager.getManager(PojoMessageHandlerWholeBinary.class);
 
-    private final List<Decoder> decoders = new ArrayList<>();
-
     private final boolean isForInputStream;
 
     public PojoMessageHandlerWholeBinary(Object pojo, Method method,
@@ -120,12 +117,4 @@ public class PojoMessageHandlerWholeBinary
             return array;
         }
     }
-
-
-    @Override
-    protected void onClose() {
-        for (Decoder decoder : decoders) {
-            decoder.destroy();
-        }
-    }
 }
diff --git a/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeText.java b/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeText.java
index 0cb5fec..ce12f16 100644
--- a/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeText.java
+++ b/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeText.java
@@ -19,7 +19,6 @@ package org.apache.tomcat.websocket.pojo;
 import java.io.IOException;
 import java.io.StringReader;
 import java.lang.reflect.Method;
-import java.util.ArrayList;
 import java.util.List;
 
 import jakarta.websocket.DecodeException;
@@ -42,7 +41,6 @@ public class PojoMessageHandlerWholeText
     private static final StringManager sm =
             StringManager.getManager(PojoMessageHandlerWholeText.class);
 
-    private final List<Decoder> decoders = new ArrayList<>();
     private final Class<?> primitiveType;
 
     public PojoMessageHandlerWholeText(Object pojo, Method method,
@@ -125,12 +123,4 @@ public class PojoMessageHandlerWholeText
     protected Object convert(String message) {
         return new StringReader(message);
     }
-
-
-    @Override
-    protected void onClose() {
-        for (Decoder decoder : decoders) {
-            decoder.destroy();
-        }
-    }
 }

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