blob: f8810c0d2d51b9bb6679f145c175d092354b9251 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1996-2005 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.rmi.transport;
27
28import java.io.IOException;
29import java.io.ObjectInput;
30import java.io.ObjectOutput;
31import java.rmi.Remote;
32import java.rmi.RemoteException;
33import java.rmi.server.ObjID;
34import java.rmi.server.RMIClientSocketFactory;
35import java.rmi.server.RMIServerSocketFactory;
36import java.util.Arrays;
37import sun.rmi.transport.tcp.TCPEndpoint;
38
39/**
40 * NOTE: There is a JDK-internal dependency on the existence of this
41 * class and its getClientSocketFactory method in the implementation
42 * of javax.management.remote.rmi.RMIConnector.
43 **/
44public class LiveRef implements Cloneable {
45 /** wire representation for the object*/
46 private final Endpoint ep;
47 private final ObjID id;
48
49 /** cached connection service for the object */
50 private transient Channel ch;
51
52 /** flag to indicate whether this ref specifies a local server or
53 * is a ref for a remote object (surrogate)
54 */
55 private final boolean isLocal;
56
57 /**
58 * Construct a "well-known" live reference to a remote object
59 * @param isLocalServer If true, indicates this ref specifies a local
60 * server in this address space; if false, the ref is for a remote
61 * object (hence a surrogate or proxy) in another address space.
62 */
63 public LiveRef(ObjID objID, Endpoint endpoint, boolean isLocal) {
64 ep = endpoint;
65 id = objID;
66 this.isLocal = isLocal;
67 }
68
69 /**
70 * Construct a new live reference for a server object in the local
71 * address space.
72 */
73 public LiveRef(int port) {
74 this((new ObjID()), port);
75 }
76
77 /**
78 * Construct a new live reference for a server object in the local
79 * address space, to use sockets of the specified type.
80 */
81 public LiveRef(int port,
82 RMIClientSocketFactory csf,
83 RMIServerSocketFactory ssf)
84 {
85 this((new ObjID()), port, csf, ssf);
86 }
87
88 /**
89 * Construct a new live reference for a "well-known" server object
90 * in the local address space.
91 */
92 public LiveRef(ObjID objID, int port) {
93 this(objID, TCPEndpoint.getLocalEndpoint(port), true);
94 }
95
96 /**
97 * Construct a new live reference for a "well-known" server object
98 * in the local address space, to use sockets of the specified type.
99 */
100 public LiveRef(ObjID objID, int port, RMIClientSocketFactory csf,
101 RMIServerSocketFactory ssf)
102 {
103 this(objID, TCPEndpoint.getLocalEndpoint(port, csf, ssf), true);
104 }
105
106 /**
107 * Return a shallow copy of this ref.
108 */
109 public Object clone() {
110 try {
111 LiveRef newRef = (LiveRef) super.clone();
112 return newRef;
113 } catch (CloneNotSupportedException e) {
114 throw new InternalError(e.toString());
115 }
116 }
117
118 /**
119 * Return the port number associated with this ref.
120 */
121 public int getPort() {
122 return ((TCPEndpoint) ep).getPort();
123 }
124
125 /**
126 * Return the client socket factory associated with this ref.
127 *
128 * NOTE: There is a JDK-internal dependency on the existence of
129 * this method in the implementation of
130 * javax.management.remote.rmi.RMIConnector.
131 **/
132 public RMIClientSocketFactory getClientSocketFactory() {
133 return ((TCPEndpoint) ep).getClientSocketFactory();
134 }
135
136 /**
137 * Return the server socket factory associated with this ref.
138 */
139 public RMIServerSocketFactory getServerSocketFactory() {
140 return ((TCPEndpoint) ep).getServerSocketFactory();
141 }
142
143 /**
144 * Export the object to accept incoming calls.
145 */
146 public void exportObject(Target target) throws RemoteException {
147 ep.exportObject(target);
148 }
149
150 public Channel getChannel() throws RemoteException {
151 if (ch == null) {
152 ch = ep.getChannel();
153 }
154 return ch;
155 }
156
157 public ObjID getObjID() {
158 return id;
159 }
160
161 Endpoint getEndpoint() {
162 return ep;
163 }
164
165 public String toString() {
166 String type;
167
168 if (isLocal)
169 type = "local";
170 else
171 type = "remote";
172 return "[endpoint:" + ep + "(" + type + ")," +
173 "objID:" + id + "]";
174 }
175
176 public int hashCode() {
177 return id.hashCode();
178 }
179
180 public boolean equals(Object obj) {
181 if (obj != null && obj instanceof LiveRef) {
182 LiveRef ref = (LiveRef) obj;
183
184 return (ep.equals(ref.ep) && id.equals(ref.id) &&
185 isLocal == ref.isLocal);
186 } else {
187 return false;
188 }
189 }
190
191 public boolean remoteEquals(Object obj) {
192 if (obj != null && obj instanceof LiveRef) {
193 LiveRef ref = (LiveRef) obj;
194
195 TCPEndpoint thisEp = ((TCPEndpoint) ep);
196 TCPEndpoint refEp = ((TCPEndpoint) ref.ep);
197
198 RMIClientSocketFactory thisClientFactory =
199 thisEp.getClientSocketFactory();
200 RMIClientSocketFactory refClientFactory =
201 refEp.getClientSocketFactory();
202
203 /**
204 * Fix for 4254103: LiveRef.remoteEquals should not fail
205 * if one of the objects in the comparison has a null
206 * server socket. Comparison should only consider the
207 * following criteria:
208 *
209 * hosts, ports, client socket factories and object IDs.
210 */
211 if (thisEp.getPort() != refEp.getPort() ||
212 !thisEp.getHost().equals(refEp.getHost()))
213 {
214 return false;
215 }
216 if ((thisClientFactory == null) ^ (refClientFactory == null)) {
217 return false;
218 }
219 if ((thisClientFactory != null) &&
220 !((thisClientFactory.getClass() ==
221 refClientFactory.getClass()) &&
222 (thisClientFactory.equals(refClientFactory))))
223 {
224 return false;
225 }
226 return (id.equals(ref.id));
227 } else {
228 return false;
229 }
230 }
231
232 public void write(ObjectOutput out, boolean useNewFormat)
233 throws IOException
234 {
235 boolean isResultStream = false;
236 if (out instanceof ConnectionOutputStream) {
237 ConnectionOutputStream stream = (ConnectionOutputStream) out;
238 isResultStream = stream.isResultStream();
239 /*
240 * Ensure that referential integrity is not broken while
241 * this LiveRef is in transit. If it is being marshalled
242 * as part of a result, it may not otherwise be strongly
243 * reachable after the remote call has completed; even if
244 * it is being marshalled as part of an argument, the VM
245 * may determine that the reference on the stack is no
246 * longer reachable after marshalling (see 6181943)--
247 * therefore, tell the stream to save a reference until a
248 * timeout expires or, for results, a DGCAck message has
249 * been received from the caller, or for arguments, the
250 * remote call has completed. For a "local" LiveRef, save
251 * a reference to the impl directly, because the impl is
252 * not reachable from the LiveRef (see 4114579);
253 * otherwise, save a reference to the LiveRef, for the
254 * client-side DGC to watch over. (Also see 4017232.)
255 */
256 if (isLocal) {
257 ObjectEndpoint oe =
258 new ObjectEndpoint(id, ep.getInboundTransport());
259 Target target = ObjectTable.getTarget(oe);
260
261 if (target != null) {
262 Remote impl = target.getImpl();
263 if (impl != null) {
264 stream.saveObject(impl);
265 }
266 }
267 } else {
268 stream.saveObject(this);
269 }
270 }
271 // All together now write out the endpoint, id, and flag
272
273 // (need to choose whether or not to use old JDK1.1 endpoint format)
274 if (useNewFormat) {
275 ((TCPEndpoint) ep).write(out);
276 } else {
277 ((TCPEndpoint) ep).writeHostPortFormat(out);
278 }
279 id.write(out);
280 out.writeBoolean(isResultStream);
281 }
282
283 public static LiveRef read(ObjectInput in, boolean useNewFormat)
284 throws IOException, ClassNotFoundException
285 {
286 Endpoint ep;
287 ObjID id;
288
289 // Now read in the endpoint, id, and result flag
290 // (need to choose whether or not to read old JDK1.1 endpoint format)
291 if (useNewFormat) {
292 ep = TCPEndpoint.read(in);
293 } else {
294 ep = TCPEndpoint.readHostPortFormat(in);
295 }
296 id = ObjID.read(in);
297 boolean isResultStream = in.readBoolean();
298
299 LiveRef ref = new LiveRef(id, ep, false);
300
301 if (in instanceof ConnectionInputStream) {
302 ConnectionInputStream stream = (ConnectionInputStream)in;
303 // save ref to send "dirty" call after all args/returns
304 // have been unmarshaled.
305 stream.saveRef(ref);
306 if (isResultStream) {
307 // set flag in stream indicating that remote objects were
308 // unmarshaled. A DGC ack should be sent by the transport.
309 stream.setAckNeeded();
310 }
311 } else {
312 DGCClient.registerRefs(ep, Arrays.asList(new LiveRef[] { ref }));
313 }
314
315 return ref;
316 }
317}