1 /* 2 * Copyright (c) 1996, 2011, 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 sun.rmi.transport; 27 28 import java.io.IOException; 29 import java.io.ObjectInput; 30 import java.io.ObjectOutput; 31 import java.rmi.Remote; 32 import java.rmi.RemoteException; 33 import java.rmi.server.ObjID; 34 import java.rmi.server.RMIClientSocketFactory; 35 import java.rmi.server.RMIServerSocketFactory; 36 import java.util.Arrays; 37 import 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 **/ 44 public 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(), e); 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 }