[jboss-svn-commits] JBoss Common SVN: r4453 - in shrinkwrap/trunk: api/src/main/java/org/jboss/shrinkwrap/api/serialization and 5 other directories.
jboss-svn-commits at lists.jboss.org
jboss-svn-commits at lists.jboss.org
Fri May 28 21:13:58 EDT 2010
Author: ALRubinger
Date: 2010-05-28 21:13:58 -0400 (Fri, 28 May 2010)
New Revision: 4453
Added:
shrinkwrap/trunk/api/src/main/java/org/jboss/shrinkwrap/api/serialization/
shrinkwrap/trunk/api/src/main/java/org/jboss/shrinkwrap/api/serialization/ZipSerializable.java
shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/serialization/
shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/serialization/ZipSerializableImpl.java
shrinkwrap/trunk/impl-base/src/main/resources/META-INF/services/org.jboss.shrinkwrap.api.serialization.ZipSerializable
shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/serialization/
shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/serialization/SerializationTestCase.java
shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/serialization/ZipSerializableOriginalImpl.java
Log:
[SHRINKWRAP-178] Define a Serializable view of Archives. TODO: Test wire compatibility in both directions. Currently working with same version present.
Added: shrinkwrap/trunk/api/src/main/java/org/jboss/shrinkwrap/api/serialization/ZipSerializable.java
===================================================================
--- shrinkwrap/trunk/api/src/main/java/org/jboss/shrinkwrap/api/serialization/ZipSerializable.java (rev 0)
+++ shrinkwrap/trunk/api/src/main/java/org/jboss/shrinkwrap/api/serialization/ZipSerializable.java 2010-05-29 01:13:58 UTC (rev 4453)
@@ -0,0 +1,36 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jboss.shrinkwrap.api.serialization;
+
+import java.io.Serializable;
+
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.Assignable;
+
+/**
+ * {@link Serializable} view of an {@link Archive} where
+ * contents are encoded in ZIP format during
+ * Serialization. May be reassigned to a normal {@link Archive}
+ * view via {@link Assignable#as(Class)}.
+ *
+ * @author <a href="mailto:andrew.rubinger at jboss.org">ALR</a>
+ * @version $Revision: $
+ */
+public interface ZipSerializable extends Serializable, Assignable
+{
+
+}
Added: shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/serialization/ZipSerializableImpl.java
===================================================================
--- shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/serialization/ZipSerializableImpl.java (rev 0)
+++ shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/serialization/ZipSerializableImpl.java 2010-05-29 01:13:58 UTC (rev 4453)
@@ -0,0 +1,234 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jboss.shrinkwrap.impl.base.serialization;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.zip.ZipInputStream;
+
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.exporter.ZipExporter;
+import org.jboss.shrinkwrap.api.importer.ZipImporter;
+import org.jboss.shrinkwrap.api.serialization.ZipSerializable;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.jboss.shrinkwrap.impl.base.AssignableBase;
+import org.jboss.shrinkwrap.impl.base.Validate;
+import org.jboss.shrinkwrap.impl.base.io.IOUtil;
+
+/**
+ * Implementation of a {@link Serializable} view of {@link Archive}s,
+ * backed by ZIP en/decoding the contents during serialization/deserialization.
+ * Defines the wire protocol and must remain backwards-compatible.
+ *
+ * @author <a href="mailto:andrew.rubinger at jboss.org">ALR</a>
+ * @version $Revision: $
+ */
+public class ZipSerializableImpl extends AssignableBase implements ZipSerializable
+{
+
+ //-------------------------------------------------------------------------------------||
+ // Class Members ----------------------------------------------------------------------||
+ //-------------------------------------------------------------------------------------||
+
+ /**
+ * serialVersionUID
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Logger
+ */
+ private static final Logger log = Logger.getLogger(ZipSerializableOriginalImpl.class.getName());
+
+ //-------------------------------------------------------------------------------------||
+ // Instance Members -------------------------------------------------------------------||
+ //-------------------------------------------------------------------------------------||
+
+ /**
+ * Name of the archive; to be serialized
+ */
+ private final String name;
+
+ /**
+ * Underlying archive. Won't be directly serialized;
+ * instead we'll encode it as ZIP and send that
+ */
+ private transient Archive<?> archive;
+
+ //-------------------------------------------------------------------------------------||
+ // Constructor ------------------------------------------------------------------------||
+ //-------------------------------------------------------------------------------------||
+
+ /**
+ * Creates a new instance, wrapping the specified {@link Archive}
+ */
+ public ZipSerializableImpl(final Archive<?> archive)
+ {
+ Validate.notNull(archive, "Archive must be specified");
+ final String name = archive.getName();
+ Validate.notNullOrEmpty(name, "Name of archive must be specified");
+ this.archive = archive;
+ this.name = name;
+ }
+
+ //-------------------------------------------------------------------------------------||
+ // Required Implementations -----------------------------------------------------------||
+ //-------------------------------------------------------------------------------------||
+
+ /**
+ * {@inheritDoc}
+ * @see org.jboss.shrinkwrap.impl.base.AssignableBase#getArchive()
+ */
+ @Override
+ protected Archive<?> getArchive()
+ {
+ assert archive != null : "Underlying archive may never be null; illegal state";
+ return archive;
+ }
+
+ //-------------------------------------------------------------------------------------||
+ // Serialization ----------------------------------------------------------------------||
+ //-------------------------------------------------------------------------------------||
+
+ /**
+ * Serializes the invocation with a custom form
+ *
+ * @serialData After all non-transient fields are written, we
+ * send the {@link Archive} contents encoded as ZIP.
+ */
+ private void writeObject(final ObjectOutputStream out) throws IOException
+ {
+ // Default write of non-transient fields
+ out.defaultWriteObject();
+
+ // Write as ZIP
+ final InputStream in = archive.as(ZipExporter.class).exportZip();
+ try
+ {
+ IOUtil.copy(in, out); // Don't close the outstream
+ }
+ finally
+ {
+ // In case we get an InputStream type that supports closing
+ in.close();
+ }
+
+ // Log
+ if (log.isLoggable(Level.FINER))
+ {
+ log.finer("Wrote archive: " + archive.toString());
+ }
+ }
+
+ /**
+ * Deserializes according to the custom form
+ * defined by {@link ZipSerializableOriginalImpl#writeObject(ObjectOutputStream)}
+ */
+ private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException
+ {
+ // Get default form
+ in.defaultReadObject();
+
+ // Create new Archive
+ final String name = this.name;
+ final ZipImporter archive = ShrinkWrap.create(ZipImporter.class, name);
+
+ // Read in archive
+ final ZipInputStream remains = new ZipInputStream(new DoNotDelegateCloseInputStream(in));
+
+ try
+ {
+ // Read in
+ archive.importZip(remains);
+
+ // Set
+ this.archive = archive.as(JavaArchive.class);
+ }
+ finally
+ {
+ // Close up our stream, but not the underlying ObjectInputStream
+ remains.close();
+ }
+
+ // Log
+ if (log.isLoggable(Level.FINER))
+ {
+ log.finer("Read in archive: " + archive.toString());
+ }
+
+ /*
+ * Leave this bit here.
+ *
+ * After reading in the ZIP stream contents, we need to also
+ * get to the EOF marker (which is not read in by the ZIP import process
+ * because it's the ZIP header, not part of the true contents. Putting
+ * this loop here ensures we reach the marker, which is *not* the true
+ * end of the stream. Object data may be read again after here
+ * via something like:
+ *
+ * in.readObject();
+ *
+ * Without this loop we'll get an OptionalDataException when trying to
+ * read more objects in from the stream. In the future we may add state
+ * which needs to be part of the serialization protocol, and things
+ * need to stay in order, so they'll be added *after* the archive ZIP contents.
+ * Thus we must be able to read them.
+ */
+ while (in.read() != -1);
+
+ }
+
+ //-------------------------------------------------------------------------------------||
+ // Internal Helper Classes ------------------------------------------------------------||
+ //-------------------------------------------------------------------------------------||
+
+ /**
+ * A {@link InputStream} which does not delegate the {@link InputStream#close()}
+ * operation to the wrapped delegate; we cannot close the {@link ObjectInputStream}
+ * passed into {@link ZipSerializableOriginalImpl#readObject(ObjectInputStream)}.
+ *
+ * @author <a href="mailto:andrew.rubinger at jboss.org">ALR</a>
+ * @version $Revision: $
+ */
+ private static class DoNotDelegateCloseInputStream extends FilterInputStream
+ {
+
+ protected DoNotDelegateCloseInputStream(final InputStream in)
+ {
+ super(in);
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see java.io.FilterInputStream#close()
+ */
+ @Override
+ public void close() throws IOException
+ {
+ // NOOP
+ }
+
+ }
+
+}
Added: shrinkwrap/trunk/impl-base/src/main/resources/META-INF/services/org.jboss.shrinkwrap.api.serialization.ZipSerializable
===================================================================
--- shrinkwrap/trunk/impl-base/src/main/resources/META-INF/services/org.jboss.shrinkwrap.api.serialization.ZipSerializable (rev 0)
+++ shrinkwrap/trunk/impl-base/src/main/resources/META-INF/services/org.jboss.shrinkwrap.api.serialization.ZipSerializable 2010-05-29 01:13:58 UTC (rev 4453)
@@ -0,0 +1 @@
+org.jboss.shrinkwrap.impl.base.serialization.ZipSerializableImpl
\ No newline at end of file
Added: shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/serialization/SerializationTestCase.java
===================================================================
--- shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/serialization/SerializationTestCase.java (rev 0)
+++ shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/serialization/SerializationTestCase.java 2010-05-29 01:13:58 UTC (rev 4453)
@@ -0,0 +1,288 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jboss.shrinkwrap.impl.base.serialization;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamClass;
+import java.io.ObjectStreamConstants;
+import java.io.ObjectStreamField;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.ArchivePath;
+import org.jboss.shrinkwrap.api.Node;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.serialization.ZipSerializable;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Ensures that serialization of Archives is possible via
+ * the {@link ZipSerializable} view.
+ *
+ * SHRINKWRAP-178
+ *
+ * @author <a href="mailto:andrew.rubinger at jboss.org">ALR</a>
+ * @version $Revision: $
+ */
+public class SerializationTestCase
+{
+
+ //-------------------------------------------------------------------------------------||
+ // Class Members ----------------------------------------------------------------------||
+ //-------------------------------------------------------------------------------------||
+
+ /**
+ * Logger
+ */
+ private static final Logger log = Logger.getLogger(SerializationTestCase.class.getName());
+
+ //-------------------------------------------------------------------------------------||
+ // Tests ------------------------------------------------------------------------------||
+ //-------------------------------------------------------------------------------------||
+
+ /**
+ * Ensures we may serialize an {@link Archive} and preserve contents
+ * as expected
+ */
+ @Test
+ public void serialize() throws Exception
+ {
+ // Define the initial archive
+ final String name = "serializedArchive.jar";
+ final JavaArchive original = ShrinkWrap.create(JavaArchive.class, name).addClasses(SerializationTestCase.class,
+ JavaArchive.class);
+ log.info("Before: " + original.toString(true));
+
+ // Serialize
+ final JavaArchive roundtrip = serializeAndDeserialize(original.as(ZipSerializable.class)).as(JavaArchive.class);
+ log.info("After: " + roundtrip.toString(true));
+
+ // Ensure contents are as expected
+ final Map<ArchivePath, Node> originalContents = original.getContent();
+ final Map<ArchivePath, Node> roundtripContents = roundtrip.getContent();
+ Assert.assertEquals("Contents after serialization were not as expected", originalContents, roundtripContents);
+ Assert.assertEquals("Name of original archive was not as expected", name, original.getName());
+ Assert.assertEquals("Name not as expected after serialization", original.getName(), roundtrip.getName());
+ }
+
+ /**
+ * Ensures that the current serialization protocol is compatible
+ * with the version initially released. We accomplish this by mocking
+ * {@link ZipSerializableOriginalImpl} and redefining its class name via
+ * {@link SerializationTestCase#serializeAndDeserialize(ZipSerializable, Class)},
+ * which uses the {@link SpoofingObjectOutputStream}.
+ * @throws Exception
+ */
+ // @Test
+ public void wireProtocolCurrentToOriginal() throws Exception
+ {
+ //TODO
+ }
+
+ /**
+ * Ensures that the original serialization protocol is compatible
+ * with the current version. We accomplish this by mocking
+ * {@link ZipSerializableOriginalImpl} and redefining its class name via
+ * {@link SerializationTestCase#serializeAndDeserialize(ZipSerializable, Class)},
+ * which uses the {@link SpoofingObjectOutputStream}.
+ * @throws Exception
+ */
+ // @Test
+ public void wireProtocolOriginalToCurrent() throws Exception
+ {
+ //TODO
+ }
+
+ //TODO Add tests for backwards-compatibility wire protocol, nested archives
+
+ /*
+ * Note: looks like nested archives aren't represented in toString(verbose);
+ * investigate if necessary and open a JIRA
+ */
+
+ //-------------------------------------------------------------------------------------||
+ // Internal Helper Methods ------------------------------------------------------------||
+ //-------------------------------------------------------------------------------------||
+
+ /**
+ * Roundtrip serializes/deserializes the specified {@link Archive}
+ *
+ * @param archive
+ * @return
+ * @throws IOException
+ * @throws ClassNotFoundException
+ */
+ private static ZipSerializable serializeAndDeserialize(final ZipSerializable archive) throws IOException,
+ ClassNotFoundException
+ {
+ assert archive != null : "Archive must be specified";
+ final ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
+ final ObjectOutputStream out = new ObjectOutputStream(byteOut);
+ out.writeObject(archive);
+ out.flush();
+ out.close();
+ final ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(byteOut.toByteArray()));
+ final ZipSerializable roundtrip = (ZipSerializable) in.readObject();
+ in.close();
+ return roundtrip;
+ }
+
+ /**
+ * Roundtrip serializes/deserializes the specified {@link Invocation}
+ * and reconsitutes/redefines as the specified target type
+ *
+ * @param archive The original {@link ZipSerializable} instance
+ * @param The new type we should cast to after deserialization
+ * @see http://crazybob.org/2006/01/unit-testing-serialization-evolution.html
+ * @see http://crazybob.org/2006/01/unit-testing-serialization-evolution_13.html
+ * @see http://www.theserverside.com/news/thread.tss?thread_id=38398
+ * @author Bob Lee
+ */
+ private static <S extends ZipSerializable> S serializeAndDeserialize(final ZipSerializable archive,
+ final Class<S> targetType) throws IOException
+ {
+ final ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ final ObjectOutputStream oout = new SpoofingObjectOutputStream(bout, archive.getClass(), targetType);
+ oout.writeObject(archive);
+ oout.flush();
+ oout.close();
+ final ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
+ final ObjectInputStream oin = new ObjectInputStream(bin);
+ try
+ {
+ final Object obj = oin.readObject();
+ oin.close();
+ log.info("Original invocation type " + archive.getClass().getName() + " now represented as "
+ + obj.getClass().getName());
+ return targetType.cast(obj);
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ //-------------------------------------------------------------------------------------||
+ // Internal Helper Classes ------------------------------------------------------------||
+ //-------------------------------------------------------------------------------------||
+
+ /**
+ * SpoofingObjectOutputStream
+ *
+ * ObjectOutputStream which will replace a class name with one explicitly given
+ *
+ * @see http://crazybob.org/2006/01/unit-testing-serialization-evolution_13.html
+ * @author Bob Lee
+ * @version $Revision: $
+ */
+ static class SpoofingObjectOutputStream extends ObjectOutputStream
+ {
+
+ String oldName;
+
+ String newName;
+
+ public SpoofingObjectOutputStream(OutputStream out, Class<?> oldClass, Class<?> newClass) throws IOException
+ {
+ super(out);
+ this.oldName = oldClass.getName();
+ this.newName = newClass.getName();
+ }
+
+ @Override
+ protected void writeClassDescriptor(ObjectStreamClass descriptor) throws IOException
+ {
+ Class<?> clazz = descriptor.forClass();
+
+ boolean externalizable = Externalizable.class.isAssignableFrom(clazz);
+ boolean serializable = Serializable.class.isAssignableFrom(clazz);
+ boolean hasWriteObjectData = hasWriteObjectMethod(clazz);
+ boolean isEnum = Enum.class.isAssignableFrom(clazz);
+
+ writeUTF(replace(descriptor.getName()));
+ writeLong(descriptor.getSerialVersionUID());
+ byte flags = 0;
+ if (externalizable)
+ {
+ flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
+ flags |= ObjectStreamConstants.SC_BLOCK_DATA;
+ }
+ else if (serializable)
+ {
+ flags |= ObjectStreamConstants.SC_SERIALIZABLE;
+ }
+ if (hasWriteObjectData)
+ {
+ flags |= ObjectStreamConstants.SC_WRITE_METHOD;
+ }
+ if (isEnum)
+ {
+ flags |= ObjectStreamConstants.SC_ENUM;
+ }
+ writeByte(flags);
+
+ ObjectStreamField[] fields = descriptor.getFields();
+ writeShort(fields.length);
+ for (ObjectStreamField field : fields)
+ {
+ writeByte(field.getTypeCode());
+ writeUTF(field.getName());
+ if (!field.isPrimitive())
+ {
+ writeObject(replace(field.getTypeString()));
+ }
+ }
+ }
+
+ String replace(String className)
+ {
+ if (className.equals(newName))
+ {
+ throw new RuntimeException("Found instance of " + className + "." + " Expected instance of " + oldName
+ + ".");
+ }
+ return className == oldName ? newName : className;
+ }
+
+ boolean hasWriteObjectMethod(Class<?> clazz)
+ {
+ try
+ {
+ Method method = clazz.getDeclaredMethod("writeObject", ObjectOutputStream.class);
+ int modifiers = method.getModifiers();
+ return method.getReturnType() == Void.TYPE && !Modifier.isStatic(modifiers)
+ && Modifier.isPrivate(modifiers);
+ }
+ catch (NoSuchMethodException e)
+ {
+ return false;
+ }
+ }
+ }
+}
Added: shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/serialization/ZipSerializableOriginalImpl.java
===================================================================
--- shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/serialization/ZipSerializableOriginalImpl.java (rev 0)
+++ shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/serialization/ZipSerializableOriginalImpl.java 2010-05-29 01:13:58 UTC (rev 4453)
@@ -0,0 +1,235 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jboss.shrinkwrap.impl.base.serialization;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.zip.ZipInputStream;
+
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.exporter.ZipExporter;
+import org.jboss.shrinkwrap.api.importer.ZipImporter;
+import org.jboss.shrinkwrap.api.serialization.ZipSerializable;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.jboss.shrinkwrap.impl.base.AssignableBase;
+import org.jboss.shrinkwrap.impl.base.Validate;
+import org.jboss.shrinkwrap.impl.base.io.IOUtil;
+
+/**
+ * Copy of {@link ZipSerializableImpl} so we may test for
+ * backwards-compatibility of the wire protocol. This class is
+ * *never to change* once we publish/lock the wire protocol. It is
+ * used to mock different ShrinkWrap versions communicating
+ * with one another.
+ *
+ * @author <a href="mailto:andrew.rubinger at jboss.org">ALR</a>
+ * @version $Revision: $
+ */
+public class ZipSerializableOriginalImpl extends AssignableBase implements ZipSerializable
+{
+
+ //-------------------------------------------------------------------------------------||
+ // Class Members ----------------------------------------------------------------------||
+ //-------------------------------------------------------------------------------------||
+
+ /**
+ * serialVersionUID
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Logger
+ */
+ private static final Logger log = Logger.getLogger(ZipSerializableImpl.class.getName());
+
+ //-------------------------------------------------------------------------------------||
+ // Instance Members -------------------------------------------------------------------||
+ //-------------------------------------------------------------------------------------||
+
+ /**
+ * Name of the archive; to be serialized
+ */
+ private final String name;
+
+ /**
+ * Underlying archive. Won't be directly serialized;
+ * instead we'll encode it as ZIP and send that
+ */
+ private transient Archive<?> archive;
+
+ //-------------------------------------------------------------------------------------||
+ // Constructor ------------------------------------------------------------------------||
+ //-------------------------------------------------------------------------------------||
+
+ /**
+ * Creates a new instance, wrapping the specified {@link Archive}
+ */
+ public ZipSerializableOriginalImpl(final Archive<?> archive)
+ {
+ Validate.notNull(archive, "Archive must be specified");
+ final String name = archive.getName();
+ Validate.notNullOrEmpty(name, "Name of archive must be specified");
+ this.archive = archive;
+ this.name = name;
+ }
+
+ //-------------------------------------------------------------------------------------||
+ // Required Implementations -----------------------------------------------------------||
+ //-------------------------------------------------------------------------------------||
+
+ /**
+ * {@inheritDoc}
+ * @see org.jboss.shrinkwrap.impl.base.AssignableBase#getArchive()
+ */
+ @Override
+ protected Archive<?> getArchive()
+ {
+ assert archive != null : "Underlying archive may never be null; illegal state";
+ return archive;
+ }
+
+ //-------------------------------------------------------------------------------------||
+ // Serialization ----------------------------------------------------------------------||
+ //-------------------------------------------------------------------------------------||
+
+ /**
+ * Serializes the invocation with a custom form
+ *
+ * @serialData After all non-transient fields are written, we
+ * send the {@link Archive} contents encoded as ZIP.
+ */
+ private void writeObject(final ObjectOutputStream out) throws IOException
+ {
+ // Default write of non-transient fields
+ out.defaultWriteObject();
+
+ // Write as ZIP
+ final InputStream in = archive.as(ZipExporter.class).exportZip();
+ try
+ {
+ IOUtil.copy(in, out); // Don't close the outstream
+ }
+ finally
+ {
+ // In case we get an InputStream type that supports closing
+ in.close();
+ }
+
+ // Log
+ if (log.isLoggable(Level.FINER))
+ {
+ log.finer("Wrote archive: " + archive.toString());
+ }
+ }
+
+ /**
+ * Deserializes according to the custom form
+ * defined by {@link ZipSerializableImpl#writeObject(ObjectOutputStream)}
+ */
+ private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException
+ {
+ // Get default form
+ in.defaultReadObject();
+
+ // Create new Archive
+ final String name = this.name;
+ final ZipImporter archive = ShrinkWrap.create(ZipImporter.class, name);
+
+ // Read in archive
+ final ZipInputStream remains = new ZipInputStream(new DoNotDelegateCloseInputStream(in));
+
+ try
+ {
+ // Read in
+ archive.importZip(remains);
+
+ // Set
+ this.archive = archive.as(JavaArchive.class);
+ }
+ finally
+ {
+ // Close up our stream, but not the underlying ObjectInputStream
+ remains.close();
+ }
+
+ // Log
+ if (log.isLoggable(Level.FINER))
+ {
+ log.finer("Read in archive: " + archive.toString());
+ }
+
+ /*
+ * Leave this bit here.
+ *
+ * After reading in the ZIP stream contents, we need to also
+ * get to the EOF marker (which is not read in by the ZIP import process
+ * because it's the ZIP header, not part of the true contents. Putting
+ * this loop here ensures we reach the marker, which is *not* the true
+ * end of the stream. Object data may be read again after here
+ * via something like:
+ *
+ * in.readObject();
+ *
+ * Without this loop we'll get an OptionalDataException when trying to
+ * read more objects in from the stream. In the future we may add state
+ * which needs to be part of the serialization protocol, and things
+ * need to stay in order, so they'll be added *after* the archive ZIP contents.
+ * Thus we must be able to read them.
+ */
+ while (in.read() != -1);
+
+ }
+
+ //-------------------------------------------------------------------------------------||
+ // Internal Helper Classes ------------------------------------------------------------||
+ //-------------------------------------------------------------------------------------||
+
+ /**
+ * A {@link InputStream} which does not delegate the {@link InputStream#close()}
+ * operation to the wrapped delegate; we cannot close the {@link ObjectInputStream}
+ * passed into {@link ZipSerializableImpl#readObject(ObjectInputStream)}.
+ *
+ * @author <a href="mailto:andrew.rubinger at jboss.org">ALR</a>
+ * @version $Revision: $
+ */
+ private static class DoNotDelegateCloseInputStream extends FilterInputStream
+ {
+
+ protected DoNotDelegateCloseInputStream(final InputStream in)
+ {
+ super(in);
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see java.io.FilterInputStream#close()
+ */
+ @Override
+ public void close() throws IOException
+ {
+ // NOOP
+ }
+
+ }
+
+}
More information about the jboss-svn-commits
mailing list