### Eclipse Workspace Patch 1.0 #P parent Index: pom.xml =================================================================== --- pom.xml (revision 94) +++ pom.xml (working copy) @@ -84,6 +84,10 @@ java.net.preferIPv4Stack true + + infinispan.marshaller.class + ${marshaller.class} + false @@ -185,5 +189,14 @@ integration + + + test-jbossmarshaller + + functional + org.infinispan.marshall.jboss.JBossMarshaller + tcp + + #P core Index: src/main/java/org/infinispan/marshall/jboss/CustomObjectTable.java =================================================================== --- src/main/java/org/infinispan/marshall/jboss/CustomObjectTable.java (revision 0) +++ src/main/java/org/infinispan/marshall/jboss/CustomObjectTable.java (revision 0) @@ -0,0 +1,84 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2009, 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.infinispan.marshall.jboss; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; + +import net.jcip.annotations.Immutable; + +import org.infinispan.remoting.transport.jgroups.RequestIgnoredResponse; +import org.jboss.marshalling.Marshaller; +import org.jboss.marshalling.ObjectTable; +import org.jboss.marshalling.Unmarshaller; + +/** + * CustomObjectTable. + * + * @author Galder Zamarreno + * @since 4.0 + */ +public class CustomObjectTable implements ObjectTable { + + private final List objects = new ArrayList(); + private final Map writers = new IdentityHashMap(); + private byte index; + + public void init() { + objects.add(RequestIgnoredResponse.INSTANCE); + writers.put(RequestIgnoredResponse.INSTANCE, new CustomObjectWriter(index++)); + } + + public void stop() { + writers.clear(); + objects.clear(); + } + + public void add(Object o) { + objects.add(o); + writers.put(o, new CustomObjectWriter(index++)); + } + + public Writer getObjectWriter(Object o) throws IOException { + return writers.get(o); + } + + public Object readObject(Unmarshaller unmarshaller) throws IOException, ClassNotFoundException { + return objects.get(unmarshaller.readUnsignedByte()); + } + + @Immutable + static class CustomObjectWriter implements Writer { + private final byte id; + + CustomObjectWriter(byte objectId) { + this.id = objectId; + } + + public void writeObject(Marshaller marshaller, Object object) throws IOException { + marshaller.write(id); + } + } +} Index: src/main/java/org/infinispan/marshall/VersionAwareMarshaller.java =================================================================== --- src/main/java/org/infinispan/marshall/VersionAwareMarshaller.java (revision 97) +++ src/main/java/org/infinispan/marshall/VersionAwareMarshaller.java (working copy) @@ -27,6 +27,7 @@ import org.infinispan.io.ExposedByteArrayOutputStream; import org.infinispan.logging.Log; import org.infinispan.logging.LogFactory; +import org.infinispan.util.Util; import org.jboss.util.stream.MarshalledValueInputStream; import java.io.ByteArrayInputStream; @@ -36,6 +37,7 @@ import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; +import java.io.OutputStream; /** * A delegate to various other marshallers like {@link HorizonMarshaller}. This delegating marshaller adds versioning @@ -109,12 +111,28 @@ } return defaultMarshaller.objectFromObjectStream(in); } + + public ObjectOutput startObjectOutput(OutputStream os) throws IOException { + return defaultMarshaller.startObjectOutput(os); + } + + public void finishObjectOutput(ObjectOutput oo) { + defaultMarshaller.finishObjectOutput(oo); + } public void objectToObjectStream(Object obj, ObjectOutput out) throws IOException { out.writeShort(VERSION_400); log.trace("Wrote version {0}", VERSION_400); defaultMarshaller.objectToObjectStream(obj, out); } + + public ObjectInput startObjectInput(InputStream is) throws IOException { + return defaultMarshaller.startObjectInput(is); + } + + public void finishObjectInput(ObjectInput oi) { + defaultMarshaller.finishObjectInput(oi); + } public Object objectFromObjectStream(ObjectInput in) throws IOException, ClassNotFoundException { int versionId; Index: src/test/java/org/infinispan/marshall/ObjectStreamMarshaller.java =================================================================== --- src/test/java/org/infinispan/marshall/ObjectStreamMarshaller.java (revision 97) +++ src/test/java/org/infinispan/marshall/ObjectStreamMarshaller.java (working copy) @@ -1,6 +1,7 @@ package org.infinispan.marshall; import org.infinispan.io.ByteBuffer; +import org.infinispan.util.Util; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -10,6 +11,7 @@ import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; +import java.io.OutputStream; import java.io.Serializable; /** @@ -18,6 +20,15 @@ * @author Manik Surtani */ public class ObjectStreamMarshaller implements Marshaller, Serializable { + + public ObjectOutput startObjectOutput(OutputStream os) throws IOException { + return new ObjectOutputStream(os); + } + + public void finishObjectOutput(ObjectOutput oo) { + Util.flushAndCloseOutput(oo); + } + public void objectToObjectStream(Object obj, ObjectOutput out) throws IOException { out.writeObject(obj); } @@ -26,6 +37,14 @@ return in.readObject(); } + public ObjectInput startObjectInput(InputStream is) throws IOException { + return new ObjectInputStream(is); + } + + public void finishObjectInput(ObjectInput oi) { + Util.closeInput(oi); + } + public Object objectFromStream(InputStream is) throws IOException, ClassNotFoundException { if (is instanceof ObjectInputStream) return objectFromObjectStream((ObjectInputStream) is); @@ -57,5 +76,4 @@ public Object objectFromByteBuffer(byte[] buf) throws IOException, ClassNotFoundException { return objectFromObjectStream(new ObjectInputStream(new ByteArrayInputStream(buf))); } - } Index: src/main/java/org/infinispan/marshall/jboss/ExternalizerClassFactory.java =================================================================== --- src/main/java/org/infinispan/marshall/jboss/ExternalizerClassFactory.java (revision 0) +++ src/main/java/org/infinispan/marshall/jboss/ExternalizerClassFactory.java (revision 0) @@ -0,0 +1,119 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2009, 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.infinispan.marshall.jboss; + +import java.io.IOException; +import java.util.Map; +import java.util.WeakHashMap; + +import net.jcip.annotations.Immutable; + +import org.infinispan.CacheException; +import org.infinispan.remoting.RpcManager; +import org.infinispan.util.Util; +import org.jboss.marshalling.ClassExternalizerFactory; +import org.jboss.marshalling.Externalizer; + +/** + * CustomExternalizerFactory. + * + * @author Galder Zamarreno + * @since 4.0 + */ +@Immutable +public class ExternalizerClassFactory implements ClassExternalizerFactory { + private static final Map EXTERNALIZERS = new WeakHashMap(); + + static { + EXTERNALIZERS.put("org.infinispan.transaction.GlobalTransaction", "org.infinispan.marshall.jboss.GlobalTransactionExternalizer"); + EXTERNALIZERS.put("org.infinispan.remoting.transport.jgroups.JGroupsAddress", "org.infinispan.marshall.jboss.JGroupsAddressExternalizer"); + EXTERNALIZERS.put("java.util.ArrayList", "org.infinispan.marshall.jboss.ArrayListExternalizer"); + EXTERNALIZERS.put("java.util.LinkedList", "org.infinispan.marshall.jboss.LinkedListExternalizer"); + EXTERNALIZERS.put("java.util.HashMap", "org.infinispan.marshall.jboss.MapExternalizer"); + EXTERNALIZERS.put("java.util.TreeMap", "org.infinispan.marshall.jboss.MapExternalizer"); + EXTERNALIZERS.put("java.util.HashSet", "org.infinispan.marshall.jboss.SetExternalizer"); + EXTERNALIZERS.put("java.util.TreeSet", "org.infinispan.marshall.jboss.SetExternalizer"); + EXTERNALIZERS.put("org.infinispan.util.Immutables$ImmutableMapWrapper", "org.infinispan.marshall.jboss.ImmutableMapExternalizer"); + EXTERNALIZERS.put("org.infinispan.marshall.MarshalledValue", "org.infinispan.marshall.jboss.MarshalledValueExternalizer"); + EXTERNALIZERS.put("org.infinispan.util.FastCopyHashMap", "org.infinispan.marshall.jboss.MapExternalizer"); + EXTERNALIZERS.put("java.util.Collections$SingletonList", "org.infinispan.marshall.jboss.SingletonListExternalizer"); + EXTERNALIZERS.put("org.infinispan.transaction.TransactionLog$LogEntry", "org.infinispan.marshall.jboss.TransactionLogExternalizer"); + EXTERNALIZERS.put("org.infinispan.remoting.transport.jgroups.ExtendedResponse", "org.infinispan.marshall.jboss.ExtendedResponseExternalizer"); + EXTERNALIZERS.put("org.infinispan.atomic.AtomicHashMap", "org.infinispan.marshall.jboss.DeltaAwareExternalizer"); + + EXTERNALIZERS.put("org.infinispan.commands.control.StateTransferControlCommand", "org.infinispan.marshall.jboss.StateTransferControlCommandExternalizer"); + EXTERNALIZERS.put("org.infinispan.commands.remote.ClusteredGetCommand", "org.infinispan.marshall.jboss.ReplicableCommandExternalizer"); + EXTERNALIZERS.put("org.infinispan.commands.remote.ReplicateCommand", "org.infinispan.marshall.jboss.ReplicableCommandExternalizer"); + EXTERNALIZERS.put("org.infinispan.commands.read.GetKeyValueCommand", "org.infinispan.marshall.jboss.ReplicableCommandExternalizer"); + EXTERNALIZERS.put("org.infinispan.commands.write.PutKeyValueCommand", "org.infinispan.marshall.jboss.ReplicableCommandExternalizer"); + EXTERNALIZERS.put("org.infinispan.commands.write.RemoveCommand", "org.infinispan.marshall.jboss.ReplicableCommandExternalizer"); + EXTERNALIZERS.put("org.infinispan.commands.write.InvalidateCommand", "org.infinispan.marshall.jboss.ReplicableCommandExternalizer"); + EXTERNALIZERS.put("org.infinispan.commands.write.ReplaceCommand", "org.infinispan.marshall.jboss.ReplicableCommandExternalizer"); + EXTERNALIZERS.put("org.infinispan.commands.write.ClearCommand", "org.infinispan.marshall.jboss.ReplicableCommandExternalizer"); + EXTERNALIZERS.put("org.infinispan.commands.write.PutMapCommand", "org.infinispan.marshall.jboss.ReplicableCommandExternalizer"); + EXTERNALIZERS.put("org.infinispan.commands.tx.PrepareCommand", "org.infinispan.marshall.jboss.ReplicableCommandExternalizer"); + EXTERNALIZERS.put("org.infinispan.commands.tx.CommitCommand", "org.infinispan.marshall.jboss.ReplicableCommandExternalizer"); + EXTERNALIZERS.put("org.infinispan.commands.tx.RollbackCommand", "org.infinispan.marshall.jboss.ReplicableCommandExternalizer"); + + EXTERNALIZERS.put("org.infinispan.container.entries.ImmortalCacheEntry", "org.infinispan.marshall.jboss.InternalCachedEntryExternalizer"); + EXTERNALIZERS.put("org.infinispan.container.entries.MortalCacheEntry", "org.infinispan.marshall.jboss.InternalCachedEntryExternalizer"); + EXTERNALIZERS.put("org.infinispan.container.entries.TransientCacheEntry", "org.infinispan.marshall.jboss.InternalCachedEntryExternalizer"); + EXTERNALIZERS.put("org.infinispan.container.entries.TransientMortalCacheEntry", "org.infinispan.marshall.jboss.InternalCachedEntryExternalizer"); + } + + private final Map, Externalizer> externalizers = new WeakHashMap, Externalizer>(); + private final RpcManager rpcManager; + private final CustomObjectTable objectTable; + + public ExternalizerClassFactory(RpcManager rpcManager, CustomObjectTable objectTable) { + this.rpcManager = rpcManager; + this.objectTable = objectTable; + } + + public void init() { + try { + for (Map.Entry entry : EXTERNALIZERS.entrySet()) { + Class typeClazz = Util.loadClass(entry.getKey()); + Externalizer ext = (Externalizer) Util.getInstance(entry.getValue()); + if (ext instanceof StateTransferControlCommandExternalizer) { + ((StateTransferControlCommandExternalizer) ext).init(rpcManager); + } + externalizers.put(typeClazz, ext); + objectTable.add(ext); + } + } catch (IOException e) { + throw new CacheException("Unable to open load magicnumbers.properties", e); + } catch (ClassNotFoundException e) { + throw new CacheException("Unable to load one of the classes defined in the magicnumbers.properties", e); + } catch (Exception e) { + throw new CacheException("Unable to instantiate Externalizer class", e); + } + } + + public void stop() { + externalizers.clear(); + } + + public Externalizer getExternalizer(Class clazz) { + return externalizers.get(clazz); + } +} Index: src/main/java/org/infinispan/util/Util.java =================================================================== --- src/main/java/org/infinispan/util/Util.java (revision 97) +++ src/main/java/org/infinispan/util/Util.java (working copy) @@ -22,6 +22,8 @@ package org.infinispan.util; import java.io.InputStream; +import java.io.ObjectInput; +import java.io.ObjectOutput; import java.io.OutputStream; import java.lang.reflect.Method; import java.text.NumberFormat; @@ -165,6 +167,15 @@ } } + public static void closeInput(ObjectInput i) { + if (i == null) return; + try { + i.close(); + } catch (Exception e) { + + } + } + public static void flushAndCloseStream(OutputStream o) { if (o == null) return; try { @@ -179,4 +190,20 @@ } } + + public static void flushAndCloseOutput(ObjectOutput o) { + if (o == null) return; + try { + o.flush(); + } catch (Exception e) { + + } + + try { + o.close(); + } catch (Exception e) { + + } + } + } Index: src/main/java/org/infinispan/marshall/jboss/JBossMarshaller.java =================================================================== --- src/main/java/org/infinispan/marshall/jboss/JBossMarshaller.java (revision 0) +++ src/main/java/org/infinispan/marshall/jboss/JBossMarshaller.java (revision 0) @@ -0,0 +1,206 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2009, 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.infinispan.marshall.jboss; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.OutputStream; + +import org.infinispan.CacheException; +import org.infinispan.factories.annotations.Inject; +import org.infinispan.factories.annotations.Stop; +import org.infinispan.factories.scopes.Scope; +import org.infinispan.factories.scopes.Scopes; +import org.infinispan.io.ByteBuffer; +import org.infinispan.io.ExposedByteArrayOutputStream; +import org.infinispan.logging.Log; +import org.infinispan.logging.LogFactory; +import org.infinispan.marshall.Marshaller; +import org.infinispan.remoting.RpcManager; +import org.infinispan.util.Util; +import org.jboss.marshalling.ContextClassResolver; +import org.jboss.marshalling.MarshallerFactory; +import org.jboss.marshalling.Marshalling; +import org.jboss.marshalling.MarshallingConfiguration; +import org.jboss.marshalling.Unmarshaller; +import org.jboss.marshalling.reflect.SunReflectiveCreator; + +/** + * JBossMarshaller. + * + * @author Galder Zamarreno + * @since 4.0 + */ +@Scope(Scopes.GLOBAL) +public class JBossMarshaller implements Marshaller { + private static final Log log = LogFactory.getLog(JBossMarshaller.class); + private static final String DEFAULT_MARSHALLER_FACTORY = "org.jboss.marshalling.river.RiverMarshallerFactory"; +// private static final int VERSION_400 = 400; +// private static final int DEFAULT_VERSION = VERSION_400; + private ClassLoader defaultClassLoader; + private MarshallingConfiguration configuration; + private MarshallerFactory factory; + private MagicNumberClassTable classTable; + private CustomObjectTable objectTable; + private ExternalizerClassFactory externalizerFactoryAndObjectTable; +/// private boolean trace; + + @Inject + public void init(ClassLoader defaultCl, RpcManager rpcManager) { + log.debug("Using JBoss Marshalling based marshaller."); + +// trace = log.isTraceEnabled(); + defaultClassLoader = defaultCl; + + try { + // Todo: Enable different marshaller factories via configuration + factory = (MarshallerFactory)Util.getInstance(DEFAULT_MARSHALLER_FACTORY); + } catch(Exception e) { + throw new CacheException("Unable to load JBoss Marshalling marshaller factory " + DEFAULT_MARSHALLER_FACTORY, e); + } + + classTable = createMagicNumberClassTable(); + objectTable = createCustomObjectTable(); + externalizerFactoryAndObjectTable = createCustomExternalizerFactory(rpcManager, objectTable); + + configuration = new MarshallingConfiguration(); + configuration.setCreator(new SunReflectiveCreator()); + configuration.setClassTable(classTable); + configuration.setClassExternalizerFactory(externalizerFactoryAndObjectTable); + configuration.setObjectTable(objectTable); + + // ContextClassResolver provides same functionality as MarshalledValueInputStream + configuration.setClassResolver(new ContextClassResolver()); +// // Todo: This is the JBMAR underlying protocol version, don't touch! Think about how to get VAM into JBMAR +// configuration.setVersion(DEFAULT_VERSION); + } + + @Stop + public void stop() { + // Do not leak classloader when cache is stopped. + defaultClassLoader = null; + classTable.stop(); + objectTable.stop(); + externalizerFactoryAndObjectTable.stop(); + } + + public byte[] objectToByteBuffer(Object obj) throws IOException { + ByteBuffer b = objectToBuffer(obj); + byte[] bytes = new byte[b.getLength()]; + System.arraycopy(b.getBuf(), b.getOffset(), bytes, 0, b.getLength()); + return bytes; + } + + public ByteBuffer objectToBuffer(Object o) throws IOException { + ExposedByteArrayOutputStream baos = new ExposedByteArrayOutputStream(128); + ObjectOutput marshaller = startObjectOutput(baos); + objectToObjectStream(o, marshaller); + finishObjectOutput(marshaller); + return new ByteBuffer(baos.getRawBuffer(), 0, baos.size()); + } + + public ObjectOutput startObjectOutput(OutputStream os) throws IOException { + org.jboss.marshalling.Marshaller marshaller = factory.createMarshaller(configuration); + marshaller.start(Marshalling.createByteOutput(os)); + return marshaller; + } + + public void finishObjectOutput(ObjectOutput oo) { + try { + ((org.jboss.marshalling.Marshaller) oo).finish(); + } catch (IOException ioe) { + } + } + + public void objectToObjectStream(Object obj, ObjectOutput out) throws IOException { + ClassLoader toUse = defaultClassLoader; + Thread current = Thread.currentThread(); + ClassLoader old = current.getContextClassLoader(); + if (old != null) toUse = old; + + try { + current.setContextClassLoader(toUse); + out.writeObject(obj); + } + finally { + current.setContextClassLoader(old); + } + } + + public Object objectFromByteBuffer(byte[] buf) throws IOException, ClassNotFoundException { + return objectFromByteBuffer(buf, 0, buf.length); + } + + public Object objectFromByteBuffer(byte[] buf, int offset, int length) throws IOException, + ClassNotFoundException { + ByteArrayInputStream is = new ByteArrayInputStream(buf, offset, length); + ObjectInput unmarshaller = startObjectInput(is); + Object o = objectFromObjectStream(unmarshaller); + finishObjectInput(unmarshaller); + return o; + } + + public ObjectInput startObjectInput(InputStream is) throws IOException { + Unmarshaller unmarshaller = factory.createUnmarshaller(configuration); + unmarshaller.start(Marshalling.createByteInput(is)); + return unmarshaller; + } + + public void finishObjectInput(ObjectInput oi) { + try { + ((Unmarshaller) oi).finish(); + } catch (IOException e) { + } + } + + public Object objectFromObjectStream(ObjectInput in) throws IOException, ClassNotFoundException { + return in.readObject(); + } + + public Object objectFromStream(InputStream is) throws IOException, ClassNotFoundException { + ObjectInput unmarshaller = startObjectInput(is); + Object o = objectFromObjectStream(unmarshaller); + finishObjectInput(unmarshaller); + return o; + } + + protected MagicNumberClassTable createMagicNumberClassTable() { + MagicNumberClassTable classTable = new MagicNumberClassTable(); + classTable.init(); + return classTable; + } + + protected ExternalizerClassFactory createCustomExternalizerFactory(RpcManager rpcManager, CustomObjectTable objectTable) { + ExternalizerClassFactory externalizerFactory = new ExternalizerClassFactory(rpcManager, objectTable); + externalizerFactory.init(); + return externalizerFactory; + } + + private CustomObjectTable createCustomObjectTable() { + CustomObjectTable objectTable = new CustomObjectTable(); + objectTable.init(); + return objectTable; + } +} Index: src/test/java/org/infinispan/test/testng/SuiteResourcesAndLogTest.java =================================================================== --- src/test/java/org/infinispan/test/testng/SuiteResourcesAndLogTest.java (revision 97) +++ src/test/java/org/infinispan/test/testng/SuiteResourcesAndLogTest.java (working copy) @@ -13,6 +13,7 @@ * This class makes sure that all files are being deleted after each test run. It also logs testsuite information. * * @author Mircea.Markus@jboss.com + * @author Galder Zamarreno */ @Test(groups = "functional", testName = "test.testng.SuiteResourcesAndLogTest") public class SuiteResourcesAndLogTest { @@ -53,6 +54,7 @@ log("sun.arch.data.model = " + System.getProperty("sun.arch.data.model")); log("sun.cpu.endian = " + System.getProperty("sun.cpu.endian")); log("jgroups.stack = " + System.getProperty("jgroups.stack")); + log("infinispan.marshaller.class = " + System.getProperty("infinispan.marshaller.class")); log("~~~~~~~~~~~~~~~~~~~~~~~~~ ENVIRONMENT INFO ~~~~~~~~~~~~~~~~~~~~~~~~~~"); } Index: src/main/java/org/infinispan/marshall/jboss/ImmutableMapExternalizer.java =================================================================== --- src/main/java/org/infinispan/marshall/jboss/ImmutableMapExternalizer.java (revision 0) +++ src/main/java/org/infinispan/marshall/jboss/ImmutableMapExternalizer.java (revision 0) @@ -0,0 +1,63 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2009, 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.infinispan.marshall.jboss; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.HashMap; +import java.util.Map; + +import net.jcip.annotations.Immutable; + +import org.infinispan.util.Immutables; +import org.jboss.marshalling.Creator; +import org.jboss.marshalling.Externalizer; + +/** + * ImmutableExternalizer. + * + * @author Galder Zamarreno + * @since 4.0 + */ +@Immutable +public class ImmutableMapExternalizer implements Externalizer { + + /** The serialVersionUID */ + private static final long serialVersionUID = -3592193723750924806L; + + public void writeExternal(Object subject, ObjectOutput output) throws IOException { + MarshallUtil.marshallMap((Map)subject, output); + } + + public Object createExternal(Class subjectType, ObjectInput input, Creator defaultCreator) + throws IOException, ClassNotFoundException { + Map map = new HashMap(); + MarshallUtil.unmarshallMap(map, input); + return Immutables.immutableMapWrap(map); + } + + public void readExternal(Object subject, ObjectInput input) throws IOException, + ClassNotFoundException { + // No-op since all the work is done in createExternal in order to be able to change identity. + } +} Index: src/main/java/org/infinispan/marshall/jboss/JGroupsAddressExternalizer.java =================================================================== --- src/main/java/org/infinispan/marshall/jboss/JGroupsAddressExternalizer.java (revision 0) +++ src/main/java/org/infinispan/marshall/jboss/JGroupsAddressExternalizer.java (revision 0) @@ -0,0 +1,61 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2009, 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.infinispan.marshall.jboss; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; + +import net.jcip.annotations.Immutable; + +import org.infinispan.remoting.transport.jgroups.JGroupsAddress; +import org.jboss.marshalling.Creator; +import org.jboss.marshalling.Externalizer; + +/** + * JGroupsAddressExternalizer. + * + * @author Galder Zamarreno + * @since 4.0 + */ +@Immutable +public class JGroupsAddressExternalizer implements Externalizer { + + /** The serialVersionUID */ + private static final long serialVersionUID = 2400716389425727329L; + + public void writeExternal(Object subject, ObjectOutput output) throws IOException { + JGroupsAddress address = (JGroupsAddress) subject; + address.writeExternal(output); + } + + public Object createExternal(Class subjectType, ObjectInput input, Creator defaultCreator) + throws IOException, ClassNotFoundException { + return new JGroupsAddress(); + } + + public void readExternal(Object subject, ObjectInput input) throws IOException, + ClassNotFoundException { + JGroupsAddress address = (JGroupsAddress) subject; + address.readExternal(input); + } +} Index: src/main/java/org/infinispan/marshall/jboss/StateTransferControlCommandExternalizer.java =================================================================== --- src/main/java/org/infinispan/marshall/jboss/StateTransferControlCommandExternalizer.java (revision 0) +++ src/main/java/org/infinispan/marshall/jboss/StateTransferControlCommandExternalizer.java (revision 0) @@ -0,0 +1,61 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2009, 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.infinispan.marshall.jboss; + +import java.io.IOException; +import java.io.ObjectInput; + +import org.infinispan.commands.control.StateTransferControlCommand; +import org.infinispan.remoting.RpcManager; +import org.jboss.marshalling.Creator; + +/** + * StateTransferControlCommandExternalizer. + * + * @author Galder Zamarreno + * @since 4.0 + */ +public class StateTransferControlCommandExternalizer extends ReplicableCommandExternalizer { + + /** The serialVersionUID */ + private static final long serialVersionUID = -3743458410265076691L; + + private RpcManager rpcManager; + + public void init(RpcManager rpcManager) { + this.rpcManager = rpcManager; + } + + /** + * In this case, subjectType will contain the class name of the ReplicableCommand subclass to + * create. + * + * Note that StateTransferControlCommand might need to be treated differently!!! + * Todo: check outcome of email sent to dev list. + */ + public Object createExternal(Class subjectType, ObjectInput input, Creator defaultCreator) + throws IOException, ClassNotFoundException { + StateTransferControlCommand command = new StateTransferControlCommand(); + command.init(rpcManager); + return command; + } +} \ No newline at end of file Index: src/main/java/org/infinispan/marshall/jboss/ExtendedResponseExternalizer.java =================================================================== --- src/main/java/org/infinispan/marshall/jboss/ExtendedResponseExternalizer.java (revision 0) +++ src/main/java/org/infinispan/marshall/jboss/ExtendedResponseExternalizer.java (revision 0) @@ -0,0 +1,62 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2009, 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.infinispan.marshall.jboss; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; + +import net.jcip.annotations.Immutable; + +import org.infinispan.remoting.transport.jgroups.ExtendedResponse; +import org.jboss.marshalling.Creator; +import org.jboss.marshalling.Externalizer; + +/** + * ExtendedResponseExternalizer. + * + * @author Galder Zamarreno + * @since 4.0 + */ +@Immutable +public class ExtendedResponseExternalizer implements Externalizer { + /** The serialVersionUID */ + private static final long serialVersionUID = 1529506931234856884L; + + public void writeExternal(Object subject, ObjectOutput output) throws IOException { + ExtendedResponse er = (ExtendedResponse) subject; + output.writeBoolean(er.isReplayIgnoredRequests()); + output.writeObject(er.getResponse()); + } + + public Object createExternal(Class subjectType, ObjectInput input, Creator defaultCreator) + throws IOException, ClassNotFoundException { + boolean replayIgnoredRequests = input.readBoolean(); + Object response = input.readObject(); + return new ExtendedResponse(response, replayIgnoredRequests); + } + + public void readExternal(Object subject, ObjectInput input) throws IOException, + ClassNotFoundException { + // No-op + } +} Index: src/main/java/org/infinispan/marshall/jboss/MapExternalizer.java =================================================================== --- src/main/java/org/infinispan/marshall/jboss/MapExternalizer.java (revision 0) +++ src/main/java/org/infinispan/marshall/jboss/MapExternalizer.java (revision 0) @@ -0,0 +1,66 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2009, 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.infinispan.marshall.jboss; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Map; + +import net.jcip.annotations.Immutable; + +import org.infinispan.CacheException; +import org.infinispan.util.Util; +import org.jboss.marshalling.Creator; +import org.jboss.marshalling.Externalizer; + +/** + * Map externalizer for all map implementations except immutable maps and singleton maps, + * i.e. FastCopyHashMap, HashMap, TreeMap. + * + * @author Galder Zamarreno + * @since 4.0 + */ +@Immutable +public class MapExternalizer implements Externalizer { + + /** The serialVersionUID */ + private static final long serialVersionUID = -532896252671303391L; + + public void writeExternal(Object subject, ObjectOutput output) throws IOException { + MarshallUtil.marshallMap((Map) subject, output); + } + + public Object createExternal(Class subjectType, ObjectInput input, Creator defaultCreator) + throws IOException, ClassNotFoundException { + try { + return Util.getInstance(subjectType); + } catch(Exception e) { + throw new CacheException("Unable to create new instance of ReplicableCommand", e); + } + } + + public void readExternal(Object subject, ObjectInput input) throws IOException, + ClassNotFoundException { + MarshallUtil.unmarshallMap((Map) subject, input); + } +} Index: src/main/java/org/infinispan/marshall/jboss/ReplicableCommandExternalizer.java =================================================================== --- src/main/java/org/infinispan/marshall/jboss/ReplicableCommandExternalizer.java (revision 0) +++ src/main/java/org/infinispan/marshall/jboss/ReplicableCommandExternalizer.java (revision 0) @@ -0,0 +1,85 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2009, 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.infinispan.marshall.jboss; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; + +import net.jcip.annotations.Immutable; + +import org.infinispan.CacheException; +import org.infinispan.commands.ReplicableCommand; +import org.infinispan.util.Util; +import org.jboss.marshalling.Creator; +import org.jboss.marshalling.Externalizer; + +/** + * ReplicableCommandExternalizer. + * + * @author Galder Zamarreno + * @since 4.0 + */ +@Immutable +public class ReplicableCommandExternalizer implements Externalizer { + + /** The serialVersionUID */ + private static final long serialVersionUID = 6915200269446867084L; + + public void writeExternal(Object subject, ObjectOutput output) throws IOException { + ReplicableCommand command = (ReplicableCommand) subject; + output.writeShort(command.getCommandId()); + Object[] args = command.getParameters(); + byte numArgs = (byte) (args == null ? 0 : args.length); + output.writeByte(numArgs); + for (int i = 0; i < numArgs; i++) { + output.writeObject(args[i]); + } + } + + /** + * In this case, subjectType will contain the class name of the ReplicableCommand subclass to + * create. Note that StateTransferControlCommand might need to be treated differently!!! + */ + public Object createExternal(Class subjectType, ObjectInput input, Creator defaultCreator) + throws IOException, ClassNotFoundException { + try { + ReplicableCommand command = (ReplicableCommand) Util.getInstance(subjectType); + return command; + } catch(Exception e) { + throw new CacheException("Unable to create new instance of ReplicableCommand", e); + } + } + + public void readExternal(Object subject, ObjectInput input) throws IOException, + ClassNotFoundException { + ReplicableCommand command = (ReplicableCommand) subject; + short methodId = input.readShort(); + byte numArgs = input.readByte(); + Object[] args = null; + if (numArgs > 0) { + args = new Object[numArgs]; + for (int i = 0; i < numArgs; i++) args[i] = input.readObject(); + } + command.setParameters(methodId, args); + } +} \ No newline at end of file Index: src/main/java/org/infinispan/marshall/Marshaller.java =================================================================== --- src/main/java/org/infinispan/marshall/Marshaller.java (revision 97) +++ src/main/java/org/infinispan/marshall/Marshaller.java (working copy) @@ -29,6 +29,7 @@ import java.io.InputStream; import java.io.ObjectInput; import java.io.ObjectOutput; +import java.io.OutputStream; /** * A marshaller is a class that is able to marshall and unmarshall objects efficiently. @@ -56,6 +57,27 @@ */ @Scope(Scopes.GLOBAL) public interface Marshaller { + + /** + * Create and open a new ObjectOutput for the given output stream. This + * method should be used for opening data outpus when multiple + * objectToObjectStream() calls will be made before the stream is closed + * + * @param os output stream + * @return ObjectOutput to write to + * @throws IOException + */ + ObjectOutput startObjectOutput(OutputStream os) throws IOException; + + /** + * Finish using the given ObjectOutput. After multiple opening a ObjectOutput + * and calling objectToObjectStream() mutliple times, use this method to + * flush the data and close if necessary + * + * @param oo data output that finished using + */ + void finishObjectOutput(ObjectOutput oo); + /** * Marshalls an object to a given {@link java.io.ObjectOutput} * @@ -65,6 +87,26 @@ void objectToObjectStream(Object obj, ObjectOutput out) throws IOException; /** + * Create and open a new ObjectInput for the given input stream. This + * method should be used for opening data inputs when multiple + * objectFromObjectStream() calls will be made before the stream is closed. + * + * @param is input stream + * @return ObjectInput to read from + * @throws IOException + */ + ObjectInput startObjectInput(InputStream is) throws IOException; + + /** + * Finish using the given ObjectInput. After multiple opening a ObjectInput + * and calling objectFromObjectStream() mutliple times, use this method to + * flush the data and close if necessary + * + * @param oi data input that finished using + */ + void finishObjectInput(ObjectInput oi); + + /** * Unmarshalls an object from an {@link java.io.ObjectInput} * * @param in stream to unmarshall from Index: src/test/java/org/infinispan/test/fwk/TestCacheManagerFactory.java =================================================================== --- src/test/java/org/infinispan/test/fwk/TestCacheManagerFactory.java (revision 97) +++ src/test/java/org/infinispan/test/fwk/TestCacheManagerFactory.java (working copy) @@ -5,6 +5,7 @@ import org.infinispan.manager.CacheManager; import org.infinispan.manager.DefaultCacheManager; import org.infinispan.remoting.transport.jgroups.JGroupsTransport; +import org.infinispan.util.Util; import java.util.Properties; @@ -12,14 +13,18 @@ * CacheManagers in unit tests should be created with this factory, in order to avoit resource clashes. * * @author Mircea.Markus@jboss.com + * @author Galder Zamarreno */ public class TestCacheManagerFactory { + + public static final String MARSHALLER = System.getProperties().getProperty("infinispan.marshaller.class"); /** * Creates an cache manager that does not support clustering. */ public static CacheManager createLocalCacheManager() { GlobalConfiguration globalConfiguration = GlobalConfiguration.getNonClusteredDefault(); + amendMarshaller(globalConfiguration); // amendJmx(globalConfiguration); return new DefaultCacheManager(globalConfiguration); } @@ -29,6 +34,7 @@ */ public static CacheManager createClusteredCacheManager() { GlobalConfiguration globalConfiguration = GlobalConfiguration.getClusteredDefault(); + amendMarshaller(globalConfiguration); // amendJmx(globalConfiguration); Properties newTransportProps = new Properties(); newTransportProps.put(JGroupsTransport.CONFIGURATION_STRING, JGroupsConfigBuilder.getJGroupsConfig()); @@ -41,6 +47,7 @@ * during running tests in parallel. */ public static CacheManager createCacheManager(GlobalConfiguration configuration) { + amendMarshaller(configuration); amendTransport(configuration); // amendJmx(configuration); return new DefaultCacheManager(configuration); @@ -52,11 +59,13 @@ */ public static CacheManager createCacheManager(Configuration defaultCacheConfig) { GlobalConfiguration globalConfiguration = GlobalConfiguration.getNonClusteredDefault(); + amendMarshaller(globalConfiguration); // amendJmx(globalConfiguration); return new DefaultCacheManager(globalConfiguration, defaultCacheConfig); } public static DefaultCacheManager createCacheManager(GlobalConfiguration configuration, Configuration defaultCfg) { + amendMarshaller(configuration); amendTransport(configuration); // amendJmx(configuration); return new DefaultCacheManager(configuration, defaultCfg); @@ -74,4 +83,15 @@ configuration.setTransportProperties(newTransportProps); } } + + private static void amendMarshaller(GlobalConfiguration configuration) { + if (MARSHALLER != null) { + try { + Util.loadClass(MARSHALLER); + configuration.setMarshallerClass(MARSHALLER); + } catch (ClassNotFoundException e) { + // No-op, stick to GlobalConfiguration default. + } + } + } } Index: src/main/java/org/infinispan/marshall/jboss/MarshallUtil.java =================================================================== --- src/main/java/org/infinispan/marshall/jboss/MarshallUtil.java (revision 0) +++ src/main/java/org/infinispan/marshall/jboss/MarshallUtil.java (revision 0) @@ -0,0 +1,120 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2009, 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.infinispan.marshall.jboss; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +import net.jcip.annotations.Immutable; + +/** + * MarshallUtil. + * + * @author Galder Zamarreno + * @since 4.0 + */ +@Immutable +public class MarshallUtil { + + /** + * 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 static void writeUnsignedInt(ObjectOutput 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 five bytes. Smaller values take fewer + * bytes. Negative numbers are not supported. + */ + protected static int readUnsignedInt(ObjectInput 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; + } + + protected static void marshallCollection(Collection c, ObjectOutput out) throws IOException { + writeUnsignedInt(out, c.size()); + for (Object o : c) { + out.writeObject(o); + } + } + + protected static void marshallMap(Map map, ObjectOutput out) throws IOException { + int mapSize = map.size(); + writeUnsignedInt(out, mapSize); + if (mapSize == 0) return; + + for (Map.Entry me : (Set) map.entrySet()) { + out.writeObject(me.getKey()); + out.writeObject(me.getValue()); + } + } + + protected static void unmarshallMap(Map map, ObjectInput in) throws IOException, ClassNotFoundException{ + int size = MarshallUtil.readUnsignedInt(in); + for (int i = 0; i < size; i++) map.put(in.readObject(), in.readObject()); + } + + /** + * Writes a long 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 static void writeUnsignedLong(ObjectOutput out, long i) throws IOException { + while ((i & ~0x7F) != 0) { + out.writeByte((byte) ((i & 0x7f) | 0x80)); + i >>>= 7; + } + out.writeByte((byte) i); + } + + /** + * Reads a long stored in variable-length format. Reads between one and nine bytes. Smaller values take fewer + * bytes. Negative numbers are not supported. + */ + protected static long readUnsignedLong(ObjectInput 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; + } +} Index: src/main/java/org/infinispan/transaction/TransactionLog.java =================================================================== --- src/main/java/org/infinispan/transaction/TransactionLog.java (revision 97) +++ src/main/java/org/infinispan/transaction/TransactionLog.java (working copy) @@ -27,6 +27,7 @@ import org.infinispan.logging.LogFactory; import org.infinispan.marshall.Marshaller; +import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.List; @@ -128,7 +129,7 @@ return entries.size(); } - public void writeCommitLog(Marshaller marshaller, ObjectOutputStream out) throws Exception { + public void writeCommitLog(Marshaller marshaller, ObjectOutput out) throws Exception { List buffer = new ArrayList(10); while (entries.drainTo(buffer, 10) > 0) { @@ -139,7 +140,7 @@ } } - public void writePendingPrepares(Marshaller marshaller, ObjectOutputStream out) throws Exception { + public void writePendingPrepares(Marshaller marshaller, ObjectOutput out) throws Exception { if (log.isTraceEnabled()) log.trace("Writing {0} pending prepares to the stream", pendingPrepares.size()); for (PrepareCommand entry : pendingPrepares.values()) marshaller.objectToObjectStream(entry, out); } Index: src/main/java/org/infinispan/marshall/jboss/MarshalledValueExternalizer.java =================================================================== --- src/main/java/org/infinispan/marshall/jboss/MarshalledValueExternalizer.java (revision 0) +++ src/main/java/org/infinispan/marshall/jboss/MarshalledValueExternalizer.java (revision 0) @@ -0,0 +1,60 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2009, 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.infinispan.marshall.jboss; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; + +import net.jcip.annotations.Immutable; + +import org.infinispan.marshall.MarshalledValue; +import org.jboss.marshalling.Creator; +import org.jboss.marshalling.Externalizer; + +/** + * MarshalledValueExternalizer. + * + * @author Galder Zamarreno + * @since 4.0 + */ +@Immutable +public class MarshalledValueExternalizer implements Externalizer { + + /** The serialVersionUID */ + private static final long serialVersionUID = 8473423584918714661L; + + public void writeExternal(Object subject, ObjectOutput output) throws IOException { + ((MarshalledValue) subject).writeExternal(output); + } + + public Object createExternal(Class subjectType, ObjectInput input, Creator defaultCreator) + throws IOException, ClassNotFoundException { + return new MarshalledValue(); + } + + public void readExternal(Object subject, ObjectInput input) throws IOException, + ClassNotFoundException { + ((MarshalledValue) subject).readExternal(input); + } + +} Property changes on: . ___________________________________________________________________ Added: svn:ignore + target Index: src/main/java/org/infinispan/marshall/jboss/LinkedListExternalizer.java =================================================================== --- src/main/java/org/infinispan/marshall/jboss/LinkedListExternalizer.java (revision 0) +++ src/main/java/org/infinispan/marshall/jboss/LinkedListExternalizer.java (revision 0) @@ -0,0 +1,65 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2009, 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.infinispan.marshall.jboss; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Collection; +import java.util.LinkedList; + +import net.jcip.annotations.Immutable; + +import org.jboss.marshalling.Creator; +import org.jboss.marshalling.Externalizer; + +/** + * LinkedListExternalizer. + * + * @author Galder Zamarreno + * @since 4.0 + */ +@Immutable +public class LinkedListExternalizer implements Externalizer { + + /** The serialVersionUID */ + private static final long serialVersionUID = -3222803557498456230L; + + public void writeExternal(Object subject, ObjectOutput output) throws IOException { + MarshallUtil.marshallCollection((Collection) subject, output); + } + + public Object createExternal(Class subjectType, ObjectInput input, Creator defaultCreator) + throws IOException, ClassNotFoundException { + int size = MarshallUtil.readUnsignedInt(input); + LinkedList l = new LinkedList(); + for (int i = 0; i < size; i++) l.add(input.readObject()); + return l; + } + + public void readExternal(Object subject, ObjectInput input) throws IOException, + ClassNotFoundException { + // No-op since size was needed both for the creation and list population, + // so work was done in createExternal + } + +} Index: pom.xml =================================================================== --- pom.xml (revision 97) +++ pom.xml (working copy) @@ -44,12 +44,26 @@ jboss-common-core 2.2.10.GA - + + + org.jboss.marshalling + marshalling-api + 1.1.1.GA + + log4j log4j 1.2.14 true + + + org.jboss.marshalling + river + 1.1.1.GA + test + + Index: src/main/java/org/infinispan/statetransfer/StateTransferManagerImpl.java =================================================================== --- src/main/java/org/infinispan/statetransfer/StateTransferManagerImpl.java (revision 97) +++ src/main/java/org/infinispan/statetransfer/StateTransferManagerImpl.java (working copy) @@ -52,7 +52,9 @@ import java.io.IOException; import java.io.InputStream; +import java.io.ObjectInput; import java.io.ObjectInputStream; +import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.util.Arrays; @@ -130,22 +132,22 @@ } public void generateState(OutputStream out) throws StateTransferException { - ObjectOutputStream oos = null; + ObjectOutput oo = null; boolean txLogActivated = false; try { boolean canProvideState = (transientState || persistentState) && (txLogActivated = transactionLog.activate()); if (log.isDebugEnabled()) log.debug("Generating state. Can provide? {0}", canProvideState); - oos = new ObjectOutputStream(out); - marshaller.objectToObjectStream(canProvideState, oos); + oo = marshaller.startObjectOutput(out); + marshaller.objectToObjectStream(canProvideState, oo); if (canProvideState) { - delimit(oos); - if (transientState) generateInMemoryState(oos); - delimit(oos); - if (persistentState) generatePersistentState(oos); - delimit(oos); - generateTransactionLog(oos); + delimit(oo); + if (transientState) generateInMemoryState(oo); + delimit(oo); + if (persistentState) generatePersistentState(oo); + delimit(oo); + generateTransactionLog(oo); if (log.isDebugEnabled()) log.debug("State generated, closing object stream"); } else { @@ -157,12 +159,12 @@ } catch (Exception e) { throw new StateTransferException(e); } finally { - Util.flushAndCloseStream(oos); + marshaller.finishObjectOutput(oo); if (txLogActivated) transactionLog.deactivate(); } } - private void generateTransactionLog(ObjectOutputStream oos) throws Exception { + private void generateTransactionLog(ObjectOutput oo) throws Exception { // todo this should be configurable int maxNonProgressingLogWrites = 100; int flushTimeout = 60000; @@ -173,7 +175,7 @@ if (trace) log.trace("Transaction log size is {0}", transactionLog.size()); for (int nonProgress = 0, size = transactionLog.size(); size > 0;) { if (trace) log.trace("Tx Log remaining entries = " + size); - transactionLog.writeCommitLog(marshaller, oos); + transactionLog.writeCommitLog(marshaller, oo); int newSize = transactionLog.size(); // If size did not decrease then we did not make progress, and could be wasting @@ -190,29 +192,29 @@ // Signal to sender that we need a flush to get a consistent view // of the remaining transactions. - delimit(oos); - oos.flush(); + delimit(oo); + oo.flush(); if (trace) log.trace("Waiting for a distributed sync block"); distributedSync.blockUntilAcquired(flushTimeout, MILLISECONDS); if (trace) log.trace("Distributed sync block received, proceeding with writing commit log"); // Write remaining transactions - transactionLog.writeCommitLog(marshaller, oos); - delimit(oos); + transactionLog.writeCommitLog(marshaller, oo); + delimit(oo); // Write all non-completed prepares - transactionLog.writePendingPrepares(marshaller, oos); - delimit(oos); - oos.flush(); + transactionLog.writePendingPrepares(marshaller, oo); + delimit(oo); + oo.flush(); } finally { distributedSync.releaseProcessingLock(); } } - private void processCommitLog(ObjectInputStream ois) throws Exception { + private void processCommitLog(ObjectInput oi) throws Exception { if (trace) log.trace("Applying commit log"); - Object object = marshaller.objectFromObjectStream(ois); + Object object = marshaller.objectFromObjectStream(oi); while (object instanceof TransactionLog.LogEntry) { WriteCommand[] mods = ((TransactionLog.LogEntry) object).getModifications(); if (trace) log.trace("Mods = {0}", Arrays.toString(mods)); @@ -224,17 +226,17 @@ interceptorChain.invoke(ctx, mod); } - object = marshaller.objectFromObjectStream(ois); + object = marshaller.objectFromObjectStream(oi); } assertDelimited(object); if (trace) log.trace("Finished applying commit log"); } - private void applyTransactionLog(ObjectInputStream ois) throws Exception { + private void applyTransactionLog(ObjectInput oi) throws Exception { if (trace) log.trace("Integrating transaction log"); - processCommitLog(ois); + processCommitLog(oi); stateSender = rpcManager.getCurrentStateTransferSource(); mimicPartialFlushViaRPC(stateSender, true); needToUnblockRPC = true; @@ -242,11 +244,11 @@ try { if (trace) log.trace("Retrieving/Applying post-flush commits"); - processCommitLog(ois); + processCommitLog(oi); if (trace) log.trace("Retrieving/Applying pending prepares"); - Object object = marshaller.objectFromObjectStream(ois); + Object object = marshaller.objectFromObjectStream(oi); while (object instanceof PrepareCommand) { PrepareCommand command = (PrepareCommand) object; @@ -260,7 +262,7 @@ } else { if (trace) log.trace("Prepare {0} not in tx log; not applying", command); } - object = marshaller.objectFromObjectStream(ois); + object = marshaller.objectFromObjectStream(oi); } assertDelimited(object); } catch (Exception e) { @@ -288,17 +290,17 @@ public void applyState(InputStream in) throws StateTransferException { if (log.isDebugEnabled()) log.debug("Applying state"); - ObjectInputStream ois = null; + ObjectInput oi = null; try { - ois = new ObjectInputStream(in); - boolean canProvideState = (Boolean) marshaller.objectFromObjectStream(ois); + oi = marshaller.startObjectInput(in); + boolean canProvideState = (Boolean) marshaller.objectFromObjectStream(oi); if (canProvideState) { - assertDelimited(ois); - if (transientState) applyInMemoryState(ois); - assertDelimited(ois); - if (persistentState) applyPersistentState(ois); - assertDelimited(ois); - applyTransactionLog(ois); + assertDelimited(oi); + if (transientState) applyInMemoryState(oi); + assertDelimited(oi); + if (persistentState) applyPersistentState(oi); + assertDelimited(oi); + applyTransactionLog(oi); if (log.isDebugEnabled()) log.debug("State applied, closing object stream"); } else { String msg = "Provider cannot provide state!"; @@ -311,11 +313,11 @@ throw new StateTransferException(e); } finally { // just close the object stream but do NOT close the underlying stream - Util.closeStream(ois); + marshaller.finishObjectInput(oi); } } - private void applyInMemoryState(ObjectInputStream i) throws StateTransferException { + private void applyInMemoryState(ObjectInput i) throws StateTransferException { dataContainer.clear(); try { Set set = (Set) marshaller.objectFromObjectStream(i); @@ -327,7 +329,7 @@ } } - private void generateInMemoryState(ObjectOutputStream o) throws StateTransferException { + private void generateInMemoryState(ObjectOutput oo) throws StateTransferException { // write all StoredEntries to the stream using the marshaller. // TODO is it safe enough to get these from the data container directly? try { @@ -336,13 +338,13 @@ if (!e.isExpired()) entries.add(e); } if (log.isDebugEnabled()) log.debug("Writing {0} StoredEntries to stream", entries.size()); - marshaller.objectToObjectStream(entries, o); + marshaller.objectToObjectStream(entries, oo); } catch (Exception e) { throw new StateTransferException(e); } } - private void applyPersistentState(ObjectInputStream i) throws StateTransferException { + private void applyPersistentState(ObjectInput i) throws StateTransferException { try { // always use the unclosable stream delegate to ensure the impl doesn't close the stream cs.fromStream(new UnclosableObjectInputStream(i)); @@ -351,20 +353,20 @@ } } - private void generatePersistentState(ObjectOutputStream o) throws StateTransferException { + private void generatePersistentState(ObjectOutput oo) throws StateTransferException { try { // always use the unclosable stream delegate to ensure the impl doesn't close the stream - cs.toStream(new UnclosableObjectOutputStream(o)); + cs.toStream(new UnclosableObjectOutputStream(oo)); } catch (CacheLoaderException cle) { throw new StateTransferException(cle); } } - private void delimit(ObjectOutputStream o) throws IOException { - marshaller.objectToObjectStream(DELIMITER, o); + private void delimit(ObjectOutput oo) throws IOException { + marshaller.objectToObjectStream(DELIMITER, oo); } - private void assertDelimited(ObjectInputStream i) throws StateTransferException { + private void assertDelimited(ObjectInput i) throws StateTransferException { Object o; try { o = marshaller.objectFromObjectStream(i); Index: src/main/java/org/infinispan/marshall/jboss/GlobalTransactionExternalizer.java =================================================================== --- src/main/java/org/infinispan/marshall/jboss/GlobalTransactionExternalizer.java (revision 0) +++ src/main/java/org/infinispan/marshall/jboss/GlobalTransactionExternalizer.java (revision 0) @@ -0,0 +1,66 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2009, 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.infinispan.marshall.jboss; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; + +import net.jcip.annotations.Immutable; + +import org.infinispan.remoting.transport.Address; +import org.infinispan.transaction.GlobalTransaction; +import org.jboss.marshalling.Creator; +import org.jboss.marshalling.Externalizer; + +/** + * GlobalTransactionExternalizer. + * + * @author Galder Zamarreno + * @since 4.0 + */ +@Immutable +public class GlobalTransactionExternalizer implements Externalizer { + + /** The serialVersionUID */ + private static final long serialVersionUID = -8677909497367726531L; + + public void writeExternal(Object subject, ObjectOutput output) throws IOException { + GlobalTransaction gtx = (GlobalTransaction) subject; + output.writeLong(gtx.getId()); + output.writeObject(gtx.getAddress()); + } + + public Object createExternal(Class subjectType, ObjectInput input, Creator defaultCreator) + throws IOException, ClassNotFoundException { + return new GlobalTransaction(); + } + + public void readExternal(Object subject, ObjectInput input) throws IOException, + ClassNotFoundException { + GlobalTransaction gtx = (GlobalTransaction) subject; + long id = input.readLong(); + Object address = input.readObject(); + gtx.setId(id); + gtx.setAddress((Address) address); + } +} Index: src/main/java/org/infinispan/marshall/jboss/DeltaAwareExternalizer.java =================================================================== --- src/main/java/org/infinispan/marshall/jboss/DeltaAwareExternalizer.java (revision 0) +++ src/main/java/org/infinispan/marshall/jboss/DeltaAwareExternalizer.java (revision 0) @@ -0,0 +1,60 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2009, 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.infinispan.marshall.jboss; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; + +import net.jcip.annotations.Immutable; + +import org.infinispan.atomic.DeltaAware; +import org.jboss.marshalling.Creator; +import org.jboss.marshalling.Externalizer; + +/** + * DeltaAwareExternalizer. + * + * @author Galder Zamarreno + * @since 4.0 + */ +@Immutable +public class DeltaAwareExternalizer implements Externalizer { + + /** The serialVersionUID */ + private static final long serialVersionUID = -1635913024455984627L; + + public void writeExternal(Object subject, ObjectOutput output) throws IOException { + DeltaAware dw = (DeltaAware) subject; + output.writeObject(dw.delta()); + } + + public Object createExternal(Class subjectType, ObjectInput input, Creator defaultCreator) + throws IOException, ClassNotFoundException { + return input.readObject(); + } + + public void readExternal(Object subject, ObjectInput input) throws IOException, + ClassNotFoundException { + // No-op + } +} Index: src/test/java/org/infinispan/marshall/jboss/JBossMarshallerTest.java =================================================================== --- src/test/java/org/infinispan/marshall/jboss/JBossMarshallerTest.java (revision 0) +++ src/test/java/org/infinispan/marshall/jboss/JBossMarshallerTest.java (revision 0) @@ -0,0 +1,328 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2009, 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.infinispan.marshall.jboss; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + +import org.infinispan.commands.ReplicableCommand; +import org.infinispan.commands.control.StateTransferControlCommand; +import org.infinispan.commands.read.GetKeyValueCommand; +import org.infinispan.commands.read.SizeCommand; +import org.infinispan.commands.remote.ClusteredGetCommand; +import org.infinispan.commands.remote.ReplicateCommand; +import org.infinispan.commands.tx.CommitCommand; +import org.infinispan.commands.tx.PrepareCommand; +import org.infinispan.commands.tx.RollbackCommand; +import org.infinispan.commands.write.ClearCommand; +import org.infinispan.commands.write.EvictCommand; +import org.infinispan.commands.write.InvalidateCommand; +import org.infinispan.commands.write.PutKeyValueCommand; +import org.infinispan.commands.write.PutMapCommand; +import org.infinispan.commands.write.RemoveCommand; +import org.infinispan.commands.write.ReplaceCommand; +import org.infinispan.container.entries.ImmortalCacheEntry; +import org.infinispan.container.entries.InternalCacheEntry; +import org.infinispan.container.entries.InternalEntryFactory; +import org.infinispan.container.entries.MortalCacheEntry; +import org.infinispan.container.entries.TransientCacheEntry; +import org.infinispan.container.entries.TransientMortalCacheEntry; +import org.infinispan.marshall.MarshalledValue; +import org.infinispan.remoting.transport.Address; +import org.infinispan.remoting.transport.jgroups.ExtendedResponse; +import org.infinispan.remoting.transport.jgroups.JGroupsAddress; +import org.infinispan.remoting.transport.jgroups.RequestIgnoredResponse; +import org.infinispan.test.TestingUtil; +import org.infinispan.transaction.GlobalTransaction; +import org.infinispan.transaction.TransactionLog; +import org.infinispan.util.FastCopyHashMap; +import org.infinispan.util.Immutables; +import org.jboss.marshalling.Unmarshaller; +import org.jboss.marshalling.ClassTable.Writer; +import org.jgroups.stack.IpAddress; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +/** + * JBossMarshallingMarshallerTest. + * + * Todo: AtomicHashMap missing. + * + * @author Galder Zamarreno + * @since 4.0 + */ +@Test(groups = "functional", testName = "marshall.jboss.JBossMarshallerTest") +public class JBossMarshallerTest { +// private final DelegatingMagicNumberClassTable classTable = new DelegatingMagicNumberClassTable(); + private final JBossMarshaller marshaller = new JBossMarshaller(); +// { +// @Override +// protected MagicNumberClassTable createMagicNumberClassTable() { +// classTable.setDelegate(super.createMagicNumberClassTable()); +// return classTable; +// } +// }; + + @BeforeTest + public void setUp() { + marshaller.init(Thread.currentThread().getContextClassLoader(), null); + } + + @AfterTest + public void tearDown() { + marshaller.stop(); + } + + public void testJGroupsAddressMarshalling() throws Exception { + JGroupsAddress address = new JGroupsAddress(new IpAddress(12345)); + marshallAndAssertEquality(address); + } + + public void testGlobalTransactionMarshalling() throws Exception { + GlobalTransaction gtx = GlobalTransaction.create(new JGroupsAddress(new IpAddress(12345))); + marshallAndAssertEquality(gtx); + } + + public void testListMarshalling() throws Exception { + List l1 = new ArrayList(); + List l2 = new LinkedList(); + for (int i = 0; i < 10; i++) { + GlobalTransaction gtx = GlobalTransaction.create(new JGroupsAddress(new IpAddress(1000 * i))); + l1.add(gtx); + l2.add(gtx); + } + marshallAndAssertEquality(l1); + marshallAndAssertEquality(l2); + } + + public void testMapMarshalling() throws Exception { + Map m1 = new HashMap(); + Map m2 = new TreeMap(); + Map m3 = new HashMap(); + Map m4 = new FastCopyHashMap(); + for (int i = 0; i < 10; i++) { + GlobalTransaction gtx = GlobalTransaction.create(new JGroupsAddress(new IpAddress(1000 * i))); + m1.put(1000 * i, gtx); + m2.put(1000 * i, gtx); + m4.put(1000 * i, gtx); + } + Map m5 = Immutables.immutableMapWrap(m3); + marshallAndAssertEquality(m1); + marshallAndAssertEquality(m2); + byte[] bytes = marshaller.objectToByteBuffer(m4); + Map m4Read = (Map) marshaller.objectFromByteBuffer(bytes); + for (Map.Entry entry : m4.entrySet()) { + assert m4Read.get(entry.getKey()).equals(entry.getValue()) : "Writen[" + entry.getValue() + "] and read[" + m4Read.get(entry.getKey()) +"] objects should be the same"; + } + +// marshallAndAssertEquality(m4); + marshallAndAssertEquality(m5); + } + + public void testSetMarshalling() throws Exception { + Set s1 = new HashSet(); + Set s2 = new TreeSet(); + for (int i = 0; i < 10; i++) { + Integer integ = new Integer(1000 * i); + s1.add(integ); + s2.add(integ); + } + marshallAndAssertEquality(s1); + marshallAndAssertEquality(s2); + } + + public void testMarshalledValueMarshalling() throws Exception { + GlobalTransaction gtx = GlobalTransaction.create(new JGroupsAddress(new IpAddress(12345))); + MarshalledValue mv = new MarshalledValue(gtx, true); + marshallAndAssertEquality(mv); + } + + public void testSingletonListMarshalling() throws Exception { + GlobalTransaction gtx = GlobalTransaction.create(new JGroupsAddress(new IpAddress(12345))); + List l = Collections.singletonList(gtx); + marshallAndAssertEquality(l); + } + + public void testTransactionLogMarshalling() throws Exception { + GlobalTransaction gtx = GlobalTransaction.create(new JGroupsAddress(new IpAddress(12345))); + PutKeyValueCommand command = new PutKeyValueCommand("k", "v", false, null, 0, 0); + TransactionLog.LogEntry entry = new TransactionLog.LogEntry(gtx, command); + byte[] bytes = marshaller.objectToByteBuffer(entry); + TransactionLog.LogEntry readObj = (TransactionLog.LogEntry) marshaller.objectFromByteBuffer(bytes); + assert Arrays.equals(readObj.getModifications(), entry.getModifications()) : + "Writen[" + entry.getModifications() + "] and read[" + readObj.getModifications() +"] objects should be the same"; + assert readObj.getTransaction().equals(entry.getTransaction()) : + "Writen[" + entry.getModifications() + "] and read[" + readObj.getModifications() +"] objects should be the same"; + } + + public void testRequestIgnoredResponseMarshalling() throws Exception { + marshallAndAssertEquality(RequestIgnoredResponse.INSTANCE); + } + + public void testExtendedResponseMarshalling() throws Exception { + PutKeyValueCommand command = new PutKeyValueCommand("k", "v", false, null, 0, 0); + ExtendedResponse extended = new ExtendedResponse(command, false); + byte[] bytes = marshaller.objectToByteBuffer(extended); + ExtendedResponse readObj = (ExtendedResponse) marshaller.objectFromByteBuffer(bytes); + assert extended.getResponse().equals(readObj.getResponse()) : + "Writen[" + extended.getResponse() + "] and read[" + readObj.getResponse() +"] objects should be the same"; + assert extended.isReplayIgnoredRequests() == readObj.isReplayIgnoredRequests() : + "Writen[" + extended.isReplayIgnoredRequests() + "] and read[" + readObj.isReplayIgnoredRequests() +"] objects should be the same"; + } + + public void testReplicableCommandsMarshalling() throws Exception { + StateTransferControlCommand c1 = new StateTransferControlCommand(true); + byte[] bytes = marshaller.objectToByteBuffer(c1); + StateTransferControlCommand rc1 = (StateTransferControlCommand)marshaller.objectFromByteBuffer(bytes); + assert rc1.getCommandId() == c1.getCommandId() : "Writen[" + c1.getCommandId() + "] and read[" + rc1.getCommandId() +"] objects should be the same"; + assert Arrays.equals(rc1.getParameters(), c1.getParameters()) : "Writen[" + c1.getParameters() + "] and read[" + rc1.getParameters() +"] objects should be the same"; + + ClusteredGetCommand c2 = new ClusteredGetCommand("key", "mycache"); + marshallAndAssertEquality(c2); + + // SizeCommand does not have an empty constructor, so doesn't look to be one that is marshallable. + + GetKeyValueCommand c4 = new GetKeyValueCommand("key", null); + bytes = marshaller.objectToByteBuffer(c4); + GetKeyValueCommand rc4 = (GetKeyValueCommand)marshaller.objectFromByteBuffer(bytes); + assert rc4.getCommandId() == c4.getCommandId() : "Writen[" + c4.getCommandId() + "] and read[" + rc4.getCommandId() +"] objects should be the same"; + assert Arrays.equals(rc4.getParameters(), c4.getParameters()) : "Writen[" + c4.getParameters() + "] and read[" + rc4.getParameters() +"] objects should be the same"; + + PutKeyValueCommand c5 = new PutKeyValueCommand("k", "v", false, null, 0, 0); + marshallAndAssertEquality(c5); + + RemoveCommand c6 = new RemoveCommand("key", null, null); + marshallAndAssertEquality(c6); + + // EvictCommand does not have an empty constructor, so doesn't look to be one that is marshallable. + + InvalidateCommand c7 = new InvalidateCommand(null, "key1", "key2"); + bytes = marshaller.objectToByteBuffer(c7); + InvalidateCommand rc7 = (InvalidateCommand)marshaller.objectFromByteBuffer(bytes); + assert rc7.getCommandId() == c7.getCommandId() : "Writen[" + c7.getCommandId() + "] and read[" + rc7.getCommandId() +"] objects should be the same"; + assert Arrays.equals(rc7.getParameters(), c7.getParameters()) : "Writen[" + c7.getParameters() + "] and read[" + rc7.getParameters() +"] objects should be the same"; + + ReplaceCommand c8 = new ReplaceCommand("key", "oldvalue", "newvalue", 0, 0); + marshallAndAssertEquality(c8); + + ClearCommand c9 = new ClearCommand(); + bytes = marshaller.objectToByteBuffer(c9); + ClearCommand rc9 = (ClearCommand)marshaller.objectFromByteBuffer(bytes); + assert rc9.getCommandId() == c9.getCommandId() : "Writen[" + c9.getCommandId() + "] and read[" + rc9.getCommandId() +"] objects should be the same"; + assert Arrays.equals(rc9.getParameters(), c9.getParameters()) : "Writen[" + c9.getParameters() + "] and read[" + rc9.getParameters() +"] objects should be the same"; + + Map m1 = new HashMap(); + for (int i = 0; i < 10; i++) { + GlobalTransaction gtx = GlobalTransaction.create(new JGroupsAddress(new IpAddress(1000 * i))); + m1.put(1000 * i, gtx); + } + PutMapCommand c10 = new PutMapCommand(m1, null, 0, 0); + marshallAndAssertEquality(c10); + + Address local = new JGroupsAddress(new IpAddress(12345)); + GlobalTransaction gtx = GlobalTransaction.create(local); + PrepareCommand c11 = new PrepareCommand(gtx, local, true, c5, c6, c8, c10); + marshallAndAssertEquality(c11); + + CommitCommand c12 = new CommitCommand(gtx); + marshallAndAssertEquality(c12); + + RollbackCommand c13 = new RollbackCommand(gtx); + marshallAndAssertEquality(c13); + + ReplicateCommand c99 = new ReplicateCommand(Arrays.asList(new ReplicableCommand[] {c2, c5, c6, c8, c10, c12, c13}), "mycache"); + marshallAndAssertEquality(c99); + } + + public void testInternalCacheEntryMarshalling() throws Exception { + ImmortalCacheEntry entry1 = (ImmortalCacheEntry) InternalEntryFactory.create("key", "value", System.currentTimeMillis() - 1000, -1, System.currentTimeMillis(), -1); + marshallAndAssertEquality(entry1); + + MortalCacheEntry entry2 = (MortalCacheEntry) InternalEntryFactory.create("key", "value", System.currentTimeMillis() - 1000, 200000, System.currentTimeMillis(), -1); + marshallAndAssertEquality(entry2); + + TransientCacheEntry entry3 = (TransientCacheEntry) InternalEntryFactory.create("key", "value", System.currentTimeMillis() - 1000, -1, System.currentTimeMillis(), 4000000); + marshallAndAssertEquality(entry3); + + TransientMortalCacheEntry entry4 = (TransientMortalCacheEntry) InternalEntryFactory.create("key", "value", System.currentTimeMillis() - 1000, 200000, System.currentTimeMillis(), 4000000); + marshallAndAssertEquality(entry4); + } + + + + + + protected void marshallAndAssertEquality(Object writeObj) throws Exception { + byte[] bytes = marshaller.objectToByteBuffer(writeObj); + Object readObj = marshaller.objectFromByteBuffer(bytes); + assert readObj.equals(writeObj) : "Writen[" + writeObj + "] and read[" + readObj +"] objects should be the same"; +// assert classTable.written; +// assert classTable.read; + } + +// static class DelegatingMagicNumberClassTable extends MagicNumberClassTable { +// private MagicNumberClassTable classTable; +// boolean written; +// boolean read; +// +// public void setDelegate(MagicNumberClassTable delegateClassTable) { +// classTable = delegateClassTable; +// } +// +// @Override +// protected Writer createWriter(byte magicNumber) { +// return classTable.createWriter(magicNumber); +// } +// +// @Override +// public Writer getClassWriter(Class clazz) throws IOException { +// Writer writer = classTable.getClassWriter(clazz); +// if (writer != null && !written) { +// written = true; +// } +// return writer; +// } +// +// @Override +// public void init() { +// classTable.init(); +// } +// +// @Override +// public Class readClass(Unmarshaller unmarshaller) throws IOException, +// ClassNotFoundException { +// read = true; +// return classTable.readClass(unmarshaller); +// } +// } +} Index: src/main/java/org/infinispan/marshall/jboss/SetExternalizer.java =================================================================== --- src/main/java/org/infinispan/marshall/jboss/SetExternalizer.java (revision 0) +++ src/main/java/org/infinispan/marshall/jboss/SetExternalizer.java (revision 0) @@ -0,0 +1,68 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2009, 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.infinispan.marshall.jboss; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Collection; +import java.util.Set; + +import net.jcip.annotations.Immutable; + +import org.infinispan.CacheException; +import org.infinispan.util.Util; +import org.jboss.marshalling.Creator; +import org.jboss.marshalling.Externalizer; + +/** + * Set externalizer for all set implementations, i.e. HashSet and TreeSet + * + * @author Galder Zamarreno + * @since 4.0 + */ +@Immutable +public class SetExternalizer implements Externalizer { + + /** The serialVersionUID */ + private static final long serialVersionUID = -3147427397000304867L; + + public void writeExternal(Object subject, ObjectOutput output) throws IOException { + MarshallUtil.marshallCollection((Collection) subject, output); + } + + public Object createExternal(Class subjectType, ObjectInput input, Creator defaultCreator) + throws IOException, ClassNotFoundException { + try { + return Util.getInstance(subjectType); + } catch(Exception e) { + throw new CacheException("Unable to create new instance of ReplicableCommand", e); + } + } + + public void readExternal(Object subject, ObjectInput input) throws IOException, + ClassNotFoundException { + Set set = (Set) subject; + int size = MarshallUtil.readUnsignedInt(input); + for (int i = 0; i < size; i++) set.add(input.readObject()); + } +} \ No newline at end of file Index: src/main/java/org/infinispan/marshall/jboss/InternalCachedEntryExternalizer.java =================================================================== --- src/main/java/org/infinispan/marshall/jboss/InternalCachedEntryExternalizer.java (revision 0) +++ src/main/java/org/infinispan/marshall/jboss/InternalCachedEntryExternalizer.java (revision 0) @@ -0,0 +1,82 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2009, 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.infinispan.marshall.jboss; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; + +import net.jcip.annotations.Immutable; + +import org.infinispan.container.entries.InternalCacheEntry; +import org.infinispan.container.entries.InternalEntryFactory; +import org.jboss.marshalling.Creator; +import org.jboss.marshalling.Externalizer; + +/** + * InternalCachedEntryExternalizer. + * + * @author Galder Zamarreno + * @since 4.0 + */ +@Immutable +public class InternalCachedEntryExternalizer implements Externalizer { + + /** The serialVersionUID */ + private static final long serialVersionUID = -3475239737916428837L; + + public void writeExternal(Object subject, ObjectOutput output) throws IOException { + InternalCacheEntry ice = (InternalCacheEntry) subject; + output.writeObject(ice.getKey()); + output.writeObject(ice.getValue()); + if (ice.canExpire()) { + output.writeBoolean(true); + MarshallUtil.writeUnsignedLong(output, ice.getCreated()); + output.writeLong(ice.getLifespan()); // could be negative so should not use unsigned longs + MarshallUtil.writeUnsignedLong(output, ice.getLastUsed()); + output.writeLong(ice.getMaxIdle()); // could be negative so should not use unsigned longs + } else { + output.writeBoolean(false); + } + } + + public Object createExternal(Class subjectType, ObjectInput input, Creator defaultCreator) + throws IOException, ClassNotFoundException { + Object k = input.readObject(); + Object v = input.readObject(); + boolean canExpire = input.readBoolean(); + if (canExpire) { + long created = MarshallUtil.readUnsignedLong(input); + long lifespan = input.readLong(); // could be negative so should not use unsigned longs + long lastUsed = MarshallUtil.readUnsignedLong(input); + long maxIdle = input.readLong(); // could be negative so should not use unsigned longs + return InternalEntryFactory.create(k, v, created, lifespan, lastUsed, maxIdle); + } else { + return InternalEntryFactory.create(k, v); + } + } + + public void readExternal(Object subject, ObjectInput input) throws IOException, + ClassNotFoundException { + // No-op + } +} Index: src/main/java/org/infinispan/marshall/jboss/MagicNumberClassTable.java =================================================================== --- src/main/java/org/infinispan/marshall/jboss/MagicNumberClassTable.java (revision 0) +++ src/main/java/org/infinispan/marshall/jboss/MagicNumberClassTable.java (revision 0) @@ -0,0 +1,131 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2009, 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.infinispan.marshall.jboss; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.WeakHashMap; + +import net.jcip.annotations.Immutable; + +import org.infinispan.CacheException; +import org.infinispan.util.Util; +import org.jboss.marshalling.ClassTable; +import org.jboss.marshalling.Marshaller; +import org.jboss.marshalling.Unmarshaller; + +/** + * MagicNumberClassTable. + * + * @author Galder Zamarreno + * @since 4.0 + */ +@Immutable +public class MagicNumberClassTable implements ClassTable { + private static final Map MAGIC_NUMBERS = new WeakHashMap(); + + static { + MAGIC_NUMBERS.put("org.infinispan.transaction.GlobalTransaction", 1); + MAGIC_NUMBERS.put("org.infinispan.remoting.transport.jgroups.JGroupsAddress", 2); + MAGIC_NUMBERS.put("java.util.ArrayList", 3); + MAGIC_NUMBERS.put("java.util.LinkedList", 8); + MAGIC_NUMBERS.put("java.util.HashMap", 9); + MAGIC_NUMBERS.put("java.util.TreeMap", 10); + MAGIC_NUMBERS.put("java.util.HashSet", 11); + MAGIC_NUMBERS.put("java.util.TreeSet", 12); + MAGIC_NUMBERS.put("org.infinispan.util.Immutables$ImmutableMapWrapper", 14); + MAGIC_NUMBERS.put("org.infinispan.marshall.MarshalledValue", 15); + MAGIC_NUMBERS.put("org.infinispan.util.FastCopyHashMap", 16); + MAGIC_NUMBERS.put("java.util.Collections$SingletonList", 23); + MAGIC_NUMBERS.put("org.infinispan.transaction.TransactionLog$LogEntry", 25); + MAGIC_NUMBERS.put("org.infinispan.remoting.transport.jgroups.ExtendedResponse", 28); + MAGIC_NUMBERS.put("org.infinispan.atomic.AtomicHashMap", 29); + + MAGIC_NUMBERS.put("org.infinispan.commands.control.StateTransferControlCommand", 30); + MAGIC_NUMBERS.put("org.infinispan.commands.remote.ClusteredGetCommand", 31); + MAGIC_NUMBERS.put("org.infinispan.commands.remote.ReplicateCommand", 32); + MAGIC_NUMBERS.put("org.infinispan.commands.read.GetKeyValueCommand", 34); + MAGIC_NUMBERS.put("org.infinispan.commands.write.PutKeyValueCommand", 35); + MAGIC_NUMBERS.put("org.infinispan.commands.write.RemoveCommand", 36); + MAGIC_NUMBERS.put("org.infinispan.commands.write.InvalidateCommand", 38); + MAGIC_NUMBERS.put("org.infinispan.commands.write.ReplaceCommand", 39); + MAGIC_NUMBERS.put("org.infinispan.commands.write.ClearCommand", 40); + MAGIC_NUMBERS.put("org.infinispan.commands.write.PutMapCommand", 41); + MAGIC_NUMBERS.put("org.infinispan.commands.tx.PrepareCommand", 42); + MAGIC_NUMBERS.put("org.infinispan.commands.tx.CommitCommand", 43); + MAGIC_NUMBERS.put("org.infinispan.commands.tx.RollbackCommand", 44); + + MAGIC_NUMBERS.put("org.infinispan.container.entries.ImmortalCacheEntry", 45); + MAGIC_NUMBERS.put("org.infinispan.container.entries.MortalCacheEntry", 46); + MAGIC_NUMBERS.put("org.infinispan.container.entries.TransientCacheEntry", 47); + MAGIC_NUMBERS.put("org.infinispan.container.entries.TransientMortalCacheEntry", 48); + } + + private final Map, Writer> writers = new WeakHashMap, Writer>(); + private final Map> classes = new HashMap>(); + + public void init() { + try { + for (Map.Entry entry : MAGIC_NUMBERS.entrySet()) { + Class clazz = Util.loadClass(entry.getKey()); + Byte magicNumber = entry.getValue().byteValue(); + Writer writer = createWriter(magicNumber); + writers.put(clazz, writer); + classes.put(magicNumber, clazz); + } + } catch (ClassNotFoundException e) { + throw new CacheException("Unable to load one of the classes defined in the magicnumbers.properties", e); + } + } + + public void stop() { + writers.clear(); + classes.clear(); + } + + public Writer getClassWriter(Class clazz) throws IOException { + return writers.get(clazz); + } + + public Class readClass(Unmarshaller unmarshaller) throws IOException, ClassNotFoundException { + byte magicNumber = unmarshaller.readByte(); + return classes.get(magicNumber); + } + + protected Writer createWriter(byte magicNumber) { + return new MagicNumberWriter(magicNumber); + } + + @Immutable + static class MagicNumberWriter implements Writer { + private final byte magicNumber; + + MagicNumberWriter(byte magicNumber) { + this.magicNumber = magicNumber; + } + + public void writeClass(Marshaller marshaller, Class clazz) throws IOException { + marshaller.writeByte(magicNumber); + } + } +} Index: src/main/java/org/infinispan/marshall/jboss/TransactionLogExternalizer.java =================================================================== --- src/main/java/org/infinispan/marshall/jboss/TransactionLogExternalizer.java (revision 0) +++ src/main/java/org/infinispan/marshall/jboss/TransactionLogExternalizer.java (revision 0) @@ -0,0 +1,70 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2009, 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.infinispan.marshall.jboss; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; + +import net.jcip.annotations.Immutable; + +import org.infinispan.commands.write.WriteCommand; +import org.infinispan.transaction.GlobalTransaction; +import org.infinispan.transaction.TransactionLog; +import org.jboss.marshalling.Creator; +import org.jboss.marshalling.Externalizer; + +/** + * TransactionLogExternalizer. + * + * @author Galder Zamarreno + * @since 4.0 + */ +@Immutable +public class TransactionLogExternalizer implements Externalizer { + + /** The serialVersionUID */ + private static final long serialVersionUID = -7341096933735222157L; + + public void writeExternal(Object subject, ObjectOutput output) throws IOException { + TransactionLog.LogEntry le = (TransactionLog.LogEntry) subject; + output.writeObject(le.getTransaction()); + WriteCommand[] cmds = le.getModifications(); + MarshallUtil.writeUnsignedInt(output, cmds.length); + for (WriteCommand c : cmds) + output.writeObject(c); + } + + public Object createExternal(Class subjectType, ObjectInput input, Creator defaultCreator) + throws IOException, ClassNotFoundException { + GlobalTransaction gtx = (GlobalTransaction) input.readObject(); + int numCommands = MarshallUtil.readUnsignedInt(input); + WriteCommand[] cmds = new WriteCommand[numCommands]; + for (int i = 0; i < numCommands; i++) cmds[i] = (WriteCommand) input.readObject(); + return new TransactionLog.LogEntry(gtx, cmds); + } + + public void readExternal(Object subject, ObjectInput input) throws IOException, + ClassNotFoundException { + // No-op since the initialisation the creation and read happens during the create phase. + } +} Index: src/main/java/org/infinispan/marshall/HorizonMarshaller.java =================================================================== --- src/main/java/org/infinispan/marshall/HorizonMarshaller.java (revision 97) +++ src/main/java/org/infinispan/marshall/HorizonMarshaller.java (working copy) @@ -40,6 +40,7 @@ import org.infinispan.transaction.TransactionLog; import org.infinispan.util.FastCopyHashMap; import org.infinispan.util.Immutables; +import org.infinispan.util.Util; import org.jboss.util.NotImplementedException; import org.jboss.util.stream.MarshalledValueInputStream; @@ -47,8 +48,10 @@ import java.io.IOException; import java.io.InputStream; import java.io.ObjectInput; +import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; +import java.io.OutputStream; import java.io.Serializable; import java.lang.reflect.Array; import java.util.*; @@ -795,6 +798,14 @@ c.equals(Double.class)); } + public ObjectOutput startObjectOutput(OutputStream os) throws IOException { + return new ObjectOutputStream(os); + } + + public void finishObjectOutput(ObjectOutput oo) { + Util.flushAndCloseOutput(oo); + } + public void objectToObjectStream(Object o, ObjectOutput out) throws IOException { Map refMap = useRefs ? new IdentityHashMap() : null; ClassLoader toUse = defaultClassLoader; @@ -810,6 +821,14 @@ current.setContextClassLoader(old); } } + + public ObjectInput startObjectInput(InputStream is) throws IOException { + return new ObjectInputStream(is); + } + + public void finishObjectInput(ObjectInput oi) { + Util.closeInput(oi); + } public Object objectFromObjectStream(ObjectInput in) throws IOException, ClassNotFoundException { UnmarshalledReferences refMap = useRefs ? new UnmarshalledReferences() : null; Index: src/main/java/org/infinispan/marshall/jboss/SingletonListExternalizer.java =================================================================== --- src/main/java/org/infinispan/marshall/jboss/SingletonListExternalizer.java (revision 0) +++ src/main/java/org/infinispan/marshall/jboss/SingletonListExternalizer.java (revision 0) @@ -0,0 +1,61 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2009, 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.infinispan.marshall.jboss; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Collections; +import java.util.List; + +import net.jcip.annotations.Immutable; + +import org.jboss.marshalling.Creator; +import org.jboss.marshalling.Externalizer; + +/** + * SingletonListExternalizer. + * + * @author Galder Zamarreno + * @since 4.0 + */ +@Immutable +public class SingletonListExternalizer implements Externalizer { + + /** The serialVersionUID */ + private static final long serialVersionUID = -714785461531351642L; + + public void writeExternal(Object subject, ObjectOutput output) throws IOException { + output.writeObject(((List) subject).get(0)); + } + + public Object createExternal(Class subjectType, ObjectInput input, Creator defaultCreator) + throws IOException, ClassNotFoundException { + return Collections.singletonList(input.readObject()); + } + + public void readExternal(Object subject, ObjectInput input) throws IOException, + ClassNotFoundException { + // No-op since all the work is done during create. + } + +} Index: src/main/java/org/infinispan/marshall/jboss/ArrayListExternalizer.java =================================================================== --- src/main/java/org/infinispan/marshall/jboss/ArrayListExternalizer.java (revision 0) +++ src/main/java/org/infinispan/marshall/jboss/ArrayListExternalizer.java (revision 0) @@ -0,0 +1,64 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2009, 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.infinispan.marshall.jboss; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.ArrayList; +import java.util.Collection; + +import net.jcip.annotations.Immutable; + +import org.jboss.marshalling.Creator; +import org.jboss.marshalling.Externalizer; + +/** + * List externalizer dealing with ArrayList and LinkedList implementations. + * + * @author Galder Zamarreno + * @since 4.0 + */ +@Immutable +public class ArrayListExternalizer implements Externalizer { + + /** The serialVersionUID */ + private static final long serialVersionUID = 589638638644295615L; + + public void writeExternal(Object subject, ObjectOutput output) throws IOException { + MarshallUtil.marshallCollection((Collection) subject, output); + } + + public Object createExternal(Class subjectType, ObjectInput input, Creator defaultCreator) + throws IOException, ClassNotFoundException { + int size = MarshallUtil.readUnsignedInt(input); + ArrayList l = new ArrayList(size); + for (int i = 0; i < size; i++) l.add(input.readObject()); + return l; + } + + public void readExternal(Object subject, ObjectInput input) throws IOException, + ClassNotFoundException { + // No-op since size was needed both for the creation and list population, + // so all the work was done in createExternal + } +} \ No newline at end of file