MarshalledObject.java revision 0
4632N/A/*
4632N/A * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
4632N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4632N/A *
4632N/A * This code is free software; you can redistribute it and/or modify it
4632N/A * under the terms of the GNU General Public License version 2 only, as
4632N/A * published by the Free Software Foundation. Sun designates this
4632N/A * particular file as subject to the "Classpath" exception as provided
4632N/A * by Sun in the LICENSE file that accompanied this code.
4632N/A *
4632N/A * This code is distributed in the hope that it will be useful, but WITHOUT
4632N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4632N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
4632N/A * version 2 for more details (a copy is included in the LICENSE file that
4632N/A * accompanied this code).
4632N/A *
4632N/A * You should have received a copy of the GNU General Public License version
4632N/A * 2 along with this work; if not, write to the Free Software Foundation,
4632N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
4632N/A *
4632N/A * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
4632N/A * CA 95054 USA or visit www.sun.com if you need additional information or
4632N/A * have any questions.
4632N/A */
4632N/A
4632N/Apackage java.rmi;
4632N/A
4632N/Aimport java.io.ByteArrayInputStream;
4632N/Aimport java.io.ByteArrayOutputStream;
4632N/Aimport java.io.IOException;
4632N/Aimport java.io.InputStream;
4632N/Aimport java.io.ObjectInputStream;
4632N/Aimport java.io.ObjectOutputStream;
4632N/Aimport java.io.ObjectStreamConstants;
4632N/Aimport java.io.OutputStream;
4632N/Aimport java.io.Serializable;
4632N/Aimport sun.rmi.server.MarshalInputStream;
4632N/Aimport sun.rmi.server.MarshalOutputStream;
4632N/A
4632N/A/**
4632N/A * A <code>MarshalledObject</code> contains a byte stream with the serialized
4632N/A * representation of an object given to its constructor. The <code>get</code>
4632N/A * method returns a new copy of the original object, as deserialized from
4632N/A * the contained byte stream. The contained object is serialized and
4632N/A * deserialized with the same serialization semantics used for marshaling
4632N/A * and unmarshaling parameters and return values of RMI calls: When the
4632N/A * serialized form is created:
4632N/A *
4632N/A * <ul>
4632N/A * <li> classes are annotated with a codebase URL from where the class
4632N/A * can be loaded (if available), and
4632N/A * <li> any remote object in the <code>MarshalledObject</code> is
4632N/A * represented by a serialized instance of its stub.
4632N/A * </ul>
4632N/A *
4632N/A * <p>When copy of the object is retrieved (via the <code>get</code> method),
4632N/A * if the class is not available locally, it will be loaded from the
4632N/A * appropriate location (specified the URL annotated with the class descriptor
4632N/A * when the class was serialized.
4632N/A *
4632N/A * <p><code>MarshalledObject</code> facilitates passing objects in RMI calls
4632N/A * that are not automatically deserialized immediately by the remote peer.
4632N/A *
4632N/A * @param <T> the type of the object contained in this
4632N/A * <code>MarshalledObject</code>
4632N/A *
4632N/A * @author Ann Wollrath
4632N/A * @author Peter Jones
4632N/A * @since 1.2
4632N/A */
4632N/Apublic final class MarshalledObject<T> implements Serializable {
4632N/A /**
4632N/A * @serial Bytes of serialized representation. If <code>objBytes</code> is
4632N/A * <code>null</code> then the object marshalled was a <code>null</code>
4632N/A * reference.
4632N/A */
4632N/A private byte[] objBytes = null;
4632N/A
4632N/A /**
4632N/A * @serial Bytes of location annotations, which are ignored by
4632N/A * <code>equals</code>. If <code>locBytes</code> is null, there were no
4632N/A * non-<code>null</code> annotations during marshalling.
4632N/A */
4632N/A private byte[] locBytes = null;
4632N/A
4632N/A /**
4632N/A * @serial Stored hash code of contained object.
4632N/A *
4632N/A * @see #hashCode
4632N/A */
4632N/A private int hash;
4632N/A
4632N/A /** Indicate compatibility with 1.2 version of class. */
4632N/A private static final long serialVersionUID = 8988374069173025854L;
4632N/A
4632N/A /**
4632N/A * Creates a new <code>MarshalledObject</code> that contains the
4632N/A * serialized representation of the current state of the supplied object.
4632N/A * The object is serialized with the semantics used for marshaling
4632N/A * parameters for RMI calls.
4632N/A *
4632N/A * @param obj the object to be serialized (must be serializable)
4632N/A * @exception IOException if an <code>IOException</code> occurs; an
4632N/A * <code>IOException</code> may occur if <code>obj</code> is not
4632N/A * serializable.
4632N/A * @since 1.2
4632N/A */
4632N/A public MarshalledObject(T obj) throws IOException {
4632N/A if (obj == null) {
4632N/A hash = 13;
4632N/A return;
4632N/A }
4632N/A
4632N/A ByteArrayOutputStream bout = new ByteArrayOutputStream();
4632N/A ByteArrayOutputStream lout = new ByteArrayOutputStream();
4632N/A MarshalledObjectOutputStream out =
4632N/A new MarshalledObjectOutputStream(bout, lout);
4632N/A out.writeObject(obj);
4632N/A out.flush();
4632N/A objBytes = bout.toByteArray();
4632N/A // locBytes is null if no annotations
4632N/A locBytes = (out.hadAnnotations() ? lout.toByteArray() : null);
4632N/A
4632N/A /*
4632N/A * Calculate hash from the marshalled representation of object
4632N/A * so the hashcode will be comparable when sent between VMs.
4632N/A */
4632N/A int h = 0;
4632N/A for (int i = 0; i < objBytes.length; i++) {
4632N/A h = 31 * h + objBytes[i];
4632N/A }
4632N/A hash = h;
4632N/A }
4632N/A
4632N/A /**
4632N/A * Returns a new copy of the contained marshalledobject. The internal
4632N/A * representation is deserialized with the semantics used for
4632N/A * unmarshaling paramters for RMI calls.
4632N/A *
4632N/A * @return a copy of the contained object
4632N/A * @exception IOException if an <code>IOException</code> occurs while
4632N/A * deserializing the object from its internal representation.
4632N/A * @exception ClassNotFoundException if a
4632N/A * <code>ClassNotFoundException</code> occurs while deserializing the
4632N/A * object from its internal representation.
4632N/A * could not be found
4632N/A * @since 1.2
4632N/A */
4632N/A public T get() throws IOException, ClassNotFoundException {
4632N/A if (objBytes == null) // must have been a null object
4632N/A return null;
4632N/A
4632N/A ByteArrayInputStream bin = new ByteArrayInputStream(objBytes);
4632N/A // locBytes is null if no annotations
4632N/A ByteArrayInputStream lin =
4632N/A (locBytes == null ? null : new ByteArrayInputStream(locBytes));
4632N/A MarshalledObjectInputStream in =
4632N/A new MarshalledObjectInputStream(bin, lin);
4632N/A T obj = (T) in.readObject();
4632N/A in.close();
4632N/A return obj;
4632N/A }
4632N/A
4632N/A /**
4632N/A * Return a hash code for this <code>MarshalledObject</code>.
4632N/A *
4632N/A * @return a hash code
4632N/A */
4632N/A public int hashCode() {
4632N/A return hash;
4632N/A }
4632N/A
4632N/A /**
4632N/A * Compares this <code>MarshalledObject</code> to another object.
4632N/A * Returns true if and only if the argument refers to a
4632N/A * <code>MarshalledObject</code> that contains exactly the same
4632N/A * serialized representation of an object as this one does. The
4632N/A * comparison ignores any class codebase annotation, meaning that
4632N/A * two objects are equivalent if they have the same serialized
4632N/A * representation <i>except</i> for the codebase of each class
4632N/A * in the serialized representation.
4632N/A *
4632N/A * @param obj the object to compare with this <code>MarshalledObject</code>
4632N/A * @return <code>true</code> if the argument contains an equaivalent
4632N/A * serialized object; <code>false</code> otherwise
4632N/A * @since 1.2
4632N/A */
4632N/A public boolean equals(Object obj) {
4632N/A if (obj == this)
4632N/A return true;
4632N/A
4632N/A if (obj != null && obj instanceof MarshalledObject) {
4632N/A MarshalledObject other = (MarshalledObject) obj;
4632N/A
4632N/A // if either is a ref to null, both must be
4632N/A if (objBytes == null || other.objBytes == null)
4632N/A return objBytes == other.objBytes;
4632N/A
4632N/A // quick, easy test
4632N/A if (objBytes.length != other.objBytes.length)
4632N/A return false;
4632N/A
4632N/A //!! There is talk about adding an array comparision method
4632N/A //!! at 1.2 -- if so, this should be rewritten. -arnold
4632N/A for (int i = 0; i < objBytes.length; ++i) {
4632N/A if (objBytes[i] != other.objBytes[i])
4632N/A return false;
4632N/A }
4632N/A return true;
4632N/A } else {
4632N/A return false;
4632N/A }
4632N/A }
4632N/A
4632N/A /**
4632N/A * This class is used to marshal objects for
4632N/A * <code>MarshalledObject</code>. It places the location annotations
4632N/A * to one side so that two <code>MarshalledObject</code>s can be
4632N/A * compared for equality if they differ only in location
4632N/A * annotations. Objects written using this stream should be read back
4632N/A * from a <code>MarshalledObjectInputStream</code>.
4632N/A *
4632N/A * @see java.rmi.MarshalledObject
4632N/A * @see MarshalledObjectInputStream
4632N/A */
4632N/A private static class MarshalledObjectOutputStream
4632N/A extends MarshalOutputStream
4632N/A {
4632N/A /** The stream on which location objects are written. */
4632N/A private ObjectOutputStream locOut;
4632N/A
4632N/A /** <code>true</code> if non-<code>null</code> annotations are
4632N/A * written.
4632N/A */
4632N/A private boolean hadAnnotations;
4632N/A
4632N/A /**
4632N/A * Creates a new <code>MarshalledObjectOutputStream</code> whose
4632N/A * non-location bytes will be written to <code>objOut</code> and whose
4632N/A * location annotations (if any) will be written to
4632N/A * <code>locOut</code>.
4632N/A */
4632N/A MarshalledObjectOutputStream(OutputStream objOut, OutputStream locOut)
4632N/A throws IOException
4632N/A {
4632N/A super(objOut);
4632N/A this.useProtocolVersion(ObjectStreamConstants.PROTOCOL_VERSION_2);
4632N/A this.locOut = new ObjectOutputStream(locOut);
4632N/A hadAnnotations = false;
4632N/A }
4632N/A
4632N/A /**
4632N/A * Returns <code>true</code> if any non-<code>null</code> location
4632N/A * annotations have been written to this stream.
4632N/A */
4632N/A boolean hadAnnotations() {
4632N/A return hadAnnotations;
4632N/A }
4632N/A
4632N/A /**
4632N/A * Overrides MarshalOutputStream.writeLocation implementation to write
4632N/A * annotations to the location stream.
4632N/A */
4632N/A protected void writeLocation(String loc) throws IOException {
4632N/A hadAnnotations |= (loc != null);
4632N/A locOut.writeObject(loc);
4632N/A }
4632N/A
4632N/A
4632N/A public void flush() throws IOException {
4632N/A super.flush();
4632N/A locOut.flush();
4632N/A }
4632N/A }
4632N/A
4632N/A /**
4632N/A * The counterpart to <code>MarshalledObjectOutputStream</code>.
4632N/A *
4632N/A * @see MarshalledObjectOutputStream
4632N/A */
4632N/A private static class MarshalledObjectInputStream
4632N/A extends MarshalInputStream
4632N/A {
4632N/A /**
4632N/A * The stream from which annotations will be read. If this is
4632N/A * <code>null</code>, then all annotations were <code>null</code>.
4632N/A */
4632N/A private ObjectInputStream locIn;
4632N/A
4632N/A /**
4632N/A * Creates a new <code>MarshalledObjectInputStream</code> that
4632N/A * reads its objects from <code>objIn</code> and annotations
4632N/A * from <code>locIn</code>. If <code>locIn</code> is
4632N/A * <code>null</code>, then all annotations will be
4632N/A * <code>null</code>.
4632N/A */
4632N/A MarshalledObjectInputStream(InputStream objIn, InputStream locIn)
4632N/A throws IOException
4632N/A {
4632N/A super(objIn);
4632N/A this.locIn = (locIn == null ? null : new ObjectInputStream(locIn));
4632N/A }
4632N/A
4632N/A /**
4632N/A * Overrides MarshalInputStream.readLocation to return locations from
4632N/A * the stream we were given, or <code>null</code> if we were given a
4632N/A * <code>null</code> location stream.
4632N/A */
4632N/A protected Object readLocation()
4632N/A throws IOException, ClassNotFoundException
4632N/A {
4632N/A return (locIn == null ? null : locIn.readObject());
4632N/A }
4632N/A }
4632N/A
4632N/A}
4632N/A