317 lines · 10.5 KB · Java
RawDownload
/* * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.rmi.transport; import java.io.IOException;import java.io.ObjectInput;import java.io.ObjectOutput;import java.rmi.Remote;import java.rmi.RemoteException;import java.rmi.server.ObjID;import java.rmi.server.RMIClientSocketFactory;import java.rmi.server.RMIServerSocketFactory;import java.util.Arrays;import sun.rmi.transport.tcp.TCPEndpoint; /** * NOTE: There is a JDK-internal dependency on the existence of this * class and its getClientSocketFactory method in the implementation * of javax.management.remote.rmi.RMIConnector. **/public class LiveRef implements Cloneable {    /** wire representation for the object*/    private final Endpoint ep;    private final ObjID id;     /** cached connection service for the object */    private transient Channel ch;     /** flag to indicate whether this ref specifies a local server or     * is a ref for a remote object (surrogate)     */    private final boolean isLocal;     /**     * Construct a "well-known" live reference to a remote object     * @param isLocalServer If true, indicates this ref specifies a local     * server in this address space; if false, the ref is for a remote     * object (hence a surrogate or proxy) in another address space.     */    public LiveRef(ObjID objID, Endpoint endpoint, boolean isLocal) {        ep = endpoint;        id = objID;        this.isLocal = isLocal;    }     /**     * Construct a new live reference for a server object in the local     * address space.     */    public LiveRef(int port) {        this((new ObjID()), port);    }     /**     * Construct a new live reference for a server object in the local     * address space, to use sockets of the specified type.     */    public LiveRef(int port,                   RMIClientSocketFactory csf,                   RMIServerSocketFactory ssf)    {        this((new ObjID()), port, csf, ssf);    }     /**     * Construct a new live reference for a "well-known" server object     * in the local address space.     */    public LiveRef(ObjID objID, int port) {        this(objID, TCPEndpoint.getLocalEndpoint(port), true);    }     /**     * Construct a new live reference for a "well-known" server object     * in the local address space, to use sockets of the specified type.     */    public LiveRef(ObjID objID, int port, RMIClientSocketFactory csf,                   RMIServerSocketFactory ssf)    {        this(objID, TCPEndpoint.getLocalEndpoint(port, csf, ssf), true);    }     /**     * Return a shallow copy of this ref.     */    public Object clone() {        try {            LiveRef newRef = (LiveRef) super.clone();            return newRef;        } catch (CloneNotSupportedException e) {            throw new InternalError(e.toString());        }    }     /**     * Return the port number associated with this ref.     */    public int getPort() {        return ((TCPEndpoint) ep).getPort();    }     /**     * Return the client socket factory associated with this ref.     *     * NOTE: There is a JDK-internal dependency on the existence of     * this method in the implementation of     * javax.management.remote.rmi.RMIConnector.     **/    public RMIClientSocketFactory getClientSocketFactory() {        return ((TCPEndpoint) ep).getClientSocketFactory();    }     /**     * Return the server socket factory associated with this ref.     */    public RMIServerSocketFactory getServerSocketFactory() {        return ((TCPEndpoint) ep).getServerSocketFactory();    }     /**     * Export the object to accept incoming calls.     */    public void exportObject(Target target) throws RemoteException {        ep.exportObject(target);    }     public Channel getChannel() throws RemoteException {        if (ch == null) {            ch = ep.getChannel();        }        return ch;    }     public ObjID getObjID() {        return id;    }     Endpoint getEndpoint() {        return ep;    }     public String toString() {        String type;         if (isLocal)            type = "local";        else            type = "remote";        return "[endpoint:" + ep + "(" + type + ")," +            "objID:" + id + "]";    }     public int hashCode() {        return id.hashCode();    }     public boolean equals(Object obj) {        if (obj != null && obj instanceof LiveRef) {            LiveRef ref = (LiveRef) obj;             return (ep.equals(ref.ep) && id.equals(ref.id) &&                    isLocal == ref.isLocal);        } else {            return false;        }    }     public boolean remoteEquals(Object obj) {        if (obj != null && obj instanceof LiveRef) {            LiveRef ref = (LiveRef) obj;             TCPEndpoint thisEp = ((TCPEndpoint) ep);            TCPEndpoint refEp = ((TCPEndpoint) ref.ep);             RMIClientSocketFactory thisClientFactory =                thisEp.getClientSocketFactory();            RMIClientSocketFactory refClientFactory =                refEp.getClientSocketFactory();             /**             * Fix for 4254103: LiveRef.remoteEquals should not fail             * if one of the objects in the comparison has a null             * server socket.  Comparison should only consider the             * following criteria:             *             * hosts, ports, client socket factories and object IDs.             */            if (thisEp.getPort() != refEp.getPort() ||                !thisEp.getHost().equals(refEp.getHost()))            {                return false;            }            if ((thisClientFactory == null) ^ (refClientFactory == null)) {                return false;            }            if ((thisClientFactory != null) &&                !((thisClientFactory.getClass() ==                   refClientFactory.getClass()) &&                  (thisClientFactory.equals(refClientFactory))))            {                return false;            }            return (id.equals(ref.id));        } else {            return false;        }    }     public void write(ObjectOutput out, boolean useNewFormat)        throws IOException    {        boolean isResultStream = false;        if (out instanceof ConnectionOutputStream) {            ConnectionOutputStream stream = (ConnectionOutputStream) out;            isResultStream = stream.isResultStream();            /*             * Ensure that referential integrity is not broken while             * this LiveRef is in transit.  If it is being marshalled             * as part of a result, it may not otherwise be strongly             * reachable after the remote call has completed; even if             * it is being marshalled as part of an argument, the VM             * may determine that the reference on the stack is no             * longer reachable after marshalling (see 6181943)--             * therefore, tell the stream to save a reference until a             * timeout expires or, for results, a DGCAck message has             * been received from the caller, or for arguments, the             * remote call has completed.  For a "local" LiveRef, save             * a reference to the impl directly, because the impl is             * not reachable from the LiveRef (see 4114579);             * otherwise, save a reference to the LiveRef, for the             * client-side DGC to watch over.  (Also see 4017232.)             */            if (isLocal) {                ObjectEndpoint oe =                    new ObjectEndpoint(id, ep.getInboundTransport());                Target target = ObjectTable.getTarget(oe);                 if (target != null) {                    Remote impl = target.getImpl();                    if (impl != null) {                        stream.saveObject(impl);                    }                }            } else {                stream.saveObject(this);            }        }        // All together now write out the endpoint, id, and flag         // (need to choose whether or not to use old JDK1.1 endpoint format)        if (useNewFormat) {            ((TCPEndpoint) ep).write(out);        } else {            ((TCPEndpoint) ep).writeHostPortFormat(out);        }        id.write(out);        out.writeBoolean(isResultStream);    }     public static LiveRef read(ObjectInput in, boolean useNewFormat)        throws IOException, ClassNotFoundException    {        Endpoint ep;        ObjID id;         // Now read in the endpoint, id, and result flag        // (need to choose whether or not to read old JDK1.1 endpoint format)        if (useNewFormat) {            ep = TCPEndpoint.read(in);        } else {            ep = TCPEndpoint.readHostPortFormat(in);        }        id = ObjID.read(in);        boolean isResultStream = in.readBoolean();         LiveRef ref = new LiveRef(id, ep, false);         if (in instanceof ConnectionInputStream) {            ConnectionInputStream stream = (ConnectionInputStream)in;            // save ref to send "dirty" call after all args/returns            // have been unmarshaled.            stream.saveRef(ref);            if (isResultStream) {                // set flag in stream indicating that remote objects were                // unmarshaled.  A DGC ack should be sent by the transport.                stream.setAckNeeded();            }        } else {            DGCClient.registerRefs(ep, Arrays.asList(new LiveRef[] { ref }));        }         return ref;    }}