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