/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.jini.activation;
import java.rmi.RemoteException;
import java.rmi.activation.ActivationException;
import java.rmi.activation.ActivationGroupDesc;
import java.rmi.activation.ActivationGroupID;
import java.rmi.activation.ActivationID;
import java.rmi.server.RMIClassLoader;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
import net.jini.export.Exporter;
import net.jini.security.Security;
/**
* Subclass of {@link java.rmi.activation.ActivationGroup
* java.rmi.activation.ActivationGroup} to allow activatable objects that
* are exported using an {@link Exporter} to go inactive.
*
* <p>This class can be used only productively in conjunction with an
* activation system daemon implementation that will cause the {@link
* #createGroup createGroup} method of this class to be called. The
* standard <code>rmid</code> does not do this.
*
* @com.sun.jini.impl <!-- Implementation Specifics -->
*
* Unlike <code>rmid</code>, <a
* href="../../../com/sun/jini/phoenix/package-summary.html#package_description">phoenix</a>
* is a configurable Java(TM) Remote Method Invocation (Java RMI)
* activation system daemon implementation that uses
* the {@link #createGroup createGroup} method of this class.
*
* @author Sun Microsystems, Inc.
*
* @since 2.0
**/
public abstract class ActivationGroup
extends java.rmi.activation.ActivationGroup
{
/** current activation group for this virtual machine */
private static ActivationGroup currGroup;
/**
* Constructs an activation group with the specified activation group
* identifier. This constructor exports the group as a
* {@link java.rmi.server.UnicastRemoteObject}. A subclass constructor
* can, if desired, unexport the group and then re-export it a different
* way.
*
* @param id the activation group identifier
* @throws RemoteException if this group could not be exported
*/
protected ActivationGroup(ActivationGroupID id)
throws RemoteException
{
super(id);
}
/**
* Creates and sets the activation group for the current virtual machine.
* This method calls
* {@link java.rmi.activation.ActivationGroup#createGroup
* java.rmi.activation.ActivationGroup.createGroup} with the same
* arguments, and returns the result. This method must be called in
* order to use the {@link #inactive inactive} method of this class.
*
* @param id the activation group identifier
* @param desc the activation group descriptor
* @param incarnation the group incarnation number (zero on initial
* creation)
* @return the created activation group
* @throws ActivationException if a group already exists, if the
* group's class is not a subclass of this class, or if an
* exception occurs creating the group
* @throws SecurityException if a security manager exists and invoking
* its {@link SecurityManager#checkSetFactory checkSetFactory} method
* throws a <code>SecurityException</code>
**/
public static synchronized
java.rmi.activation.ActivationGroup createGroup(
ActivationGroupID id,
final ActivationGroupDesc desc,
long incarnation)
throws ActivationException
{
String className = desc.getClassName();
if (className == null ||
!isAssignableFrom(className, desc.getLocation()))
{
throw new ActivationException("group class not subclass");
}
currGroup = (ActivationGroup)
java.rmi.activation.ActivationGroup.createGroup(id, desc,
incarnation);
return currGroup;
}
/**
* Returns <code>true</code> if the specified class (loaded from the
* specified location) is a subclass of <code>ActivationGroup</code>
* and returns <code>false</code> otherwise.
*
* @return <code>true</code> if the specified class is a subclass
* @throws ActivationException if the specified class could not be
* loaded
**/
private static boolean isAssignableFrom(final String className,
final String location)
throws ActivationException
{
try {
Class cl = (Class) Security.doPrivileged(
new PrivilegedExceptionAction() {
public Object run() throws Exception {
return RMIClassLoader.loadClass(location, className);
}
});
return ActivationGroup.class.isAssignableFrom(cl);
} catch (PrivilegedActionException e) {
throw new ActivationException("unable to load group class",
e.getException());
}
}
/**
* Attempts to make the remote object that is associated with the
* specified activation identifier, and that was exported through the
* specified exporter, inactive. This method calls the
* {@link #inactiveObject inactiveObject} method of the current group
* with the same arguments, and returns the result. The overall effect
* is as follows. The {@link Exporter#unexport unexport} method of the
* specified exporter is called with <code>false</code> as an argument.
* If that call returns <code>false</code>, this method returns
* <code>false</code>. If that call returns <code>true</code>, the
* object is marked inactive in this virtual machine, the {@link
* java.rmi.activation.ActivationMonitor#inactiveObject
* ActivationMonitor.inactiveObject} method of the group's monitor is
* called to inform the activation system daemon that the object is
* inactive, and this method returns <code>true</code>.
*
* @param id the object's activation identifier
* @param exporter the exporter to use to unexport the object
* @return <code>true</code> if the object was successfully made
* inactive; <code>false</code> otherwise
* @throws java.rmi.activation.UnknownObjectException if the object is
* not known to be active (it may already be inactive)
* @throws ActivationException if the group is not active
* @throws RemoteException if the remote call to the activation
* monitor fails
*/
public static boolean inactive(ActivationID id, Exporter exporter)
throws ActivationException, RemoteException
{
ActivationGroup group;
synchronized (ActivationGroup.class) {
group = currGroup;
}
if (group == null) {
throw new ActivationException("group is not active");
}
return group.inactiveObject(id, exporter);
}
/**
* Attempts to make the remote object that is associated with the
* specified activation identifier, and that was exported through the
* specified exporter, inactive. The {@link Exporter#unexport unexport}
* method of the specified exporter is called with <code>false</code>
* as an argument. If that call returns <code>false</code>, this method
* returns <code>false</code>. If that call returns <code>true</code>,
* the object is marked inactive in this virtual machine, the {@link
* java.rmi.activation.ActivationMonitor#inactiveObject
* ActivationMonitor.inactiveObject} method of the group's monitor is
* called to inform the activation system daemon that the object is
* inactive, and this method returns <code>true</code>.
*
* @param id the object's activation identifier
* @param exporter the exporter to use to unexport the object
* @return <code>true</code> if the object was successfully made
* inactive; <code>false</code> otherwise
* @throws java.rmi.activation.UnknownObjectException if the object is
* not known to be active (it may already be inactive)
* @throws ActivationException if the group is not active
* @throws RemoteException if the remote call to the activation
* monitor fails
*/
public abstract boolean inactiveObject(ActivationID id, Exporter exporter)
throws ActivationException, RemoteException;
}