/*
* Copyright (c) 1997, 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 java.rmi.activation;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.rmi.MarshalledObject;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.UnmarshalException;
import java.rmi.server.RemoteObject;
import java.rmi.server.RemoteObjectInvocationHandler;
import java.rmi.server.RemoteRef;
import java.rmi.server.UID;
/**
* Activation makes use of special identifiers to denote remote
* objects that can be activated over time. An activation identifier
* (an instance of the class ActivationID
) contains several
* pieces of information needed for activating an object:
*
* * An activation identifier for an object can be obtained by registering * an object with the activation system. Registration is accomplished * in a few ways:
Activatable.register
method
* Activatable
constructor (that takes
* three arguments and both registers and exports the object, and
* Activatable.exportObject
method
* that takes the activation descriptor, object and port as arguments;
* this method both registers and exports the object. ActivationID
takes a single
* argument, activator, that specifies a remote reference to the
* activator responsible for activating the object associated with
* this identifier. An instance of ActivationID
is globally
* unique.
*
* @param activator reference to the activator responsible for
* activating the object
* @since 1.2
*/
public ActivationID(Activator activator) {
this.activator = activator;
}
/**
* Activate the object for this id.
*
* @param force if true, forces the activator to contact the group
* when activating the object (instead of returning a cached reference);
* if false, returning a cached value is acceptable.
* @return the reference to the active remote object
* @exception ActivationException if activation fails
* @exception UnknownObjectException if the object is unknown
* @exception RemoteException if remote call fails
* @since 1.2
*/
public Remote activate(boolean force)
throws ActivationException, UnknownObjectException, RemoteException
{
try {
MarshalledObject extends Remote> mobj =
activator.activate(this, force);
return mobj.get();
} catch (RemoteException e) {
throw e;
} catch (IOException e) {
throw new UnmarshalException("activation failed", e);
} catch (ClassNotFoundException e) {
throw new UnmarshalException("activation failed", e);
}
}
/**
* Returns a hashcode for the activation id. Two identifiers that
* refer to the same remote object will have the same hash code.
*
* @see java.util.Hashtable
* @since 1.2
*/
public int hashCode() {
return uid.hashCode();
}
/**
* Compares two activation ids for content equality.
* Returns true if both of the following conditions are true:
* 1) the unique identifiers equivalent (by content), and
* 2) the activator specified in each identifier
* refers to the same remote object.
*
* @param obj the Object to compare with
* @return true if these Objects are equal; false otherwise.
* @see java.util.Hashtable
* @since 1.2
*/
public boolean equals(Object obj) {
if (obj instanceof ActivationID) {
ActivationID id = (ActivationID) obj;
return (uid.equals(id.uid) && activator.equals(id.activator));
} else {
return false;
}
}
/**
* writeObject
for custom serialization.
*
* This method writes this object's serialized form for * this class as follows: * *
The writeObject
method is invoked on
* out
passing this object's unique identifier
* (a {@link java.rmi.server.UID UID} instance) as the argument.
*
*
Next, the {@link
* java.rmi.server.RemoteRef#getRefClass(java.io.ObjectOutput)
* getRefClass} method is invoked on the activator's
* RemoteRef
instance to obtain its external ref
* type name. Next, the writeUTF
method is
* invoked on out
with the value returned by
* getRefClass
, and then the
* writeExternal
method is invoked on the
* RemoteRef
instance passing out
* as the argument.
*
* @serialData The serialized data for this class comprises a
* java.rmi.server.UID
(written with
* ObjectOutput.writeObject
) followed by the
* external ref type name of the activator's
* RemoteRef
instance (a string written with
* ObjectOutput.writeUTF
), followed by the
* external form of the RemoteRef
instance as
* written by its writeExternal
method.
*
*
The external ref type name of the
* RemoteRef
instance is
* determined using the definitions of external ref type
* names specified in the {@link java.rmi.server.RemoteObject
* RemoteObject} writeObject
method
* serialData specification. Similarly, the data
* written by the writeExternal
method and read
* by the readExternal
method of
* RemoteRef
implementation classes
* corresponding to each of the defined external ref type
* names is specified in the {@link
* java.rmi.server.RemoteObject RemoteObject}
* writeObject
method serialData
* specification.
**/
private void writeObject(ObjectOutputStream out)
throws IOException, ClassNotFoundException
{
out.writeObject(uid);
RemoteRef ref;
if (activator instanceof RemoteObject) {
ref = ((RemoteObject) activator).getRef();
} else if (Proxy.isProxyClass(activator.getClass())) {
InvocationHandler handler = Proxy.getInvocationHandler(activator);
if (!(handler instanceof RemoteObjectInvocationHandler)) {
throw new InvalidObjectException(
"unexpected invocation handler");
}
ref = ((RemoteObjectInvocationHandler) handler).getRef();
} else {
throw new InvalidObjectException("unexpected activator type");
}
out.writeUTF(ref.getRefClass(out));
ref.writeExternal(out);
}
/**
* readObject
for custom serialization.
*
*
This method reads this object's serialized form for this * class as follows: * *
The readObject
method is invoked on
* in
to read this object's unique identifier
* (a {@link java.rmi.server.UID UID} instance).
*
*
Next, the readUTF
method is invoked on
* in
to read the external ref type name of the
* RemoteRef
instance for this object's
* activator. Next, the RemoteRef
* instance is created of an implementation-specific class
* corresponding to the external ref type name (returned by
* readUTF
), and the readExternal
* method is invoked on that RemoteRef
instance
* to read the external form corresponding to the external
* ref type name.
*
*
Note: If the external ref type name is
* "UnicastRef"
, "UnicastServerRef"
,
* "UnicastRef2"
, "UnicastServerRef2"
,
* or "ActivatableRef"
, a corresponding
* implementation-specific class must be found, and its
* readExternal
method must read the serial data
* for that external ref type name as specified to be written
* in the serialData documentation for this class.
* If the external ref type name is any other string (of non-zero
* length), a ClassNotFoundException
will be thrown,
* unless the implementation provides an implementation-specific
* class corresponding to that external ref type name, in which
* case the RemoteRef
will be an instance of
* that implementation-specific class.
*/
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException
{
uid = (UID)in.readObject();
try {
Class extends RemoteRef> refClass =
Class.forName(RemoteRef.packagePrefix + "." + in.readUTF())
.asSubclass(RemoteRef.class);
RemoteRef ref = refClass.newInstance();
ref.readExternal(in);
activator = (Activator)
Proxy.newProxyInstance(null,
new Class>[] { Activator.class },
new RemoteObjectInvocationHandler(ref));
} catch (InstantiationException e) {
throw (IOException)
new InvalidObjectException(
"Unable to create remote reference").initCause(e);
} catch (IllegalAccessException e) {
throw (IOException)
new InvalidObjectException(
"Unable to create remote reference").initCause(e);
}
}
}