Save This Page
Home » openjdk-7 » java » rmi » [javadoc | source]
    1   /*
    2    * Copyright (c) 1997, 2005, 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 paramters 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           T obj = (T) in.readObject();
  160           in.close();
  161           return obj;
  162       }
  163   
  164       /**
  165        * Return a hash code for this <code>MarshalledObject</code>.
  166        *
  167        * @return a hash code
  168        */
  169       public int hashCode() {
  170           return hash;
  171       }
  172   
  173       /**
  174        * Compares this <code>MarshalledObject</code> to another object.
  175        * Returns true if and only if the argument refers to a
  176        * <code>MarshalledObject</code> that contains exactly the same
  177        * serialized representation of an object as this one does. The
  178        * comparison ignores any class codebase annotation, meaning that
  179        * two objects are equivalent if they have the same serialized
  180        * representation <i>except</i> for the codebase of each class
  181        * in the serialized representation.
  182        *
  183        * @param obj the object to compare with this <code>MarshalledObject</code>
  184        * @return <code>true</code> if the argument contains an equaivalent
  185        * serialized object; <code>false</code> otherwise
  186        * @since 1.2
  187        */
  188       public boolean equals(Object obj) {
  189           if (obj == this)
  190               return true;
  191   
  192           if (obj != null && obj instanceof MarshalledObject) {
  193               MarshalledObject other = (MarshalledObject) obj;
  194   
  195               // if either is a ref to null, both must be
  196               if (objBytes == null || other.objBytes == null)
  197                   return objBytes == other.objBytes;
  198   
  199               // quick, easy test
  200               if (objBytes.length != other.objBytes.length)
  201                   return false;
  202   
  203               //!! There is talk about adding an array comparision method
  204               //!! at 1.2 -- if so, this should be rewritten.  -arnold
  205               for (int i = 0; i < objBytes.length; ++i) {
  206                   if (objBytes[i] != other.objBytes[i])
  207                       return false;
  208               }
  209               return true;
  210           } else {
  211               return false;
  212           }
  213       }
  214   
  215       /**
  216        * This class is used to marshal objects for
  217        * <code>MarshalledObject</code>.  It places the location annotations
  218        * to one side so that two <code>MarshalledObject</code>s can be
  219        * compared for equality if they differ only in location
  220        * annotations.  Objects written using this stream should be read back
  221        * from a <code>MarshalledObjectInputStream</code>.
  222        *
  223        * @see java.rmi.MarshalledObject
  224        * @see MarshalledObjectInputStream
  225        */
  226       private static class MarshalledObjectOutputStream
  227           extends MarshalOutputStream
  228       {
  229           /** The stream on which location objects are written. */
  230           private ObjectOutputStream locOut;
  231   
  232           /** <code>true</code> if non-<code>null</code> annotations are
  233            *  written.
  234            */
  235           private boolean hadAnnotations;
  236   
  237           /**
  238            * Creates a new <code>MarshalledObjectOutputStream</code> whose
  239            * non-location bytes will be written to <code>objOut</code> and whose
  240            * location annotations (if any) will be written to
  241            * <code>locOut</code>.
  242            */
  243           MarshalledObjectOutputStream(OutputStream objOut, OutputStream locOut)
  244               throws IOException
  245           {
  246               super(objOut);
  247               this.useProtocolVersion(ObjectStreamConstants.PROTOCOL_VERSION_2);
  248               this.locOut = new ObjectOutputStream(locOut);
  249               hadAnnotations = false;
  250           }
  251   
  252           /**
  253            * Returns <code>true</code> if any non-<code>null</code> location
  254            * annotations have been written to this stream.
  255            */
  256           boolean hadAnnotations() {
  257               return hadAnnotations;
  258           }
  259   
  260           /**
  261            * Overrides MarshalOutputStream.writeLocation implementation to write
  262            * annotations to the location stream.
  263            */
  264           protected void writeLocation(String loc) throws IOException {
  265               hadAnnotations |= (loc != null);
  266               locOut.writeObject(loc);
  267           }
  268   
  269   
  270           public void flush() throws IOException {
  271               super.flush();
  272               locOut.flush();
  273           }
  274       }
  275   
  276       /**
  277        * The counterpart to <code>MarshalledObjectOutputStream</code>.
  278        *
  279        * @see MarshalledObjectOutputStream
  280        */
  281       private static class MarshalledObjectInputStream
  282           extends MarshalInputStream
  283       {
  284           /**
  285            * The stream from which annotations will be read.  If this is
  286            * <code>null</code>, then all annotations were <code>null</code>.
  287            */
  288           private ObjectInputStream locIn;
  289   
  290           /**
  291            * Creates a new <code>MarshalledObjectInputStream</code> that
  292            * reads its objects from <code>objIn</code> and annotations
  293            * from <code>locIn</code>.  If <code>locIn</code> is
  294            * <code>null</code>, then all annotations will be
  295            * <code>null</code>.
  296            */
  297           MarshalledObjectInputStream(InputStream objIn, InputStream locIn)
  298               throws IOException
  299           {
  300               super(objIn);
  301               this.locIn = (locIn == null ? null : new ObjectInputStream(locIn));
  302           }
  303   
  304           /**
  305            * Overrides MarshalInputStream.readLocation to return locations from
  306            * the stream we were given, or <code>null</code> if we were given a
  307            * <code>null</code> location stream.
  308            */
  309           protected Object readLocation()
  310               throws IOException, ClassNotFoundException
  311           {
  312               return (locIn == null ? null : locIn.readObject());
  313           }
  314       }
  315   
  316   }

Save This Page
Home » openjdk-7 » java » rmi » [javadoc | source]