[jbosscache-commits] JBoss Cache SVN: r6943 - core/branches/flat/src/main/java/org/jboss/starobrno/marshall.

jbosscache-commits at lists.jboss.org jbosscache-commits at lists.jboss.org
Tue Oct 14 13:47:28 EDT 2008


Author: mircea.markus
Date: 2008-10-14 13:47:27 -0400 (Tue, 14 Oct 2008)
New Revision: 6943

Added:
   core/branches/flat/src/main/java/org/jboss/starobrno/marshall/CacheMarshallerStarobrno.java
   core/branches/flat/src/main/java/org/jboss/starobrno/marshall/CommandAwareRpcDispatcher.java
   core/branches/flat/src/main/java/org/jboss/starobrno/marshall/ExtendedMarshaller.java
   core/branches/flat/src/main/java/org/jboss/starobrno/marshall/MarshalledValue2.java
   core/branches/flat/src/main/java/org/jboss/starobrno/marshall/MarshalledValueHelper2.java
   core/branches/flat/src/main/java/org/jboss/starobrno/marshall/NodeData.java
   core/branches/flat/src/main/java/org/jboss/starobrno/marshall/NodeDataExceptionMarker.java
   core/branches/flat/src/main/java/org/jboss/starobrno/marshall/NodeDataMarker.java
   core/branches/flat/src/main/java/org/jboss/starobrno/marshall/UnmarshalledReferences.java
Modified:
   core/branches/flat/src/main/java/org/jboss/starobrno/marshall/MarshalledValueMap.java
Log:
enabling replication 

Added: core/branches/flat/src/main/java/org/jboss/starobrno/marshall/CacheMarshallerStarobrno.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/marshall/CacheMarshallerStarobrno.java	                        (rev 0)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/marshall/CacheMarshallerStarobrno.java	2008-10-14 17:47:27 UTC (rev 6943)
@@ -0,0 +1,802 @@
+/*
+ * 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.jboss.starobrno.marshall;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.starobrno.CacheException;
+import org.jboss.starobrno.io.ByteBuffer;
+import org.jboss.starobrno.commands.CommandsFactory;
+import org.jboss.starobrno.commands.ReplicableCommand;
+import org.jboss.starobrno.config.Configuration;
+import org.jboss.starobrno.factories.annotations.Inject;
+import org.jboss.starobrno.transaction.GlobalTransaction;
+import org.jboss.starobrno.util.FastCopyHashMap;
+import org.jboss.starobrno.util.Immutables;
+import org.jboss.util.NotImplementedException;
+import org.jgroups.Address;
+import org.jgroups.stack.IpAddress;
+import org.jgroups.util.Buffer;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.InputStream;
+import java.lang.reflect.Array;
+import java.util.*;
+
+/**
+ * Abstract AbstractMarshaller for JBoss Cache.
+ *
+ * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
+ */
+public class CacheMarshallerStarobrno implements ExtendedMarshaller
+{
+   // magic numbers
+   protected static final int MAGICNUMBER_METHODCALL = 1;
+   protected static final int MAGICNUMBER_FQN = 2;
+   protected static final int MAGICNUMBER_GTX = 3;
+   protected static final int MAGICNUMBER_IPADDRESS = 4;
+   protected static final int MAGICNUMBER_ARRAY_LIST = 5;
+   protected static final int MAGICNUMBER_INTEGER = 6;
+   protected static final int MAGICNUMBER_LONG = 7;
+   protected static final int MAGICNUMBER_BOOLEAN = 8;
+   protected static final int MAGICNUMBER_STRING = 9;
+   protected static final int MAGICNUMBER_DEFAULT_DATA_VERSION = 10;
+   protected static final int MAGICNUMBER_LINKED_LIST = 11;
+   protected static final int MAGICNUMBER_HASH_MAP = 12;
+   protected static final int MAGICNUMBER_TREE_MAP = 13;
+   protected static final int MAGICNUMBER_HASH_SET = 14;
+   protected static final int MAGICNUMBER_TREE_SET = 15;
+   protected static final int MAGICNUMBER_NODEDATA_MARKER = 16;
+   protected static final int MAGICNUMBER_NODEDATA_EXCEPTION_MARKER = 17;
+   protected static final int MAGICNUMBER_NODEDATA = 18;
+   protected static final int MAGICNUMBER_GRAVITATERESULT = 19;
+   protected static final int MAGICNUMBER_SHORT = 20;
+   protected static final int MAGICNUMBER_IMMUTABLE_MAPCOPY = 21;
+   protected static final int MAGICNUMBER_MARSHALLEDVALUE = 22;
+   protected static final int MAGICNUMBER_FASTCOPY_HASHMAP = 23;
+   protected static final int MAGICNUMBER_ARRAY = 24;
+   protected static final int MAGICNUMBER_BYTE = 25;
+   protected static final int MAGICNUMBER_CHAR = 26;
+   protected static final int MAGICNUMBER_FLOAT = 27;
+   protected static final int MAGICNUMBER_DOUBLE = 28;
+   protected static final int MAGICNUMBER_OBJECT = 29;
+   protected static final int MAGICNUMBER_NULL = 99;
+   protected static final int MAGICNUMBER_SERIALIZABLE = 100;
+
+   protected static final int MAGICNUMBER_REF = 101;
+
+   public CacheMarshallerStarobrno()
+   {
+      initLogger();
+      // enabled, since this is always enabled in JBC 2.0.0.
+      useRefs = false;
+   }
+
+   protected Log log;
+   protected boolean trace;
+
+   protected Configuration configuration;
+   protected ClassLoader defaultClassLoader;
+   protected boolean useRefs = false;
+
+   @Inject
+   void injectDependencies(Configuration configuration, ClassLoader defaultClassLoader)
+   {
+      this.defaultClassLoader = defaultClassLoader;
+      this.configuration = configuration;
+   }
+
+   protected void initLogger()
+   {
+      log = LogFactory.getLog(getClass());
+      trace = log.isTraceEnabled();
+   }
+
+   // implement the basic contract set in RPCDispatcher.AbstractMarshaller
+   public byte[] objectToByteBuffer(Object obj) throws Exception
+   {
+      Buffer b = objectToBuffer(obj);
+      byte[] bytes = new byte[b.getLength()];
+      System.arraycopy(b.getBuf(), b.getOffset(), bytes, 0, b.getLength());
+      return bytes;
+   }
+
+   protected CommandsFactory commandsFactory;
+
+
+   @Inject
+   public void injectCommandsFactory(CommandsFactory commandsFactory)
+   {
+      this.commandsFactory = commandsFactory;
+   }
+
+   protected void marshallObject(Object o, ObjectOutputStream out, Map<Object, Integer> refMap) throws Exception
+   {
+      if (o != null && o.getClass().isArray() && isKnownType(o.getClass().getComponentType()))
+      {
+         marshallArray(o, out, refMap);
+      } else
+      {
+         marshallObject(o, out, refMap);
+      }
+   }
+
+
+   protected void marshallString(String s, ObjectOutputStream out) throws Exception
+   {
+      //StringUtil.saveString(out, s);
+      out.writeObject(s);
+   }
+
+   private void marshallCommand(ReplicableCommand command, ObjectOutputStream out, Map<Object, Integer> refMap) throws Exception
+   {
+      out.writeShort(command.getCommandId());
+      Object[] args = command.getParameters();
+      byte numArgs = (byte) (args == null ? 0 : args.length);
+      out.writeByte(numArgs);
+
+      for (int i = 0; i < numArgs; i++)
+      {
+         marshallObject(args[i], out, refMap);
+      }
+   }
+
+
+   private void marshallGlobalTransaction(GlobalTransaction globalTransaction, ObjectOutputStream out, Map<Object, Integer> refMap) throws Exception
+   {
+      out.writeLong(globalTransaction.getId());
+      marshallObject(globalTransaction.getAddress(), out, refMap);
+   }
+
+   private void marshallIpAddress(IpAddress ipAddress, ObjectOutputStream out) throws Exception
+   {
+      ipAddress.writeExternal(out);
+   }
+
+   @SuppressWarnings("unchecked")
+   private void marshallCollection(Collection c, ObjectOutputStream out, Map refMap) throws Exception
+   {
+      writeUnsignedInt(out, c.size());
+      for (Object o : c)
+      {
+         marshallObject(o, out, refMap);
+      }
+   }
+
+   @SuppressWarnings("unchecked")
+   private void marshallMap(Map map, ObjectOutputStream out, Map<Object, Integer> refMap) throws Exception
+   {
+      int mapSize = map.size();
+      writeUnsignedInt(out, mapSize);
+      if (mapSize == 0) return;
+
+      for (Map.Entry me : (Set<Map.Entry>) map.entrySet())
+      {
+         marshallObject(me.getKey(), out, refMap);
+         marshallObject(me.getValue(), out, refMap);
+      }
+   }
+
+   // --------- Unmarshalling methods
+
+   protected Object unmarshallObject(ObjectInputStream in, ClassLoader loader, UnmarshalledReferences refMap, boolean overrideContextClassloaderOnThread) throws Exception
+   {
+      if (loader == null)
+      {
+         return unmarshallObject(in, refMap);
+      } else
+      {
+         Thread currentThread = Thread.currentThread();
+         ClassLoader old = currentThread.getContextClassLoader();
+         try
+         {
+            // only do this if we haven't already set a context class loader elsewhere.
+            if (overrideContextClassloaderOnThread || old == null) currentThread.setContextClassLoader(loader);
+            return unmarshallObject(in, refMap);
+         }
+         finally
+         {
+            if (overrideContextClassloaderOnThread || old == null) currentThread.setContextClassLoader(old);
+         }
+      }
+   }
+
+   protected Object unmarshallObject(ObjectInputStream in, UnmarshalledReferences refMap) throws Exception
+   {
+      byte magicNumber = in.readByte();
+      int reference = 0;
+      Object retVal;
+      switch (magicNumber)
+      {
+         case MAGICNUMBER_NULL:
+            return null;
+         case MAGICNUMBER_REF:
+            if (useRefs)
+            {
+               reference = readReference(in);
+               return refMap.getReferencedObject(reference);
+            } else break;
+         case MAGICNUMBER_SERIALIZABLE:
+            if (useRefs) reference = readReference(in);
+            retVal = in.readObject();
+            if (useRefs) refMap.putReferencedObject(reference, retVal);
+            return retVal;
+         case MAGICNUMBER_MARSHALLEDVALUE:
+            MarshalledValue2 mv = new MarshalledValue2();
+            mv.readExternal(in);
+            return mv;
+         case MAGICNUMBER_METHODCALL:
+            retVal = unmarshallCommand(in, refMap);
+            return retVal;
+         case MAGICNUMBER_GTX:
+            if (useRefs) reference = readReference(in);
+            retVal = unmarshallGlobalTransaction(in, refMap);
+            if (useRefs) refMap.putReferencedObject(reference, retVal);
+            return retVal;
+         case MAGICNUMBER_IPADDRESS:
+            retVal = unmarshallIpAddress(in);
+            return retVal;
+         case MAGICNUMBER_ARRAY:
+            return unmarshallArray(in, refMap);
+         case MAGICNUMBER_ARRAY_LIST:
+            return unmarshallArrayList(in, refMap);
+         case MAGICNUMBER_LINKED_LIST:
+            return unmarshallLinkedList(in, refMap);
+         case MAGICNUMBER_HASH_MAP:
+            return unmarshallHashMap(in, refMap);
+         case MAGICNUMBER_TREE_MAP:
+            return unmarshallTreeMap(in, refMap);
+         case MAGICNUMBER_HASH_SET:
+            return unmarshallHashSet(in, refMap);
+         case MAGICNUMBER_TREE_SET:
+            return unmarshallTreeSet(in, refMap);
+         case MAGICNUMBER_IMMUTABLE_MAPCOPY:
+            return unmarshallMapCopy(in, refMap);
+         case MAGICNUMBER_FASTCOPY_HASHMAP:
+            return unmarshallFastCopyHashMap(in, refMap);
+         case MAGICNUMBER_BOOLEAN:
+            return in.readBoolean() ? Boolean.TRUE : Boolean.FALSE;
+         case MAGICNUMBER_INTEGER:
+            return in.readInt();
+         case MAGICNUMBER_LONG:
+            return in.readLong();
+         case MAGICNUMBER_SHORT:
+            return in.readShort();
+         case MAGICNUMBER_STRING:
+            if (useRefs) reference = readReference(in);
+            retVal = unmarshallString(in);
+            if (useRefs) refMap.putReferencedObject(reference, retVal);
+            return retVal;
+         case MAGICNUMBER_NODEDATA_MARKER:
+            retVal = new NodeDataMarker();
+            ((NodeDataMarker) retVal).readExternal(in);
+            return retVal;
+         case MAGICNUMBER_NODEDATA_EXCEPTION_MARKER:
+            retVal = new NodeDataExceptionMarker();
+            ((NodeDataExceptionMarker) retVal).readExternal(in);
+            return retVal;
+         case MAGICNUMBER_NODEDATA:
+            retVal = new NodeData();
+            ((NodeData) retVal).readExternal(in);
+            return retVal;
+         default:
+            if (log.isErrorEnabled())
+            {
+               log.error("Unknown Magic Number " + magicNumber);
+            }
+            throw new Exception("Unknown magic number " + magicNumber);
+      }
+      throw new Exception("Unknown magic number " + magicNumber);
+   }
+
+   private FastCopyHashMap unmarshallFastCopyHashMap(ObjectInputStream in, UnmarshalledReferences refMap) throws Exception
+   {
+      FastCopyHashMap map = new FastCopyHashMap();
+      populateFromStream(in, refMap, map);
+      return map;
+   }
+
+   protected String unmarshallString(ObjectInputStream in) throws Exception
+   {
+      return (String) in.readObject();
+   }
+
+   private ReplicableCommand unmarshallCommand(ObjectInputStream in, UnmarshalledReferences refMap) throws Exception
+   {
+      short methodId = in.readShort();
+      byte numArgs = in.readByte();
+      Object[] args = null;
+
+      if (numArgs > 0)
+      {
+         args = new Object[numArgs];
+         for (int i = 0; i < numArgs; i++) args[i] = unmarshallObject(in, refMap);
+      }
+
+      return commandsFactory.fromStream((byte) methodId, args);
+   }
+
+
+   private GlobalTransaction unmarshallGlobalTransaction(ObjectInputStream in, UnmarshalledReferences refMap) throws Exception
+   {
+      GlobalTransaction gtx = new GlobalTransaction();
+      long id = in.readLong();
+      Object address = unmarshallObject(in, refMap);
+      gtx.setId(id);
+      gtx.setAddress((Address) address);
+      return gtx;
+   }
+
+   private IpAddress unmarshallIpAddress(ObjectInputStream in) throws Exception
+   {
+      IpAddress ipAddress = new IpAddress();
+      ipAddress.readExternal(in);
+      return ipAddress;
+   }
+
+   private List unmarshallArrayList(ObjectInputStream in, UnmarshalledReferences refMap) throws Exception
+   {
+      int listSize = readUnsignedInt(in);
+      List list = new ArrayList(listSize);
+      populateFromStream(in, refMap, list, listSize);
+      return list;
+   }
+
+   private List unmarshallLinkedList(ObjectInputStream in, UnmarshalledReferences refMap) throws Exception
+   {
+      List list = new LinkedList();
+      populateFromStream(in, refMap, list, readUnsignedInt(in));
+      return list;
+   }
+
+   private Map unmarshallHashMap(ObjectInputStream in, UnmarshalledReferences refMap) throws Exception
+   {
+      Map map = new HashMap();
+      populateFromStream(in, refMap, map);
+      return map;
+   }
+
+   @SuppressWarnings("unchecked")
+   private Map unmarshallMapCopy(ObjectInputStream in, UnmarshalledReferences refMap) throws Exception
+   {
+      // read in as a HashMap first
+      Map m = unmarshallHashMap(in, refMap);
+      return Immutables.immutableMapWrap(m);
+   }
+
+   private Map unmarshallTreeMap(ObjectInputStream in, UnmarshalledReferences refMap) throws Exception
+   {
+      Map map = new TreeMap();
+      populateFromStream(in, refMap, map);
+      return map;
+   }
+
+   private Set unmarshallHashSet(ObjectInputStream in, UnmarshalledReferences refMap) throws Exception
+   {
+      Set set = new HashSet();
+      populateFromStream(in, refMap, set);
+      return set;
+   }
+
+   private Set unmarshallTreeSet(ObjectInputStream in, UnmarshalledReferences refMap) throws Exception
+   {
+      Set set = new TreeSet();
+      populateFromStream(in, refMap, set);
+      return set;
+   }
+
+   @SuppressWarnings("unchecked")
+   private void populateFromStream(ObjectInputStream in, UnmarshalledReferences refMap, Map mapToPopulate) throws Exception
+   {
+      int size = readUnsignedInt(in);
+      for (int i = 0; i < size; i++) mapToPopulate.put(unmarshallObject(in, refMap), unmarshallObject(in, refMap));
+   }
+
+   @SuppressWarnings("unchecked")
+   private void populateFromStream(ObjectInputStream in, UnmarshalledReferences refMap, Set setToPopulate) throws Exception
+   {
+      int size = readUnsignedInt(in);
+      for (int i = 0; i < size; i++) setToPopulate.add(unmarshallObject(in, refMap));
+   }
+
+   @SuppressWarnings("unchecked")
+   private void populateFromStream(ObjectInputStream in, UnmarshalledReferences refMap, List listToPopulate, int listSize) throws Exception
+   {
+      for (int i = 0; i < listSize; i++) listToPopulate.add(unmarshallObject(in, refMap));
+   }
+
+   /**
+    * This version of writeReference is written to solve JBCACHE-1211, where references are encoded as ints rather than shorts.
+    *
+    * @param out       stream to write to
+    * @param reference reference to write
+    * @throws java.io.IOException propagated from OOS
+    * @see <a href="http://jira.jboss.org/jira/browse/JBCACHE-1211">JBCACHE-1211</a>
+    */
+   protected void writeReference(ObjectOutputStream out, int reference) throws IOException
+   {
+      writeUnsignedInt(out, reference);
+   }
+
+   /**
+    * This version of readReference is written to solve JBCACHE-1211, where references are encoded as ints rather than shorts.
+    *
+    * @param in stream to read from
+    * @return reference
+    * @throws java.io.IOException propagated from OUS
+    * @see <a href="http://jira.jboss.org/jira/browse/JBCACHE-1211">JBCACHE-1211</a>
+    */
+   protected int readReference(ObjectInputStream in) throws IOException
+   {
+      return readUnsignedInt(in);
+   }
+
+   /**
+    * Reads an int stored in variable-length format.  Reads between one and
+    * five bytes.  Smaller values take fewer bytes.  Negative numbers are not
+    * supported.
+    */
+   protected int readUnsignedInt(ObjectInputStream in) throws IOException
+   {
+      byte b = in.readByte();
+      int i = b & 0x7F;
+      for (int shift = 7; (b & 0x80) != 0; shift += 7)
+      {
+         b = in.readByte();
+         i |= (b & 0x7FL) << shift;
+      }
+      return i;
+   }
+
+   /**
+    * Writes an int in a variable-length format.  Writes between one and
+    * five bytes.  Smaller values take fewer bytes.  Negative numbers are not
+    * supported.
+    *
+    * @param i int to write
+    */
+   protected void writeUnsignedInt(ObjectOutputStream out, int i) throws IOException
+   {
+      while ((i & ~0x7F) != 0)
+      {
+         out.writeByte((byte) ((i & 0x7f) | 0x80));
+         i >>>= 7;
+      }
+      out.writeByte((byte) i);
+   }
+
+
+   /**
+    * Reads an int stored in variable-length format.  Reads between one and
+    * nine bytes.  Smaller values take fewer bytes.  Negative numbers are not
+    * supported.
+    */
+   protected long readUnsignedLong(ObjectInputStream in) throws IOException
+   {
+      byte b = in.readByte();
+      long i = b & 0x7F;
+      for (int shift = 7; (b & 0x80) != 0; shift += 7)
+      {
+         b = in.readByte();
+         i |= (b & 0x7FL) << shift;
+      }
+      return i;
+   }
+
+   /**
+    * Writes an int in a variable-length format.  Writes between one and
+    * nine bytes.  Smaller values take fewer bytes.  Negative numbers are not
+    * supported.
+    *
+    * @param i int to write
+    */
+   protected void writeUnsignedLong(ObjectOutputStream out, long i) throws IOException
+   {
+      while ((i & ~0x7F) != 0)
+      {
+         out.writeByte((byte) ((i & 0x7f) | 0x80));
+         i >>>= 7;
+      }
+      out.writeByte((byte) i);
+   }
+
+   protected Object unmarshallArray(ObjectInputStream in, UnmarshalledReferences refs) throws Exception
+   {
+      int sz = readUnsignedInt(in);
+      byte type = in.readByte();
+      switch (type)
+      {
+         case MAGICNUMBER_BOOLEAN:
+         {
+            boolean isPrim = in.readBoolean();
+            if (isPrim)
+            {
+               boolean[] a = new boolean[sz];
+               for (int i = 0; i < sz; i++) a[i] = in.readBoolean();
+               return a;
+            } else
+            {
+               Boolean[] a = new Boolean[sz];
+               for (int i = 0; i < sz; i++) a[i] = in.readBoolean();
+               return a;
+            }
+         }
+         case MAGICNUMBER_INTEGER:
+         {
+            boolean isPrim = in.readBoolean();
+            if (isPrim)
+            {
+               int[] a = new int[sz];
+               for (int i = 0; i < sz; i++) a[i] = in.readInt();
+               return a;
+            } else
+            {
+               Integer[] a = new Integer[sz];
+               for (int i = 0; i < sz; i++) a[i] = in.readInt();
+               return a;
+            }
+         }
+         case MAGICNUMBER_LONG:
+         {
+            boolean isPrim = in.readBoolean();
+            if (isPrim)
+            {
+               long[] a = new long[sz];
+               for (int i = 0; i < sz; i++) a[i] = in.readLong();
+               return a;
+            } else
+            {
+               Long[] a = new Long[sz];
+               for (int i = 0; i < sz; i++) a[i] = in.readLong();
+               return a;
+            }
+         }
+         case MAGICNUMBER_CHAR:
+         {
+            boolean isPrim = in.readBoolean();
+            if (isPrim)
+            {
+               char[] a = new char[sz];
+               for (int i = 0; i < sz; i++) a[i] = in.readChar();
+               return a;
+            } else
+            {
+               Character[] a = new Character[sz];
+               for (int i = 0; i < sz; i++) a[i] = in.readChar();
+               return a;
+            }
+         }
+         case MAGICNUMBER_BYTE:
+         {
+            boolean isPrim = in.readBoolean();
+            if (isPrim)
+            {
+               byte[] a = new byte[sz];
+               int bsize = 10240;
+               int offset = 0;
+               int bytesLeft = sz;
+               while (bytesLeft > 0)
+               {
+                  int read = in.read(a, offset, Math.min(bsize, bytesLeft));
+                  offset += read;
+                  bytesLeft -= read;
+               }
+               return a;
+            } else
+            {
+               Byte[] a = new Byte[sz];
+               for (int i = 0; i < sz; i++) a[i] = in.readByte();
+               return a;
+            }
+         }
+         case MAGICNUMBER_SHORT:
+         {
+            boolean isPrim = in.readBoolean();
+            if (isPrim)
+            {
+               short[] a = new short[sz];
+               for (int i = 0; i < sz; i++) a[i] = in.readShort();
+               return a;
+            } else
+            {
+               Short[] a = new Short[sz];
+               for (int i = 0; i < sz; i++) a[i] = in.readShort();
+               return a;
+            }
+         }
+         case MAGICNUMBER_FLOAT:
+         {
+            boolean isPrim = in.readBoolean();
+            if (isPrim)
+            {
+               float[] a = new float[sz];
+               for (int i = 0; i < sz; i++) a[i] = in.readFloat();
+               return a;
+            } else
+            {
+               Float[] a = new Float[sz];
+               for (int i = 0; i < sz; i++) a[i] = in.readFloat();
+               return a;
+            }
+         }
+         case MAGICNUMBER_DOUBLE:
+         {
+            boolean isPrim = in.readBoolean();
+            if (isPrim)
+            {
+               double[] a = new double[sz];
+               for (int i = 0; i < sz; i++) a[i] = in.readDouble();
+               return a;
+            } else
+            {
+               Double[] a = new Double[sz];
+               for (int i = 0; i < sz; i++) a[i] = in.readDouble();
+               return a;
+            }
+         }
+         case MAGICNUMBER_OBJECT:
+         {
+            Object[] a = new Object[sz];
+            for (int i = 0; i < sz; i++) a[i] = unmarshallObject(in, refs);
+            return a;
+         }
+         default:
+            throw new CacheException("Unknown array type");
+      }
+   }
+
+   protected void marshallArray(Object o, ObjectOutputStream out, Map<Object, Integer> refMap) throws Exception
+   {
+      out.writeByte(MAGICNUMBER_ARRAY);
+      Class arrayTypeClass = o.getClass().getComponentType();
+      int sz = Array.getLength(o);
+      writeUnsignedInt(out, sz);
+      boolean isPrim = arrayTypeClass.isPrimitive();
+
+      if (!isPrim && arrayTypeClass.equals(Object.class))
+      {
+         out.writeByte(MAGICNUMBER_OBJECT);
+         for (int i = 0; i < sz; i++) marshallObject(Array.get(o, i), out, refMap);
+      } else if (arrayTypeClass.equals(byte.class) || arrayTypeClass.equals(Byte.class))
+      {
+         out.writeByte(MAGICNUMBER_BYTE);
+         out.writeBoolean(isPrim);
+         if (isPrim)
+            out.write((byte[]) o);
+         else
+            for (int i = 0; i < sz; i++) out.writeByte((Byte) Array.get(o, i));
+      } else if (arrayTypeClass.equals(int.class) || arrayTypeClass.equals(Integer.class))
+      {
+         out.writeByte(MAGICNUMBER_INTEGER);
+         out.writeBoolean(isPrim);
+         if (isPrim)
+            for (int i = 0; i < sz; i++) out.writeInt(Array.getInt(o, i));
+         else
+            for (int i = 0; i < sz; i++) out.writeInt((Integer) Array.get(o, i));
+      } else if (arrayTypeClass.equals(long.class) || arrayTypeClass.equals(Long.class))
+      {
+         out.writeByte(MAGICNUMBER_LONG);
+         out.writeBoolean(isPrim);
+         if (isPrim)
+            for (int i = 0; i < sz; i++) out.writeLong(Array.getLong(o, i));
+         else
+            for (int i = 0; i < sz; i++) out.writeLong((Long) Array.get(o, i));
+      } else if (arrayTypeClass.equals(boolean.class) || arrayTypeClass.equals(Boolean.class))
+      {
+         out.writeByte(MAGICNUMBER_BOOLEAN);
+         out.writeBoolean(isPrim);
+         if (isPrim)
+            for (int i = 0; i < sz; i++) out.writeBoolean(Array.getBoolean(o, i));
+         else
+            for (int i = 0; i < sz; i++) out.writeBoolean((Boolean) Array.get(o, i));
+      } else if (arrayTypeClass.equals(char.class) || arrayTypeClass.equals(Character.class))
+      {
+         out.writeByte(MAGICNUMBER_CHAR);
+         out.writeBoolean(isPrim);
+         if (isPrim)
+            for (int i = 0; i < sz; i++) out.writeChar(Array.getChar(o, i));
+         else
+            for (int i = 0; i < sz; i++) out.writeChar((Character) Array.get(o, i));
+      } else if (arrayTypeClass.equals(short.class) || arrayTypeClass.equals(Short.class))
+      {
+         out.writeByte(MAGICNUMBER_SHORT);
+         out.writeBoolean(isPrim);
+         if (isPrim)
+            for (int i = 0; i < sz; i++) out.writeShort(Array.getShort(o, i));
+         else
+            for (int i = 0; i < sz; i++) out.writeShort((Short) Array.get(o, i));
+      } else if (arrayTypeClass.equals(float.class) || arrayTypeClass.equals(Float.class))
+      {
+         out.writeByte(MAGICNUMBER_FLOAT);
+         out.writeBoolean(isPrim);
+         if (isPrim)
+            for (int i = 0; i < sz; i++) out.writeFloat(Array.getFloat(o, i));
+         else
+            for (int i = 0; i < sz; i++) out.writeFloat((Float) Array.get(o, i));
+      } else if (arrayTypeClass.equals(double.class) || arrayTypeClass.equals(Double.class))
+      {
+         out.writeByte(MAGICNUMBER_DOUBLE);
+         out.writeBoolean(isPrim);
+         if (isPrim)
+            for (int i = 0; i < sz; i++) out.writeDouble(Array.getDouble(o, i));
+         else
+            for (int i = 0; i < sz; i++) out.writeDouble((Double) Array.get(o, i));
+      } else throw new CacheException("Unknown array type!");
+   }
+
+   protected boolean isKnownType(Class c)
+   {
+      return (c.equals(Object.class) ||
+            c.isPrimitive() || c.equals(Character.class) || c.equals(Integer.class) || c.equals(Long.class) ||
+            c.equals(Byte.class) || c.equals(Boolean.class) || c.equals(Short.class) || c.equals(Float.class) ||
+            c.equals(Double.class));
+   }
+
+   public void objectToObjectStream(Object o, ObjectOutputStream out) throws Exception
+   {
+      Map<Object, Integer> refMap = useRefs ? new IdentityHashMap<Object, Integer>() : null;
+      ClassLoader toUse = defaultClassLoader;
+      Thread current = Thread.currentThread();
+      ClassLoader old = current.getContextClassLoader();
+      if (old != null) toUse = old;
+
+      try
+      {
+         current.setContextClassLoader(toUse);
+         marshallObject(o, out, refMap);
+      }
+      finally
+      {
+         current.setContextClassLoader(old);
+      }
+   }
+
+   public Object objectFromObjectStream(ObjectInputStream in) throws Exception
+   {
+      UnmarshalledReferences refMap = useRefs ? new UnmarshalledReferences() : null;
+      Object retValue = unmarshallObject(in, defaultClassLoader, refMap, false);
+      if (trace) log.trace("Unmarshalled object " + retValue);
+      return retValue;
+   }
+
+   public Object objectFromStream(InputStream is) throws Exception
+   {
+      throw new NotImplementedException("not implemented");
+   }
+
+   public ByteBuffer objectToBuffer(Object o) throws Exception
+   {
+      throw new RuntimeException("Needs to be overridden!");
+   }
+
+   public Object objectFromByteBuffer(byte[] buf, int offset, int length) throws Exception
+   {
+      throw new RuntimeException("Needs to be overridden!");
+   }
+
+   public Object objectFromByteBuffer(byte[] bytes) throws Exception
+   {
+      return objectFromByteBuffer(bytes, 0, bytes.length);
+   }
+}
\ No newline at end of file

Copied: core/branches/flat/src/main/java/org/jboss/starobrno/marshall/CommandAwareRpcDispatcher.java (from rev 6897, core/branches/flat/src/main/java/org/jboss/cache/marshall/CommandAwareRpcDispatcher.java)
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/marshall/CommandAwareRpcDispatcher.java	                        (rev 0)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/marshall/CommandAwareRpcDispatcher.java	2008-10-14 17:47:27 UTC (rev 6943)
@@ -0,0 +1,301 @@
+/*
+ * 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.jboss.starobrno.marshall;
+
+import org.jboss.cache.util.concurrent.WithinThreadExecutor;
+import org.jboss.starobrno.commands.ReplicableCommand;
+import org.jboss.starobrno.commands.VisitableCommand;
+import org.jboss.starobrno.commands.remote.AnnounceBuddyPoolNameCommand;
+import org.jboss.starobrno.commands.remote.AssignToBuddyGroupCommand;
+import org.jboss.starobrno.commands.remote.RemoveFromBuddyGroupCommand;
+import org.jboss.starobrno.config.Configuration;
+import org.jboss.starobrno.context.InvocationContext;
+import org.jboss.starobrno.factories.ComponentRegistry;
+import org.jboss.starobrno.interceptors.InterceptorChain;
+import org.jboss.starobrno.invocation.InvocationContextContainer;
+import org.jgroups.Address;
+import org.jgroups.Channel;
+import org.jgroups.MembershipListener;
+import org.jgroups.Message;
+import org.jgroups.MessageListener;
+import org.jgroups.blocks.RpcDispatcher;
+import org.jgroups.blocks.RspFilter;
+import org.jgroups.util.Buffer;
+import org.jgroups.util.Rsp;
+import org.jgroups.util.RspList;
+
+import java.io.NotSerializableException;
+import java.util.Vector;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * A JGroups RPC dispatcher that knows how to deal with {@link org.jboss.cache.commands.ReplicableCommand}s.
+ *
+ * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @since 2.2.0
+ */
+public class CommandAwareRpcDispatcher extends RpcDispatcher
+{
+   protected InvocationContextContainer invocationContextContainer;
+   protected InterceptorChain interceptorChain;
+   protected ComponentRegistry componentRegistry;
+   protected boolean trace;
+   private ExecutorService replicationProcessor;
+   private AtomicInteger replicationProcessorCount;
+   private boolean asyncSerial;
+
+   public CommandAwareRpcDispatcher()
+   {
+   }
+
+   public CommandAwareRpcDispatcher(Channel channel, MessageListener l, MembershipListener l2, Object serverObj,
+                                    InvocationContextContainer container, InterceptorChain interceptorChain,
+                                    ComponentRegistry componentRegistry)
+   {
+      super(channel, l, l2, serverObj);
+      this.invocationContextContainer = container;
+      this.componentRegistry = componentRegistry;
+      this.interceptorChain = interceptorChain;
+      trace = log.isTraceEnabled();
+
+      // what sort of a repl processor do we need?
+      Configuration c = componentRegistry.getComponent(Configuration.class);
+      replicationProcessor = c.getRuntimeConfig().getAsyncSerializationExecutor();
+      if (c.getCacheMode().isSynchronous() ||
+            (replicationProcessor == null && c.getSerializationExecutorPoolSize() < 1)) // if an executor has not been injected and the pool size is set
+      {
+         // in-process thread.  Not async.
+         replicationProcessor = new WithinThreadExecutor();
+         asyncSerial = false;
+      }
+      else
+      {
+         asyncSerial = true;
+         if (replicationProcessor == null)
+         {
+            replicationProcessorCount = new AtomicInteger(0);
+            replicationProcessor = Executors.newFixedThreadPool(c.isUseReplQueue() ? 1 : c.getSerializationExecutorPoolSize(),
+                  new ThreadFactory()
+                  {
+                     public Thread newThread(Runnable r)
+                     {
+                        return new Thread(r, "AsyncReplicationProcessor-" + replicationProcessorCount.incrementAndGet());
+                     }
+                  }
+            );
+         }
+      }
+   }
+
+   @Override
+   public void stop()
+   {
+      replicationProcessor.shutdownNow();
+      try
+      {
+         replicationProcessor.awaitTermination(60, TimeUnit.SECONDS);
+      }
+      catch (InterruptedException e)
+      {
+         Thread.currentThread().interrupt();
+      }
+      super.stop();
+   }
+
+   protected boolean isValid(Message req)
+   {
+      if (server_obj == null)
+      {
+         log.error("no method handler is registered. Discarding request.");
+         return false;
+      }
+
+      if (req == null || req.getLength() == 0)
+      {
+         log.error("message or message buffer is null");
+         return false;
+      }
+
+      return true;
+   }
+
+   /**
+    * Similar to {@link #callRemoteMethods(java.util.Vector, org.jgroups.blocks.MethodCall, int, long, boolean, boolean, org.jgroups.blocks.RspFilter)} except that this version
+    * is aware of {@link org.jboss.cache.commands.ReplicableCommand} objects.
+    */
+   public RspList invokeRemoteCommands(Vector<Address> dests, ReplicableCommand command, int mode, long timeout,
+                                       boolean oob, RspFilter filter) throws NotSerializableException, ExecutionException, InterruptedException
+   {
+      if (dests != null && dests.isEmpty())
+      {
+         // don't send if dest list is empty
+         if (trace) log.trace("Destination list is empty: no need to send message");
+         return new RspList();
+      }
+
+      if (trace)
+         log.trace(new StringBuilder("dests=").append(dests).append(", command=").append(command).
+               append(", mode=").append(mode).append(", timeout=").append(timeout));
+
+      ReplicationTask replicationTask = new ReplicationTask(command, oob, dests, mode, timeout, false, filter);
+      Future<RspList> response = replicationProcessor.submit(replicationTask);
+      if (asyncSerial)
+      {
+         // don't care about the response.  return.
+         return null;
+      }
+      else
+      {
+         RspList retval = response.get();
+         if (retval.isEmpty() || containsOnlyNulls(retval))
+            return null;
+         else
+            return retval;
+      }
+   }
+
+   private boolean containsOnlyNulls(RspList l)
+   {
+      for (Rsp r : l.values())
+      {
+         if (r.getValue() != null || !r.wasReceived() || r.wasSuspected()) return false;
+      }
+      return true;
+   }
+
+   /**
+    * Message contains a Command. Execute it against *this* object and return result.
+    */
+   @Override
+   public Object handle(Message req)
+   {
+      if (isValid(req))
+      {
+         try
+         {
+            return executeCommand((ReplicableCommand) req_marshaller.objectFromByteBuffer(req.getBuffer(), req.getOffset(), req.getLength()), req);
+         }
+         catch (Throwable x)
+         {
+            if (trace) log.trace("Problems invoking command.", x);
+            return x;
+         }
+      }
+      else
+      {
+         return null;
+      }
+   }
+
+   protected Object executeCommand(ReplicableCommand cmd, Message req) throws Throwable
+   {
+      if (cmd == null) throw new NullPointerException("Unable to execute a null command!  Message was " + req);
+      if (trace) log.trace("Executing command: " + cmd + " [sender=" + req.getSrc() + "]");
+
+      if (cmd instanceof VisitableCommand)
+      {
+         InvocationContext ctx = invocationContextContainer.get();
+         ctx.setOriginLocal(false);
+         if (!componentRegistry.invocationsAllowed(false))
+         {
+            return null;
+         }
+         return interceptorChain.invoke(ctx, (VisitableCommand) cmd);
+      }
+      else
+      {
+         if (trace) log.trace("This is a non-visitable command - so performing directly and not via the invoker.");
+
+         // need to check cache status for all except buddy replication commands.
+         if (!(cmd instanceof AnnounceBuddyPoolNameCommand ||
+               cmd instanceof AssignToBuddyGroupCommand ||
+               cmd instanceof RemoveFromBuddyGroupCommand)
+               && !componentRegistry.invocationsAllowed(false))
+         {
+            return null;
+         }
+         return cmd.perform(null);
+      }
+   }
+
+   @Override
+   public String toString()
+   {
+      return getClass().getSimpleName() + "[Outgoing marshaller: " + req_marshaller + "; incoming marshaller: " + rsp_marshaller + "]";
+   }
+
+   private class ReplicationTask implements Callable<RspList>
+   {
+      private ReplicableCommand command;
+      private boolean oob;
+      private Vector<Address> dests;
+      private int mode;
+      private long timeout;
+      private boolean anycasting;
+      private RspFilter filter;
+
+      private ReplicationTask(ReplicableCommand command, boolean oob, Vector<Address> dests, int mode, long timeout, boolean anycasting, RspFilter filter)
+      {
+         this.command = command;
+         this.oob = oob;
+         this.dests = dests;
+         this.mode = mode;
+         this.timeout = timeout;
+         this.anycasting = anycasting;
+         this.filter = filter;
+      }
+
+      public RspList call() throws Exception
+      {
+         Buffer buf;
+         try
+         {
+            buf = req_marshaller.objectToBuffer(command);
+         }
+         catch (Exception e)
+         {
+            throw new RuntimeException("Failure to marshal argument(s)", e);
+         }
+
+         Message msg = new Message();
+         msg.setBuffer(buf);
+         if (oob) msg.setFlag(Message.OOB);
+         RspList retval = castMessage(dests, msg, mode, timeout, anycasting, filter);
+         if (trace) log.trace("responses: " + retval);
+
+         // a null response is 99% likely to be due to a marshalling problem - we throw a NSE, this needs to be changed when
+         // JGroups supports http://jira.jboss.com/jira/browse/JGRP-193
+         // the serialization problem could be on the remote end and this is why we cannot catch this above, when marshalling.
+
+         if (retval == null)
+            throw new NotSerializableException("RpcDispatcher returned a null.  This is most often caused by args for " + command.getClass().getSimpleName() + " not being serializable.");
+         return retval;
+      }
+   }
+}
\ No newline at end of file

Copied: core/branches/flat/src/main/java/org/jboss/starobrno/marshall/ExtendedMarshaller.java (from rev 6897, core/branches/flat/src/main/java/org/jboss/cache/marshall/Marshaller.java)
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/marshall/ExtendedMarshaller.java	                        (rev 0)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/marshall/ExtendedMarshaller.java	2008-10-14 17:47:27 UTC (rev 6943)
@@ -0,0 +1,89 @@
+/*
+ * 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.jboss.starobrno.marshall;
+
+import org.jboss.starobrno.io.ByteBuffer;
+import org.jgroups.blocks.RpcDispatcher;
+
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+/**
+ * A marshaller is a class that is able to marshall and unmarshall objects efficiently.
+ * <p/>
+ * The reason why this is implemented specially in JBoss Cache rather than resorting to
+ * Java serialization or even the more efficient JBoss serialization is that a lot of efficiency
+ * can be gained when a majority of the serialization that occurs has to do with a small set
+ * of known types such as {@link org.jboss.cache.Fqn} or {@link org.jboss.cache.commands.ReplicableCommand}, and class type information
+ * can be replaced with simple magic numbers.
+ * <p/>
+ * Unknown types (typically user data) falls back to JBoss serialization.
+ * <p/>
+ * In addition, using a marshaller allows adding additional data to the byte stream, such as context
+ * class loader information on which class loader to use to deserialize the object stream, or versioning
+ * information to allow streams to interoperate between different versions of JBoss Cache (see {@link org.jboss.cache.marshall.VersionAwareMarshaller}
+ * <p/>
+ * This interface implements the JGroups building-block interface {@link org.jgroups.blocks.RpcDispatcher.Marshaller} which
+ * is used to marshall {@link org.jboss.cache.commands.ReplicableCommand}s, their parameters and their response values.
+ * <p/>
+ * The interface is also used by the {@link org.jboss.cache.loader.CacheLoader} framework to efficiently serialize data to be persisted, as well as
+ * the {@link org.jboss.starobrno.statetransfer.StateTransferManager} when serializing the cache for transferring state en-masse.
+ *
+ * @author <a href="mailto://manik@jboss.org">Manik Surtani</a>
+ * @since 2.0.0
+ */
+public interface ExtendedMarshaller extends RpcDispatcher.Marshaller2
+{
+   /**
+    * Marshalls an object to a given {@link java.io.ObjectOutputStream}
+    *
+    * @param obj object to marshall
+    * @param out stream to marshall to
+    */
+   void objectToObjectStream(Object obj, ObjectOutputStream out) throws Exception;
+
+   /**
+    * Unmarshalls an object from an {@link java.io.ObjectInputStream}
+    *
+    * @param in stream to unmarshall from
+    */
+   Object objectFromObjectStream(ObjectInputStream in) throws Exception;
+
+   /**
+    * Unmarshalls an object from an {@link java.io.InputStream}
+    *
+    * @param is stream to unmarshall from
+    * @return Object from stream passed in.
+    */
+   Object objectFromStream(InputStream is) throws Exception;
+
+   /**
+    * A specialized form of {@link org.jgroups.blocks.RpcDispatcher.Marshaller2#objectToBuffer(Object)} that returns an instance
+    * of {@link org.jboss.starobrno.io.ByteBuffer} instead of {@link org.jgroups.util.Buffer}.
+    *
+    * @param o object to marshall
+    * @return a ByteBuffer
+    * @throws Exception
+    */
+   ByteBuffer objectToBuffer(Object o) throws Exception;
+}
\ No newline at end of file


Property changes on: core/branches/flat/src/main/java/org/jboss/starobrno/marshall/ExtendedMarshaller.java
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + native

Added: core/branches/flat/src/main/java/org/jboss/starobrno/marshall/MarshalledValue2.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/marshall/MarshalledValue2.java	                        (rev 0)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/marshall/MarshalledValue2.java	2008-10-14 17:47:27 UTC (rev 6943)
@@ -0,0 +1,229 @@
+/*
+ * 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.jboss.starobrno.marshall;
+
+import org.jboss.starobrno.CacheException;
+import org.jboss.util.stream.MarshalledValueInputStream;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.NotSerializableException;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.Arrays;
+
+/**
+ * Wrapper that wraps cached data, providing lazy deserialization using the calling thread's context class loader.
+ * <p/>
+ * The {@link org.jboss.cache.interceptors.MarshalledValueInterceptor} handles transparent
+ * wrapping/unwrapping of cached data.
+ * <p/>
+ *
+ * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @see org.jboss.cache.interceptors.MarshalledValueInterceptor
+ * @since 2.1.0
+ */
+public class MarshalledValue2 implements Externalizable
+{
+   protected Object instance;
+   protected byte[] raw;
+   private int cachedHashCode = 0;
+   // by default equals() will test on the istance rather than the byte array if conversion is required.
+   private transient boolean equalityPreferenceForInstance = true;
+
+   public MarshalledValue2(Object instance) 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.");
+   }
+
+   public MarshalledValue2()
+   {
+      // empty ctor for serialization
+   }
+
+   public void setEqualityPreferenceForInstance(boolean equalityPreferenceForInstance)
+   {
+      this.equalityPreferenceForInstance = equalityPreferenceForInstance;
+   }
+
+   public synchronized void serialize()
+   {
+      if (raw == null)
+      {
+         try
+         {
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            ObjectOutputStream oos = new ObjectOutputStream(baos);
+            oos.writeObject(instance);
+            oos.close();
+            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)
+         {
+            throw new CacheException("Unable to marshall value " + instance, e);
+         }
+      }
+   }
+
+   public synchronized void deserialize()
+   {
+      if (instance == null)
+      {
+         try
+         {
+            ByteArrayInputStream bais = new ByteArrayInputStream(raw);
+            // use a MarshalledValueInputStream since it needs to be aware of any context class loaders on the current thread.
+            ObjectInputStream ois = new MarshalledValueInputStream(bais);
+            instance = ois.readObject();
+            ois.close();
+            bais.close();
+//            raw = null;
+         }
+         catch (Exception e)
+         {
+            throw new CacheException("Unable to unmarshall value", e);
+         }
+      }
+   }
+
+   /**
+    * Compacts the references held by this class to a single reference.  If only one representation exists this method
+    * is a no-op unless the 'force' parameter is used, in which case the reference held is forcefully switched to the
+    * 'preferred representation'.
+    * <p/>
+    * Either way, a call to compact() will ensure that only one representation is held.
+    * <p/>
+    *
+    * @param preferSerializedRepresentation if true and both representations exist, the serialized representation is favoured.  If false, the deserialized representation is preferred.
+    * @param force                          ensures the preferred representation is maintained and the other released, even if this means serializing or deserializing.
+    */
+   public void compact(boolean preferSerializedRepresentation, boolean force)
+   {
+      // reset the equalityPreference
+      equalityPreferenceForInstance = true;
+      if (force)
+      {
+         if (preferSerializedRepresentation && raw == null) serialize();
+         else if (!preferSerializedRepresentation && instance == null) deserialize();
+      }
+
+      if (instance != null && raw != null)
+      {
+         // need to lose one representation!
+
+         if (preferSerializedRepresentation)
+         {
+            instance = null;
+         }
+         else
+         {
+            raw = null;
+         }
+      }
+   }
+
+   public void writeExternal(ObjectOutput out) throws IOException
+   {
+      if (raw == null) serialize();
+      out.writeInt(raw.length);
+      out.write(raw);
+      out.writeInt(hashCode());
+   }
+
+   public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
+   {
+      int size = in.readInt();
+      raw = new byte[size];
+      cachedHashCode = 0;
+      in.readFully(raw);
+      cachedHashCode = in.readInt();
+   }
+
+   public Object get() throws IOException, ClassNotFoundException
+   {
+      if (instance == null) deserialize();
+      return instance;
+   }
+
+   @Override
+   public boolean equals(Object o)
+   {
+      if (this == o) return true;
+      if (o == null || getClass() != o.getClass()) return false;
+
+      MarshalledValue2 that = (MarshalledValue2) o;
+
+      // if both versions are serialized or deserialized, just compare the relevant representations.
+      if (raw != null && that.raw != null) return Arrays.equals(raw, that.raw);
+      if (instance != null && that.instance != null) return instance.equals(that.instance);
+
+      // if conversion of one representation to the other is necessary, then see which we prefer converting.
+      if (equalityPreferenceForInstance)
+      {
+         if (instance == null) deserialize();
+         if (that.instance == null) that.deserialize();
+         return instance.equals(that.instance);
+      }
+      else
+      {
+         if (raw == null) serialize();
+         if (that.raw == null) that.serialize();
+         return Arrays.equals(raw, that.raw);
+      }
+   }
+
+   @Override
+   public int hashCode()
+   {
+      if (cachedHashCode == 0)
+      {
+         // always calculate the hashcode based on the instance since this is where we're getting the equals()
+         if (instance == null) deserialize();
+         cachedHashCode = instance.hashCode();
+         if (cachedHashCode == 0) // degenerate case
+         {
+            cachedHashCode = 0xFEED;
+         }
+      }
+      return cachedHashCode;
+   }
+
+   @Override
+   public String toString()
+   {
+      return "MarshalledValue2(cachedHashCode=" + cachedHashCode + "; serialized=" + (raw != null) + ")";
+   }
+}

Added: core/branches/flat/src/main/java/org/jboss/starobrno/marshall/MarshalledValueHelper2.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/marshall/MarshalledValueHelper2.java	                        (rev 0)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/marshall/MarshalledValueHelper2.java	2008-10-14 17:47:27 UTC (rev 6943)
@@ -0,0 +1,56 @@
+/*
+ * 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.jboss.starobrno.marshall;
+
+import org.jboss.cache.Fqn;
+import org.jboss.cache.commands.ReplicableCommand;
+import org.jboss.cache.transaction.GlobalTransaction;
+import org.jboss.starobrno.marshall.MarshalledValue2;
+import org.jgroups.Address;
+
+/**
+ * Common functionality used by the {@link org.jboss.cache.interceptors.MarshalledValueInterceptor} and the {@link org.jboss.cache.marshall.MarshalledValueMap}.
+ *
+ * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @see MarshalledValue2
+ * @see org.jboss.cache.interceptors.MarshalledValueInterceptor
+ * @see org.jboss.cache.marshall.MarshalledValueMap
+ * @since 2.1.0
+ */
+public class MarshalledValueHelper2
+{
+   /**
+    * 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(Fqn.class) || type.equals(GlobalTransaction.class) || type.equals(Address.class) ||
+            ReplicableCommand.class.isAssignableFrom(type) || type.equals(MarshalledValue2.class);
+   }
+}

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/marshall/MarshalledValueMap.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/marshall/MarshalledValueMap.java	2008-10-14 17:44:04 UTC (rev 6942)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/marshall/MarshalledValueMap.java	2008-10-14 17:47:27 UTC (rev 6943)
@@ -42,7 +42,7 @@
  * <p/>
  *
  * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
- * @see MarshalledValue
+ * @see MarshalledValue2
  * @since 2.1.0
  */
 @Immutable
@@ -145,7 +145,7 @@
    {
       try
       {
-         return o instanceof MarshalledValue ? ((MarshalledValue) o).get() : o;
+         return o instanceof MarshalledValue2 ? ((MarshalledValue2) o).get() : o;
       }
       catch (Exception e)
       {

Copied: core/branches/flat/src/main/java/org/jboss/starobrno/marshall/NodeData.java (from rev 6897, core/branches/flat/src/main/java/org/jboss/cache/marshall/NodeData.java)
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/marshall/NodeData.java	                        (rev 0)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/marshall/NodeData.java	2008-10-14 17:47:27 UTC (rev 6943)
@@ -0,0 +1,145 @@
+/*
+ * 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.jboss.starobrno.marshall;
+
+import org.jboss.cache.Fqn;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Serializable representation of the data of a node (FQN and attributes)
+ *
+ * @author Bela Ban
+ * @version $Id$
+ */
+// TODO: 3.0.0: remove Externalizable and rely on the CacheMarshaller.
+public class NodeData<K, V> implements Externalizable
+{
+   private Fqn fqn = null;
+   private Map<K, V> attrs = null;
+
+   static final long serialVersionUID = -7571995794010294485L;
+
+   public NodeData()
+   {
+   }
+
+   public NodeData(Fqn fqn)
+   {
+      this.fqn = fqn;
+   }
+
+   public NodeData(Fqn fqn, Map<K, V> attrs, boolean mapSafe)
+   {
+      this.fqn = fqn;
+      if (mapSafe || attrs == null)
+         this.attrs = attrs;
+      else
+         this.attrs = new HashMap<K, V>(attrs);
+   }
+
+   public NodeData(String fqn, Map<K, V> attrs, boolean mapSafe)
+   {
+      this(Fqn.fromString(fqn), attrs, mapSafe);
+   }
+
+   public Map<K, V> getAttributes()
+   {
+      return attrs;
+   }
+
+   public Fqn getFqn()
+   {
+      return fqn;
+   }
+
+   public boolean isMarker()
+   {
+      return false;
+   }
+
+   public boolean isExceptionMarker()
+   {
+      return false;
+   }
+
+   // TODO: 3.0.0: Remove and replace with marshallNodeData/unmarshallNodeData methods in the CacheMarshaller so that we can use the same marshalling framework for Fqns.
+   public void writeExternal(ObjectOutput out) throws IOException
+   {
+      out.writeObject(fqn);
+      if (attrs != null)
+      {
+         out.writeBoolean(true);
+         out.writeObject(attrs);
+      }
+      else
+      {
+         out.writeBoolean(false);
+      }
+   }
+
+   // TODO: 3.0.0: Remove in and replace with marshallNodeData/unmarshallNodeData methods in the CacheMarshaller so that we can use the same marshalling framework for Fqns.
+   @SuppressWarnings("unchecked")
+   public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
+   {
+      fqn = (Fqn) in.readObject();
+      if (in.readBoolean())
+      {
+         attrs = (Map<K, V>) in.readObject();
+      }
+   }
+
+   @Override
+   public String toString()
+   {
+      return "NodeData {fqn: " + fqn + ", attrs=" + attrs + "}";
+   }
+
+
+   @Override
+   public boolean equals(Object o)
+   {
+      if (this == o) return true;
+      if (o == null || getClass() != o.getClass()) return false;
+
+      NodeData nodeData = (NodeData) o;
+
+      if (attrs != null ? !attrs.equals(nodeData.attrs) : nodeData.attrs != null) return false;
+      if (fqn != null ? !fqn.equals(nodeData.fqn) : nodeData.fqn != null) return false;
+
+      return true;
+   }
+
+   @Override
+   public int hashCode()
+   {
+      int result;
+      result = (fqn != null ? fqn.hashCode() : 0);
+      result = 31 * result + (attrs != null ? attrs.hashCode() : 0);
+      return result;
+   }
+}


Property changes on: core/branches/flat/src/main/java/org/jboss/starobrno/marshall/NodeData.java
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + native

Copied: core/branches/flat/src/main/java/org/jboss/starobrno/marshall/NodeDataExceptionMarker.java (from rev 6897, core/branches/flat/src/main/java/org/jboss/cache/marshall/NodeDataExceptionMarker.java)
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/marshall/NodeDataExceptionMarker.java	                        (rev 0)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/marshall/NodeDataExceptionMarker.java	2008-10-14 17:47:27 UTC (rev 6943)
@@ -0,0 +1,85 @@
+/*
+ * 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.jboss.starobrno.marshall;
+
+import org.jboss.starobrno.marshall.NodeData;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+public class NodeDataExceptionMarker extends NodeData
+{
+
+   private static final long serialVersionUID = 240199474174502551L;
+   private Throwable cause;
+   private Object cacheNodeIdentity;
+
+   public NodeDataExceptionMarker()
+   {
+      super();
+   }
+
+   public NodeDataExceptionMarker(Throwable t, Object node)
+   {
+      cause = t;
+      cacheNodeIdentity = node;
+   }
+
+   public Throwable getCause()
+   {
+      return cause;
+   }
+
+   public Object getCacheNodeIdentity()
+   {
+      return cacheNodeIdentity;
+   }
+
+   @Override
+   public boolean isExceptionMarker()
+   {
+      return true;
+   }
+
+   @Override
+   public void writeExternal(ObjectOutput out) throws IOException
+   {
+      super.writeExternal(out);
+      out.writeObject(cause);
+      out.writeObject(cacheNodeIdentity);
+   }
+
+   @Override
+   public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
+   {
+      super.readExternal(in);
+      cause = (Throwable) in.readObject();
+      cacheNodeIdentity = in.readObject();
+   }
+
+   @Override
+   public String toString()
+   {
+      return "NodeDataExceptionMarker";
+   }
+}


Property changes on: core/branches/flat/src/main/java/org/jboss/starobrno/marshall/NodeDataExceptionMarker.java
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + native

Copied: core/branches/flat/src/main/java/org/jboss/starobrno/marshall/NodeDataMarker.java (from rev 6897, core/branches/flat/src/main/java/org/jboss/cache/marshall/NodeDataMarker.java)
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/marshall/NodeDataMarker.java	                        (rev 0)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/marshall/NodeDataMarker.java	2008-10-14 17:47:27 UTC (rev 6943)
@@ -0,0 +1,42 @@
+/*
+ * 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.jboss.starobrno.marshall;
+
+import org.jboss.starobrno.marshall.NodeData;
+
+public class NodeDataMarker extends NodeData
+{
+
+   private static final long serialVersionUID = 4851793846346021014L;
+
+   @Override
+   public boolean isMarker()
+   {
+      return true;
+   }
+
+   @Override
+   public String toString()
+   {
+      return "NodeDataMarker";
+   }
+}


Property changes on: core/branches/flat/src/main/java/org/jboss/starobrno/marshall/NodeDataMarker.java
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + native

Copied: core/branches/flat/src/main/java/org/jboss/starobrno/marshall/UnmarshalledReferences.java (from rev 6897, core/branches/flat/src/main/java/org/jboss/cache/marshall/UnmarshalledReferences.java)
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/marshall/UnmarshalledReferences.java	                        (rev 0)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/marshall/UnmarshalledReferences.java	2008-10-14 17:47:27 UTC (rev 6943)
@@ -0,0 +1,73 @@
+/*
+ * 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.jboss.starobrno.marshall;
+
+import org.jboss.starobrno.CacheException;
+
+import java.util.ArrayList;
+
+/**
+ * An efficient array-based list of referenced objects, using the reference id as a subscript for the array.
+ *
+ * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
+ */
+public class UnmarshalledReferences
+{
+   private final ArrayList<Object> referencedObjects = new ArrayList<Object>();
+
+   /**
+    * Retrieves an object referenced by an id
+    *
+    * @param ref reference
+    * @return object
+    */
+   public Object getReferencedObject(int ref)
+   {
+      if (ref >= referencedObjects.size())
+         throw new CacheException("Attempting to look up a ref that hasn't been inserted yet");
+      return referencedObjects.get(ref);
+   }
+
+   /**
+    * Adds a referenced object to the list of references
+    *
+    * @param ref reference id
+    * @param o   object
+    */
+   public void putReferencedObject(int ref, Object o)
+   {
+      int sz = referencedObjects.size();
+      // if we are not adding the object to the end of the list, make sure we use a specific position
+      if (ref < sz)
+      {
+         referencedObjects.set(ref, o);
+         return;
+      }
+      else if (ref > sz)
+      {
+         // if we are adding the reference to a position beyond the end of the list, make sure we expand the list first.
+         // this can happen, weirdly enough, since marshallObject() can be called recursively, such as from marshallFqn().
+         for (int i = sz; i < ref; i++) referencedObjects.add(null);
+      }
+      referencedObjects.add(o);
+   }
+}




More information about the jbosscache-commits mailing list