aboutsummaryrefslogtreecommitdiff
path: root/src/share/classes/sun/rmi/server/ActivatableRef.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/share/classes/sun/rmi/server/ActivatableRef.java')
-rw-r--r--src/share/classes/sun/rmi/server/ActivatableRef.java411
1 files changed, 411 insertions, 0 deletions
diff --git a/src/share/classes/sun/rmi/server/ActivatableRef.java b/src/share/classes/sun/rmi/server/ActivatableRef.java
new file mode 100644
index 000000000..94af9b01b
--- /dev/null
+++ b/src/share/classes/sun/rmi/server/ActivatableRef.java
@@ -0,0 +1,411 @@
+/*
+ * Copyright 1997-2003 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.rmi.server;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.lang.reflect.Proxy;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.rmi.*;
+import java.rmi.activation.*;
+import java.rmi.server.Operation;
+import java.rmi.server.RMIClassLoader;
+import java.rmi.server.RemoteCall;
+import java.rmi.server.RemoteObject;
+import java.rmi.server.RemoteObjectInvocationHandler;
+import java.rmi.server.RemoteRef;
+import java.rmi.server.RemoteStub;
+
+public class ActivatableRef implements RemoteRef {
+
+ private static final long serialVersionUID = 7579060052569229166L;
+
+ protected ActivationID id;
+ protected RemoteRef ref;
+ transient boolean force = false;
+
+ private static final int MAX_RETRIES = 3;
+ private static final String versionComplaint =
+ "activation requires 1.2 stubs";
+
+ /**
+ * Create a new (empty) ActivatableRef
+ */
+ public ActivatableRef()
+ {}
+
+ /**
+ * Create a ActivatableRef with the specified id
+ */
+ public ActivatableRef(ActivationID id, RemoteRef ref)
+ {
+ this.id = id;
+ this.ref = ref;
+ }
+
+ /**
+ * Returns the stub for the remote object whose class is
+ * specified in the activation descriptor. The ActivatableRef
+ * in the resulting stub has its activation id set to the
+ * activation id supplied as the second argument.
+ */
+ public static Remote getStub(ActivationDesc desc, ActivationID id)
+ throws StubNotFoundException
+ {
+ String className = desc.getClassName();
+
+ try {
+ Class cl =
+ RMIClassLoader.loadClass(desc.getLocation(), className);
+ RemoteRef clientRef = new ActivatableRef(id, null);
+ return Util.createProxy(cl, clientRef, false);
+
+ } catch (IllegalArgumentException e) {
+ throw new StubNotFoundException(
+ "class implements an illegal remote interface", e);
+
+ } catch (ClassNotFoundException e) {
+ throw new StubNotFoundException("unable to load class: " +
+ className, e);
+ } catch (MalformedURLException e) {
+ throw new StubNotFoundException("malformed URL", e);
+ }
+ }
+
+ /**
+ * Invoke method on remote object. This method delegates remote
+ * method invocation to the underlying ref type. If the
+ * underlying reference is not known (is null), then the object
+ * must be activated first. If an attempt at method invocation
+ * fails, the object should force reactivation. Method invocation
+ * must preserve "at most once" call semantics. In RMI, "at most
+ * once" applies to parameter deserialization at the remote site
+ * and the remote object's method execution. "At most once" does
+ * not apply to parameter serialization at the client so the
+ * parameters of a call don't need to be buffered in anticipation
+ * of call retry. Thus, a method call is only be retried if the
+ * initial method invocation does not execute at all at the server
+ * (including parameter deserialization).
+ */
+ public Object invoke(Remote obj,
+ java.lang.reflect.Method method,
+ Object[] params,
+ long opnum)
+ throws Exception
+ {
+
+ boolean force = false;
+ RemoteRef localRef;
+ Exception exception = null;
+
+ /*
+ * Attempt object activation if active ref is unknown.
+ * Throws a RemoteException if object can't be activated.
+ */
+ synchronized (this) {
+ if (ref == null) {
+ localRef = activate(force);
+ force = true;
+ } else {
+ localRef = ref;
+ }
+ }
+
+ for (int retries = MAX_RETRIES; retries > 0; retries--) {
+
+ try {
+ return localRef.invoke(obj, method, params, opnum);
+ } catch (NoSuchObjectException e) {
+ /*
+ * Object is not active in VM; retry call
+ */
+ exception = e;
+ } catch (ConnectException e) {
+ /*
+ * Failure during connection setup; retry call
+ */
+ exception = e;
+ } catch (UnknownHostException e) {
+ /*
+ * Failure during connection setup; retry call.
+ */
+ exception = e;
+ } catch (ConnectIOException e) {
+ /*
+ * Failure setting up multiplexed connection or reusing
+ * cached connection; retry call
+ */
+ exception = e;
+ } catch (MarshalException e) {
+ /*
+ * Failure during parameter serialization; call may
+ * have reached server, so call retry not possible.
+ */
+ throw e;
+ } catch (ServerError e) {
+ /*
+ * Call reached server; propagate remote exception.
+ */
+ throw e;
+ } catch (ServerException e) {
+ /*
+ * Call reached server; propagate remote exception
+ */
+ throw e;
+ } catch (RemoteException e) {
+ /*
+ * This is a catch-all for other RemoteExceptions.
+ * UnmarshalException being the only one relevant.
+ *
+ * StubNotFoundException should never show up because
+ * it is generally thrown when attempting to locate
+ * a stub.
+ *
+ * UnexpectedException should never show up because
+ * it is only thrown by a stub and would be wrapped
+ * in a ServerException if it was propagated by a
+ * remote call.
+ */
+ synchronized (this) {
+ if (localRef == ref) {
+ ref = null; // this may be overly conservative
+ }
+ }
+
+ throw e;
+ }
+
+ if (retries > 1) {
+ /*
+ * Activate object, since object could not be reached.
+ */
+ synchronized (this) {
+ if (localRef.remoteEquals(ref) || ref == null) {
+ RemoteRef newRef = activate(force);
+
+ if (newRef.remoteEquals(localRef) &&
+ exception instanceof NoSuchObjectException &&
+ force == false) {
+ /*
+ * If last exception was NoSuchObjectException,
+ * then old value of ref is definitely wrong,
+ * so make sure that it is different.
+ */
+ newRef = activate(true);
+ }
+
+ localRef = newRef;
+ force = true;
+ } else {
+ localRef = ref;
+ force = false;
+ }
+ }
+ }
+ }
+
+ /*
+ * Retries unsuccessful, so throw last exception
+ */
+ throw exception;
+ }
+
+ /**
+ * private method to obtain the ref for a call.
+ */
+ private synchronized RemoteRef getRef()
+ throws RemoteException
+ {
+ if (ref == null) {
+ ref = activate(false);
+ }
+
+ return ref;
+ }
+
+ /**
+ * private method to activate the remote object.
+ *
+ * NOTE: the caller must be synchronized on "this" before
+ * calling this method.
+ */
+ private RemoteRef activate(boolean force)
+ throws RemoteException
+ {
+ assert Thread.holdsLock(this);
+
+ ref = null;
+ try {
+ /*
+ * Activate the object and retrieve the remote reference
+ * from inside the stub returned as the result. Then
+ * set this activatable ref's internal ref to be the
+ * ref inside the ref of the stub. In more clear terms,
+ * the stub returned from the activate call contains an
+ * ActivatableRef. We need to set the ref in *this*
+ * ActivatableRef to the ref inside the ActivatableRef
+ * retrieved from the stub. The ref type embedded in the
+ * ActivatableRef is typically a UnicastRef.
+ */
+
+ Remote proxy = id.activate(force);
+ ActivatableRef newRef = null;
+
+ if (proxy instanceof RemoteStub) {
+ newRef = (ActivatableRef) ((RemoteStub) proxy).getRef();
+ } else {
+ /*
+ * Assume that proxy is an instance of a dynamic proxy
+ * class. If that assumption is not correct, or either of
+ * the casts below fails, the resulting exception will be
+ * wrapped in an ActivateFailedException below.
+ */
+ RemoteObjectInvocationHandler handler =
+ (RemoteObjectInvocationHandler)
+ Proxy.getInvocationHandler(proxy);
+ newRef = (ActivatableRef) handler.getRef();
+ }
+ ref = newRef.ref;
+ return ref;
+
+ } catch (ConnectException e) {
+ throw new ConnectException("activation failed", e);
+ } catch (RemoteException e) {
+ throw new ConnectIOException("activation failed", e);
+ } catch (UnknownObjectException e) {
+ throw new NoSuchObjectException("object not registered");
+ } catch (ActivationException e) {
+ throw new ActivateFailedException("activation failed", e);
+ }
+ }
+
+ /**
+ * This call is used by the old 1.1 stub protocol and is
+ * unsupported since activation requires 1.2 stubs.
+ */
+ public synchronized RemoteCall newCall(RemoteObject obj,
+ Operation[] ops,
+ int opnum,
+ long hash)
+ throws RemoteException
+ {
+ throw new UnsupportedOperationException(versionComplaint);
+ }
+
+ /**
+ * This call is used by the old 1.1 stub protocol and is
+ * unsupported since activation requires 1.2 stubs.
+ */
+ public void invoke(RemoteCall call) throws Exception
+ {
+ throw new UnsupportedOperationException(versionComplaint);
+ }
+
+ /**
+ * This call is used by the old 1.1 stub protocol and is
+ * unsupported since activation requires 1.2 stubs.
+ */
+ public void done(RemoteCall call) throws RemoteException {
+ throw new UnsupportedOperationException(versionComplaint);
+ }
+
+ /**
+ * Returns the class of the ref type to be serialized
+ */
+ public String getRefClass(ObjectOutput out)
+ {
+ return "ActivatableRef";
+ }
+
+ /**
+ * Write out external representation for remote ref.
+ */
+ public void writeExternal(ObjectOutput out) throws IOException
+ {
+ RemoteRef localRef = ref;
+
+ out.writeObject(id);
+ if (localRef == null) {
+ out.writeUTF("");
+ } else {
+ out.writeUTF(localRef.getRefClass(out));
+ localRef.writeExternal(out);
+ }
+ }
+
+ /**
+ * Read in external representation for remote ref.
+ * @exception ClassNotFoundException If the class for an object
+ * being restored cannot be found.
+ */
+ public void readExternal(ObjectInput in)
+ throws IOException, ClassNotFoundException
+ {
+ id = (ActivationID)in.readObject();
+ ref = null;
+ String className = in.readUTF();
+
+ if (className.equals("")) return;
+
+ try {
+ Class refClass = Class.forName(RemoteRef.packagePrefix + "." +
+ className);
+ ref = (RemoteRef)refClass.newInstance();
+ ref.readExternal(in);
+ } catch (InstantiationException e) {
+ throw new UnmarshalException("Unable to create remote reference",
+ e);
+ } catch (IllegalAccessException e) {
+ throw new UnmarshalException("Illegal access creating remote reference");
+ }
+ }
+
+ //----------------------------------------------------------------------;
+ /**
+ * Method from object, forward from RemoteObject
+ */
+ public String remoteToString() {
+ return Util.getUnqualifiedName(getClass()) +
+ " [remoteRef: " + ref + "]";
+ }
+
+ /**
+ * default implementation of hashCode for remote objects
+ */
+ public int remoteHashCode() {
+ return id.hashCode();
+ }
+
+ /** default implementation of equals for remote objects
+ */
+ public boolean remoteEquals(RemoteRef ref) {
+ if (ref instanceof ActivatableRef)
+ return id.equals(((ActivatableRef)ref).id);
+ return false;
+ }
+}