1. /*
  2. * @(#)MarshalledObject.java 1.28 00/02/02
  3. *
  4. * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package java.rmi;
  11. import java.io.*;
  12. import sun.rmi.server.MarshalInputStream;
  13. import sun.rmi.server.MarshalOutputStream;
  14. /**
  15. * A <code>MarshalledObject</code> contains a byte stream with the serialized
  16. * representation of an object given to its constructor. The <code>get</code>
  17. * method returns a new copy of the original object, as deserialized from
  18. * the contained byte stream. The contained object is serialized and
  19. * deserialized with the same serialization semantics used for marshaling
  20. * and unmarshaling parameters and return values of RMI calls: When the
  21. * serialized form is created:
  22. *
  23. * <ul>
  24. * <li> classes are annotated with a codebase URL from where the class
  25. * can be loaded (if available), and
  26. * <li> any remote object in the <code>MarshalledObject</code> is
  27. * represented by a serialized instance of its stub.
  28. * </ul>
  29. *
  30. * <p>When copy of the object is retrieved (via the <code>get</code> method),
  31. * if the class is not available locally, it will be loaded from the
  32. * appropriate location (specified the URL annotated with the class descriptor
  33. * when the class was serialized.
  34. *
  35. * <p><code>MarshalledObject</code> facilitates passing objects in RMI calls
  36. * that are not automatically deserialized immediately by the remote peer.
  37. *
  38. * @version 1.28, 02/02/00
  39. * @author Ann Wollrath
  40. * @author Peter Jones
  41. * @since 1.2
  42. */
  43. public final class MarshalledObject implements Serializable {
  44. /**
  45. * @serial Bytes of serialized representation. If <code>objBytes</code> is
  46. * <code>null</code> then the object marshalled was a <code>null</code>
  47. * reference.
  48. */
  49. private byte[] objBytes = null;
  50. /**
  51. * @serial Bytes of location annotations, which are ignored by
  52. * <code>equals</code>. If <code>locBytes</code> is null, there were no
  53. * non-<code>null</code> annotations during marshalling.
  54. */
  55. private byte[] locBytes = null;
  56. /**
  57. * @serial Stored hash code of contained object.
  58. *
  59. * @see #hashCode
  60. */
  61. private int hash;
  62. /** Indicate compatibility with 1.2 version of class. */
  63. private static final long serialVersionUID = 8988374069173025854L;
  64. /**
  65. * Creates a new <code>MarshalledObject</code> that contains the
  66. * serialized representation of the current state of the supplied object.
  67. * The object is serialized with the semantics used for marshaling
  68. * parameters for RMI calls.
  69. *
  70. * @param obj the object to be serialized (must be serializable)
  71. * @exception IOException if an <code>IOException</code> occurs; an
  72. * <code>IOException</code> may occur if <code>obj</code> is not
  73. * serializable.
  74. * @since 1.2
  75. */
  76. public MarshalledObject(Object obj)
  77. throws java.io.IOException
  78. {
  79. if (obj == null) {
  80. hash = 13;
  81. return;
  82. }
  83. ByteArrayOutputStream bout = new ByteArrayOutputStream();
  84. ByteArrayOutputStream lout = new ByteArrayOutputStream();
  85. MarshalledObjectOutputStream out =
  86. new MarshalledObjectOutputStream(bout, lout);
  87. out.writeObject(obj);
  88. out.flush();
  89. objBytes = bout.toByteArray();
  90. // locBytes is null if no annotations
  91. locBytes = (out.hadAnnotations() ? lout.toByteArray() : null);
  92. /*
  93. * Calculate hash from the marshalled representation of object
  94. * so the hashcode will be comparable when sent between VMs.
  95. */
  96. int h = 0;
  97. for (int i = 0; i < objBytes.length; i++) {
  98. h = 31 * h + objBytes[i];
  99. }
  100. hash = h;
  101. }
  102. /**
  103. * Returns a new copy of the contained marshalledobject. The internal
  104. * representation is deserialized with the semantics used for
  105. * unmarshaling paramters for RMI calls.
  106. *
  107. * @return a copy of the contained object
  108. * @exception IOException if an <code>IOException</code> occurs while
  109. * deserializing the object from its internal representation.
  110. * @exception ClassNotFoundException if a
  111. * <code>ClassNotFoundException</code> occurs while deserializing the
  112. * object from its internal representation.
  113. * could not be found
  114. * @since 1.2
  115. */
  116. public Object get()
  117. throws java.io.IOException, java.lang.ClassNotFoundException
  118. {
  119. if (objBytes == null) // must have been a null object
  120. return null;
  121. ByteArrayInputStream bin = new ByteArrayInputStream(objBytes);
  122. // locBytes is null if no annotations
  123. ByteArrayInputStream lin =
  124. (locBytes == null ? null : new ByteArrayInputStream(locBytes));
  125. MarshalledObjectInputStream in =
  126. new MarshalledObjectInputStream(bin, lin);
  127. return in.readObject();
  128. }
  129. /**
  130. * Return a hash code for this <code>MarshalledObject</code>.
  131. *
  132. * @return a hash code
  133. */
  134. public int hashCode() {
  135. return hash;
  136. }
  137. /**
  138. * Compares this <code>MarshalledObject</code> to another object.
  139. * Returns true if and only if the argument refers to a
  140. * <code>MarshalledObject</code> that contains exactly the same
  141. * serialized representation of an object as this one does. The
  142. * comparison ignores any class codebase annotation, meaning that
  143. * two objects are equivalent if they have the same serialized
  144. * representation <i>except</i> for the codebase of each class
  145. * in the serialized representation.
  146. *
  147. * @param obj the object to compare with this <code>MarshalledObject</code>
  148. * @return <code>true</code> if the argument contains an equaivalent
  149. * serialized object; <code>false</code> otherwise
  150. * @since 1.2
  151. */
  152. public boolean equals(Object obj) {
  153. if (obj == this)
  154. return true;
  155. if (obj != null && obj instanceof MarshalledObject) {
  156. MarshalledObject other = (MarshalledObject) obj;
  157. // if either is a ref to null, both must be
  158. if (objBytes == null || other.objBytes == null)
  159. return objBytes == other.objBytes;
  160. // quick, easy test
  161. if (objBytes.length != other.objBytes.length)
  162. return false;
  163. //!! There is talk about adding an array comparision method
  164. //!! at 1.2 -- if so, this should be rewritten. -arnold
  165. for (int i = 0; i < objBytes.length; ++i) {
  166. if (objBytes[i] != other.objBytes[i])
  167. return false;
  168. }
  169. return true;
  170. } else {
  171. return false;
  172. }
  173. }
  174. /**
  175. * This class is used to marshal objects for
  176. * <code>MarshalledObject</code>. It places the location annotations
  177. * to one side so that two <code>MarshalledObject</code>s can be
  178. * compared for equality if they differ only in location
  179. * annotations. Objects written using this stream should be read back
  180. * from a <code>MarshalledObjectInputStream</code>.
  181. *
  182. * @see java.rmi.MarshalledObject
  183. * @see MarshalledObjectInputStream
  184. */
  185. private static class MarshalledObjectOutputStream
  186. extends MarshalOutputStream
  187. {
  188. /** The stream on which location objects are written. */
  189. private ObjectOutputStream locOut;
  190. /** <code>true</code> if non-<code>null</code> annotations are
  191. * written.
  192. */
  193. private boolean hadAnnotations;
  194. /**
  195. * Creates a new <code>MarshalledObjectOutputStream</code> whose
  196. * non-location bytes will be written to <code>objOut</code> and whose
  197. * location annotations (if any) will be written to
  198. * <code>locOut</code>.
  199. */
  200. public MarshalledObjectOutputStream(OutputStream objOut,
  201. OutputStream locOut)
  202. throws IOException
  203. {
  204. super(objOut);
  205. this.useProtocolVersion(ObjectStreamConstants.PROTOCOL_VERSION_2);
  206. this.locOut = new ObjectOutputStream(locOut);
  207. hadAnnotations = false;
  208. }
  209. /**
  210. * Returns <code>true</code> if any non-<code>null</code> location
  211. * annotations have been written to this stream.
  212. */
  213. public boolean hadAnnotations() {
  214. return hadAnnotations;
  215. }
  216. /**
  217. * Overrides MarshalOutputStream.writeLocation implementation to write
  218. * annotations to the location stream.
  219. */
  220. protected void writeLocation(String loc) throws IOException {
  221. hadAnnotations |= (loc != null);
  222. locOut.writeObject(loc);
  223. }
  224. public void flush() throws IOException {
  225. super.flush();
  226. locOut.flush();
  227. }
  228. }
  229. /**
  230. * The counterpart to <code>MarshalledObjectOutputStream</code>.
  231. *
  232. * @see MarshalledObjectOutputStream
  233. */
  234. private static class MarshalledObjectInputStream
  235. extends MarshalInputStream
  236. {
  237. /**
  238. * The stream from which annotations will be read. If this is
  239. * <code>null</code>, then all annotations were <code>null</code>.
  240. */
  241. private ObjectInputStream locIn;
  242. /**
  243. * Creates a new <code>MarshalledObjectInputStream</code> that
  244. * reads its objects from <code>objIn</code> and annotations
  245. * from <code>locIn</code>. If <code>locIn</code> is
  246. * <code>null</code>, then all annotations will be
  247. * <code>null</code>.
  248. */
  249. MarshalledObjectInputStream(InputStream objIn, InputStream locIn)
  250. throws IOException
  251. {
  252. super(objIn);
  253. this.locIn = (locIn == null ? null : new ObjectInputStream(locIn));
  254. }
  255. /**
  256. * Overrides MarshalInputStream.readLocation to return locations from
  257. * the stream we were given, or <code>null</code> if we were given a
  258. * <code>null</code> location stream.
  259. */
  260. protected Object readLocation()
  261. throws IOException, ClassNotFoundException
  262. {
  263. return (locIn == null ? null : locIn.readObject());
  264. }
  265. }
  266. }