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 }