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