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