[jboss-svn-commits] JBoss Common SVN: r3642 - in invokablecontainer/trunk: core/src/test/java/org/jboss/ejb3/container/core and 1 other directories.
jboss-svn-commits at lists.jboss.org
jboss-svn-commits at lists.jboss.org
Sat Nov 7 17:26:13 EST 2009
Author: ALRubinger
Date: 2009-11-07 17:26:13 -0500 (Sat, 07 Nov 2009)
New Revision: 3642
Added:
invokablecontainer/trunk/spi/src/main/java/org/jboss/ejb3/container/spi/InvocationContextProvider.java
Modified:
invokablecontainer/trunk/core/src/main/java/org/jboss/ejb3/container/core/InvocationImpl.java
invokablecontainer/trunk/core/src/main/java/org/jboss/ejb3/container/core/MapBasedInvocationContext.java
invokablecontainer/trunk/core/src/test/java/org/jboss/ejb3/container/core/InvocationImplTest.java
invokablecontainer/trunk/core/src/test/java/org/jboss/ejb3/container/core/OriginalVersionInvocationImpl.java
Log:
[EJBTHREE-1948] Do not send the InvocationContext during serialization if it is empty; more tests
Modified: invokablecontainer/trunk/core/src/main/java/org/jboss/ejb3/container/core/InvocationImpl.java
===================================================================
--- invokablecontainer/trunk/core/src/main/java/org/jboss/ejb3/container/core/InvocationImpl.java 2009-11-07 07:07:27 UTC (rev 3641)
+++ invokablecontainer/trunk/core/src/main/java/org/jboss/ejb3/container/core/InvocationImpl.java 2009-11-07 22:26:13 UTC (rev 3642)
@@ -34,6 +34,7 @@
import org.jboss.ejb3.container.api.Invocation;
import org.jboss.ejb3.container.api.InvocationContext;
+import org.jboss.ejb3.container.spi.InvocationContextProvider;
/**
* InvocationImpl
@@ -89,9 +90,11 @@
private transient Method targetMethod;
/**
- * Associated Invocation Context (properties)
+ * Associated Invocation Context (properties); transient because this
+ * won't be written during serialization if empty; instead we put a null placeholder
+ * which will be replaced with a new instance during deserialization
*/
- private final InvocationContext context;
+ private transient InvocationContextProvider context;
//-------------------------------------------------------------------------------------||
// Constructors -----------------------------------------------------------------------||
@@ -119,7 +122,7 @@
* @param args
* @throws IllegalArgumentException If any of the required arguments are not present
*/
- public InvocationImpl(final Method targetMethod, final Object[] args, final InvocationContext context)
+ InvocationImpl(final Method targetMethod, final Object[] args, final InvocationContextProvider context)
{
// Precondition checks
if (targetMethod == null)
@@ -184,7 +187,7 @@
public String toString()
{
return this.getClass().getSimpleName() + " [args=" + Arrays.asList(args).toString() + ", targetMethod="
- + targetMethod + "]";
+ + targetMethod + ", context=" + context + "]";
}
/**
@@ -250,6 +253,18 @@
out.writeObject(name);
out.writeObject(paramTypes);
+ // See if the invocation context is empty
+ InvocationContextProvider contextToWrite = this.context;
+ if (context.isEmpty())
+ {
+ // Null out; we don't need to send empty properties. On deserialization
+ // we'll just re-instantiate.
+ contextToWrite = null;
+ }
+
+ // Write invocation context
+ out.writeObject(contextToWrite);
+
// Log
if (log.isLoggable(Level.FINER))
{
@@ -307,6 +322,22 @@
// Set the target method
this.setTargetMethod(targetMethod);
+ // Set the InvocationContext
+ InvocationContextProvider context = (InvocationContextProvider) in.readObject();
+ // If no context is provided
+ if (context == null)
+ {
+ // Replace with a new instance; this signals empty properties were present when the instance
+ // was serialized
+ if (log.isLoggable(Level.FINER))
+ {
+ log.finer("Encountered null pointer for " + InvocationContext.class.getSimpleName()
+ + " which represents no properties; creating new instance.");
+ }
+ context = new MapBasedInvocationContext();
+ }
+ this.context = context;
+
// Log
if (log.isLoggable(Level.FINER))
{
Modified: invokablecontainer/trunk/core/src/main/java/org/jboss/ejb3/container/core/MapBasedInvocationContext.java
===================================================================
--- invokablecontainer/trunk/core/src/main/java/org/jboss/ejb3/container/core/MapBasedInvocationContext.java 2009-11-07 07:07:27 UTC (rev 3641)
+++ invokablecontainer/trunk/core/src/main/java/org/jboss/ejb3/container/core/MapBasedInvocationContext.java 2009-11-07 22:26:13 UTC (rev 3642)
@@ -20,6 +20,7 @@
import java.util.Map;
import org.jboss.ejb3.container.api.InvocationContext;
+import org.jboss.ejb3.container.spi.InvocationContextProvider;
/**
* MapBasedInvocationContext
@@ -32,7 +33,7 @@
* @author <a href="mailto:andrew.rubinger at jboss.org">ALR</a>
* @version $Revision: $
*/
-final class MapBasedInvocationContext implements InvocationContext
+final class MapBasedInvocationContext implements InvocationContextProvider
{
//-------------------------------------------------------------------------------------||
@@ -104,6 +105,15 @@
return this.getMap().put(key, value);
}
+ /**
+ * @see org.jboss.ejb3.container.spi.InvocationContextProvider#isEmpty()
+ */
+ @Override
+ public boolean isEmpty()
+ {
+ return this.getMap().isEmpty();
+ }
+
//-------------------------------------------------------------------------------------||
// Internal Helper Methods ------------------------------------------------------------||
//-------------------------------------------------------------------------------------||
@@ -128,4 +138,5 @@
{
return "MapBasedInvocationContext [map=" + map + "]";
}
+
}
Modified: invokablecontainer/trunk/core/src/test/java/org/jboss/ejb3/container/core/InvocationImplTest.java
===================================================================
--- invokablecontainer/trunk/core/src/test/java/org/jboss/ejb3/container/core/InvocationImplTest.java 2009-11-07 07:07:27 UTC (rev 3641)
+++ invokablecontainer/trunk/core/src/test/java/org/jboss/ejb3/container/core/InvocationImplTest.java 2009-11-07 22:26:13 UTC (rev 3642)
@@ -41,6 +41,7 @@
import org.jboss.ejb3.container.api.Invocation;
import org.jboss.ejb3.container.api.InvocationContext;
+import org.jboss.ejb3.container.spi.InvocationContextProvider;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -75,6 +76,16 @@
*/
private static Invocation roundtrip;
+ /**
+ * Key for a property within the invocation context
+ */
+ private static final String KEY = "KEY";
+
+ /**
+ * Value to be associated with "KEY" in the invocation context
+ */
+ private static final String VALUE = "VALUE";
+
//-------------------------------------------------------------------------------------||
// Lifecycle --------------------------------------------------------------------------||
//-------------------------------------------------------------------------------------||
@@ -88,24 +99,14 @@
@BeforeClass
public static void initialize() throws Exception
{
- // Obtain information needed to construct an Invocation instance
- final Method targetMethod = Calculator.class.getMethods()[0];
- final Integer[] args =
- {1, 2, 3};
-
// Create an Invocation
- original = new InvocationImpl(targetMethod, args);
- log.info("Created invocation: " + original);
+ original = getInvocation();
+ // Set an InvocationContext property
+ original.getContext().setProperty(KEY, VALUE);
+
// Create a roundtrip instance via serialization
- final ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
- final ObjectOutputStream out = new ObjectOutputStream(byteOut);
- out.writeObject(original);
- out.flush();
- out.close();
- final ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(byteOut.toByteArray()));
- roundtrip = (Invocation) in.readObject();
- in.close();
+ roundtrip = serializeAndDeserialize(original);
log.info("Created a serialized copy of the invocation: " + roundtrip);
}
@@ -211,19 +212,63 @@
public void testInvocationContext() throws IOException
{
// Obtain
- final Invocation invocation = original;
+ final Invocation invocation = roundtrip;
final InvocationContext context = invocation.getContext();
log.info("Got context " + context + " from " + invocation);
// Test
TestCase.assertNotNull("Invocation context should not be null", context);
+
+ // Get out the property
+ final String actual = (String) context.getProperty(KEY);
+ TestCase.assertEquals("Property value was not as expected after serialization", VALUE, actual);
}
+ /**
+ * Tests that an empty {@link InvocationContext} is reinstantiated
+ * during deserialization
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testEmptyInvocationContextReinstantiated() throws Exception
+ {
+ // Make an invocation (with empty InvocationContext)
+ final Invocation invocation = getInvocation();
+
+ // Roundtrip serialization
+ final Invocation roundtrip = serializeAndDeserialize(invocation);
+
+ // Test
+ final InvocationContextProvider context = (InvocationContextProvider) roundtrip.getContext();
+ TestCase.assertNotNull("Empty invocation context after serialization should not be null", context);
+ TestCase.assertTrue("Empty invocation context after serialization should still be empty", context.isEmpty());
+ }
+
//-------------------------------------------------------------------------------------||
// Internal Helper Methods ------------------------------------------------------------||
//-------------------------------------------------------------------------------------||
/**
+ * Obtains a test {@link Invocation}
+ * @return
+ */
+ private static Invocation getInvocation()
+ {
+ // Obtain information needed to construct an Invocation instance
+ final Method targetMethod = Addable.class.getMethods()[0];
+ final Integer[] args =
+ {1, 2, 3};
+
+ // Create an Invocation
+ final Invocation invocation = new InvocationImpl(targetMethod, args);
+ log.info("Created invocation: " + invocation);
+
+ // Return
+ return invocation;
+ }
+
+ /**
* Ensures that the specified client object may be serialized to the specified type
*
* @param clientObject The object to be serialzed
@@ -242,21 +287,44 @@
/**
* Roundtrip serializes/deserializes the specified {@link Invocation}
+ *
+ * @param invocation
+ * @return
+ * @throws IOException
+ * @throws ClassNotFoundException
+ */
+ private static Invocation serializeAndDeserialize(final Invocation invocation) throws IOException,
+ ClassNotFoundException
+ {
+ assert invocation != null : "Invocation must be specified";
+ final ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
+ final ObjectOutputStream out = new ObjectOutputStream(byteOut);
+ out.writeObject(invocation);
+ out.flush();
+ out.close();
+ final ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(byteOut.toByteArray()));
+ final Invocation roundtrip = (Invocation) in.readObject();
+ in.close();
+ return roundtrip;
+ }
+
+ /**
+ * Roundtrip serializes/deserializes the specified {@link Invocation}
* and reconsitutes/redefines as the specified target type
*
- * @param o The original {@link Invocation} instance
+ * @param invocation The original {@link Invocation} instance
* @param The new type we should cast to after deserialization
* @see http://crazybob.org/2006/01/unit-testing-serialization-evolution.html
* @see http://crazybob.org/2006/01/unit-testing-serialization-evolution_13.html
* @see http://www.theserverside.com/news/thread.tss?thread_id=38398
* @author Bob Lee
*/
- private static <S extends Invocation> S serializeAndDeserialize(final Invocation o, final Class<S> targetType)
- throws IOException
+ private static <S extends Invocation> S serializeAndDeserialize(final Invocation invocation,
+ final Class<S> targetType) throws IOException
{
final ByteArrayOutputStream bout = new ByteArrayOutputStream();
- final ObjectOutputStream oout = new SpoofingObjectOutputStream(bout, o.getClass(), targetType);
- oout.writeObject(o);
+ final ObjectOutputStream oout = new SpoofingObjectOutputStream(bout, invocation.getClass(), targetType);
+ oout.writeObject(invocation);
oout.flush();
oout.close();
final ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
@@ -265,7 +333,7 @@
{
final Object obj = oin.readObject();
oin.close();
- log.info("Original invocation type " + o.getClass().getName() + " now represented as "
+ log.info("Original invocation type " + invocation.getClass().getName() + " now represented as "
+ obj.getClass().getName());
return targetType.cast(obj);
}
Modified: invokablecontainer/trunk/core/src/test/java/org/jboss/ejb3/container/core/OriginalVersionInvocationImpl.java
===================================================================
--- invokablecontainer/trunk/core/src/test/java/org/jboss/ejb3/container/core/OriginalVersionInvocationImpl.java 2009-11-07 07:07:27 UTC (rev 3641)
+++ invokablecontainer/trunk/core/src/test/java/org/jboss/ejb3/container/core/OriginalVersionInvocationImpl.java 2009-11-07 22:26:13 UTC (rev 3642)
@@ -22,16 +22,19 @@
package org.jboss.ejb3.container.core;
import java.io.IOException;
+import java.io.InvalidClassException;
+import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Arrays;
+import java.util.logging.Level;
import java.util.logging.Logger;
import org.jboss.ejb3.container.api.Invocation;
import org.jboss.ejb3.container.api.InvocationContext;
-import org.jboss.ejb3.container.core.InvocationImpl;
+import org.jboss.ejb3.container.spi.InvocationContextProvider;
/**
* OriginalVersionInvocationImpl
@@ -76,6 +79,13 @@
*/
private transient Method targetMethod;
+ /**
+ * Associated Invocation Context (properties); transient because this
+ * won't be written during serialization if empty; instead we put a null placeholder
+ * which will be replaced with a new instance during deserialization
+ */
+ private transient InvocationContextProvider context;
+
//-------------------------------------------------------------------------------------||
// Constructors -----------------------------------------------------------------------||
//-------------------------------------------------------------------------------------||
@@ -90,6 +100,20 @@
*/
public OriginalVersionInvocationImpl(final Method targetMethod, final Object[] args)
{
+ this(targetMethod, args, new MapBasedInvocationContext());
+ }
+
+ /**
+ * Constructs a new instance of this invocation, representing the
+ * specified target method and arguments. Backed by the specified
+ * {@link InvocationContext}.
+ *
+ * @param targetMethod
+ * @param args
+ * @throws IllegalArgumentException If any of the required arguments are not present
+ */
+ OriginalVersionInvocationImpl(final Method targetMethod, final Object[] args, final InvocationContextProvider context)
+ {
// Precondition checks
if (targetMethod == null)
{
@@ -99,10 +123,16 @@
{
throw new IllegalArgumentException("Arguments for the target method must be specified");
}
+ if (context == null)
+ {
+ throw new IllegalArgumentException("Context must be specified");
+ }
// Set
this.targetMethod = targetMethod;
this.args = args;
+ // We don't need to defensively copy the invocation context as it's exposed via getContext() anyway
+ this.context = context;
}
//-------------------------------------------------------------------------------------||
@@ -112,6 +142,7 @@
/**
* @see org.jboss.ejb3.container.api.Invocation#getArgs()
*/
+ @Override
public Object[] getArgs()
{
return args;
@@ -120,15 +151,16 @@
/**
* @see org.jboss.ejb3.container.api.Invocation#getContext()
*/
+ @Override
public InvocationContext getContext()
{
- // TODO Auto-generated method stub
- return null;
+ return this.context;
}
/**
* @see org.jboss.ejb3.container.api.Invocation#getTargetMethod()
*/
+ @Override
public Method getTargetMethod()
{
return this.targetMethod;
@@ -144,8 +176,8 @@
@Override
public String toString()
{
- return this.getClass().getSimpleName() + " [args=" + Arrays.toString(args) + ", targetMethod=" + targetMethod
- + "]";
+ return this.getClass().getSimpleName() + " [args=" + Arrays.asList(args).toString() + ", targetMethod="
+ + targetMethod + "]";
}
/**
@@ -165,7 +197,7 @@
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
- public boolean equals(Object obj)
+ public boolean equals(final Object obj)
{
if (this == obj)
return true;
@@ -211,8 +243,23 @@
out.writeObject(name);
out.writeObject(paramTypes);
+ // See if the invocation context is empty
+ InvocationContextProvider contextToWrite = this.context;
+ if (context.isEmpty())
+ {
+ // Null out; we don't need to send empty properties. On deserialization
+ // we'll just re-instantiate.
+ contextToWrite = null;
+ }
+
+ // Write invocation context
+ out.writeObject(contextToWrite);
+
// Log
- log.finer("Serialized: " + this);
+ if (log.isLoggable(Level.FINER))
+ {
+ log.finer("Serialized: " + this);
+ }
}
/**
@@ -238,15 +285,15 @@
// Some more assertions
if (declaringClass == null)
{
- throw new IllegalArgumentException("Declaring class was not read in during deserialization");
+ throw new InvalidObjectException("Declaring class was not read in during deserialization");
}
if (methodName == null)
{
- throw new IllegalArgumentException("Target method name was not read in during deserialization");
+ throw new InvalidObjectException("Target method name was not read in during deserialization");
}
if (paramTypes == null)
{
- throw new IllegalArgumentException(
+ throw new InvalidObjectException(
"Parameter types of the target method were not read in during deserialization");
}
@@ -258,15 +305,34 @@
}
catch (final NoSuchMethodException nsme)
{
- throw new RuntimeException("Could not deserialize; no target method \"" + methodName + " found in "
+ throw new InvalidClassException("Could not deserialize; no target method \"" + methodName + " found in "
+ declaringClass.getName() + " with param types " + Arrays.asList(paramTypes));
}
// Set the target method
this.setTargetMethod(targetMethod);
+ // Set the InvocationContext
+ InvocationContextProvider context = (InvocationContextProvider) in.readObject();
+ // If no context is provided
+ if (context == null)
+ {
+ // Replace with a new instance; this signals empty properties were present when the instance
+ // was serialized
+ if (log.isLoggable(Level.FINER))
+ {
+ log.finer("Encountered null pointer for " + InvocationContext.class.getSimpleName()
+ + " which represents no properties; creating new instance.");
+ }
+ context = new MapBasedInvocationContext();
+ }
+ this.context = context;
+
// Log
- log.finer("Deserialized: " + this);
+ if (log.isLoggable(Level.FINER))
+ {
+ log.finer("Deserialized: " + this);
+ }
}
//-------------------------------------------------------------------------------------||
Added: invokablecontainer/trunk/spi/src/main/java/org/jboss/ejb3/container/spi/InvocationContextProvider.java
===================================================================
--- invokablecontainer/trunk/spi/src/main/java/org/jboss/ejb3/container/spi/InvocationContextProvider.java (rev 0)
+++ invokablecontainer/trunk/spi/src/main/java/org/jboss/ejb3/container/spi/InvocationContextProvider.java 2009-11-07 22:26:13 UTC (rev 3642)
@@ -0,0 +1,41 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * Licensed 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.jboss.ejb3.container.spi;
+
+import org.jboss.ejb3.container.api.InvocationContext;
+
+/**
+ * InvocationContextProvider
+ *
+ * Contract for implementations of an
+ * {@link InvocationContext}
+ *
+ * @author <a href="mailto:andrew.rubinger at jboss.org">ALR</a>
+ * @version $Revision: $
+ */
+public interface InvocationContextProvider extends InvocationContext
+{
+
+ //-------------------------------------------------------------------------------------||
+ // Contracts --------------------------------------------------------------------------||
+ //-------------------------------------------------------------------------------------||
+
+ /**
+ * Determines whether the context properties are empty (ie. none exist)
+ */
+ boolean isEmpty();
+}
More information about the jboss-svn-commits
mailing list