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