1. /*
  2. * @(#)RemoteObject.java 1.28 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.server;
  8. import java.rmi.Remote;
  9. import java.rmi.UnmarshalException;
  10. import java.rmi.NoSuchObjectException;
  11. /**
  12. * The <code>RemoteObject</code> class implements the
  13. * <code>java.lang.Object</code> behavior for remote objects.
  14. * <code>RemoteObject</code> provides the remote semantics of Object by
  15. * implementing methods for hashCode, equals, and toString.
  16. *
  17. * @author Ann Wollrath
  18. * @author Laird Dornin
  19. * @author Peter Jones
  20. * @version 1.28, 03/01/23
  21. * @since JDK1.1
  22. */
  23. public abstract class RemoteObject implements Remote, java.io.Serializable {
  24. /** The object's remote reference. */
  25. transient protected RemoteRef ref;
  26. /** indicate compatibility with JDK 1.1.x version of class */
  27. private static final long serialVersionUID = -3215090123894869218L;
  28. /**
  29. * Creates a remote object.
  30. */
  31. protected RemoteObject() {
  32. ref = null;
  33. }
  34. /**
  35. * Creates a remote object, initialized with the specified remote
  36. * reference.
  37. * @param newref remote reference
  38. */
  39. protected RemoteObject(RemoteRef newref) {
  40. ref = newref;
  41. }
  42. /**
  43. * Returns the remote reference for the remote object.
  44. *
  45. * <p>Note: The object returned from this method may be an instance of
  46. * an implementation-specific class. The <code>RemoteObject</code>
  47. * class ensures serialization portability of its instances' remote
  48. * references through the behavior of its custom
  49. * <code>writeObject</code> and <code>readObject</code> methods. An
  50. * instance of <code>RemoteRef</code> should not be serialized outside
  51. * of its <code>RemoteObject</code> wrapper instance or the result may
  52. * be unportable.
  53. *
  54. * @return remote reference for the remote object
  55. * @since 1.2
  56. */
  57. public RemoteRef getRef() {
  58. return ref;
  59. }
  60. /**
  61. * Returns the stub for the remote object <code>obj</code> passed
  62. * as a parameter. This operation is only valid <i>after</i>
  63. * the object has been exported.
  64. * @param obj the remote object whose stub is neede
  65. * @return the stub for the remote object, <code>obj</code>.
  66. * @exception NoSuchObjectException if the stub for the
  67. * remote object could not be found.
  68. * @since 1.2
  69. */
  70. public static Remote toStub(Remote obj) throws NoSuchObjectException {
  71. if (obj instanceof RemoteStub) {
  72. return (RemoteStub)obj;
  73. } else {
  74. return sun.rmi.transport.ObjectTable.getStub(obj);
  75. }
  76. }
  77. /**
  78. * Returns a hashcode for a remote object. Two remote object stubs
  79. * that refer to the same remote object will have the same hash code
  80. * (in order to support remote objects as keys in hash tables).
  81. *
  82. * @see java.util.Hashtable
  83. */
  84. public int hashCode() {
  85. return (ref == null) ? super.hashCode() : ref.remoteHashCode();
  86. }
  87. /**
  88. * Compares two remote objects for equality.
  89. * Returns a boolean that indicates whether this remote object is
  90. * equivalent to the specified Object. This method is used when a
  91. * remote object is stored in a hashtable.
  92. * If the specified Object is not itself an instance of RemoteObject,
  93. * then this method delegates by returning the result of invoking the
  94. * <code>equals</code> method of its parameter with this remote object
  95. * as the argument.
  96. * @param obj the Object to compare with
  97. * @return true if these Objects are equal; false otherwise.
  98. * @see java.util.Hashtable
  99. */
  100. public boolean equals(Object obj) {
  101. if (obj instanceof RemoteObject) {
  102. if (ref == null) {
  103. return obj == this;
  104. } else {
  105. return ref.remoteEquals(((RemoteObject)obj).ref);
  106. }
  107. } else if (obj != null) {
  108. /*
  109. * Fix for 4099660: if object is not an instance of RemoteObject,
  110. * use the result of its equals method, to support symmetry is a
  111. * remote object implementation class that does not extend
  112. * RemoteObject wishes to support equality with its stub objects.
  113. */
  114. return obj.equals(this);
  115. } else {
  116. return false;
  117. }
  118. }
  119. /**
  120. * Returns a String that represents the value of this remote object.
  121. */
  122. public String toString() {
  123. String classname = this.getClass().getName();
  124. return (ref == null) ? classname :
  125. classname + "[" +ref.remoteToString() + "]";
  126. }
  127. /**
  128. * <code>writeObject</code> for custom serialization.
  129. *
  130. * <p>This method writes this object's serialized form for this class
  131. * as follows:
  132. *
  133. * <p>The {@link RemoteRef#getRefClass(java.io.ObjectOutput) getRefClass}
  134. * method is invoked on this object's <code>ref</code> field
  135. * to obtain its external ref type name.
  136. * If the value returned by <code>getRefClass</code> was
  137. * a non-<code>null</code> string of length greater than zero,
  138. * the <code>writeUTF</code> method is invoked on <code>out</code>
  139. * with the value returned by <code>getRefClass</code>, and then
  140. * the <code>writeExternal</code> method is invoked on
  141. * this object's <code>ref</code> field passing <code>out</code>
  142. * as the argument; otherwise,
  143. * the <code>writeUTF</code> method is invoked on <code>out</code>
  144. * with a zero-length string (<code>""</code>), and then
  145. * the <code>writeObject</code> method is invoked on <code>out</code>
  146. * passing this object's <code>ref</code> field as the argument.
  147. *
  148. * @serialData
  149. *
  150. * The serialized data for this class comprises a string (written with
  151. * <code>ObjectOutput.writeUTF</code>) that is either the external
  152. * ref type name of the contained <code>RemoteRef</code> instance
  153. * (the <code>ref</code> field) or a zero-length string, followed by
  154. * either the external form of the <code>ref</code> field as written by
  155. * its <code>writeExternal</code> method if the string was of non-zero
  156. * length, or the serialized form of the <code>ref</code> field as
  157. * written by passing it to the serialization stream's
  158. * <code>writeObject</code> if the string was of zero length.
  159. *
  160. * <p>If this object is an instance of
  161. * <code>java.rmi.server.RemoteStub</code> that was returned from any of
  162. * the <code>UnicastRemoteObject.exportObject</code> methods
  163. * and custom socket factories are not used,
  164. * the external ref type name is <code>"UnicastRef"</code>.
  165. *
  166. * If this object is an instance of
  167. * <code>RemoteStub</code> that was returned from any of
  168. * the <code>UnicastRemoteObject.exportObject</code> methods
  169. * and custom socket factories are used,
  170. * the external ref type name is <code>"UnicastRef2"</code>.
  171. *
  172. * If this object is an instance of
  173. * <code>RemoteStub</code> that was returned from any of
  174. * the <code>java.rmi.activation.Activatable.exportObject</code> methods,
  175. * the external ref type name is <code>"ActivatableRef"</code>.
  176. *
  177. * If this object is an instance of
  178. * <code>RemoteStub</code> that was returned from
  179. * the <code>RemoteObject.toStub</code> method (and the argument passed
  180. * to <code>toStub</code> was not itself a <code>RemoteStub</code>),
  181. * the external ref type name is a function of how the remote object
  182. * passed to <code>toStub</code> was exported, as described above.
  183. *
  184. * If this object is an instance of
  185. * <code>RemoteStub</code> that was originally
  186. * created via deserialization,
  187. * the external ref type name is the same as that which was read
  188. * when this object was deserialized.
  189. *
  190. * <p>If this object is an instance of
  191. * <code>java.rmi.server.UnicastRemoteObject</code> that does not
  192. * use custom socket factories,
  193. * the external ref type name is <code>"UnicastServerRef"</code>.
  194. *
  195. * If this object is an instance of
  196. * <code>UnicastRemoteObject</code> that does
  197. * use custom socket factories,
  198. * the external ref type name is <code>"UnicastServerRef2"</code>.
  199. *
  200. * <p>If this object is an instance of
  201. * <code>java.rmi.activation.Activatable</code>,
  202. * the external ref type name is <code>"ActivatableServerRef"</code>.
  203. *
  204. * <p>Following is the data that must be written by the
  205. * <code>writeExternal</code> method and read by the
  206. * <code>readExternal</code> method of <code>RemoteRef</code>
  207. * implementation classes that correspond to the each of the
  208. * defined external ref type names:
  209. *
  210. * <p>For <code>"UnicastRef"</code>:
  211. *
  212. * <ul>
  213. *
  214. * <li>the hostname of the referenced remote object,
  215. * written by {@link java.io.ObjectOutput#writeUTF(String)}
  216. *
  217. * <li>the port of the referenced remote object,
  218. * written by {@link java.io.ObjectOutput#writeInt(int)}
  219. *
  220. * <li>the data written as a result of calling
  221. * {link java.rmi.server.ObjID#write(java.io.ObjectOutput)}
  222. * on the <code>ObjID</code> instance contained in the reference
  223. *
  224. * <li>the boolean value <code>false</code>,
  225. * written by {@link java.io.ObjectOutput#writeBoolean(boolean)}
  226. *
  227. * </ul>
  228. *
  229. * <p>For <code>"UnicastRef2"</code> with a
  230. * <code>null</code> client socket factory:
  231. *
  232. * <ul>
  233. *
  234. * <li>the byte value <code>0x00</code>
  235. * (indicating <code>null</code> client socket factory),
  236. * written by {@link java.io.ObjectOutput#writeByte(int)}
  237. *
  238. * <li>the hostname of the referenced remote object,
  239. * written by {@link java.io.ObjectOutput#writeUTF(String)}
  240. *
  241. * <li>the port of the referenced remote object,
  242. * written by {@link java.io.ObjectOutput#writeInt(int)}
  243. *
  244. * <li>the data written as a result of calling
  245. * {link java.rmi.server.ObjID#write(java.io.ObjectOutput)}
  246. * on the <code>ObjID</code> instance contained in the reference
  247. *
  248. * <li>the boolean value <code>false</code>,
  249. * written by {@link java.io.ObjectOutput#writeBoolean(boolean)}
  250. *
  251. * </ul>
  252. *
  253. * <p>For <code>"UnicastRef2"</code> with a
  254. * non-<code>null</code> client socket factory:
  255. *
  256. * <ul>
  257. *
  258. * <li>the byte value <code>0x01</code>
  259. * (indicating non-<code>null</code> client socket factory),
  260. * written by {@link java.io.ObjectOutput#writeByte(int)}
  261. *
  262. * <li>the hostname of the referenced remote object,
  263. * written by {@link java.io.ObjectOutput#writeUTF(String)}
  264. *
  265. * <li>the port of the referenced remote object,
  266. * written by {@link java.io.ObjectOutput#writeInt(int)}
  267. *
  268. * <li>a client socket factory (object of type
  269. * <code>java.rmi.server.RMIClientSocketFactory</code>),
  270. * written by passing it to an invocation of
  271. * <code>writeObject</code> on the stream instance
  272. *
  273. * <li>the data written as a result of calling
  274. * {link java.rmi.server.ObjID#write(java.io.ObjectOutput)}
  275. * on the <code>ObjID</code> instance contained in the reference
  276. *
  277. * <li>the boolean value <code>false</code>,
  278. * written by {@link java.io.ObjectOutput#writeBoolean(boolean)}
  279. *
  280. * </ul>
  281. *
  282. * <p>For <code>"ActivatableRef"</code> with a
  283. * <code>null</code> nested remote reference:
  284. *
  285. * <ul>
  286. *
  287. * <li>an instance of
  288. * <code>java.rmi.activation.ActivationID</code>,
  289. * written by passing it to an invocation of
  290. * <code>writeObject</code> on the stream instance
  291. *
  292. * <li>a zero-length string (<code>""</code>),
  293. * written by {@link java.io.ObjectOutput#writeUTF(String)}
  294. *
  295. * </ul>
  296. *
  297. * <p>For <code>"ActivatableRef"</code> with a
  298. * non-<code>null</code> nested remote reference:
  299. *
  300. * <ul>
  301. *
  302. * <li>an instance of
  303. * <code>java.rmi.activation.ActivationID</code>,
  304. * written by passing it to an invocation of
  305. * <code>writeObject</code> on the stream instance
  306. *
  307. * <li>the external ref type name of the nested remote reference,
  308. * which must be <code>"UnicastRef2"</code>,
  309. * written by {@link java.io.ObjectOutput#writeUTF(String)}
  310. *
  311. * <li>the external form of the nested remote reference,
  312. * written by invoking its <code>writeExternal</code> method
  313. * with the stream instance
  314. * (see the description of the external form for
  315. * <code>"UnicastRef2"</code> above)
  316. *
  317. * </ul>
  318. *
  319. * <p>For <code>"UnicastServerRef"</code>,
  320. * <code>"UnicastServerRef2"</code>, and
  321. * <code>"ActivatableServerRef"</code>, no data is written by the
  322. * <code>writeExternal</code> method or read by the
  323. * <code>readExternal</code> method.
  324. */
  325. private void writeObject(java.io.ObjectOutputStream out)
  326. throws java.io.IOException, java.lang.ClassNotFoundException
  327. {
  328. if (ref == null) {
  329. throw new java.rmi.MarshalException("Invalid remote object");
  330. } else {
  331. String refClassName = ref.getRefClass(out);
  332. if (refClassName == null || refClassName.length() == 0) {
  333. /*
  334. * No reference class name specified, so serialize
  335. * remote reference.
  336. */
  337. out.writeUTF("");
  338. out.writeObject(ref);
  339. } else {
  340. /*
  341. * Built-in reference class specified, so delegate
  342. * to reference to write out its external form.
  343. */
  344. out.writeUTF(refClassName);
  345. ref.writeExternal(out);
  346. }
  347. }
  348. }
  349. /**
  350. * <code>readObject</code> for custom serialization.
  351. *
  352. * <p>This method reads this object's serialized form for this class
  353. * as follows:
  354. *
  355. * <p>The <code>readUTF</code> method is invoked on <code>in</code>
  356. * to read the external ref type name for the <code>RemoteRef</code>
  357. * instance to be filled in to this object's <code>ref</code> field.
  358. * If the string returned by <code>readUTF</code> has length zero,
  359. * the <code>readObject</code> method is invoked on <code>in</code>,
  360. * and than the value returned by <code>readObject</code> is cast to
  361. * <code>RemoteRef</code> and this object's <code>ref</code> field is
  362. * set to that value.
  363. * Otherwise, this object's <code>ref</code> field is set to a
  364. * <code>RemoteRef</code> instance that is created of an
  365. * implementation-specific class corresponding to the external ref
  366. * type name returned by <code>readUTF</code>, and then
  367. * the <code>readExternal</code> method is invoked on
  368. * this object's <code>ref</code> field.
  369. *
  370. * <p>If the external ref type name is
  371. * <code>"UnicastRef"</code>, <code>"UnicastServerRef"</code>,
  372. * <code>"UnicastRef2"</code>, <code>"UnicastServerRef2"</code>,
  373. * <code>"ActivatableRef"</code>, or
  374. * <code>"ActivatableServerRef"</code>, a corresponding
  375. * implementation-specific class must be found, and its
  376. * <code>readExternal</code> method must read the serial data
  377. * for that external ref type name as specified to be written
  378. * in the <b>serialData</b> documentation for this class.
  379. * If the external ref type name is any other string (of non-zero
  380. * length), a <code>ClassNotFoundException</code> will be thrown,
  381. * unless the implementation provides an implementation-specific
  382. * class corresponding to that external ref type name, in which
  383. * case this object's <code>ref</code> field will be set to an
  384. * instance of that implementation-specific class.
  385. */
  386. private void readObject(java.io.ObjectInputStream in)
  387. throws java.io.IOException, java.lang.ClassNotFoundException
  388. {
  389. try {
  390. String refClassName = in.readUTF();
  391. if (refClassName == null || refClassName.length() == 0) {
  392. /*
  393. * No reference class name specified, so construct
  394. * remote reference from its serialized form.
  395. */
  396. ref = (RemoteRef) in.readObject();
  397. } else {
  398. /*
  399. * Built-in reference class specified, so delegate
  400. * to reference to initialize its fields from its
  401. * external form.
  402. */
  403. Class refClass = Class.forName(RemoteRef.packagePrefix + "." +
  404. refClassName);
  405. ref = (RemoteRef) refClass.newInstance();
  406. ref.readExternal(in);
  407. }
  408. } catch (InstantiationException e) {
  409. throw new UnmarshalException("Unable to create remote reference",
  410. e);
  411. } catch (IllegalAccessException e) {
  412. throw new UnmarshalException("Illegal access creating remote reference");
  413. }
  414. }
  415. }