[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