jdk/src/java.rmi/share/classes/java/rmi/MarshalledObject.java
changeset 25859 3317bb8137f4
parent 23010 6dadb192ad81
child 43211 f264afd5082c
equal deleted inserted replaced
25858:836adbf7a2cd 25859:3317bb8137f4
       
     1 /*
       
     2  * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package java.rmi;
       
    27 
       
    28 import java.io.ByteArrayInputStream;
       
    29 import java.io.ByteArrayOutputStream;
       
    30 import java.io.IOException;
       
    31 import java.io.InputStream;
       
    32 import java.io.ObjectInputStream;
       
    33 import java.io.ObjectOutputStream;
       
    34 import java.io.ObjectStreamConstants;
       
    35 import java.io.OutputStream;
       
    36 import java.io.Serializable;
       
    37 import sun.rmi.server.MarshalInputStream;
       
    38 import sun.rmi.server.MarshalOutputStream;
       
    39 
       
    40 /**
       
    41  * A <code>MarshalledObject</code> contains a byte stream with the serialized
       
    42  * representation of an object given to its constructor.  The <code>get</code>
       
    43  * method returns a new copy of the original object, as deserialized from
       
    44  * the contained byte stream.  The contained object is serialized and
       
    45  * deserialized with the same serialization semantics used for marshaling
       
    46  * and unmarshaling parameters and return values of RMI calls:  When the
       
    47  * serialized form is created:
       
    48  *
       
    49  * <ul>
       
    50  * <li> classes are annotated with a codebase URL from where the class
       
    51  *      can be loaded (if available), and
       
    52  * <li> any remote object in the <code>MarshalledObject</code> is
       
    53  *      represented by a serialized instance of its stub.
       
    54  * </ul>
       
    55  *
       
    56  * <p>When copy of the object is retrieved (via the <code>get</code> method),
       
    57  * if the class is not available locally, it will be loaded from the
       
    58  * appropriate location (specified the URL annotated with the class descriptor
       
    59  * when the class was serialized.
       
    60  *
       
    61  * <p><code>MarshalledObject</code> facilitates passing objects in RMI calls
       
    62  * that are not automatically deserialized immediately by the remote peer.
       
    63  *
       
    64  * @param <T> the type of the object contained in this
       
    65  * <code>MarshalledObject</code>
       
    66  *
       
    67  * @author  Ann Wollrath
       
    68  * @author  Peter Jones
       
    69  * @since   1.2
       
    70  */
       
    71 public final class MarshalledObject<T> implements Serializable {
       
    72     /**
       
    73      * @serial Bytes of serialized representation.  If <code>objBytes</code> is
       
    74      * <code>null</code> then the object marshalled was a <code>null</code>
       
    75      * reference.
       
    76      */
       
    77     private byte[] objBytes = null;
       
    78 
       
    79     /**
       
    80      * @serial Bytes of location annotations, which are ignored by
       
    81      * <code>equals</code>.  If <code>locBytes</code> is null, there were no
       
    82      * non-<code>null</code> annotations during marshalling.
       
    83      */
       
    84     private byte[] locBytes = null;
       
    85 
       
    86     /**
       
    87      * @serial Stored hash code of contained object.
       
    88      *
       
    89      * @see #hashCode
       
    90      */
       
    91     private int hash;
       
    92 
       
    93     /** Indicate compatibility with 1.2 version of class. */
       
    94     private static final long serialVersionUID = 8988374069173025854L;
       
    95 
       
    96     /**
       
    97      * Creates a new <code>MarshalledObject</code> that contains the
       
    98      * serialized representation of the current state of the supplied object.
       
    99      * The object is serialized with the semantics used for marshaling
       
   100      * parameters for RMI calls.
       
   101      *
       
   102      * @param obj the object to be serialized (must be serializable)
       
   103      * @exception IOException if an <code>IOException</code> occurs; an
       
   104      * <code>IOException</code> may occur if <code>obj</code> is not
       
   105      * serializable.
       
   106      * @since 1.2
       
   107      */
       
   108     public MarshalledObject(T obj) throws IOException {
       
   109         if (obj == null) {
       
   110             hash = 13;
       
   111             return;
       
   112         }
       
   113 
       
   114         ByteArrayOutputStream bout = new ByteArrayOutputStream();
       
   115         ByteArrayOutputStream lout = new ByteArrayOutputStream();
       
   116         MarshalledObjectOutputStream out =
       
   117             new MarshalledObjectOutputStream(bout, lout);
       
   118         out.writeObject(obj);
       
   119         out.flush();
       
   120         objBytes = bout.toByteArray();
       
   121         // locBytes is null if no annotations
       
   122         locBytes = (out.hadAnnotations() ? lout.toByteArray() : null);
       
   123 
       
   124         /*
       
   125          * Calculate hash from the marshalled representation of object
       
   126          * so the hashcode will be comparable when sent between VMs.
       
   127          */
       
   128         int h = 0;
       
   129         for (int i = 0; i < objBytes.length; i++) {
       
   130             h = 31 * h + objBytes[i];
       
   131         }
       
   132         hash = h;
       
   133     }
       
   134 
       
   135     /**
       
   136      * Returns a new copy of the contained marshalledobject.  The internal
       
   137      * representation is deserialized with the semantics used for
       
   138      * unmarshaling parameters for RMI calls.
       
   139      *
       
   140      * @return a copy of the contained object
       
   141      * @exception IOException if an <code>IOException</code> occurs while
       
   142      * deserializing the object from its internal representation.
       
   143      * @exception ClassNotFoundException if a
       
   144      * <code>ClassNotFoundException</code> occurs while deserializing the
       
   145      * object from its internal representation.
       
   146      * could not be found
       
   147      * @since 1.2
       
   148      */
       
   149     public T get() throws IOException, ClassNotFoundException {
       
   150         if (objBytes == null)   // must have been a null object
       
   151             return null;
       
   152 
       
   153         ByteArrayInputStream bin = new ByteArrayInputStream(objBytes);
       
   154         // locBytes is null if no annotations
       
   155         ByteArrayInputStream lin =
       
   156             (locBytes == null ? null : new ByteArrayInputStream(locBytes));
       
   157         MarshalledObjectInputStream in =
       
   158             new MarshalledObjectInputStream(bin, lin);
       
   159         @SuppressWarnings("unchecked")
       
   160         T obj = (T) in.readObject();
       
   161         in.close();
       
   162         return obj;
       
   163     }
       
   164 
       
   165     /**
       
   166      * Return a hash code for this <code>MarshalledObject</code>.
       
   167      *
       
   168      * @return a hash code
       
   169      */
       
   170     public int hashCode() {
       
   171         return hash;
       
   172     }
       
   173 
       
   174     /**
       
   175      * Compares this <code>MarshalledObject</code> to another object.
       
   176      * Returns true if and only if the argument refers to a
       
   177      * <code>MarshalledObject</code> that contains exactly the same
       
   178      * serialized representation of an object as this one does. The
       
   179      * comparison ignores any class codebase annotation, meaning that
       
   180      * two objects are equivalent if they have the same serialized
       
   181      * representation <i>except</i> for the codebase of each class
       
   182      * in the serialized representation.
       
   183      *
       
   184      * @param obj the object to compare with this <code>MarshalledObject</code>
       
   185      * @return <code>true</code> if the argument contains an equivalent
       
   186      * serialized object; <code>false</code> otherwise
       
   187      * @since 1.2
       
   188      */
       
   189     public boolean equals(Object obj) {
       
   190         if (obj == this)
       
   191             return true;
       
   192 
       
   193         if (obj != null && obj instanceof MarshalledObject) {
       
   194             MarshalledObject<?> other = (MarshalledObject<?>) obj;
       
   195 
       
   196             // if either is a ref to null, both must be
       
   197             if (objBytes == null || other.objBytes == null)
       
   198                 return objBytes == other.objBytes;
       
   199 
       
   200             // quick, easy test
       
   201             if (objBytes.length != other.objBytes.length)
       
   202                 return false;
       
   203 
       
   204             //!! There is talk about adding an array comparision method
       
   205             //!! at 1.2 -- if so, this should be rewritten.  -arnold
       
   206             for (int i = 0; i < objBytes.length; ++i) {
       
   207                 if (objBytes[i] != other.objBytes[i])
       
   208                     return false;
       
   209             }
       
   210             return true;
       
   211         } else {
       
   212             return false;
       
   213         }
       
   214     }
       
   215 
       
   216     /**
       
   217      * This class is used to marshal objects for
       
   218      * <code>MarshalledObject</code>.  It places the location annotations
       
   219      * to one side so that two <code>MarshalledObject</code>s can be
       
   220      * compared for equality if they differ only in location
       
   221      * annotations.  Objects written using this stream should be read back
       
   222      * from a <code>MarshalledObjectInputStream</code>.
       
   223      *
       
   224      * @see java.rmi.MarshalledObject
       
   225      * @see MarshalledObjectInputStream
       
   226      */
       
   227     private static class MarshalledObjectOutputStream
       
   228         extends MarshalOutputStream
       
   229     {
       
   230         /** The stream on which location objects are written. */
       
   231         private ObjectOutputStream locOut;
       
   232 
       
   233         /** <code>true</code> if non-<code>null</code> annotations are
       
   234          *  written.
       
   235          */
       
   236         private boolean hadAnnotations;
       
   237 
       
   238         /**
       
   239          * Creates a new <code>MarshalledObjectOutputStream</code> whose
       
   240          * non-location bytes will be written to <code>objOut</code> and whose
       
   241          * location annotations (if any) will be written to
       
   242          * <code>locOut</code>.
       
   243          */
       
   244         MarshalledObjectOutputStream(OutputStream objOut, OutputStream locOut)
       
   245             throws IOException
       
   246         {
       
   247             super(objOut);
       
   248             this.useProtocolVersion(ObjectStreamConstants.PROTOCOL_VERSION_2);
       
   249             this.locOut = new ObjectOutputStream(locOut);
       
   250             hadAnnotations = false;
       
   251         }
       
   252 
       
   253         /**
       
   254          * Returns <code>true</code> if any non-<code>null</code> location
       
   255          * annotations have been written to this stream.
       
   256          */
       
   257         boolean hadAnnotations() {
       
   258             return hadAnnotations;
       
   259         }
       
   260 
       
   261         /**
       
   262          * Overrides MarshalOutputStream.writeLocation implementation to write
       
   263          * annotations to the location stream.
       
   264          */
       
   265         protected void writeLocation(String loc) throws IOException {
       
   266             hadAnnotations |= (loc != null);
       
   267             locOut.writeObject(loc);
       
   268         }
       
   269 
       
   270 
       
   271         public void flush() throws IOException {
       
   272             super.flush();
       
   273             locOut.flush();
       
   274         }
       
   275     }
       
   276 
       
   277     /**
       
   278      * The counterpart to <code>MarshalledObjectOutputStream</code>.
       
   279      *
       
   280      * @see MarshalledObjectOutputStream
       
   281      */
       
   282     private static class MarshalledObjectInputStream
       
   283         extends MarshalInputStream
       
   284     {
       
   285         /**
       
   286          * The stream from which annotations will be read.  If this is
       
   287          * <code>null</code>, then all annotations were <code>null</code>.
       
   288          */
       
   289         private ObjectInputStream locIn;
       
   290 
       
   291         /**
       
   292          * Creates a new <code>MarshalledObjectInputStream</code> that
       
   293          * reads its objects from <code>objIn</code> and annotations
       
   294          * from <code>locIn</code>.  If <code>locIn</code> is
       
   295          * <code>null</code>, then all annotations will be
       
   296          * <code>null</code>.
       
   297          */
       
   298         MarshalledObjectInputStream(InputStream objIn, InputStream locIn)
       
   299             throws IOException
       
   300         {
       
   301             super(objIn);
       
   302             this.locIn = (locIn == null ? null : new ObjectInputStream(locIn));
       
   303         }
       
   304 
       
   305         /**
       
   306          * Overrides MarshalInputStream.readLocation to return locations from
       
   307          * the stream we were given, or <code>null</code> if we were given a
       
   308          * <code>null</code> location stream.
       
   309          */
       
   310         protected Object readLocation()
       
   311             throws IOException, ClassNotFoundException
       
   312         {
       
   313             return (locIn == null ? null : locIn.readObject());
       
   314         }
       
   315     }
       
   316 
       
   317 }