[jbosscache-commits] JBoss Cache SVN: r7682 - in core/branches/flat/src: main/java/org/horizon/config and 10 other directories.

jbosscache-commits at lists.jboss.org jbosscache-commits at lists.jboss.org
Wed Feb 11 07:53:09 EST 2009


Author: mircea.markus
Date: 2009-02-11 07:53:09 -0500 (Wed, 11 Feb 2009)
New Revision: 7682

Added:
   core/branches/flat/src/test/java/org/horizon/interceptors/
   core/branches/flat/src/test/java/org/horizon/interceptors/MarshalledValueInterceptorTest.java
   core/branches/flat/src/test/java/org/horizon/marshall/
   core/branches/flat/src/test/java/org/horizon/marshall/MarshalledValueTest.java
Removed:
   core/branches/flat/src/main/java/org/horizon/marshall/MarshalledValueHelper.java
   core/branches/flat/src/main/java/org/horizon/marshall/MarshalledValueMap.java
Modified:
   core/branches/flat/src/main/java/org/horizon/Cache.java
   core/branches/flat/src/main/java/org/horizon/CacheDelegate.java
   core/branches/flat/src/main/java/org/horizon/config/GlobalConfiguration.java
   core/branches/flat/src/main/java/org/horizon/config/parsing/XmlConfigurationParserImpl.java
   core/branches/flat/src/main/java/org/horizon/interceptors/MarshalledValueInterceptor.java
   core/branches/flat/src/main/java/org/horizon/marshall/MarshalledValue.java
   core/branches/flat/src/main/resources/config-samples/all.xml
   core/branches/flat/src/main/resources/schema/horizon-config-1.0.xsd
   core/branches/flat/src/test/java/org/horizon/config/parsing/ConfigurationParserTest.java
   core/branches/flat/src/test/java/org/horizon/config/parsing/XmlFileParsingTest.java
   core/branches/flat/src/test/resources/configs/named-cache-test.xml
Log:
added support for lazy deserialization

Modified: core/branches/flat/src/main/java/org/horizon/Cache.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/Cache.java	2009-02-11 11:09:31 UTC (rev 7681)
+++ core/branches/flat/src/main/java/org/horizon/Cache.java	2009-02-11 12:53:09 UTC (rev 7682)
@@ -140,5 +140,14 @@
 
    AdvancedCache<K, V> getAdvancedCache();
 
+   /**
+    * Method that releases object references of cached objects held in the cache by serializing them to byte buffers.
+    * Cached objects are lazily deserialized when accessed again, based on the calling thread's context class loader.
+    * <p/>
+    * This can be expensive, based on the effort required to serialize cached objects.
+    * <p/>
+    */
+   void compact();
+
    ComponentStatus getStatus();
 }

Modified: core/branches/flat/src/main/java/org/horizon/CacheDelegate.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/CacheDelegate.java	2009-02-11 11:09:31 UTC (rev 7681)
+++ core/branches/flat/src/main/java/org/horizon/CacheDelegate.java	2009-02-11 12:53:09 UTC (rev 7682)
@@ -50,6 +50,7 @@
 import org.horizon.logging.Log;
 import org.horizon.logging.LogFactory;
 import org.horizon.manager.CacheManager;
+import org.horizon.marshall.MarshalledValue;
 import org.horizon.marshall.Marshaller;
 import org.horizon.notifications.cachelistener.CacheNotifier;
 import org.horizon.remoting.RPCManager;
@@ -432,4 +433,23 @@
    public AdvancedCache<K, V> getAdvancedCache() {
       return this;
    }
+
+   public void compact() {
+      for (Object key : dataContainer.keySet())
+      {
+         // get the key first, before attempting to serialize stuff since data.get() may deserialize the key if doing
+         // a hashcode() or equals().
+
+         Object value = dataContainer.get(key);
+         if (key instanceof MarshalledValue)
+         {
+            ((MarshalledValue) key).compact(true, true);
+         }
+
+         if (value instanceof MarshalledValue)
+         {
+            ((MarshalledValue) value).compact(true, true);
+         }
+      }
+   }
 }

Modified: core/branches/flat/src/main/java/org/horizon/config/GlobalConfiguration.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/config/GlobalConfiguration.java	2009-02-11 11:09:31 UTC (rev 7681)
+++ core/branches/flat/src/main/java/org/horizon/config/GlobalConfiguration.java	2009-02-11 12:53:09 UTC (rev 7682)
@@ -31,23 +31,23 @@
     */
    public static final short DEFAULT_MARSHALL_VERSION = Version.getVersionShort();
 
-   String asyncListenerExecutorFactoryClass = DefaultExecutorFactory.class.getName();
-   TypedProperties asyncListenerExecutorProperties = EMPTY_PROPERTIES;
-   String asyncSerializationExecutorFactoryClass = DefaultExecutorFactory.class.getName();
-   TypedProperties asyncSerializationExecutorProperties = EMPTY_PROPERTIES;
-   String evictionScheduledExecutorFactoryClass = DefaultScheduledExecutorFactory.class.getName();
-   TypedProperties evictionScheduledExecutorProperties = EMPTY_PROPERTIES;
-   String replicationQueueScheduledExecutorFactoryClass = DefaultScheduledExecutorFactory.class.getName();
-   TypedProperties replicationQueueScheduledExecutorProperties = EMPTY_PROPERTIES;
-   String marshallerClass = VersionAwareMarshaller.class.getName(); // the default
-   int objectInputStreamPoolSize = 50; // defaults
-   int objectOutputStreamPoolSize = 50; // defaults
-   String transportClass = null; // this defaults to a non-clustered cache.
-   TypedProperties transportProperties = EMPTY_PROPERTIES;
-   Configuration defaultConfiguration;
-   String clusterName = "Horizon-Cluster";
-   ShutdownHookBehavior shutdownHookBehavior = ShutdownHookBehavior.DEFAULT;
-   short marshallVersion = DEFAULT_MARSHALL_VERSION;
+   private String asyncListenerExecutorFactoryClass = DefaultExecutorFactory.class.getName();
+   private TypedProperties asyncListenerExecutorProperties = EMPTY_PROPERTIES;
+   private String asyncSerializationExecutorFactoryClass = DefaultExecutorFactory.class.getName();
+   private TypedProperties asyncSerializationExecutorProperties = EMPTY_PROPERTIES;
+   private String evictionScheduledExecutorFactoryClass = DefaultScheduledExecutorFactory.class.getName();
+   private TypedProperties evictionScheduledExecutorProperties = EMPTY_PROPERTIES;
+   private String replicationQueueScheduledExecutorFactoryClass = DefaultScheduledExecutorFactory.class.getName();
+   private TypedProperties replicationQueueScheduledExecutorProperties = EMPTY_PROPERTIES;
+   private String marshallerClass = VersionAwareMarshaller.class.getName(); // the default
+   private int objectInputStreamPoolSize = 50; // defaults
+   private int objectOutputStreamPoolSize = 50; // defaults
+   private String transportClass = null; // this defaults to a non-clustered cache.
+   private TypedProperties transportProperties = EMPTY_PROPERTIES;
+   private Configuration defaultConfiguration;
+   private String clusterName = "Horizon-Cluster";
+   private ShutdownHookBehavior shutdownHookBehavior = ShutdownHookBehavior.DEFAULT;
+   private short marshallVersion = DEFAULT_MARSHALL_VERSION;
 
    private GlobalComponentRegistry gcr;
 

Modified: core/branches/flat/src/main/java/org/horizon/config/parsing/XmlConfigurationParserImpl.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/config/parsing/XmlConfigurationParserImpl.java	2009-02-11 11:09:31 UTC (rev 7681)
+++ core/branches/flat/src/main/java/org/horizon/config/parsing/XmlConfigurationParserImpl.java	2009-02-11 12:53:09 UTC (rev 7682)
@@ -151,6 +151,7 @@
       configureLocking(getSingleElementInCoreNS("locking", e), c);
       configureTransaction(getSingleElementInCoreNS("transaction", e), c);
       configureJmxStatistics(getSingleElementInCoreNS("jmxStatistics", e), c);
+      configureLazyDeserialization(getSingleElementInCoreNS("lazyDeserialization", e), c);
       configureInvocationBatching(getSingleElementInCoreNS("invocationBatching", e), c);
       configureClustering(getSingleElementInCoreNS("clustering", e), c);
       configureEviction(getSingleElementInCoreNS("eviction", e), c);
@@ -293,6 +294,15 @@
       }
    }
 
+   void configureLazyDeserialization(Element element, Configuration config) {
+      if (element != null) {
+         String enabled = getAttributeValue(element, "enabled");
+         if (existsAttribute(enabled)) {
+            config.setUseLazyDeserialization(getBoolean(enabled));
+         }
+      }
+   }
+
    void configureInvalidation(Element element, Configuration config) {
       if (element == null) return; //might be replication
       Element async = getSingleElement("async");

Modified: core/branches/flat/src/main/java/org/horizon/interceptors/MarshalledValueInterceptor.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/interceptors/MarshalledValueInterceptor.java	2009-02-11 11:09:31 UTC (rev 7681)
+++ core/branches/flat/src/main/java/org/horizon/interceptors/MarshalledValueInterceptor.java	2009-02-11 12:53:09 UTC (rev 7682)
@@ -28,7 +28,6 @@
 import org.horizon.context.InvocationContext;
 import org.horizon.interceptors.base.CommandInterceptor;
 import org.horizon.marshall.MarshalledValue;
-import org.horizon.marshall.MarshalledValueHelper;
 
 import java.io.IOException;
 import java.io.NotSerializableException;
@@ -47,6 +46,7 @@
  * representations.
  *
  * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @author Mircea.Markus at jboss.com
  * @see org.horizon.marshall.MarshalledValue
  * @since 1.0
  */
@@ -54,59 +54,68 @@
    @Override
    public Object visitPutMapCommand(InvocationContext ctx, PutMapCommand command) throws Throwable {
       Set<MarshalledValue> marshalledValues = new HashSet<MarshalledValue>();
-
-      command.setMap(wrapMap(command.getMap(), marshalledValues, ctx));
+      Map map = wrapMap(command.getMap(), marshalledValues, ctx);
+      command.setMap(map);
       Object retVal = invokeNextInterceptor(ctx, command);
       return compactAndProcessRetVal(marshalledValues, retVal);
    }
 
    @Override
    public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable {
-      Set<MarshalledValue> marshalledValues = new HashSet<MarshalledValue>();
-      if (!MarshalledValueHelper.isTypeExcluded(command.getKey().getClass())) {
-         Object newKey = createAndAddMarshalledValue(command.getKey(), marshalledValues, ctx);
-         command.setKey(newKey);
+      MarshalledValue key = null;
+      MarshalledValue value = null;
+      if (!MarshalledValue.isTypeExcluded(command.getKey().getClass())) {
+         key = createMarshalledValue(command.getKey(), ctx);
+         command.setKey(key);
       }
-      if (!MarshalledValueHelper.isTypeExcluded(command.getValue().getClass())) {
-         Object value = createAndAddMarshalledValue(command.getValue(), marshalledValues, ctx);
+      if (!MarshalledValue.isTypeExcluded(command.getValue().getClass())) {
+         value = createMarshalledValue(command.getValue(), ctx);
          command.setValue(value);
       }
       Object retVal = invokeNextInterceptor(ctx, command);
-      return compactAndProcessRetVal(marshalledValues, retVal);
+      compact(key);
+      compact(value);
+      return processRetVal(retVal);
    }
 
    @Override
    public Object visitRemoveCommand(InvocationContext ctx, RemoveCommand command) throws Throwable {
-      Set<MarshalledValue> marshalledValues = new HashSet<MarshalledValue>();
-      if (!MarshalledValueHelper.isTypeExcluded(command.getKey().getClass())) {
-         Object value = createAndAddMarshalledValue(command.getKey(), marshalledValues, ctx);
+      MarshalledValue value = null;
+      if (!MarshalledValue.isTypeExcluded(command.getKey().getClass())) {
+         value = createMarshalledValue(command.getKey(), ctx);
          command.setKey(value);
       }
       Object retVal = invokeNextInterceptor(ctx, command);
-      return compactAndProcessRetVal(marshalledValues, retVal);
+      compact(value);
+      return processRetVal(retVal);
    }
 
    @Override
    public Object visitGetKeyValueCommand(InvocationContext ctx, GetKeyValueCommand command) throws Throwable {
-      Set<MarshalledValue> marshalledValues = new HashSet<MarshalledValue>();
-      if (!MarshalledValueHelper.isTypeExcluded(command.getKey().getClass())) {
-         Object value = createAndAddMarshalledValue(command.getKey(), marshalledValues, ctx);
-         command.setKey(value);
+      MarshalledValue mv = null;
+      if (!MarshalledValue.isTypeExcluded(command.getKey().getClass())) {
+         mv = createMarshalledValue(command.getKey(), ctx);
+         command.setKey(mv);
+         compact(mv);
       }
       Object retVal = invokeNextInterceptor(ctx, command);
-      return compactAndProcessRetVal(marshalledValues, retVal);
+      compact(mv);
+      return processRetVal(retVal);
    }
 
    private Object compactAndProcessRetVal(Set<MarshalledValue> marshalledValues, Object retVal)
          throws IOException, ClassNotFoundException {
       if (trace) log.trace("Compacting MarshalledValues created");
-      for (MarshalledValue mv : marshalledValues) mv.compact(false, false);
-
+      for (MarshalledValue mv : marshalledValues) compact(mv);
       return processRetVal(retVal);
    }
 
-   private Object processRetVal(Object retVal)
-         throws IOException, ClassNotFoundException {
+   private void compact(MarshalledValue mv) {
+      if (mv == null) return;
+      mv.compact(false, false);
+   }
+
+   private Object processRetVal(Object retVal) throws IOException, ClassNotFoundException {
       if (retVal instanceof MarshalledValue) {
          if (trace) log.trace("Return value is a MarshalledValue.  Unwrapping.");
          retVal = ((MarshalledValue) retVal).get();
@@ -125,16 +134,16 @@
       for (Map.Entry me : m.entrySet()) {
          Object key = me.getKey();
          Object value = me.getValue();
-         copy.put((key == null || MarshalledValueHelper.isTypeExcluded(key.getClass())) ? key : createAndAddMarshalledValue(key, marshalledValues, ctx),
-                  (value == null || MarshalledValueHelper.isTypeExcluded(value.getClass())) ? value : createAndAddMarshalledValue(value, marshalledValues, ctx));
+         Object newKey = (key == null || MarshalledValue.isTypeExcluded(key.getClass())) ? key : createMarshalledValue(key, ctx);
+         Object newValue = (value == null || MarshalledValue.isTypeExcluded(value.getClass())) ? value : createMarshalledValue(value, ctx);
+         if (newKey instanceof MarshalledValue) marshalledValues.add((MarshalledValue) newKey);
+         if (newValue instanceof MarshalledValue) marshalledValues.add((MarshalledValue) newValue);
+         copy.put(newKey, newValue);
       }
       return copy;
    }
 
-   protected MarshalledValue createAndAddMarshalledValue(Object toWrap, Set<MarshalledValue> marshalledValues, InvocationContext ctx) throws NotSerializableException {
-      MarshalledValue mv = new MarshalledValue(toWrap);
-      marshalledValues.add(mv);
-      if (!ctx.isOriginLocal()) mv.setEqualityPreferenceForInstance(false);
-      return mv;
+   protected MarshalledValue createMarshalledValue(Object toWrap, InvocationContext ctx) throws NotSerializableException {
+      return new MarshalledValue(toWrap, ctx.isOriginLocal());
    }
 }

Modified: core/branches/flat/src/main/java/org/horizon/marshall/MarshalledValue.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/marshall/MarshalledValue.java	2009-02-11 11:09:31 UTC (rev 7681)
+++ core/branches/flat/src/main/java/org/horizon/marshall/MarshalledValue.java	2009-02-11 12:53:09 UTC (rev 7682)
@@ -22,6 +22,9 @@
 package org.horizon.marshall;
 
 import org.horizon.CacheException;
+import org.horizon.commands.ReplicableCommand;
+import org.horizon.remoting.transport.Address;
+import org.horizon.transaction.GlobalTransaction;
 import org.jboss.util.stream.MarshalledValueInputStream;
 
 import java.io.*;
@@ -35,6 +38,7 @@
  * <p/>
  *
  * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @author Mircea.Markus at jboss.com
  * @see org.horizon.interceptors.MarshalledValueInterceptor
  * @since 1.0
  */
@@ -45,23 +49,20 @@
    // by default equals() will test on the istance rather than the byte array if conversion is required.
    private transient boolean equalityPreferenceForInstance = true;
 
-   public MarshalledValue(Object instance) throws NotSerializableException {
+   public MarshalledValue(Object instance, boolean equalityPreferenceForInstance) throws NotSerializableException {
       if (instance == null) throw new NullPointerException("Null values cannot be wrapped as MarshalledValues!");
 
       if (instance instanceof Serializable)
          this.instance = instance;
       else
          throw new NotSerializableException("Marshalled values can only wrap Objects that are serializable!  Instance of " + instance.getClass() + " won't Serialize.");
+      this.equalityPreferenceForInstance = equalityPreferenceForInstance;
    }
 
    public MarshalledValue() {
       // empty ctor for serialization
    }
 
-   public void setEqualityPreferenceForInstance(boolean equalityPreferenceForInstance) {
-      this.equalityPreferenceForInstance = equalityPreferenceForInstance;
-   }
-
    public synchronized void serialize() {
       if (raw == null) {
          try {
@@ -72,7 +73,6 @@
             baos.close();
             // Do NOT set instance to null over here, since it may be used elsewhere (e.g., in a cache listener).
             // this will be compacted by the MarshalledValueInterceptor when the call returns.
-//            instance = null;
             raw = baos.toByteArray();
          }
          catch (Exception e) {
@@ -90,7 +90,6 @@
             instance = ois.readObject();
             ois.close();
             bais.close();
-//            raw = null;
          }
          catch (Exception e) {
             throw new CacheException("Unable to unmarshall value", e);
@@ -123,13 +122,17 @@
          // need to lose one representation!
 
          if (preferSerializedRepresentation) {
-            instance = null;
+            nullifyInstance();
          } else {
             raw = null;
          }
       }
    }
 
+   private synchronized void nullifyInstance() {
+      instance = null;
+   }
+
    public void writeExternal(ObjectOutput out) throws IOException {
       if (raw == null) serialize();
       out.writeInt(raw.length);
@@ -145,7 +148,13 @@
       cachedHashCode = in.readInt();
    }
 
-   public Object get() throws IOException, ClassNotFoundException {
+   /**
+    * Returns the 'cached' instance.
+    * Impl note: this method is synchronized so that it synchronizez with the code that nullifies the instance.
+    *
+    * @see #nullifyInstance() 
+    */
+   public synchronized Object get() throws IOException, ClassNotFoundException {
       if (instance == null) deserialize();
       return instance;
    }
@@ -191,4 +200,19 @@
    public String toString() {
       return "MarshalledValue(cachedHashCode=" + cachedHashCode + "; serialized=" + (raw != null) + ")";
    }
+
+   /**
+    * Tests whether the type should be excluded from MarshalledValue wrapping.
+    *
+    * @param type type to test.  Should not be null.
+    * @return true if it should be excluded from MarshalledValue wrapping.
+    */
+   public static boolean isTypeExcluded(Class type) {
+      return type.equals(String.class) || type.isPrimitive() ||
+            type.equals(Void.class) || type.equals(Boolean.class) || type.equals(Character.class) ||
+            type.equals(Byte.class) || type.equals(Short.class) || type.equals(Integer.class) ||
+            type.equals(Long.class) || type.equals(Float.class) || type.equals(Double.class) ||
+            (type.isArray() && isTypeExcluded(type.getComponentType())) || type.equals(GlobalTransaction.class) || Address.class.isAssignableFrom(type) ||
+            ReplicableCommand.class.isAssignableFrom(type) || type.equals(MarshalledValue.class);
+   }
 }

Deleted: core/branches/flat/src/main/java/org/horizon/marshall/MarshalledValueHelper.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/marshall/MarshalledValueHelper.java	2009-02-11 11:09:31 UTC (rev 7681)
+++ core/branches/flat/src/main/java/org/horizon/marshall/MarshalledValueHelper.java	2009-02-11 12:53:09 UTC (rev 7682)
@@ -1,53 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.horizon.marshall;
-
-import org.horizon.commands.ReplicableCommand;
-import org.horizon.remoting.transport.Address;
-import org.horizon.transaction.GlobalTransaction;
-
-/**
- * Common functionality used by the {@link org.horizon.interceptors.MarshalledValueInterceptor} and the {@link
- * MarshalledValueMap}.
- *
- * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
- * @see MarshalledValue
- * @see org.horizon.interceptors.MarshalledValueInterceptor
- * @see MarshalledValueMap
- * @since 1.0
- */
-public class MarshalledValueHelper {
-   /**
-    * Tests whether the type should be excluded from MarshalledValue wrapping.
-    *
-    * @param type type to test.  Should not be null.
-    * @return true if it should be excluded from MarshalledValue wrapping.
-    */
-   public static boolean isTypeExcluded(Class type) {
-      return type.equals(String.class) || type.isPrimitive() ||
-            type.equals(Void.class) || type.equals(Boolean.class) || type.equals(Character.class) ||
-            type.equals(Byte.class) || type.equals(Short.class) || type.equals(Integer.class) ||
-            type.equals(Long.class) || type.equals(Float.class) || type.equals(Double.class) ||
-            (type.isArray() && isTypeExcluded(type.getComponentType())) || type.equals(GlobalTransaction.class) || Address.class.isAssignableFrom(type) ||
-            ReplicableCommand.class.isAssignableFrom(type) || type.equals(MarshalledValue.class);
-   }
-}

Deleted: core/branches/flat/src/main/java/org/horizon/marshall/MarshalledValueMap.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/marshall/MarshalledValueMap.java	2009-02-11 11:09:31 UTC (rev 7681)
+++ core/branches/flat/src/main/java/org/horizon/marshall/MarshalledValueMap.java	2009-02-11 12:53:09 UTC (rev 7682)
@@ -1,155 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.horizon.marshall;
-
-import net.jcip.annotations.Immutable;
-import org.horizon.CacheException;
-
-import java.io.Externalizable;
-import java.io.IOException;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * A Map that is able to wrap/unwrap MarshalledValues in keys or values.  Note that calling keySet(), entrySet() or
- * values() could be expensive if this map is large!!
- * <p/>
- * Also note that this is an immutable Map.
- * <p/>
- *
- * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
- * @see MarshalledValue
- * @since 1.0
- */
- at Immutable
-public class MarshalledValueMap implements Map, Externalizable {
-   Map delegate;
-   Map<Object, Object> unmarshalled;
-
-   public MarshalledValueMap() {
-      // for externalization
-   }
-
-   public MarshalledValueMap(Map delegate) {
-      this.delegate = delegate;
-   }
-
-   @SuppressWarnings("unchecked")
-   protected synchronized Map getUnmarshalledMap() {
-      if (unmarshalled == null) unmarshalled = unmarshalledMap(delegate.entrySet());
-      return unmarshalled;
-   }
-
-   public int size() {
-      return delegate.size();
-   }
-
-   public boolean isEmpty() {
-      return delegate.isEmpty();
-   }
-
-   public boolean containsKey(Object key) {
-      return getUnmarshalledMap().containsKey(key);
-   }
-
-   public boolean containsValue(Object value) {
-      return getUnmarshalledMap().containsValue(value);
-   }
-
-   public Object get(Object key) {
-      return getUnmarshalledMap().get(key);
-   }
-
-   public Object put(Object key, Object value) {
-      throw new UnsupportedOperationException("This is an immutable map!");
-   }
-
-   public Object remove(Object key) {
-      throw new UnsupportedOperationException("This is an immutable map!");
-   }
-
-   public void putAll(Map t) {
-      throw new UnsupportedOperationException("This is an immutable map!");
-   }
-
-   public void clear() {
-      throw new UnsupportedOperationException("This is an immutable map!");
-   }
-
-   public Set keySet() {
-      return getUnmarshalledMap().keySet();
-   }
-
-   public Collection values() {
-      return getUnmarshalledMap().values();
-   }
-
-   public Set entrySet() {
-      return getUnmarshalledMap().entrySet();
-   }
-
-   @SuppressWarnings("unchecked")
-   protected Map unmarshalledMap(Set entries) {
-      if (entries == null || entries.isEmpty()) return Collections.emptyMap();
-      Map map = new HashMap(entries.size());
-      for (Object e : entries) {
-         Map.Entry entry = (Map.Entry) e;
-         map.put(getUnmarshalledValue(entry.getKey()), getUnmarshalledValue(entry.getValue()));
-      }
-      return map;
-   }
-
-   private Object getUnmarshalledValue(Object o) {
-      try {
-         return o instanceof MarshalledValue ? ((MarshalledValue) o).get() : o;
-      }
-      catch (Exception e) {
-         throw new CacheException("Unable to unmarshall value", e);
-      }
-   }
-
-   @Override
-   public boolean equals(Object other) {
-      if (other instanceof Map) {
-         return getUnmarshalledMap().equals(other);
-      }
-      return false;
-   }
-
-   @Override
-   public int hashCode() {
-      return getUnmarshalledMap().hashCode();
-   }
-
-   public void writeExternal(ObjectOutput out) throws IOException {
-      out.writeObject(delegate);
-   }
-
-   public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
-      delegate = (Map) in.readObject();
-   }
-}

Modified: core/branches/flat/src/main/resources/config-samples/all.xml
===================================================================
--- core/branches/flat/src/main/resources/config-samples/all.xml	2009-02-11 11:09:31 UTC (rev 7681)
+++ core/branches/flat/src/main/resources/config-samples/all.xml	2009-02-11 12:53:09 UTC (rev 7682)
@@ -77,6 +77,8 @@
       -->
       <jmxStatistics enabled="false"/>
 
+      <lazyDeserialization enabled="false"/>
+
       <!--
          Used to enable invocation batching and allow the use of Cache.startBatch()/endBatch() methods.
       -->

Modified: core/branches/flat/src/main/resources/schema/horizon-config-1.0.xsd
===================================================================
--- core/branches/flat/src/main/resources/schema/horizon-config-1.0.xsd	2009-02-11 11:09:31 UTC (rev 7681)
+++ core/branches/flat/src/main/resources/schema/horizon-config-1.0.xsd	2009-02-11 12:53:09 UTC (rev 7682)
@@ -47,6 +47,7 @@
          <xs:element name="locking" type="tns:lockingType" minOccurs="0" maxOccurs="1"/>
          <xs:element name="transaction" type="tns:transactionType" minOccurs="0" maxOccurs="1"/>
          <xs:element name="jmxStatistics" type="tns:jmxStatisticsType" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="lazyDeserialization" type="tns:lazyDeserialization" minOccurs="0" maxOccurs="1"/>
          <xs:element name="invocationBatching" type="tns:invocationBatchingType" minOccurs="0" maxOccurs="1"/>
          <xs:element name="eviction" type="tns:evictionType" minOccurs="0" maxOccurs="1"/>
          <xs:element name="loaders" type="tns:loadersType" minOccurs="0" maxOccurs="1"/>
@@ -108,10 +109,6 @@
       </xs:attribute>
    </xs:complexType>
 
-   <xs:complexType name="serializationType">
-      <xs:attribute name="useLazyDeserialization" type="tns:booleanType"/>
-   </xs:complexType>
-
    <xs:simpleType name="booleanType">
       <xs:restriction base="xs:string">
          <xs:pattern value="\$\{.*\}|[Tt][Rr][Uu][Ee]|[Ff][Aa][Ll][Ss][Ee]"/>
@@ -128,6 +125,10 @@
       <xs:attribute name="enabled" type="tns:booleanType"/>
    </xs:complexType>
 
+   <xs:complexType name="lazyDeserialization">
+      <xs:attribute name="enabled" type="tns:booleanType"/>
+   </xs:complexType>
+
    <xs:complexType name="invocationBatchingType">
       <xs:attribute name="enabled" type="tns:booleanType"/>
    </xs:complexType>

Modified: core/branches/flat/src/test/java/org/horizon/config/parsing/ConfigurationParserTest.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/config/parsing/ConfigurationParserTest.java	2009-02-11 11:09:31 UTC (rev 7681)
+++ core/branches/flat/src/test/java/org/horizon/config/parsing/ConfigurationParserTest.java	2009-02-11 12:53:09 UTC (rev 7682)
@@ -75,6 +75,17 @@
       assert c.isExposeManagementStatistics();
    }
 
+   public void testLazyDeserialization() throws Exception {
+      XmlConfigurationParserImpl parser = new XmlConfigurationParserImpl();
+      String xml = "<lazyDeserialization enabled=\"true\"/>";
+      Element e = XmlConfigHelper.stringToElement(xml);
+
+      Configuration c = new Configuration();
+      parser.configureLazyDeserialization(e, c);
+
+      assert c.isExposeManagementStatistics();
+   }
+
    public void testJmxStatisticsDefaults() throws Exception {
       XmlConfigurationParserImpl parser = new XmlConfigurationParserImpl();
       String xml = "<jmxStatistics />";

Modified: core/branches/flat/src/test/java/org/horizon/config/parsing/XmlFileParsingTest.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/config/parsing/XmlFileParsingTest.java	2009-02-11 11:09:31 UTC (rev 7681)
+++ core/branches/flat/src/test/java/org/horizon/config/parsing/XmlFileParsingTest.java	2009-02-11 12:53:09 UTC (rev 7682)
@@ -87,6 +87,10 @@
       assert c.getLockAcquisitionTimeout() == 20000;
       assert c.getConcurrencyLevel() == 1000;
       assert c.getIsolationLevel() == IsolationLevel.REPEATABLE_READ;
+      assert !c.isUseLazyDeserialization();
+
+      c = namedCaches.get("lazyDeserialization");
+      assert c.isUseLazyDeserialization();
    }
 
    public void testConfigurationMerging() throws IOException {

Added: core/branches/flat/src/test/java/org/horizon/interceptors/MarshalledValueInterceptorTest.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/interceptors/MarshalledValueInterceptorTest.java	                        (rev 0)
+++ core/branches/flat/src/test/java/org/horizon/interceptors/MarshalledValueInterceptorTest.java	2009-02-11 12:53:09 UTC (rev 7682)
@@ -0,0 +1,135 @@
+package org.horizon.interceptors;
+
+import org.horizon.Cache;
+import org.horizon.config.Configuration;
+import org.horizon.config.GlobalConfiguration;
+import org.horizon.manager.CacheManager;
+import org.horizon.manager.DefaultCacheManager;
+import org.horizon.marshall.MarshalledValue;
+import org.horizon.util.TestingUtil;
+import org.testng.annotations.AfterTest;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Manik Surtani (<a href="mailto:manik AT jboss DOT org">manik AT jboss DOT org</a>)
+ * @author Mircea.Markus at jboss.com
+ * @since 1.0
+ */
+ at Test(groups = "functional", sequential = true, testName = "interceptors.MarshalledValueInterceptorTest")
+public class MarshalledValueInterceptorTest {
+   CacheManager cm;
+
+   @BeforeTest
+   public void setUp() {
+      cm = new DefaultCacheManager(GlobalConfiguration.getNonClusteredDefault());
+   }
+
+   @AfterTest
+   public void tearDown() {
+      TestingUtil.killCacheManagers(cm);
+   }
+
+   public void testDefaultInterceptorStack() {
+      assert TestingUtil.findInterceptor(cm.getCache(), MarshalledValueInterceptor.class) == null;
+
+      Configuration configuration = new Configuration();
+      configuration.setUseLazyDeserialization(true);
+      cm.defineCache("someCache", configuration);
+      Cache c = cm.getCache("someCache");
+
+      assert TestingUtil.findInterceptor(c, MarshalledValueInterceptor.class) != null;
+      TestingUtil.killCaches(c);
+   }
+
+   public void testDisabledInterceptorStack() {
+      Configuration cfg = new Configuration();
+      cfg.setUseLazyDeserialization(false);
+      cm.defineCache("a", cfg);
+      Cache c = cm.getCache("a");
+      assert TestingUtil.findInterceptor(c, MarshalledValueInterceptor.class) == null;
+   }
+
+   public void testExcludedTypes() {
+      // Strings
+      assert MarshalledValue.isTypeExcluded(String.class);
+      assert MarshalledValue.isTypeExcluded(String[].class);
+      assert MarshalledValue.isTypeExcluded(String[][].class);
+      assert MarshalledValue.isTypeExcluded(String[][][].class);
+
+      // primitives
+      assert MarshalledValue.isTypeExcluded(void.class);
+      assert MarshalledValue.isTypeExcluded(boolean.class);
+      assert MarshalledValue.isTypeExcluded(char.class);
+      assert MarshalledValue.isTypeExcluded(byte.class);
+      assert MarshalledValue.isTypeExcluded(short.class);
+      assert MarshalledValue.isTypeExcluded(int.class);
+      assert MarshalledValue.isTypeExcluded(long.class);
+      assert MarshalledValue.isTypeExcluded(float.class);
+      assert MarshalledValue.isTypeExcluded(double.class);
+
+      assert MarshalledValue.isTypeExcluded(boolean[].class);
+      assert MarshalledValue.isTypeExcluded(char[].class);
+      assert MarshalledValue.isTypeExcluded(byte[].class);
+      assert MarshalledValue.isTypeExcluded(short[].class);
+      assert MarshalledValue.isTypeExcluded(int[].class);
+      assert MarshalledValue.isTypeExcluded(long[].class);
+      assert MarshalledValue.isTypeExcluded(float[].class);
+      assert MarshalledValue.isTypeExcluded(double[].class);
+
+      assert MarshalledValue.isTypeExcluded(boolean[][].class);
+      assert MarshalledValue.isTypeExcluded(char[][].class);
+      assert MarshalledValue.isTypeExcluded(byte[][].class);
+      assert MarshalledValue.isTypeExcluded(short[][].class);
+      assert MarshalledValue.isTypeExcluded(int[][].class);
+      assert MarshalledValue.isTypeExcluded(long[][].class);
+      assert MarshalledValue.isTypeExcluded(float[][].class);
+      assert MarshalledValue.isTypeExcluded(double[][].class);
+
+      assert MarshalledValue.isTypeExcluded(Void.class);
+      assert MarshalledValue.isTypeExcluded(Boolean.class);
+      assert MarshalledValue.isTypeExcluded(Character.class);
+      assert MarshalledValue.isTypeExcluded(Byte.class);
+      assert MarshalledValue.isTypeExcluded(Short.class);
+      assert MarshalledValue.isTypeExcluded(Integer.class);
+      assert MarshalledValue.isTypeExcluded(Long.class);
+      assert MarshalledValue.isTypeExcluded(Float.class);
+      assert MarshalledValue.isTypeExcluded(Double.class);
+
+      assert MarshalledValue.isTypeExcluded(Boolean[].class);
+      assert MarshalledValue.isTypeExcluded(Character[].class);
+      assert MarshalledValue.isTypeExcluded(Byte[].class);
+      assert MarshalledValue.isTypeExcluded(Short[].class);
+      assert MarshalledValue.isTypeExcluded(Integer[].class);
+      assert MarshalledValue.isTypeExcluded(Long[].class);
+      assert MarshalledValue.isTypeExcluded(Float[].class);
+      assert MarshalledValue.isTypeExcluded(Double[].class);
+
+      assert MarshalledValue.isTypeExcluded(Boolean[][].class);
+      assert MarshalledValue.isTypeExcluded(Character[][].class);
+      assert MarshalledValue.isTypeExcluded(Byte[][].class);
+      assert MarshalledValue.isTypeExcluded(Short[][].class);
+      assert MarshalledValue.isTypeExcluded(Integer[][].class);
+      assert MarshalledValue.isTypeExcluded(Long[][].class);
+      assert MarshalledValue.isTypeExcluded(Float[][].class);
+      assert MarshalledValue.isTypeExcluded(Double[][].class);
+   }
+
+   public void testNonExcludedTypes() {
+      assert !MarshalledValue.isTypeExcluded(Object.class);
+      assert !MarshalledValue.isTypeExcluded(List.class);
+      assert !MarshalledValue.isTypeExcluded(Collection.class);
+      assert !MarshalledValue.isTypeExcluded(Map.class);
+      assert !MarshalledValue.isTypeExcluded(Date.class);
+      assert !MarshalledValue.isTypeExcluded(Thread.class);
+      assert !MarshalledValue.isTypeExcluded(Collection.class);
+      assert !MarshalledValue.isTypeExcluded(new Object() {
+         String blah;
+      }.getClass());
+   }
+}


Property changes on: core/branches/flat/src/test/java/org/horizon/interceptors/MarshalledValueInterceptorTest.java
___________________________________________________________________
Name: svn:keywords
   + Id Revision
Name: svn:eol-style
   + LF

Added: core/branches/flat/src/test/java/org/horizon/marshall/MarshalledValueTest.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/marshall/MarshalledValueTest.java	                        (rev 0)
+++ core/branches/flat/src/test/java/org/horizon/marshall/MarshalledValueTest.java	2009-02-11 12:53:09 UTC (rev 7682)
@@ -0,0 +1,373 @@
+package org.horizon.marshall;
+
+import org.horizon.AdvancedCache;
+import org.horizon.BaseClusteredTest;
+import org.horizon.Cache;
+import org.horizon.CacheException;
+import org.horizon.commands.write.PutKeyValueCommand;
+import org.horizon.config.CacheLoaderManagerConfig;
+import org.horizon.config.Configuration;
+import org.horizon.container.DataContainer;
+import org.horizon.context.InvocationContext;
+import org.horizon.interceptors.InterceptorChain;
+import org.horizon.interceptors.MarshalledValueInterceptor;
+import org.horizon.interceptors.base.CommandInterceptor;
+import org.horizon.loader.CacheLoaderConfig;
+import org.horizon.loader.dummy.DummyInMemoryCacheLoader;
+import org.horizon.manager.CacheManager;
+import org.horizon.notifications.Listener;
+import org.horizon.notifications.cachelistener.annotation.CacheEntryModified;
+import org.horizon.notifications.cachelistener.event.CacheEntryModifiedEvent;
+import org.horizon.util.TestingUtil;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.util.Collections;
+
+/**
+ * Tests implicit marshalled values
+ *
+ * @author Manik Surtani (<a href="mailto:manik AT jboss DOT org">manik AT jboss DOT org</a>)
+ * @author Mircea.Markus at jboss.com
+ * @since 1.0
+ */
+ at Test(groups = "functional", testName = "marshall.MarshalledValueTest")
+public class MarshalledValueTest extends BaseClusteredTest {
+   private Cache cache1, cache2;
+   private MarshalledValueListenerInterceptor mvli;
+   String k = "key", v = "value";
+
+   @BeforeMethod(alwaysRun = true)
+   public void setUp() {
+      CacheManager cm1 = addClusterEnabledCacheManager();
+      CacheManager cm2 = addClusterEnabledCacheManager();
+
+      Configuration replSync = new Configuration();
+      replSync.setCacheMode(Configuration.CacheMode.REPL_SYNC);
+      replSync.setUseLazyDeserialization(true);
+
+      defineCacheOnAllManagers("replSync", replSync);
+
+      cache1 = cm1.getCache("replSync");
+      cache2 = cm2.getCache("replSync");
+
+      assertMarshalledValueInterceptorPresent(cache1);
+      assertMarshalledValueInterceptorPresent(cache2);
+
+      mvli = new MarshalledValueListenerInterceptor();
+      ((AdvancedCache)cache1).addInterceptorAfter(mvli, MarshalledValueInterceptor.class);
+
+      TestingUtil.blockUntilViewsReceived(60000, true, cm1, cm2);
+   }
+
+   private void assertMarshalledValueInterceptorPresent(Cache c) {
+      InterceptorChain ic1 = TestingUtil.extractComponent(c, InterceptorChain.class);
+      assert ic1.containsInterceptorType(MarshalledValueInterceptor.class);
+   }
+
+   @AfterMethod
+   public void tearDown() {
+      TestingUtil.killCaches(cache1, cache2);
+      Pojo.serializationCount = 0;
+      Pojo.deserializationCount = 0;
+   }
+
+   private void assertOnlyOneRepresentationExists(MarshalledValue mv) {
+      assert (mv.instance != null && mv.raw == null) || (mv.instance == null && mv.raw != null) : "Only instance or raw representations should exist in a MarshalledValue; never both";
+   }
+
+   private void assertSerialized(MarshalledValue mv) {
+      assert mv.raw != null : "Should be serialized";
+   }
+
+   private void assertDeserialized(MarshalledValue mv) {
+      assert mv.instance != null : "Should be deserialized";
+   }
+
+   private void assertSerializationCounts(int serializationCount, int deserializationCount) {
+      assert Pojo.serializationCount == serializationCount : "Serialization count: expected " + serializationCount + " but was " + Pojo.serializationCount;
+      assert Pojo.deserializationCount == deserializationCount : "Deserialization count: expected " + deserializationCount + " but was " + Pojo.deserializationCount;
+   }
+
+   public void testNonSerializable() {
+      try {
+         cache1.put("Hello", new Object());
+         assert false : "Should have failed";
+      }
+      catch (CacheException expected) {
+
+      }
+
+      assert mvli.invocationCount == 0 : "Call should not have gone beyond the MarshalledValueInterceptor";
+
+      try {
+         cache1.put(new Object(), "Hello");
+         assert false : "Should have failed";
+      }
+      catch (CacheException expected) {
+
+      }
+
+      assert mvli.invocationCount == 0 : "Call should not have gone beyond the MarshalledValueInterceptor";
+   }
+
+   public void testNodeReleaseObjectValueReferences() {
+      Pojo value = new Pojo();
+      cache1.put("key", value);
+      assertSerializationCounts(1, 0);
+
+      DataContainer dc1 = TestingUtil.extractComponent(cache1, DataContainer.class);
+
+      Object o = dc1.get("key");
+      assert o instanceof MarshalledValue;
+      MarshalledValue mv = (MarshalledValue) o;
+      assertDeserialized(mv);
+      assert cache1.get("key").equals(value);
+      assertDeserialized(mv);
+      assertSerializationCounts(1, 0);
+      cache1.compact();
+      assertSerializationCounts(2, 0);
+      assertOnlyOneRepresentationExists(mv);
+      assertSerialized(mv);
+
+      // now on cache 2
+      DataContainer dc2 = TestingUtil.extractComponent(cache2, DataContainer.class);
+      o = dc2.get("key");
+      assert o instanceof MarshalledValue;
+      mv = (MarshalledValue) o;
+      assertSerialized(mv); // this proves that unmarshalling on the recipient cache instance is lazy
+
+      assert cache2.get("key").equals(value);
+      assertDeserialized(mv);
+      assertSerializationCounts(2, 1);
+      cache2.compact();
+      assertSerializationCounts(2, 1);
+      assertOnlyOneRepresentationExists(mv);
+      assertSerialized(mv);
+   }
+
+   public void testNodeReleaseObjectKeyReferences() throws IOException, ClassNotFoundException {
+      Pojo key = new Pojo();
+      cache1.put(key, "value");
+
+      assertSerializationCounts(1, 0);
+
+      DataContainer dc1 = TestingUtil.extractComponent(cache1, DataContainer.class);
+
+      Object o = dc1.keySet().iterator().next();
+      assert o instanceof MarshalledValue;
+      MarshalledValue mv = (MarshalledValue) o;
+      assertDeserialized(mv);
+
+      assert cache1.get(key).equals("value");
+      assertDeserialized(mv);
+      assertSerializationCounts(1, 0);
+
+      cache1.compact();
+      assertSerializationCounts(2, 0);
+      assertOnlyOneRepresentationExists(mv);
+      assertSerialized(mv);
+
+
+      // now on cache 2
+      DataContainer dc2 = TestingUtil.extractComponent(cache2, DataContainer.class);
+      o = dc2.keySet().iterator().next();
+      assert o instanceof MarshalledValue;
+      mv = (MarshalledValue) o;
+      assertSerialized(mv);
+      assert cache2.get(key).equals("value");
+      assertSerializationCounts(2, 1);
+      assertDeserialized(mv);
+      cache2.compact();
+
+      assertOnlyOneRepresentationExists(mv);
+      assertSerialized(mv);
+      assertSerializationCounts(2, 1);
+   }
+
+   public void testEqualsAndHashCode() throws Exception {
+      Pojo pojo = new Pojo();
+      MarshalledValue mv = new MarshalledValue(pojo, true);
+      assertDeserialized(mv);
+      int oldHashCode = mv.hashCode();
+
+      mv.serialize();
+      assertSerialized(mv);
+      assert oldHashCode == mv.hashCode();
+
+      MarshalledValue mv2 = new MarshalledValue(pojo, true);
+      assertSerialized(mv);
+      assertDeserialized(mv2);
+
+      assert mv2.hashCode() == oldHashCode;
+      assert mv.equals(mv2);
+   }
+
+   public void assertUseOfMagicNumbers() throws Exception {
+      Pojo pojo = new Pojo();
+      MarshalledValue mv = new MarshalledValue(pojo, true);
+
+      Configuration c = new Configuration();
+//      ComponentRegistry cr = new ComponentRegistry(c, new CacheDelegate("aaa"));
+
+      HorizonMarshaller marshaller = new HorizonMarshaller();
+//      cr.registerComponent(marshaller, Marshaller.class);
+
+      // Wire the marshaller
+//      cr.start();
+
+      // start the test
+      ByteArrayOutputStream bout = new ByteArrayOutputStream();
+      ObjectOutputStream out = new ObjectOutputStream(bout);
+      marshaller.objectToObjectStream(mv, out);
+      out.close();
+      bout.close();
+
+      // check that the rest just contains a byte stream which a MarshalledValue will be able to deserialize.
+      ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
+      ObjectInputStream in = new ObjectInputStream(bin);
+
+      assert in.read() == HorizonMarshaller.MAGICNUMBER_MARSHALLEDVALUE;
+      MarshalledValue recreated = new MarshalledValue();
+      recreated.readExternal(in);
+
+      // there should be nothing more
+      assert in.available() == 0;
+      in.close();
+      bin.close();
+
+      assertSerialized(recreated);
+      assert recreated.equals(mv);
+
+      // since both objects being compared are serialized, the equals() above should just compare byte arrays.
+      assertSerialized(recreated);
+      assertOnlyOneRepresentationExists(recreated);
+   }
+
+   public void testCacheLoaders() throws CloneNotSupportedException {
+      tearDown();
+
+      Configuration cacheCofig = new Configuration();
+      cacheCofig.setCacheMode(Configuration.CacheMode.REPL_SYNC);
+      cacheCofig.setUseLazyDeserialization(true);
+      CacheLoaderManagerConfig clmc = new CacheLoaderManagerConfig();
+      DummyInMemoryCacheLoader.Cfg clc = new DummyInMemoryCacheLoader.Cfg();
+      clc.setStore(getClass().getSimpleName());
+      clmc.setIndividualCacheLoaderConfigs(Collections.singletonList((CacheLoaderConfig)clc));
+      cacheCofig.setCacheLoaderConfig(clmc);
+
+      defineCacheOnAllManagers("replSync2", cacheCofig);
+      cache1 = getCacheManagers().get(0).getCache("replSync2");
+      cache2 = getCacheManagers().get(1).getCache("replSync2");
+
+      TestingUtil.blockUntilViewsReceived(60000, cache1, cache2);
+
+      Pojo pojo = new Pojo();
+      cache1.put("key", pojo);
+
+      assertMarshalledValueInterceptorPresent(cache1);
+      assertMarshalledValueInterceptorPresent(cache2);
+      assertSerializationCounts(1, 0);
+
+      cache2.get("key");
+
+      assertSerializationCounts(1, 1);
+   }
+
+   public void testCallbackValues() {
+      MockListener l = new MockListener();
+      cache1.addListener(l);
+      Pojo pojo = new Pojo();
+      cache1.put("key", pojo);
+
+      assert l.newValue != null;
+      assert l.newValue instanceof MarshalledValue;
+      MarshalledValue mv = (MarshalledValue) l.newValue;
+      assert mv.instance instanceof Pojo;
+      assertSerializationCounts(1, 0);
+   }
+
+   public void testRemoteCallbackValues() throws Exception {
+      MockListener l = new MockListener();
+      cache2.addListener(l);
+      Pojo pojo = new Pojo();
+      cache1.put("key", pojo);
+
+      assert l.newValue != null;
+      assert l.newValue instanceof MarshalledValue;
+      MarshalledValue mv = (MarshalledValue) l.newValue;
+      assert mv.get() instanceof Pojo;
+      assertSerializationCounts(1, 1);
+   }
+
+   @Listener
+   public static class MockListener {
+      Object newValue;
+
+      @CacheEntryModified
+      public void nodeModified(CacheEntryModifiedEvent e) {
+         if (!e.isPre()) newValue = e.getValue();
+      }
+   }
+
+   class MarshalledValueListenerInterceptor extends CommandInterceptor {
+      int invocationCount = 0;
+      public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable {
+         invocationCount++;
+         if (command.getKey() instanceof MarshalledValue)
+            assertOnlyOneRepresentationExists((MarshalledValue) command.getKey());
+         if (command.getValue() instanceof MarshalledValue)
+            assertOnlyOneRepresentationExists((MarshalledValue) command.getValue());
+         Object retval = invokeNextInterceptor(ctx, command);
+         if (retval instanceof MarshalledValue) assertOnlyOneRepresentationExists((MarshalledValue) retval);
+         return retval;
+      }
+
+   }
+
+   public static class Pojo implements Externalizable {
+      int i;
+      boolean b;
+      static int serializationCount, deserializationCount;
+
+      public boolean equals(Object o) {
+         if (this == o) return true;
+         if (o == null || getClass() != o.getClass()) return false;
+
+         Pojo pojo = (Pojo) o;
+
+         if (b != pojo.b) return false;
+         if (i != pojo.i) return false;
+
+         return true;
+      }
+
+      public int hashCode() {
+         int result;
+         result = i;
+         result = 31 * result + (b ? 1 : 0);
+         return result;
+      }
+
+      public void writeExternal(ObjectOutput out) throws IOException {
+         out.writeInt(i);
+         out.writeBoolean(b);
+         serializationCount++;
+      }
+
+      public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+         i = in.readInt();
+         b = in.readBoolean();
+         deserializationCount++;
+      }
+   }
+}


Property changes on: core/branches/flat/src/test/java/org/horizon/marshall/MarshalledValueTest.java
___________________________________________________________________
Name: svn:keywords
   + Id Revision
Name: svn:eol-style
   + LF

Modified: core/branches/flat/src/test/resources/configs/named-cache-test.xml
===================================================================
--- core/branches/flat/src/test/resources/configs/named-cache-test.xml	2009-02-11 11:09:31 UTC (rev 7681)
+++ core/branches/flat/src/test/resources/configs/named-cache-test.xml	2009-02-11 12:53:09 UTC (rev 7682)
@@ -69,4 +69,9 @@
       <locking isolationLevel="REPEATABLE_READ" concurrencyLevel="1000" lockAcquisitionTimeout="20000" />         
    </namedCache>
 
+   <namedCache name="lazyDeserialization">
+      <locking isolationLevel="REPEATABLE_READ" concurrencyLevel="1000" lockAcquisitionTimeout="20000" />
+      <lazyDeserialization enabled="true"/>
+   </namedCache>
+
 </horizon>




More information about the jbosscache-commits mailing list