org.jboss.shrinkwrap.impl.base.serialization.ZipSerializableViewImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of shrinkwrap-impl-base Show documentation
Show all versions of shrinkwrap-impl-base Show documentation
Common Base for Implementations of the ShrinkWrap Project
The newest version!
/*
* 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.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OptionalDataException;
import java.io.Serializable;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.Assignable;
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.ZipSerializableView;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.jboss.shrinkwrap.impl.base.Validate;
import org.jboss.shrinkwrap.impl.base.io.IOUtil;
import org.jboss.shrinkwrap.spi.Identifiable;
/**
* 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 ALR
* @version $Revision: $
*/
public class ZipSerializableViewImpl implements ZipSerializableView {
// -------------------------------------------------------------------------------------||
// Class Members ----------------------------------------------------------------------||
// -------------------------------------------------------------------------------------||
/**
* serialVersionUID
*/
private static final long serialVersionUID = 1L;
/**
* Logger
*/
private static final Logger log = Logger.getLogger(ZipSerializableViewImpl.class.getName());
// -------------------------------------------------------------------------------------||
// Instance Members -------------------------------------------------------------------||
// -------------------------------------------------------------------------------------||
/**
* Name of the archive; to be serialized
*/
private final String name;
/**
* String form of the ID
*/
private final transient String id;
/**
* 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 ZipSerializableViewImpl(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;
this.id = archive.getId();
}
// -------------------------------------------------------------------------------------||
// Required Implementations -----------------------------------------------------------||
// -------------------------------------------------------------------------------------||
/**
* {@inheritDoc}
*
* @see org.jboss.shrinkwrap.api.Assignable#as(java.lang.Class)
*/
@Override
public TYPE as(final Class clazz) {
return archive.as(clazz);
}
// -------------------------------------------------------------------------------------||
// 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
try (InputStream in = archive.as(ZipExporter.class).exportAsInputStream()) {
IOUtil.copy(in, out); // Don't close the outstream
// Write the ID explicitly
out.writeObject(id);
}
// Log
if (log.isLoggable(Level.FINER)) {
log.finer("Wrote archive: " + archive.toString());
}
}
/**
* Deserializes according to the custom form defined by {@link ZipSerializableViewImpl#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.importFrom(in);
// Set
this.archive = archive.as(JavaArchive.class);
// Log
if (log.isLoggable(Level.FINER)) {
log.finer("Read in archive: " + archive);
}
/*
* 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) {
}
// We've now added an ID to archives, so add this into the wire protocol
try {
final String id = (String) in.readObject();
this.archive.as(Identifiable.class).setId(id);
} catch (final OptionalDataException ode) {
/*
* Swallow; this occurs when an older wire format (without notion of ID) attempts to send an archive to a
* new format. The new archive will have the ID assigned to it at creation time, and we'll ignore that we
* can't read in the remote one from this stream (as the remote one from the old version does not have an ID
* to send
*/
if (log.isLoggable(Level.FINER)) {
log.finer("Detected an older version of the archive sent over the wire; no ID was sent. "
+ "Ignoring and using the default ID for this archive: " + archive);
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy