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