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

jbonofre pushed a commit to branch activemq-5.15.x
in repository https://gitbox.apache.org/repos/asf/activemq.git

commit 9905e2a5bf9862a049f94ce0a2465b0c7ad52436
Author: Christopher L. Shannon (cshannon) <[email protected]>
AuthorDate: Mon Oct 23 18:24:38 2023 -0400

    AMQ-9370 - Openwire marshaller should validate Throwable class type
    
    (cherry picked from commit 3eaf3107f4fb9a3ce7ab45c175bfaeac7e866d5b)
    (cherry picked from commit d0ccdd31544ada83185554c87c7aa141064020f0)
---
 activemq-client/pom.xml                            |  11 ++
 .../org/apache/activemq/openwire/OpenWireUtil.java |  32 ++++
 .../openwire/v1/BaseDataStreamMarshaller.java      |   4 +
 .../openwire/v10/BaseDataStreamMarshaller.java     |   4 +
 .../openwire/v11/BaseDataStreamMarshaller.java     |   4 +
 .../openwire/v12/BaseDataStreamMarshaller.java     |   4 +
 .../openwire/v9/BaseDataStreamMarshaller.java      |   4 +
 .../activemq/openwire/OpenWireValidationTest.java  | 166 +++++++++++++++++++++
 activemq-openwire-legacy/pom.xml                   |  12 ++
 .../openwire/v2/BaseDataStreamMarshaller.java      |   4 +
 .../openwire/v3/BaseDataStreamMarshaller.java      |   4 +
 .../openwire/v4/BaseDataStreamMarshaller.java      |   4 +
 .../openwire/v5/BaseDataStreamMarshaller.java      |   4 +
 .../openwire/v6/BaseDataStreamMarshaller.java      |   4 +
 .../openwire/v7/BaseDataStreamMarshaller.java      |   4 +
 .../openwire/v8/BaseDataStreamMarshaller.java      |   4 +
 .../openwire/OpenWireLegacyValidationTest.java     | 129 ++++++++++++++++
 pom.xml                                            |   7 +
 18 files changed, 405 insertions(+)

diff --git a/activemq-client/pom.xml b/activemq-client/pom.xml
index 35942e7b6..fd415111f 100644
--- a/activemq-client/pom.xml
+++ b/activemq-client/pom.xml
@@ -261,6 +261,17 @@
               </execution>
           </executions>
       </plugin>
+      <!-- generate the attached tests jar -->
+      <plugin>
+        <artifactId>maven-jar-plugin</artifactId>
+        <executions>
+          <execution>
+            <goals>
+              <goal>test-jar</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
     <pluginManagement>
         <plugins>
diff --git 
a/activemq-client/src/main/java/org/apache/activemq/openwire/OpenWireUtil.java 
b/activemq-client/src/main/java/org/apache/activemq/openwire/OpenWireUtil.java
new file mode 100644
index 000000000..f52e6c3e0
--- /dev/null
+++ 
b/activemq-client/src/main/java/org/apache/activemq/openwire/OpenWireUtil.java
@@ -0,0 +1,32 @@
+/**
+ * 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.activemq.openwire;
+
+public class OpenWireUtil {
+
+    /**
+     * Verify that the provided class extends {@link Throwable} and throw an
+     * {@link IllegalArgumentException} if it does not.
+     *
+     * @param clazz
+     */
+    public static void validateIsThrowable(Class<?> clazz) {
+        if (!Throwable.class.isAssignableFrom(clazz)) {
+            throw new IllegalArgumentException("Class " + clazz + " is not 
assignable to Throwable");
+        }
+    }
+}
diff --git 
a/activemq-client/src/main/java/org/apache/activemq/openwire/v1/BaseDataStreamMarshaller.java
 
b/activemq-client/src/main/java/org/apache/activemq/openwire/v1/BaseDataStreamMarshaller.java
index b2c997ea7..cfe2716a9 100644
--- 
a/activemq-client/src/main/java/org/apache/activemq/openwire/v1/BaseDataStreamMarshaller.java
+++ 
b/activemq-client/src/main/java/org/apache/activemq/openwire/v1/BaseDataStreamMarshaller.java
@@ -25,6 +25,7 @@ import org.apache.activemq.command.DataStructure;
 import org.apache.activemq.openwire.BooleanStream;
 import org.apache.activemq.openwire.DataStreamMarshaller;
 import org.apache.activemq.openwire.OpenWireFormat;
+import org.apache.activemq.openwire.OpenWireUtil;
 import org.apache.activemq.util.ByteSequence;
 
 public abstract class BaseDataStreamMarshaller implements DataStreamMarshaller 
{
@@ -229,8 +230,11 @@ public abstract class BaseDataStreamMarshaller implements 
DataStreamMarshaller {
     private Throwable createThrowable(String className, String message) {
         try {
             Class clazz = Class.forName(className, false, 
BaseDataStreamMarshaller.class.getClassLoader());
+            OpenWireUtil.validateIsThrowable(clazz);
             Constructor constructor = clazz.getConstructor(new Class[] 
{String.class});
             return (Throwable)constructor.newInstance(new Object[] {message});
+        } catch (IllegalArgumentException e) {
+            return e;
         } catch (Throwable e) {
             return new Throwable(className + ": " + message);
         }
diff --git 
a/activemq-client/src/main/java/org/apache/activemq/openwire/v10/BaseDataStreamMarshaller.java
 
b/activemq-client/src/main/java/org/apache/activemq/openwire/v10/BaseDataStreamMarshaller.java
index a570d3d17..6dc87a29a 100644
--- 
a/activemq-client/src/main/java/org/apache/activemq/openwire/v10/BaseDataStreamMarshaller.java
+++ 
b/activemq-client/src/main/java/org/apache/activemq/openwire/v10/BaseDataStreamMarshaller.java
@@ -24,6 +24,7 @@ import org.apache.activemq.command.DataStructure;
 import org.apache.activemq.openwire.BooleanStream;
 import org.apache.activemq.openwire.DataStreamMarshaller;
 import org.apache.activemq.openwire.OpenWireFormat;
+import org.apache.activemq.openwire.OpenWireUtil;
 import org.apache.activemq.util.ByteSequence;
 
 public abstract class BaseDataStreamMarshaller implements DataStreamMarshaller 
{
@@ -228,8 +229,11 @@ public abstract class BaseDataStreamMarshaller implements 
DataStreamMarshaller {
     private Throwable createThrowable(String className, String message) {
         try {
             Class clazz = Class.forName(className, false, 
BaseDataStreamMarshaller.class.getClassLoader());
+            OpenWireUtil.validateIsThrowable(clazz);
             Constructor constructor = clazz.getConstructor(new Class[] 
{String.class});
             return (Throwable)constructor.newInstance(new Object[] {message});
+        } catch (IllegalArgumentException e) {
+            return e;
         } catch (Throwable e) {
             return new Throwable(className + ": " + message);
         }
diff --git 
a/activemq-client/src/main/java/org/apache/activemq/openwire/v11/BaseDataStreamMarshaller.java
 
b/activemq-client/src/main/java/org/apache/activemq/openwire/v11/BaseDataStreamMarshaller.java
index c61d16fa3..4bcf10944 100644
--- 
a/activemq-client/src/main/java/org/apache/activemq/openwire/v11/BaseDataStreamMarshaller.java
+++ 
b/activemq-client/src/main/java/org/apache/activemq/openwire/v11/BaseDataStreamMarshaller.java
@@ -24,6 +24,7 @@ import org.apache.activemq.command.DataStructure;
 import org.apache.activemq.openwire.BooleanStream;
 import org.apache.activemq.openwire.DataStreamMarshaller;
 import org.apache.activemq.openwire.OpenWireFormat;
+import org.apache.activemq.openwire.OpenWireUtil;
 import org.apache.activemq.util.ByteSequence;
 
 public abstract class BaseDataStreamMarshaller implements DataStreamMarshaller 
{
@@ -227,8 +228,11 @@ public abstract class BaseDataStreamMarshaller implements 
DataStreamMarshaller {
     private Throwable createThrowable(String className, String message) {
         try {
             Class clazz = Class.forName(className, false, 
BaseDataStreamMarshaller.class.getClassLoader());
+            OpenWireUtil.validateIsThrowable(clazz);
             Constructor constructor = clazz.getConstructor(new Class[] 
{String.class});
             return (Throwable)constructor.newInstance(new Object[] {message});
+        } catch (IllegalArgumentException e) {
+            return e;
         } catch (Throwable e) {
             return new Throwable(className + ": " + message);
         }
diff --git 
a/activemq-client/src/main/java/org/apache/activemq/openwire/v12/BaseDataStreamMarshaller.java
 
b/activemq-client/src/main/java/org/apache/activemq/openwire/v12/BaseDataStreamMarshaller.java
index 820d9a632..10fdebcbc 100644
--- 
a/activemq-client/src/main/java/org/apache/activemq/openwire/v12/BaseDataStreamMarshaller.java
+++ 
b/activemq-client/src/main/java/org/apache/activemq/openwire/v12/BaseDataStreamMarshaller.java
@@ -24,6 +24,7 @@ import org.apache.activemq.command.DataStructure;
 import org.apache.activemq.openwire.BooleanStream;
 import org.apache.activemq.openwire.DataStreamMarshaller;
 import org.apache.activemq.openwire.OpenWireFormat;
+import org.apache.activemq.openwire.OpenWireUtil;
 import org.apache.activemq.util.ByteSequence;
 
 public abstract class BaseDataStreamMarshaller implements DataStreamMarshaller 
{
@@ -227,8 +228,11 @@ public abstract class BaseDataStreamMarshaller implements 
DataStreamMarshaller {
     private Throwable createThrowable(String className, String message) {
         try {
             Class clazz = Class.forName(className, false, 
BaseDataStreamMarshaller.class.getClassLoader());
+            OpenWireUtil.validateIsThrowable(clazz);
             Constructor constructor = clazz.getConstructor(new Class[] 
{String.class});
             return (Throwable)constructor.newInstance(new Object[] {message});
+        } catch (IllegalArgumentException e) {
+            return e;
         } catch (Throwable e) {
             return new Throwable(className + ": " + message);
         }
diff --git 
a/activemq-client/src/main/java/org/apache/activemq/openwire/v9/BaseDataStreamMarshaller.java
 
b/activemq-client/src/main/java/org/apache/activemq/openwire/v9/BaseDataStreamMarshaller.java
index 80abd32dc..1f99292d5 100644
--- 
a/activemq-client/src/main/java/org/apache/activemq/openwire/v9/BaseDataStreamMarshaller.java
+++ 
b/activemq-client/src/main/java/org/apache/activemq/openwire/v9/BaseDataStreamMarshaller.java
@@ -24,6 +24,7 @@ import org.apache.activemq.command.DataStructure;
 import org.apache.activemq.openwire.BooleanStream;
 import org.apache.activemq.openwire.DataStreamMarshaller;
 import org.apache.activemq.openwire.OpenWireFormat;
+import org.apache.activemq.openwire.OpenWireUtil;
 import org.apache.activemq.util.ByteSequence;
 
 public abstract class BaseDataStreamMarshaller implements DataStreamMarshaller 
{
@@ -227,8 +228,11 @@ public abstract class BaseDataStreamMarshaller implements 
DataStreamMarshaller {
     private Throwable createThrowable(String className, String message) {
         try {
             Class clazz = Class.forName(className, false, 
BaseDataStreamMarshaller.class.getClassLoader());
+            OpenWireUtil.validateIsThrowable(clazz);
             Constructor constructor = clazz.getConstructor(new Class[] 
{String.class});
             return (Throwable)constructor.newInstance(new Object[] {message});
+        } catch (IllegalArgumentException e) {
+            return e;
         } catch (Throwable e) {
             return new Throwable(className + ": " + message);
         }
diff --git 
a/activemq-client/src/test/java/org/apache/activemq/openwire/OpenWireValidationTest.java
 
b/activemq-client/src/test/java/org/apache/activemq/openwire/OpenWireValidationTest.java
new file mode 100644
index 000000000..a7a6a4f7c
--- /dev/null
+++ 
b/activemq-client/src/test/java/org/apache/activemq/openwire/OpenWireValidationTest.java
@@ -0,0 +1,166 @@
+/**
+ * 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.activemq.openwire;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.apache.activemq.command.CommandTypes;
+import org.apache.activemq.command.ExceptionResponse;
+import org.apache.activemq.util.ByteSequence;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * Test that Openwire marshalling will validate Throwable types during
+ * unmarshalling commands that contain a Throwable
+ */
+@RunWith(Parameterized.class)
+public class OpenWireValidationTest {
+
+    protected final int version;
+
+    @Parameters(name = "version={0}")
+    public static Collection<Object[]> data() {
+        List<Integer> versions = List.of(1, 9, 10, 11, 12);
+        List<Object[]> versionObjs = new ArrayList<>();
+        for (int i : versions) {
+            versionObjs.add(new Object[]{i});
+        }
+
+        // Sanity check to make sure the latest generated version is contained 
in the list
+        // This will make sure that we don't forget to update this test to 
include
+        // any future versions that are generated
+        assertTrue("List of Openwire versions does not include latest version",
+            versions.contains((int)CommandTypes.PROTOCOL_VERSION));
+
+        return versionObjs;
+    }
+
+    public OpenWireValidationTest(int version) {
+        this.version = version;
+    }
+
+    @Test
+    public void testOpenwireThrowableValidation() throws Exception {
+        // Create a format which will use loose encoding by default
+        // The code for handling exception creation is shared between both
+        // tight/loose encoding so only need to test 1
+        OpenWireFormat format = new OpenWireFormat();
+
+        // Override the marshaller map with a custom impl to purposely marshal 
a class type that is
+        // not a Throwable for testing the unmarshaller
+        Class<?> marshallerFactory = getMarshallerFactory();
+        Method createMarshallerMap = 
marshallerFactory.getMethod("createMarshallerMap", OpenWireFormat.class);
+        DataStreamMarshaller[] map = (DataStreamMarshaller[]) 
createMarshallerMap.invoke(marshallerFactory, format);
+        map[ExceptionResponse.DATA_STRUCTURE_TYPE] = getExceptionMarshaller();
+        // This will trigger updating the marshaller from the marshaller map 
with the right version
+        format.setVersion(version);
+
+        // Build the response and try to unmarshal which should give an 
IllegalArgumentExeption on unmarshall
+        // as the test marshaller should have encoded a class type that is not 
a Throwable
+        ExceptionResponse r = new ExceptionResponse();
+        r.setException(new Exception());
+        ByteSequence bss = format.marshal(r);
+        ExceptionResponse response = (ExceptionResponse) format.unmarshal(bss);
+
+        assertTrue(response.getException() instanceof 
IllegalArgumentException);
+        assertTrue(response.getException().getMessage().contains("is not 
assignable to Throwable"));
+    }
+
+    static class NotAThrowable {
+        private String message;
+
+        public NotAThrowable(String message) {
+            this.message = message;
+        }
+
+        public NotAThrowable() {
+        }
+    }
+
+    private Class<?> getMarshallerFactory() throws ClassNotFoundException {
+        return Class.forName("org.apache.activemq.openwire.v" + version + 
".MarshallerFactory");
+    }
+
+    // Create test marshallers for all non-legacy versions that will encode 
NotAThrowable
+    // instead of the exception type for testing purposes
+    protected DataStreamMarshaller getExceptionMarshaller() {
+        switch (version) {
+            case 12:
+                return new 
org.apache.activemq.openwire.v12.ExceptionResponseMarshaller() {
+                    @Override
+                    protected void looseMarshalThrowable(OpenWireFormat 
wireFormat, Throwable o,
+                        DataOutput dataOut) throws IOException {
+                        dataOut.writeBoolean(o != null);
+                        looseMarshalString(NotAThrowable.class.getName(), 
dataOut);
+                        looseMarshalString(o.getMessage(), dataOut);
+                    }
+                };
+            case 11:
+                return new 
org.apache.activemq.openwire.v11.ExceptionResponseMarshaller() {
+                    @Override
+                    protected void looseMarshalThrowable(OpenWireFormat 
wireFormat, Throwable o,
+                        DataOutput dataOut) throws IOException {
+                        dataOut.writeBoolean(o != null);
+                        looseMarshalString(NotAThrowable.class.getName(), 
dataOut);
+                        looseMarshalString(o.getMessage(), dataOut);
+                    }
+                };
+            case 10:
+                return new 
org.apache.activemq.openwire.v10.ExceptionResponseMarshaller() {
+                    @Override
+                    protected void looseMarshalThrowable(OpenWireFormat 
wireFormat, Throwable o,
+                        DataOutput dataOut) throws IOException {
+                        dataOut.writeBoolean(o != null);
+                        looseMarshalString(NotAThrowable.class.getName(), 
dataOut);
+                        looseMarshalString(o.getMessage(), dataOut);
+                    }
+                };
+            case 9:
+                return new 
org.apache.activemq.openwire.v9.ExceptionResponseMarshaller() {
+                    @Override
+                    protected void looseMarshalThrowable(OpenWireFormat 
wireFormat, Throwable o,
+                        DataOutput dataOut) throws IOException {
+                        dataOut.writeBoolean(o != null);
+                        looseMarshalString(NotAThrowable.class.getName(), 
dataOut);
+                        looseMarshalString(o.getMessage(), dataOut);
+                    }
+                };
+            case 1:
+                return new 
org.apache.activemq.openwire.v1.ExceptionResponseMarshaller() {
+                    @Override
+                    protected void looseMarshalThrowable(OpenWireFormat 
wireFormat, Throwable o,
+                        DataOutput dataOut) throws IOException {
+                        dataOut.writeBoolean(o != null);
+                        looseMarshalString(NotAThrowable.class.getName(), 
dataOut);
+                        looseMarshalString(o.getMessage(), dataOut);
+                    }
+                };
+            default:
+                throw new IllegalArgumentException("Unknown openwire version 
of " + version);
+        }
+    }
+
+}
diff --git a/activemq-openwire-legacy/pom.xml b/activemq-openwire-legacy/pom.xml
index d1dd264cb..05ccdbf3d 100644
--- a/activemq-openwire-legacy/pom.xml
+++ b/activemq-openwire-legacy/pom.xml
@@ -35,6 +35,18 @@
       <groupId>org.apache.activemq</groupId>
       <artifactId>activemq-client</artifactId>
     </dependency>
+
+    <dependency>
+      <groupId>org.apache.activemq</groupId>
+      <artifactId>activemq-client</artifactId>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
 </project>
diff --git 
a/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v2/BaseDataStreamMarshaller.java
 
b/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v2/BaseDataStreamMarshaller.java
index b05a9912f..ed8c90445 100644
--- 
a/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v2/BaseDataStreamMarshaller.java
+++ 
b/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v2/BaseDataStreamMarshaller.java
@@ -25,6 +25,7 @@ import org.apache.activemq.command.DataStructure;
 import org.apache.activemq.openwire.BooleanStream;
 import org.apache.activemq.openwire.DataStreamMarshaller;
 import org.apache.activemq.openwire.OpenWireFormat;
+import org.apache.activemq.openwire.OpenWireUtil;
 import org.apache.activemq.util.ByteSequence;
 
 public abstract class BaseDataStreamMarshaller implements DataStreamMarshaller 
{
@@ -228,8 +229,11 @@ public abstract class BaseDataStreamMarshaller implements 
DataStreamMarshaller {
     private Throwable createThrowable(String className, String message) {
         try {
             Class clazz = Class.forName(className, false, 
BaseDataStreamMarshaller.class.getClassLoader());
+            OpenWireUtil.validateIsThrowable(clazz);
             Constructor constructor = clazz.getConstructor(new Class[] 
{String.class});
             return (Throwable)constructor.newInstance(new Object[] {message});
+        } catch (IllegalArgumentException e) {
+            return e;
         } catch (Throwable e) {
             return new Throwable(className + ": " + message);
         }
diff --git 
a/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v3/BaseDataStreamMarshaller.java
 
b/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v3/BaseDataStreamMarshaller.java
index 872f8eaf0..4199157a1 100644
--- 
a/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v3/BaseDataStreamMarshaller.java
+++ 
b/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v3/BaseDataStreamMarshaller.java
@@ -25,6 +25,7 @@ import org.apache.activemq.command.DataStructure;
 import org.apache.activemq.openwire.BooleanStream;
 import org.apache.activemq.openwire.DataStreamMarshaller;
 import org.apache.activemq.openwire.OpenWireFormat;
+import org.apache.activemq.openwire.OpenWireUtil;
 import org.apache.activemq.util.ByteSequence;
 
 public abstract class BaseDataStreamMarshaller implements DataStreamMarshaller 
{
@@ -228,8 +229,11 @@ public abstract class BaseDataStreamMarshaller implements 
DataStreamMarshaller {
     private Throwable createThrowable(String className, String message) {
         try {
             Class clazz = Class.forName(className, false, 
BaseDataStreamMarshaller.class.getClassLoader());
+            OpenWireUtil.validateIsThrowable(clazz);
             Constructor constructor = clazz.getConstructor(new Class[] 
{String.class});
             return (Throwable)constructor.newInstance(new Object[] {message});
+        } catch (IllegalArgumentException e) {
+            return e;
         } catch (Throwable e) {
             return new Throwable(className + ": " + message);
         }
diff --git 
a/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v4/BaseDataStreamMarshaller.java
 
b/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v4/BaseDataStreamMarshaller.java
index 798b94a24..2c9720512 100644
--- 
a/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v4/BaseDataStreamMarshaller.java
+++ 
b/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v4/BaseDataStreamMarshaller.java
@@ -25,6 +25,7 @@ import org.apache.activemq.command.DataStructure;
 import org.apache.activemq.openwire.BooleanStream;
 import org.apache.activemq.openwire.DataStreamMarshaller;
 import org.apache.activemq.openwire.OpenWireFormat;
+import org.apache.activemq.openwire.OpenWireUtil;
 import org.apache.activemq.util.ByteSequence;
 
 public abstract class BaseDataStreamMarshaller implements DataStreamMarshaller 
{
@@ -228,8 +229,11 @@ public abstract class BaseDataStreamMarshaller implements 
DataStreamMarshaller {
     private Throwable createThrowable(String className, String message) {
         try {
             Class clazz = Class.forName(className, false, 
BaseDataStreamMarshaller.class.getClassLoader());
+            OpenWireUtil.validateIsThrowable(clazz);
             Constructor constructor = clazz.getConstructor(new Class[] 
{String.class});
             return (Throwable)constructor.newInstance(new Object[] {message});
+        } catch (IllegalArgumentException e) {
+            return e;
         } catch (Throwable e) {
             return new Throwable(className + ": " + message);
         }
diff --git 
a/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v5/BaseDataStreamMarshaller.java
 
b/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v5/BaseDataStreamMarshaller.java
index 180d9c759..264f260a7 100644
--- 
a/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v5/BaseDataStreamMarshaller.java
+++ 
b/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v5/BaseDataStreamMarshaller.java
@@ -25,6 +25,7 @@ import org.apache.activemq.command.DataStructure;
 import org.apache.activemq.openwire.BooleanStream;
 import org.apache.activemq.openwire.DataStreamMarshaller;
 import org.apache.activemq.openwire.OpenWireFormat;
+import org.apache.activemq.openwire.OpenWireUtil;
 import org.apache.activemq.util.ByteSequence;
 
 public abstract class BaseDataStreamMarshaller implements DataStreamMarshaller 
{
@@ -228,8 +229,11 @@ public abstract class BaseDataStreamMarshaller implements 
DataStreamMarshaller {
     private Throwable createThrowable(String className, String message) {
         try {
             Class clazz = Class.forName(className, false, 
BaseDataStreamMarshaller.class.getClassLoader());
+            OpenWireUtil.validateIsThrowable(clazz);
             Constructor constructor = clazz.getConstructor(new Class[] 
{String.class});
             return (Throwable)constructor.newInstance(new Object[] {message});
+        } catch (IllegalArgumentException e) {
+            return e;
         } catch (Throwable e) {
             return new Throwable(className + ": " + message);
         }
diff --git 
a/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v6/BaseDataStreamMarshaller.java
 
b/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v6/BaseDataStreamMarshaller.java
index a0d066a4a..fee3c0e4b 100644
--- 
a/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v6/BaseDataStreamMarshaller.java
+++ 
b/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v6/BaseDataStreamMarshaller.java
@@ -25,6 +25,7 @@ import org.apache.activemq.command.DataStructure;
 import org.apache.activemq.openwire.BooleanStream;
 import org.apache.activemq.openwire.DataStreamMarshaller;
 import org.apache.activemq.openwire.OpenWireFormat;
+import org.apache.activemq.openwire.OpenWireUtil;
 import org.apache.activemq.util.ByteSequence;
 
 public abstract class BaseDataStreamMarshaller implements DataStreamMarshaller 
{
@@ -228,8 +229,11 @@ public abstract class BaseDataStreamMarshaller implements 
DataStreamMarshaller {
     private Throwable createThrowable(String className, String message) {
         try {
             Class clazz = Class.forName(className, false, 
BaseDataStreamMarshaller.class.getClassLoader());
+            OpenWireUtil.validateIsThrowable(clazz);
             Constructor constructor = clazz.getConstructor(new Class[] 
{String.class});
             return (Throwable)constructor.newInstance(new Object[] {message});
+        } catch (IllegalArgumentException e) {
+            return e;
         } catch (Throwable e) {
             return new Throwable(className + ": " + message);
         }
diff --git 
a/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v7/BaseDataStreamMarshaller.java
 
b/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v7/BaseDataStreamMarshaller.java
index 99dae6420..db8aeb73c 100644
--- 
a/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v7/BaseDataStreamMarshaller.java
+++ 
b/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v7/BaseDataStreamMarshaller.java
@@ -24,6 +24,7 @@ import org.apache.activemq.command.DataStructure;
 import org.apache.activemq.openwire.BooleanStream;
 import org.apache.activemq.openwire.DataStreamMarshaller;
 import org.apache.activemq.openwire.OpenWireFormat;
+import org.apache.activemq.openwire.OpenWireUtil;
 import org.apache.activemq.util.ByteSequence;
 
 public abstract class BaseDataStreamMarshaller implements DataStreamMarshaller 
{
@@ -227,8 +228,11 @@ public abstract class BaseDataStreamMarshaller implements 
DataStreamMarshaller {
     private Throwable createThrowable(String className, String message) {
         try {
             Class clazz = Class.forName(className, false, 
BaseDataStreamMarshaller.class.getClassLoader());
+            OpenWireUtil.validateIsThrowable(clazz);
             Constructor constructor = clazz.getConstructor(new Class[] 
{String.class});
             return (Throwable)constructor.newInstance(new Object[] {message});
+        } catch (IllegalArgumentException e) {
+            return e;
         } catch (Throwable e) {
             return new Throwable(className + ": " + message);
         }
diff --git 
a/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v8/BaseDataStreamMarshaller.java
 
b/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v8/BaseDataStreamMarshaller.java
index 62c847316..47a0165ae 100644
--- 
a/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v8/BaseDataStreamMarshaller.java
+++ 
b/activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v8/BaseDataStreamMarshaller.java
@@ -24,6 +24,7 @@ import org.apache.activemq.command.DataStructure;
 import org.apache.activemq.openwire.BooleanStream;
 import org.apache.activemq.openwire.DataStreamMarshaller;
 import org.apache.activemq.openwire.OpenWireFormat;
+import org.apache.activemq.openwire.OpenWireUtil;
 import org.apache.activemq.util.ByteSequence;
 
 public abstract class BaseDataStreamMarshaller implements DataStreamMarshaller 
{
@@ -227,8 +228,11 @@ public abstract class BaseDataStreamMarshaller implements 
DataStreamMarshaller {
     private Throwable createThrowable(String className, String message) {
         try {
             Class clazz = Class.forName(className, false, 
BaseDataStreamMarshaller.class.getClassLoader());
+            OpenWireUtil.validateIsThrowable(clazz);
             Constructor constructor = clazz.getConstructor(new Class[] 
{String.class});
             return (Throwable)constructor.newInstance(new Object[] {message});
+        } catch (IllegalArgumentException e) {
+            return e;
         } catch (Throwable e) {
             return new Throwable(className + ": " + message);
         }
diff --git 
a/activemq-openwire-legacy/src/test/java/org/apache/activemq/openwire/OpenWireLegacyValidationTest.java
 
b/activemq-openwire-legacy/src/test/java/org/apache/activemq/openwire/OpenWireLegacyValidationTest.java
new file mode 100644
index 000000000..daee1344b
--- /dev/null
+++ 
b/activemq-openwire-legacy/src/test/java/org/apache/activemq/openwire/OpenWireLegacyValidationTest.java
@@ -0,0 +1,129 @@
+/**
+ * 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.activemq.openwire;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * Test that Openwire marshalling for legacy versions will validate Throwable 
types during
+ * unmarshalling commands that contain a Throwable
+ */
+@RunWith(Parameterized.class)
+public class OpenWireLegacyValidationTest extends OpenWireValidationTest {
+
+
+    // Run through version 2 - 8 which are legacy
+    @Parameters(name = "version={0}")
+    public static Collection<Object[]> data() {
+        List<Object[]> versions = new ArrayList<>();
+        for (int i = 2; i <= 8; i++) {
+            versions.add(new Object[]{i});
+        }
+        return versions;
+    }
+
+    public OpenWireLegacyValidationTest(int version) {
+        super(version);
+    }
+
+    // Create test marshallers for all legacy versions that will encode 
NotAThrowable
+    // instead of the exception type for testing purposes
+    protected DataStreamMarshaller getExceptionMarshaller() {
+        switch (version) {
+            case 2:
+                return new 
org.apache.activemq.openwire.v2.ExceptionResponseMarshaller() {
+                    @Override
+                    protected void looseMarshalThrowable(OpenWireFormat 
wireFormat, Throwable o,
+                        DataOutput dataOut) throws IOException {
+                        dataOut.writeBoolean(o != null);
+                        looseMarshalString(NotAThrowable.class.getName(), 
dataOut);
+                        looseMarshalString(o.getMessage(), dataOut);
+                    }
+                };
+            case 3:
+                return new 
org.apache.activemq.openwire.v3.ExceptionResponseMarshaller() {
+                    @Override
+                    protected void looseMarshalThrowable(OpenWireFormat 
wireFormat, Throwable o,
+                        DataOutput dataOut) throws IOException {
+                        dataOut.writeBoolean(o != null);
+                        looseMarshalString(NotAThrowable.class.getName(), 
dataOut);
+                        looseMarshalString(o.getMessage(), dataOut);
+                    }
+                };
+            case 4:
+                return new 
org.apache.activemq.openwire.v4.ExceptionResponseMarshaller() {
+                    @Override
+                    protected void looseMarshalThrowable(OpenWireFormat 
wireFormat, Throwable o,
+                        DataOutput dataOut) throws IOException {
+                        dataOut.writeBoolean(o != null);
+                        looseMarshalString(NotAThrowable.class.getName(), 
dataOut);
+                        looseMarshalString(o.getMessage(), dataOut);
+                    }
+                };
+            case 5:
+                return new 
org.apache.activemq.openwire.v5.ExceptionResponseMarshaller() {
+                    @Override
+                    protected void looseMarshalThrowable(OpenWireFormat 
wireFormat, Throwable o,
+                        DataOutput dataOut) throws IOException {
+                        dataOut.writeBoolean(o != null);
+                        looseMarshalString(NotAThrowable.class.getName(), 
dataOut);
+                        looseMarshalString(o.getMessage(), dataOut);
+                    }
+                };
+            case 6:
+                return new 
org.apache.activemq.openwire.v6.ExceptionResponseMarshaller() {
+                    @Override
+                    protected void looseMarshalThrowable(OpenWireFormat 
wireFormat, Throwable o,
+                        DataOutput dataOut) throws IOException {
+                        dataOut.writeBoolean(o != null);
+                        looseMarshalString(NotAThrowable.class.getName(), 
dataOut);
+                        looseMarshalString(o.getMessage(), dataOut);
+                    }
+                };
+            case 7:
+                return new 
org.apache.activemq.openwire.v7.ExceptionResponseMarshaller() {
+                    @Override
+                    protected void looseMarshalThrowable(OpenWireFormat 
wireFormat, Throwable o,
+                        DataOutput dataOut) throws IOException {
+                        dataOut.writeBoolean(o != null);
+                        looseMarshalString(NotAThrowable.class.getName(), 
dataOut);
+                        looseMarshalString(o.getMessage(), dataOut);
+                    }
+                };
+            case 8:
+                return new 
org.apache.activemq.openwire.v8.ExceptionResponseMarshaller() {
+                    @Override
+                    protected void looseMarshalThrowable(OpenWireFormat 
wireFormat, Throwable o,
+                        DataOutput dataOut) throws IOException {
+                        dataOut.writeBoolean(o != null);
+                        looseMarshalString(NotAThrowable.class.getName(), 
dataOut);
+                        looseMarshalString(o.getMessage(), dataOut);
+                    }
+                };
+            default:
+                throw new IllegalArgumentException("Unknown openwire version 
of " + version);
+        }
+    }
+
+}
diff --git a/pom.xml b/pom.xml
index 1a87e99c3..2482fe748 100644
--- a/pom.xml
+++ b/pom.xml
@@ -325,6 +325,13 @@
         <artifactId>activemq-client</artifactId>
         <version>${project.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.apache.activemq</groupId>
+        <artifactId>activemq-client</artifactId>
+        <version>${project.version}</version>
+        <type>test-jar</type>
+        <scope>test</scope>
+      </dependency>
       <dependency>
         <groupId>org.apache.activemq</groupId>
         <artifactId>activemq-openwire-legacy</artifactId>


Reply via email to