You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@river.apache.org by pe...@apache.org on 2013/05/22 14:46:26 UTC
svn commit: r1485194 [1/2] - in /river/jtsk/skunk/qa_refactor/trunk: qa/
qa/src/com/sun/jini/qa/harness/
qa/src/com/sun/jini/test/impl/outrigger/transaction/
qa/src/com/sun/jini/test/share/ src/com/sun/jini/fiddler/
src/com/sun/jini/norm/ src/com/sun/j...
Author: peter_firmstone
Date: Wed May 22 12:46:25 2013
New Revision: 1485194
URL: http://svn.apache.org/r1485194
Log:
River-420 Fixes for unsafe publication during construction.
Added:
river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/phoenix/AbstractActivationGroup.java
- copied, changed from r1484449, river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/phoenix/ActivationGroupImpl.java
river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/start/AbstractSharedGroup.java
- copied, changed from r1484449, river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/start/SharedGroupImpl.java
river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/start/AbstractSharedGroupInit.java
Modified:
river/jtsk/skunk/qa_refactor/trunk/qa/ (props changed)
river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/qa/harness/KillerImpl.java
river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/qa/harness/NonActivatableGroupImpl.java
river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/impl/outrigger/transaction/SimpleEventListener.java
river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/share/DiscoveryServiceUtil.java
river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/share/LeaseBackEndImpl.java
river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/fiddler/FiddlerImpl.java
river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/norm/ActivatableNormServerImpl.java
river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/norm/NormServerBaseImpl.java
river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/outrigger/OutriggerServerImpl.java
river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/outrigger/OutriggerServerWrapper.java
river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/phoenix/ActivationGroupImpl.java
river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/start/SharedGroupImpl.java
river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/start/Starter.java
Propchange: river/jtsk/skunk/qa_refactor/trunk/qa/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Wed May 22 12:46:25 2013
@@ -1,6 +1,7 @@
+hs_err_pid4712.log
classes
-lib-ext
result
+lib-ext
lib
build.properties
riverruntimelastbuild
Modified: river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/qa/harness/KillerImpl.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/qa/harness/KillerImpl.java?rev=1485194&r1=1485193&r2=1485194&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/qa/harness/KillerImpl.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/qa/harness/KillerImpl.java Wed May 22 12:46:25 2013
@@ -25,6 +25,7 @@ import java.rmi.MarshalledObject;
import java.rmi.NoSuchObjectException;
import java.rmi.Remote;
import java.rmi.RemoteException;
+import java.rmi.server.ExportException;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -51,10 +52,10 @@ class KillerImpl
Logger.getLogger("com.sun.jini.qa.harness");
/** The inner proxy of this server */
- private final Remote ourStub;
+ private Remote ourStub;
/** The exporter */
- Exporter exporter;
+ final Exporter exporter;
/**
* Shared activation constructor required by the
@@ -66,13 +67,29 @@ class KillerImpl
public KillerImpl(ActivationID activationID, MarshalledObject data)
throws IOException, ClassNotFoundException
{
- logger.log(Level.INFO, "Starting VMKiller service");
- exporter =
+ this(getExporter(activationID));
+ // Before we call export, the final freeze has occurred after calling
+ // our private constructor, we are also synchronized during export.
+ export();
+ }
+
+ private KillerImpl(Exporter exporter) throws
+ IOException, ClassNotFoundException
+ {
+ this.exporter = exporter;
+ }
+
+ private static Exporter getExporter(ActivationID activationID){
+ logger.log(Level.INFO, "Starting VMKiller service");
+ return
new ActivationExporter(
activationID,
new BasicJeriExporter(TcpServerEndpoint.getInstance(0),
new BasicILFactory()));
- ourStub = exporter.export(this);
+ }
+
+ private synchronized void export() throws ExportException{
+ ourStub = exporter.export(this);
}
// inherit javadoc
@@ -81,7 +98,7 @@ class KillerImpl
System.exit(0);
}
- public Object getAdmin() throws RemoteException {
+ public synchronized Object getAdmin() throws RemoteException {
return ourStub;
}
@@ -159,7 +176,7 @@ class KillerImpl
}
// inherit javadoc
- public Object getProxy() {
+ public synchronized Object getProxy() {
return ourStub;
}
}
Modified: river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/qa/harness/NonActivatableGroupImpl.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/qa/harness/NonActivatableGroupImpl.java?rev=1485194&r1=1485193&r2=1485194&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/qa/harness/NonActivatableGroupImpl.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/qa/harness/NonActivatableGroupImpl.java Wed May 22 12:46:25 2013
@@ -93,30 +93,40 @@ class NonActivatableGroupImpl {
private Object proxy;
/** the groups exporter */
- private Exporter exporter;
+ private final Exporter exporter;
/** store service references here to ensure no GC interference */
- private ArrayList serviceList = new ArrayList();
+ private final ArrayList serviceList = new ArrayList();
/**
* Construct a <code>NonActivatableGroup</code>. Instances export themselves
* at construction time using a <code>JrmpExporter</code>.
*/
public GroupImpl() {
- exporter = new JrmpExporter();
- try {
- proxy = exporter.export(this);
+ this (new JrmpExporter());
+ export();
+ }
+
+ private GroupImpl(Exporter exporter){
+ this.exporter = exporter;
+ }
+
+ private void export(){
+ try {
+ synchronized (this){
+ proxy = exporter.export(this);
+ }
} catch (ExportException e) {
e.printStackTrace();
try {Thread.sleep(5000);} catch (Exception e2){}
throw new RuntimeException("Export of group failed", e);
}
- }
-
+ }
+
/**
* Return the proxy for the NonActivatableGroup remote object
*/
- Object getProxy() {
+ synchronized Object getProxy() {
return proxy;
}
@@ -180,7 +190,9 @@ class NonActivatableGroupImpl {
}
try {
Created created = (Created) desc.create(starterConfig);
- serviceList.add(created);
+ synchronized (this){
+ serviceList.add(created);
+ }
return created.proxy;
} catch (Exception e) {
throw new RemoteException("Create failed", e);
@@ -193,7 +205,7 @@ class NonActivatableGroupImpl {
*/
private static class DestroyThread extends Thread {
- Exporter exporter;
+ final Exporter exporter;
/** Create a non-daemon thread */
public DestroyThread(Exporter exporter) {
Modified: river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/impl/outrigger/transaction/SimpleEventListener.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/impl/outrigger/transaction/SimpleEventListener.java?rev=1485194&r1=1485193&r2=1485194&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/impl/outrigger/transaction/SimpleEventListener.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/impl/outrigger/transaction/SimpleEventListener.java Wed May 22 12:46:25 2013
@@ -34,6 +34,7 @@ import net.jini.security.proxytrust.Serv
import com.sun.jini.proxy.BasicProxyTrustVerifier;
import com.sun.jini.qa.harness.QAConfig;
+import java.rmi.server.ExportException;
/**
* Simple event listener class.
@@ -46,25 +47,40 @@ public class SimpleEventListener
{
private long maxSeqNum = 0;
private Object proxy;
+ private final Exporter exporter;
public SimpleEventListener(Configuration c) throws RemoteException {
- try {
+ this(getExporter(c));
+ //
+ export();
+ }
+
+ private SimpleEventListener(Exporter exporter){
+ this.exporter = exporter;
+ }
+
+ private static Exporter getExporter(Configuration c) throws RemoteException {
+ try {
Exporter exporter = QAConfig.getDefaultExporter();
if (c instanceof com.sun.jini.qa.harness.QAConfiguration) {
exporter =
(Exporter) c.getEntry("test", "outriggerListenerExporter", Exporter.class);
}
- proxy = exporter.export(this);
+ return exporter;
} catch (ConfigurationException e) {
throw new IllegalArgumentException("Bad configuration" + e);
}
}
+
+ private synchronized void export() throws ExportException{
+ proxy = exporter.export(this);
+ }
- public Object writeReplace() throws ObjectStreamException {
+ public synchronized Object writeReplace() throws ObjectStreamException {
return proxy;
}
- public TrustVerifier getProxyVerifier() {
+ public synchronized TrustVerifier getProxyVerifier() {
return new BasicProxyTrustVerifier(proxy);
}
@@ -74,7 +90,7 @@ public class SimpleEventListener
*
* @param ev Remote event object.
*/
- public void notify(RemoteEvent ev) throws RemoteException {
+ public synchronized void notify(RemoteEvent ev) throws RemoteException {
maxSeqNum = Math.max(ev.getSequenceNumber(), maxSeqNum);
}
@@ -83,7 +99,7 @@ public class SimpleEventListener
*
* @return number of <code>notify</code> called.
*/
- public long getNotifyCount(EventRegistration reg) {
+ public synchronized long getNotifyCount(EventRegistration reg) {
return (maxSeqNum - reg.getSequenceNumber());
}
}
Modified: river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/share/DiscoveryServiceUtil.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/share/DiscoveryServiceUtil.java?rev=1485194&r1=1485193&r2=1485194&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/share/DiscoveryServiceUtil.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/share/DiscoveryServiceUtil.java Wed May 22 12:46:25 2013
@@ -79,17 +79,19 @@ public class DiscoveryServiceUtil {
throw new RemoteException("Configuration problem", e);
}
}
- proxy = exporter.export(this);
+ synchronized (this){
+ proxy = exporter.export(this);
+ }
}
- private Object writeReplace() throws ObjectStreamException {
+ private synchronized Object writeReplace() throws ObjectStreamException {
return proxy;
}
public void notify(RemoteEvent ev) {
}
- public TrustVerifier getProxyVerifier() {
+ public synchronized TrustVerifier getProxyVerifier() {
return new BasicProxyTrustVerifier(proxy);
}
}//end class BasicEventListener
Modified: river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/share/LeaseBackEndImpl.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/share/LeaseBackEndImpl.java?rev=1485194&r1=1485193&r2=1485194&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/share/LeaseBackEndImpl.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/share/LeaseBackEndImpl.java Wed May 22 12:46:25 2013
@@ -31,6 +31,7 @@ import java.io.Serializable;
import com.sun.jini.qa.harness.QATestEnvironment;
import com.sun.jini.qa.harness.QAConfig;
+import java.rmi.server.ExportException;
import net.jini.export.Exporter;
import net.jini.config.Configuration;
@@ -63,7 +64,10 @@ public class LeaseBackEndImpl implements
/**
* The TestLease factory used to create TestLease instances
*/
- final private AbstractTestLeaseFactory testLeaseFactory;
+ private AbstractTestLeaseFactory testLeaseFactory;
+
+ final private Exporter exporter;
+ final private Class factoryClass;
/**
* Simple constructor
@@ -106,7 +110,12 @@ public class LeaseBackEndImpl implements
throw new RemoteException("Configuration error", e);
}
}
- LeaseBackEnd stub =
+ this.exporter = exporter;
+ this.factoryClass = factoryClass;
+ }
+
+ private synchronized void export() throws ExportException, RemoteException {
+ LeaseBackEnd stub =
(LeaseBackEnd) exporter.export(this);
// create the lease factory
@@ -139,13 +148,8 @@ public class LeaseBackEndImpl implements
}
/** Return the array of owners */
- public LeaseOwner[] getOwners() {
- return owners;
- }
-
- /** Return the array of leases */
- TestLease[] getLeases() {
- return leases;
+ public synchronized LeaseOwner[] getOwners() {
+ return owners.clone();
}
// inherit doc comment
Modified: river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/fiddler/FiddlerImpl.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/fiddler/FiddlerImpl.java?rev=1485194&r1=1485193&r2=1485194&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/fiddler/FiddlerImpl.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/fiddler/FiddlerImpl.java Wed May 22 12:46:25 2013
@@ -385,6 +385,8 @@ class FiddlerImpl implements ServerProxy
private boolean persistent;
private LocalLogHandler logHandler;
private AccessControlContext context;
+
+ private boolean started;
/* ************************* BEGIN Constructors ************************ */
/**
@@ -5154,8 +5156,12 @@ class FiddlerImpl implements ServerProxy
/* **************** END Private Static Utility Methods ***************** */
/* BEGIN public start method*/
- public void start() throws Exception
+ public void start() throws IOException, ActivationException, ConfigurationException, LoginException, ClassNotFoundException
{
+ synchronized (this){
+ if (started) return;
+ started = true;
+ }
try {
AccessController.doPrivileged(new PrivilegedExceptionAction(){
Modified: river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/norm/ActivatableNormServerImpl.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/norm/ActivatableNormServerImpl.java?rev=1485194&r1=1485193&r2=1485194&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/norm/ActivatableNormServerImpl.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/norm/ActivatableNormServerImpl.java Wed May 22 12:46:25 2013
@@ -46,10 +46,10 @@ import net.jini.security.ProxyPreparer;
*/
class ActivatableNormServerImpl extends NormServerBaseImpl {
/** Our activation ID */
- private ActivationID activationID;
+ private final ActivationID activationID;
/** The activation system, prepared */
- private ActivationSystem activationSystem;
+ private final ActivationSystem activationSystem;
// Inherit java doc from super type
public void destroy() throws RemoteException {
Modified: river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/norm/NormServerBaseImpl.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/norm/NormServerBaseImpl.java?rev=1485194&r1=1485193&r2=1485194&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/norm/NormServerBaseImpl.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/norm/NormServerBaseImpl.java Wed May 22 12:46:25 2013
@@ -245,6 +245,8 @@ abstract class NormServerBaseImpl
* set to null at completion of start() */
private AccessControlContext context;
private Configuration config;
+
+ private boolean started;
////////////////////////////////
// Methods defined in NormServer
@@ -1828,6 +1830,10 @@ abstract class NormServerBaseImpl
}
public void start() throws Exception {
+ synchronized (this){
+ if (started) return;
+ started = true;
+ }
try {
AccessController.doPrivileged(new PrivilegedExceptionAction(){
Modified: river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/outrigger/OutriggerServerImpl.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/outrigger/OutriggerServerImpl.java?rev=1485194&r1=1485193&r2=1485194&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/outrigger/OutriggerServerImpl.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/outrigger/OutriggerServerImpl.java Wed May 22 12:46:25 2013
@@ -79,6 +79,7 @@ import java.rmi.UnmarshalException;
import java.rmi.activation.ActivationID;
import java.rmi.activation.ActivationSystem;
import java.rmi.activation.ActivationException;
+import java.rmi.server.ExportException;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.SecureRandom;
@@ -641,7 +642,7 @@ public class OutriggerServerImpl
}
}
- public void start() throws Exception {
+ public void start() throws IOException, ConfigurationException, LoginException {
// Threads are created with login context if it exists, but started in
// privileged context.
synchronized (this){
@@ -649,12 +650,18 @@ public class OutriggerServerImpl
started = true;
}
if (thrown != null) throw (Error) thrown;
- if (except != null) throw except;
+ if (except != null){
+ if (except instanceof IOException) throw (IOException) except;
+ else if (except instanceof ConfigurationException) throw (ConfigurationException) except;
+ else if (except instanceof LoginException) throw (LoginException) except;
+ else if (except instanceof RuntimeException) throw (RuntimeException) except;
+ }
+
try {
AccessController.doPrivileged(new PrivilegedExceptionAction(){
@Override
- public Object run() throws Exception {
+ public Object run() throws ExportException, ConfigurationException, IOException {
ourRemoteRef = (OutriggerServer) exporter.export(serverGate);
// This takes a while the first time, so let's get it going
txnMonitor.start();
@@ -729,7 +736,8 @@ public class OutriggerServerImpl
}, context);
- } catch (Exception e) {
+ } catch (PrivilegedActionException ex) {
+ Exception e = ex.getException();
// Clean up and rethrow.
lifecycleLogger.log(Level.SEVERE, "Failed to start Outrigger server", e);
@@ -782,7 +790,10 @@ public class OutriggerServerImpl
// Ignore and go on
}
}
- throw e;
+ if (e instanceof IOException) throw (IOException) e;
+ else if (e instanceof ConfigurationException) throw (ConfigurationException) e;
+ else if (e instanceof LoginException) throw (LoginException) e;
+ else if (e instanceof RuntimeException) throw (RuntimeException) e;
} finally {
config = null;
starter = null;
Modified: river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/outrigger/OutriggerServerWrapper.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/outrigger/OutriggerServerWrapper.java?rev=1485194&r1=1485193&r2=1485194&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/outrigger/OutriggerServerWrapper.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/outrigger/OutriggerServerWrapper.java Wed May 22 12:46:25 2013
@@ -486,7 +486,7 @@ class OutriggerServerWrapper
return delegate.getProxyVerifier();
}
- public void start() throws Exception {
- ((Starter) delegate).start();
+ public void start() throws IOException, ConfigurationException, LoginException {
+ delegate.start();
}
}
Copied: river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/phoenix/AbstractActivationGroup.java (from r1484449, river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/phoenix/ActivationGroupImpl.java)
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/phoenix/AbstractActivationGroup.java?p2=river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/phoenix/AbstractActivationGroup.java&p1=river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/phoenix/ActivationGroupImpl.java&r1=1484449&r2=1485194&rev=1485194&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/phoenix/ActivationGroupImpl.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/phoenix/AbstractActivationGroup.java Wed May 22 12:46:25 2013
@@ -39,6 +39,7 @@ import java.rmi.activation.ActivationID;
import java.rmi.activation.ActivationInstantiator;
import java.rmi.activation.ActivationMonitor;
import java.rmi.activation.ActivationSystem;
+import java.rmi.activation.UnknownGroupException;
import java.rmi.activation.UnknownObjectException;
import java.rmi.server.ExportException;
import java.rmi.server.RMIClassLoader;
@@ -204,7 +205,7 @@ import net.jini.security.proxytrust.Serv
*
* @since 2.0
**/
-public class ActivationGroupImpl extends ActivationGroup
+abstract class AbstractActivationGroup extends ActivationGroup
implements ServerProxyTrust
{
private static final long serialVersionUID = 5758693559430427303L;
@@ -350,7 +351,7 @@ public class ActivationGroupImpl extends
unexportWait = getInt(config, "unexportWait", 10);
ActivationSystem sys = (ActivationSystem)
sysPreparer.prepareProxy(id.getSystem());
- ActivationGroupImpl.incarnation = incarnation;
+ AbstractActivationGroup.incarnation = incarnation;
groupID = id;
state = CREATING;
ActivationGroupID gid = (sys == id.getSystem() ?
@@ -380,7 +381,7 @@ public class ActivationGroupImpl extends
throws ConfigurationException, IOException, ClassNotFoundException
{
ActivationGroupData data = (ActivationGroupData) mobj.get();
- ClassLoader cl = ActivationGroupImpl.class.getClassLoader();
+ ClassLoader cl = AbstractActivationGroup.class.getClassLoader();
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (!covers(cl, ccl)) {
cl = ccl;
@@ -428,6 +429,7 @@ public class ActivationGroupImpl extends
return ((Integer) config.getEntry(PHOENIX, name, int.class,
Integer.valueOf(defValue))).intValue();
}
+ private final ActivationGroupID id;
/**
* ActivationGroupID containing a prepared ActivationSystem proxy and
@@ -485,34 +487,48 @@ public class ActivationGroupImpl extends
* @throws ActivationException if the constructor was not called
* indirectly from <code>createGroup</code>
*/
- public ActivationGroupImpl(ActivationGroupID id, MarshalledObject data)
+ AbstractActivationGroup(ActivationGroupID id, MarshalledObject data)
throws ActivationException, RemoteException
{
super(id);
- synchronized (ActivationGroupImpl.class) {
+ this.id = id;
+ synchronized (AbstractActivationGroup.class) {
if (state != CREATING) {
throw new ActivationException("not called from createGroup");
}
}
- if (refuseCalls) {
- unexportObject(this, true);
- refuseCalls = false;
- }
- proxy = (ActivationInstantiator) exporter.export(this);
- try {
- monitor = (ActivationMonitor) monPreparer.prepareProxy(
- id.getSystem().activeGroup(id, proxy, incarnation));
- state = CREATED;
- } finally {
- if (state != CREATED) {
- exporter.unexport(true);
+
+ }
+
+ void export() throws NoSuchObjectException, ExportException,
+ RemoteException, UnknownGroupException, ActivationException
+ {
+ synchronized (AbstractActivationGroup.class) {
+ if (state != CREATING) {
+ throw new ActivationException("not called from createGroup");
}
- }
- monPreparer = null;
+ if (refuseCalls) {
+ unexportObject(this, true);
+ refuseCalls = false;
+ }
+ proxy = (ActivationInstantiator) exporter.export(this);
+ try {
+ monitor = (ActivationMonitor) monPreparer.prepareProxy(
+ id.getSystem().activeGroup(id, proxy, incarnation));
+ state = CREATED;
+ } finally {
+ if (state != CREATED) {
+ exporter.unexport(true);
+ }
+ }
+ monPreparer = null;
+ }
}
public TrustVerifier getProxyVerifier() {
- return new BasicProxyTrustVerifier(proxy);
+ synchronized (AbstractActivationGroup.class){
+ return new BasicProxyTrustVerifier(proxy);
+ }
}
/**
@@ -559,7 +575,9 @@ public class ActivationGroupImpl extends
* @return the proxy for this remote object
*/
protected Object writeReplace() {
- return proxy;
+ synchronized (AbstractActivationGroup.class){
+ return proxy;
+ }
}
/*
@@ -682,7 +700,7 @@ public class ActivationGroupImpl extends
final ActivationDesc desc)
throws ActivationException
{
- synchronized (ActivationGroupImpl.class) {
+ synchronized (AbstractActivationGroup.class) {
if (refuseCalls) {
throw new SecurityException("call refused");
}
@@ -691,7 +709,7 @@ public class ActivationGroupImpl extends
acquireLock(id);
try {
ActiveEntry entry;
- synchronized (ActivationGroupImpl.class) {
+ synchronized (AbstractActivationGroup.class) {
if (state != ACTIVE) {
throw new InactiveGroupException("group not active");
}
@@ -758,7 +776,7 @@ public class ActivationGroupImpl extends
}
entry = new ActiveEntry(impl);
- synchronized (ActivationGroupImpl.class) {
+ synchronized (AbstractActivationGroup.class) {
active.put(id, entry);
}
return entry.mobj;
@@ -824,7 +842,7 @@ public class ActivationGroupImpl extends
acquireLock(id);
try {
ActiveEntry entry;
- synchronized (ActivationGroupImpl.class) {
+ synchronized (AbstractActivationGroup.class) {
if (state != ACTIVE) {
throw new InactiveGroupException("group not active");
}
@@ -852,7 +870,7 @@ public class ActivationGroupImpl extends
} catch (UnknownObjectException allowUnregisteredObjects) {
}
- synchronized (ActivationGroupImpl.class) {
+ synchronized (AbstractActivationGroup.class) {
active.remove(id);
}
} finally {
@@ -902,7 +920,7 @@ public class ActivationGroupImpl extends
acquireLock(id);
try {
ActiveEntry entry;
- synchronized (ActivationGroupImpl.class) {
+ synchronized (AbstractActivationGroup.class) {
if (state != ACTIVE) {
throw new InactiveGroupException("group not active");
}
@@ -927,7 +945,7 @@ public class ActivationGroupImpl extends
} catch (UnknownObjectException allowUnregisteredObjects) {
}
- synchronized (ActivationGroupImpl.class) {
+ synchronized (AbstractActivationGroup.class) {
active.remove(id);
}
} finally {
@@ -943,7 +961,7 @@ public class ActivationGroupImpl extends
* marks it as such, notifies the daemon, and unexports the group.
*/
private static void checkInactiveGroup() {
- synchronized (ActivationGroupImpl.class) {
+ synchronized (AbstractActivationGroup.class) {
if (state == ACTIVE) {
if (!active.isEmpty() || !lockedIDs.isEmpty()) {
return;
@@ -1048,7 +1066,7 @@ public class ActivationGroupImpl extends
final ActiveEntry entry = new ActiveEntry(impl);
acquireLock(id);
try {
- synchronized (ActivationGroupImpl.class) {
+ synchronized (AbstractActivationGroup.class) {
if (state != ACTIVE) {
throw new InactiveGroupException("group not active");
}
@@ -1113,8 +1131,8 @@ public class ActivationGroupImpl extends
* Entry in table for active object.
*/
private static class ActiveEntry {
- Remote impl;
- MarshalledObject mobj;
+ final Remote impl;
+ final MarshalledObject mobj;
ActiveEntry(Remote impl) throws ActivationException {
this.impl = impl;
Modified: river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/phoenix/ActivationGroupImpl.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/phoenix/ActivationGroupImpl.java?rev=1485194&r1=1485193&r2=1485194&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/phoenix/ActivationGroupImpl.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/phoenix/ActivationGroupImpl.java Wed May 22 12:46:25 2013
@@ -1,1139 +1,246 @@
-/*
- * 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 com.sun.jini.phoenix;
-
-import com.sun.jini.thread.Executor;
-import com.sun.jini.thread.GetThreadPoolAction;
-import com.sun.jini.proxy.BasicProxyTrustVerifier;
-import java.io.IOException;
-import java.io.ObjectStreamClass;
-import java.io.ObjectStreamField;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.rmi.MarshalledObject;
-import java.rmi.NoSuchObjectException;
-import java.rmi.Remote;
-import java.rmi.RemoteException;
-import java.rmi.activation.Activatable;
-import java.rmi.activation.ActivationDesc;
-import java.rmi.activation.ActivationException;
-import java.rmi.activation.ActivationGroupDesc;
-import java.rmi.activation.ActivationGroupID;
-import java.rmi.activation.ActivationID;
-import java.rmi.activation.ActivationInstantiator;
-import java.rmi.activation.ActivationMonitor;
-import java.rmi.activation.ActivationSystem;
-import java.rmi.activation.UnknownObjectException;
-import java.rmi.server.ExportException;
-import java.rmi.server.RMIClassLoader;
-import java.rmi.server.RemoteObject;
-import java.rmi.server.UnicastRemoteObject;
-import java.security.AccessController;
-import java.security.Permission;
-import java.security.PrivilegedAction;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import javax.security.auth.Subject;
-import javax.security.auth.login.LoginContext;
-import javax.security.auth.login.LoginException;
-import net.jini.activation.ActivationGroup;
-import net.jini.config.Configuration;
-import net.jini.config.ConfigurationException;
-import net.jini.config.ConfigurationProvider;
-import net.jini.export.Exporter;
-import net.jini.export.ProxyAccessor;
-import net.jini.jeri.BasicJeriExporter;
-import net.jini.jeri.tcp.TcpServerEndpoint;
-import net.jini.security.BasicProxyPreparer;
-import net.jini.security.ProxyPreparer;
-import net.jini.security.Security;
-import net.jini.security.TrustVerifier;
-import net.jini.security.proxytrust.ServerProxyTrust;
-
-/**
- * The default activation group implementation for phoenix. Instances of
- * this class are configurable through a {@link Configuration}, as detailed
- * further below, and provide the necessary support to allow exporter-based
- * remote objects to go inactive. Instances of this class support the
- * creation of remote objects through the normal activatable constructor;
- * an activatable remote object must either implement the {@link
- * ProxyAccessor} interface to return a suitable proxy for the remote
- * object, or the remote object must itself be serializable and marshalling
- * the object must produce a suitable proxy for the remote object.
- *
- * <p>An instance of this class can be configured by specifying an
- * {@link ActivationGroupData} instance containing configuration options
- * as the initialization data for the activation group. Typically
- * this is accomplished indirectly, by setting the
- * <code>groupConfig</code> configuration entry for
- * phoenix itself. The following entries are obtained from the configuration,
- * all for the component named <code>com.sun.jini.phoenix</code>:
- *
- * <table summary="Describes the loginContext configuration entry"
- * border="0" cellpadding="2">
- * <tr valign="top">
- * <th scope="col" summary="layout"> <font size="+1">•</font>
- * <th scope="col" align="left" colspan="2"> <font size="+1"><code>
- * loginContext</code></font>
- * <tr valign="top"> <td>   <th scope="row" align="right">
- * Type: <td> <code>{@link javax.security.auth.login.LoginContext}</code>
- * <tr valign="top"> <td>   <th scope="row" align="right">
- * Default: <td> <code>null</code>
- * <tr valign="top"> <td>   <th scope="row" align="right">
- * Description: <td> JAAS login context
- * </table>
- *
- * <table summary="Describes the inheritGroupSubject configuration entry"
- * border="0" cellpadding="2">
- * <tr valign="top">
- * <th scope="col" summary="layout"> <font size="+1">•</font>
- * <th scope="col" align="left" colspan="2"> <font size="+1"><code>
- * inheritGroupSubject</code></font>
- * <tr valign="top"> <td>   <th scope="row" align="right">
- * Type: <td> <code>boolean</code>
- * <tr valign="top"> <td>   <th scope="row" align="right">
- * Default: <td> <code>false</code>
- * <tr valign="top"> <td>   <th scope="row" align="right">
- * Description: <td> if <code>true</code>, group subject is inherited
- * when an activatable object is created
- * </table>
- *
- * <table summary="Describes the instantiatorExporter configuration entry"
- * border="0" cellpadding="2">
- * <tr valign="top">
- * <th scope="col" summary="layout"> <font size="+1">•</font>
- * <th scope="col" align="left" colspan="2"> <font size="+1"><code>
- * instantiatorExporter</code></font>
- * <tr valign="top"> <td>   <th scope="row" align="right">
- * Type: <td> <code>{@link net.jini.export.Exporter}</code>
- * <tr valign="top"> <td>   <th scope="row" align="right">
- * Default: <td> retains existing JRMP export of instantiator
- * <tr valign="top"> <td>   <th scope="row" align="right">
- * Description: <td> {@link java.rmi.activation.ActivationInstantiator}
- * exporter
- * </table>
- *
- * <table summary="Describes the monitorPreparer configuration entry"
- * border="0" cellpadding="2">
- * <tr valign="top">
- * <th scope="col" summary="layout"> <font size="+1">•</font>
- * <th scope="col" align="left" colspan="2"> <font size="+1"><code>
- * monitorPreparer</code></font>
- * <tr valign="top"> <td>   <th scope="row" align="right">
- * Type: <td> <code>{@link net.jini.security.ProxyPreparer}</code>
- * <tr valign="top"> <td>   <th scope="row" align="right">
- * Default: <td> <code>new {@link
- * net.jini.security.BasicProxyPreparer}()</code>
- * <tr valign="top"> <td>   <th scope="row" align="right">
- * Description: <td> {@link java.rmi.activation.ActivationMonitor}
- * proxy preparer
- * </table>
- *
- * <table summary="Describes the systemPreparer configuration entry"
- * border="0" cellpadding="2">
- * <tr valign="top">
- * <th scope="col" summary="layout"> <font size="+1">•</font>
- * <th scope="col" align="left" colspan="2"> <font size="+1"><code>
- * systemPreparer</code></font>
- * <tr valign="top"> <td>   <th scope="row" align="right">
- * Type: <td> <code>{@link net.jini.security.ProxyPreparer}</code>
- * <tr valign="top"> <td>   <th scope="row" align="right">
- * Default: <td> <code>new {@link
- * net.jini.security.BasicProxyPreparer}()</code>
- * <tr valign="top"> <td>   <th scope="row" align="right">
- * Description: <td> {@link java.rmi.activation.ActivationSystem}
- * proxy preparer
- * </table>
- *
- * <table summary="Describes the unexportTimeout configuration entry"
- * border="0" cellpadding="2">
- * <tr valign="top">
- * <th scope="col" summary="layout"> <font size="+1">•</font>
- * <th scope="col" align="left" colspan="2"> <font size="+1"><code>
- * unexportTimeout</code></font>
- * <tr valign="top"> <td>   <th scope="row" align="right">
- * Type: <td> <code>int</code>
- * <tr valign="top"> <td>   <th scope="row" align="right">
- * Default: <td> <code>60000</code>
- * <tr valign="top"> <td>   <th scope="row" align="right">
- * Description: <td> maximum time in milliseconds to wait for
- * in-progress calls to finish before forcibly unexporting the
- * group when going inactive
- * </table>
- *
- * <table summary="Describes the unexportWait configuration entry"
- * border="0" cellpadding="2">
- * <tr valign="top">
- * <th scope="col" summary="layout"> <font size="+1">•</font>
- * <th scope="col" align="left" colspan="2"> <font size="+1"><code>
- * unexportWait</code></font>
- * <tr valign="top"> <td>   <th scope="row" align="right">
- * Type: <td> <code>int</code>
- * <tr valign="top"> <td>   <th scope="row" align="right">
- * Default: <td> <code>10</code>
- * <tr valign="top"> <td>   <th scope="row" align="right">
- * Description: <td> milliseconds to wait between unexport attempts
- * when going inactive
- * </table>
- *
- * <p>This class depends on its {@link #createGroup createGroup} method being
- * called to initialize the activation group. As such, this class cannot be
- * used in conjunction with the standard <code>rmid</code>.
- *
- * @author Sun Microsystems, Inc.
- *
- * @since 2.0
- **/
-public class ActivationGroupImpl extends ActivationGroup
- implements ServerProxyTrust
-{
- private static final long serialVersionUID = 5758693559430427303L;
-
- private static final String PHOENIX = "com.sun.jini.phoenix";
- /** instance has not been created */
- private static final int UNUSED = 0;
- /** in the middle of createGroup */
- private static final int CREATING = 1;
- /** constructor (including activeGroup) has succeeded */
- private static final int CREATED = 2;
- /** createGroup has succeeded */
- private static final int ACTIVE = 3;
- /** group is inactive */
- private static final int INACTIVE = 4;
- /** parameter types for activatable constructor */
- private static Class[] paramTypes = {
- ActivationID.class, MarshalledObject.class
- };
-
- /* avoid serial field clutter */
- private static final ObjectStreamField[] serialPersistentFields =
- ObjectStreamClass.NO_FIELDS;
-
- private static int state = UNUSED;
- private static long incarnation;
- /** original unprepared group id */
- private static ActivationGroupID groupID;
-
- /** server LoginContext or null */
- private static LoginContext login;
- private static Exporter exporter;
- /** true if calls should be refused, false otherwise */
- private static boolean refuseCalls = false;
- /** monitor proxy preparer */
- private static ProxyPreparer monPreparer;
- private static ActivationMonitor monitor;
- /** timeout on wait for unexport to succeed */
- private static long unexportTimeout;
- /** timeout on wait between unexport attempts */
- private static long unexportWait;
- /** maps ActivationID to ActiveEntry */
- private static Map active = new HashMap();
- /** ActivationIDs with operations in progress */
- private static List lockedIDs = new ArrayList();
- /** true if group subject is inherited when creating activatable objects */
- private static boolean inheritGroupSubject;
-
- /** permission to check for monitor's activeObject call */
- private final static Permission activeObjectPermission =
- new MonitorPermission(
- "java.rmi.activation.ActivationMonitor.activeObject");
-
- /** permission to check for monitor's activeObject call */
- private static Permission inactiveObjectPermission =
- new MonitorPermission(
- "java.rmi.activation.ActivationMonitor.inactiveObject");
-
- /** proxy for this activation group */
- private ActivationInstantiator proxy;
-
- /**
- * Creates an {@link java.rmi.activation.ActivationGroup} instance and
- * returns it. An {@link ActivationGroupData} instance is extracted from
- * the initialization data, and a {@link Configuration} is obtained by
- * calling
- * {@link net.jini.config.ConfigurationProvider#getInstance
- * Configuration.Provider.getInstance} with the configuration options from
- * that instance. A {@link LoginContext} is obtained from the
- * <code>loginContext</code> configuration entry, if one exists; if the
- * value is not <code>null</code>, a login is performed on that context,
- * and the resulting {@link Subject} (set to be read-only) is used as the
- * subject when executing the rest of this method. The subject is also
- * used for all subsequent remote calls by this class to the
- * {@link ActivationMonitor}. The {@link ActivationSystem} proxy
- * (obtained from the <code>ActivationGroupID</code>) is passed to the
- * {@link ProxyPreparer} given by the <code>systemPreparer</code>
- * configuration entry, if one exists; a new
- * <code>ActivationGroupID</code> is constructed with the resulting proxy.
- * An {@link Exporter} instance is obtained from the
- * <code>instantiatorExporter</code> configuration entry, if one exists;
- * this exporter will be used (in the constructor of this class) to export
- * the group. A <code>ProxyPreparer</code> instance is obtained from the
- * <code>monitorPreparer</code> configuration entry, if one exists; this
- * preparer will be used (in the constructor of this class) to prepare the
- * <code>ActivationMonitor</code>. A call is then made to
- * {@link ActivationGroup#createGroup ActivationGroup.createGroup} with
- * the new group identifier, the activation group descriptor, and the
- * group incarnation number, and the result of that call is returned.
- *
- * @param id the activation group identifier
- * @param desc the activation group descriptor
- * @param incarnation the group's incarnation number (zero on initial
- * creation)
- * @return the created activation group
- * @throws ActivationException if a group already exists or if an
- * exception occurs during group creation
- */
- public static synchronized
- java.rmi.activation.ActivationGroup createGroup(
- final ActivationGroupID id,
- final ActivationGroupDesc desc,
- final long incarnation)
- throws ActivationException
- {
- if (state != UNUSED) {
- throw new ActivationException("group previously created");
- }
- try {
- final Configuration config = getConfiguration(desc.getData());
- login = (LoginContext) config.getEntry(
- PHOENIX, "loginContext", LoginContext.class, null);
- if (login != null) {
- login.login();
- }
-
- inheritGroupSubject =
- ((Boolean) config.getEntry(
- PHOENIX, "inheritGroupSubject", boolean.class,
- Boolean.FALSE)).booleanValue();
-
- return (java.rmi.activation.ActivationGroup) doAction(
- new PrivilegedExceptionAction() {
- public Object run() throws Exception {
- ProxyPreparer sysPreparer =
- getPreparer(config, "systemPreparer");
- monPreparer = getPreparer(config,
- "monitorPreparer");
- TcpServerEndpoint se =
- TcpServerEndpoint.getInstance(0);
- Exporter defaultExporter =
- new BasicJeriExporter(se, new AccessILFactory());
- exporter = (Exporter) config.getEntry(
- PHOENIX, "instantiatorExporter",
- Exporter.class, defaultExporter);
- if (exporter == null) {
- exporter = new AlreadyExportedExporter();
- }
- refuseCalls =
- !(exporter instanceof AlreadyExportedExporter);
- unexportTimeout = getInt(config, "unexportTimeout",
- 60000);
- unexportWait = getInt(config, "unexportWait", 10);
- ActivationSystem sys = (ActivationSystem)
- sysPreparer.prepareProxy(id.getSystem());
- ActivationGroupImpl.incarnation = incarnation;
- groupID = id;
- state = CREATING;
- ActivationGroupID gid = (sys == id.getSystem() ?
- id : new WrappedGID(id, sys));
- Object group = ActivationGroup.createGroup(
- gid, desc, incarnation);
- state = ACTIVE;
- return group;
- }
- });
- } catch (ActivationException e) {
- throw e;
- } catch (Exception e) {
- throw new ActivationException("creation failed", e);
- } finally {
- if (state != ACTIVE) {
- checkInactiveGroup();
- }
- }
- }
-
- /**
- * Returns the configuration obtained from the specified marshalled
- * object.
- */
- private static Configuration getConfiguration(MarshalledObject mobj)
- throws ConfigurationException, IOException, ClassNotFoundException
- {
- ActivationGroupData data = (ActivationGroupData) mobj.get();
- ClassLoader cl = ActivationGroupImpl.class.getClassLoader();
- ClassLoader ccl = Thread.currentThread().getContextClassLoader();
- if (!covers(cl, ccl)) {
- cl = ccl;
- }
- return ConfigurationProvider.getInstance(data.getConfig(), cl);
- }
-
- /**
- * Returns true if the first argument is either equal to, or is a
- * descendant of, the second argument. Null is treated as the root of
- * the tree.
- */
- private static boolean covers(ClassLoader sub, ClassLoader sup) {
- if (sup == null) {
- return true;
- } else if (sub == null) {
- return false;
- }
- do {
- if (sub == sup) {
- return true;
- }
- sub = sub.getParent();
- } while (sub != null);
- return false;
- }
-
- /**
- * Return a ProxyPreparer configuration entry.
- */
- private static ProxyPreparer getPreparer(Configuration config, String name)
- throws ConfigurationException
- {
- return (ProxyPreparer) config.getEntry(PHOENIX, name,
- ProxyPreparer.class,
- new BasicProxyPreparer());
- }
-
- /**
- * Return an int configuration entry.
- */
- private static int getInt(Configuration config, String name, int defValue)
- throws ConfigurationException
- {
- return ((Integer) config.getEntry(PHOENIX, name, int.class,
- Integer.valueOf(defValue))).intValue();
- }
-
- /**
- * ActivationGroupID containing a prepared ActivationSystem proxy and
- * the original ActivationGroupID (with unprepared ActivationSystem
- * proxy), that writeReplaces itself to the original.
- */
- private static class WrappedGID extends ActivationGroupID {
- /** Original gid */
- private final ActivationGroupID id;
- /** Prepared system proxy */
- private final ActivationSystem sys;
-
- WrappedGID(ActivationGroupID id, ActivationSystem sys) {
- super(sys);
- this.id = id;
- this.sys = sys;
- }
-
- /* override */
- public ActivationSystem getSystem() {
- return sys;
- }
-
- private Object writeReplace() {
- return id;
- }
- }
-
- /**
- * Creates an instance with the specified group identifier and
- * initialization data. This constructor must be called indirectly,
- * via {@link #createGroup createGroup}. By default, this instance
- * automatically exports itself as a {@link UnicastRemoteObject}. (This
- * is a limitation of the existing activation system design.) If an
- * {@link Exporter} was obtained by {@link #createGroup createGroup},
- * then this instance is unexported from the JRMP runtime and re-exported
- * using that exporter. (Any incoming remote calls received on the
- * original JRMP export before this instance can be unexported will be
- * refused with a security exception thrown.) The
- * {@link ActivationSystem#activeGroup activeGroup} method of the
- * activation system proxy (in the group identifier) is called to
- * make the group active. The returned {@link ActivationMonitor} proxy
- * is passed to the corresponding {@link ProxyPreparer} obtained by
- * <code>createGroup</code>. Note that after this constructor returns,
- * {@link ActivationGroup#createGroup ActivationGroup.createGroup} will
- * also call <code>activeGroup</code> (so the activation system must
- * accept idempotent calls to that method), but the
- * <code>ActivationMonitor</code> proxy returned by that call will not be
- * used.
- *
- * @param id the activation group identifier
- * @param data group initialization data (ignored)
- * @throws RemoteException if the group could not be exported or
- * made active, or proxy preparation fails
- * @throws ActivationException if the constructor was not called
- * indirectly from <code>createGroup</code>
- */
- public ActivationGroupImpl(ActivationGroupID id, MarshalledObject data)
- throws ActivationException, RemoteException
- {
- super(id);
- synchronized (ActivationGroupImpl.class) {
- if (state != CREATING) {
- throw new ActivationException("not called from createGroup");
- }
- }
- if (refuseCalls) {
- unexportObject(this, true);
- refuseCalls = false;
- }
- proxy = (ActivationInstantiator) exporter.export(this);
- try {
- monitor = (ActivationMonitor) monPreparer.prepareProxy(
- id.getSystem().activeGroup(id, proxy, incarnation));
- state = CREATED;
- } finally {
- if (state != CREATED) {
- exporter.unexport(true);
- }
- }
- monPreparer = null;
- }
-
- public TrustVerifier getProxyVerifier() {
- return new BasicProxyTrustVerifier(proxy);
- }
-
- /**
- * Exporter for an object that is already exported to JRMP.
- */
- private static class AlreadyExportedExporter implements Exporter {
- /**
- * A strong reference to the impl is OK because ActivationGroup
- * also holds a strong reference.
- */
- private Remote impl;
-
- AlreadyExportedExporter() {
- }
-
- public synchronized Remote export(Remote impl) throws ExportException {
- this.impl = impl;
- try {
- return RemoteObject.toStub(impl);
- } catch (NoSuchObjectException e) {
- throw new ExportException("no stub found", e);
- }
- }
-
- public synchronized boolean unexport(boolean force) {
- try {
- if (impl != null &&
- !UnicastRemoteObject.unexportObject(impl, force))
- {
- return false;
- }
- } catch (NoSuchObjectException e) {
- }
- impl = null;
- return true;
- }
- }
-
- /**
- * Returns the proxy for this remote object. Group creation was designed
- * to rely on automatic stub replacement (as provided by the JRMP runtime),
- * which is not supported by all exporters.
- *
- * @return the proxy for this remote object
- */
- protected Object writeReplace() {
- return proxy;
- }
-
- /*
- * Obtains a lock on the ActivationID id before returning. Allows only one
- * thread at a time to hold a lock on a particular id. If the lock for id
- * is in use, all requests for an equivalent (in the .equals sense)
- * id will wait for the id to be notified and use the supplied id as the
- * next lock. The caller of "acquireLock" must execute the "releaseLock"
- * method" to release the lock and "notifyAll" waiters for the id lock
- * obtained from this method. The typical usage pattern is as follows:
- *
- * acquireLock(id);
- * try {
- * // do stuff pertaining to id...
- * } finally {
- * releaseLock(id);
- * }
- */
- private void acquireLock(ActivationID id) {
- while (true) {
- synchronized (id) {
- synchronized (lockedIDs) {
- int index = lockedIDs.indexOf(id);
- if (index < 0) {
- lockedIDs.add(id);
- return;
- }
- ActivationID lockedID =
- (ActivationID) lockedIDs.get(index);
- if (lockedID != id) {
- // don't wait on an id that won't be notified
- id = lockedID;
- continue;
- }
- }
- try {
- id.wait();
- } catch (InterruptedException ignore) {
- }
- }
- }
- }
-
- /*
- * Releases the id lock obtained via the "acquireLock" method and then
- * notifies all threads waiting on the lock.
- */
- private void releaseLock(ActivationID id) {
- synchronized (lockedIDs) {
- id = (ActivationID) lockedIDs.remove(lockedIDs.indexOf(id));
- }
- synchronized (id) {
- id.notifyAll();
- }
- }
-
- /**
- * Creates a new instance of an activatable remote object and returns
- * a marshalled object containing the activated object's proxy.
- *
- * <p>If an active object already exists for the specified identifier,
- * the existing marshalled object for it is returned.
- *
- * <p>Otherwise:
- *
- * <p>The class for the object is loaded by invoking {@link
- * RMIClassLoader#loadClass(String,String) RMIClassLoader.loadClass}
- * passing the class location (obtained by invoking {@link
- * ActivationDesc#getLocation getLocation} on the activation
- * descriptor) and the class name (obtained by invoking {@link
- * ActivationDesc#getClassName getClassName} on the activation
- * descriptor).
- *
- * <p>The new instance is constructed as follows. If the class defines
- * a constructor with two parameters of type {@link ActivationID} and
- * {@link MarshalledObject}, that constructor is called with the
- * specified activation identifier and the initialization data from the
- * specified activation descriptor. Otherwise, an
- * <code>ActivationException</code> is thrown.
- *
- * <p>If the class loader of the object's class is a descendant of the
- * current context class loader, then that class loader is set as the
- * context class loader when the constructor is called.
- *
- * <p>If the <code>inheritGroupSubject</code> configuration entry is
- * <code>true</code> then the constructor is invoked in an action
- * passed to the {@link Security#doPrivileged Security.doPrivileged}
- * method; otherwise the constructor is invoked in an action passed to
- * the {@link AccessController#doPrivileged
- * AccessController.doPrivileged} method.
- *
- * <p>A proxy for the newly created instance is returned as follows:
- *
- * <ul><li>If the newly created instance implements {@link
- * ProxyAccessor}, a proxy is obtained by invoking the {@link
- * ProxyAccessor#getProxy getProxy} method on that instance. If the
- * obtained proxy is not <code>null</code>, that proxy is returned in a
- * <code>MarshalledObject</code>; otherwise, an
- * <code>ActivationException</code> is thrown.
- *
- * <li>If the newly created instance does not implement
- * <code>ProxyAccessor</code>, the instance is returned in a
- * <code>MarshalledObject</code>. In this case, the instance must be
- * serializable, and marshalling the instance must produce a suitable
- * proxy for the remote object (for example, the object implements
- * {@link java.io.Serializable} and defines a <code>writeReplace</code>
- * method that returns the object's proxy).
- * </ul>
- *
- * <p>If both the remote object and the activation group are exported
- * using JRMP, then automatic stub replacement will produce the desired
- * result, but otherwise the remote object implementation must provide
- * a means for this group to obtain its proxy as indicated above.
- *
- * @throws ActivationException if the object's class could not be
- * loaded, if the loaded class does not define the appropriate
- * constructor, or any exception occurs activating the object
- **/
- public MarshalledObject newInstance(final ActivationID id,
- final ActivationDesc desc)
- throws ActivationException
- {
- synchronized (ActivationGroupImpl.class) {
- if (refuseCalls) {
- throw new SecurityException("call refused");
- }
- }
-
- acquireLock(id);
- try {
- ActiveEntry entry;
- synchronized (ActivationGroupImpl.class) {
- if (state != ACTIVE) {
- throw new InactiveGroupException("group not active");
- }
- entry = (ActiveEntry) active.get(id);
- }
- if (entry != null) {
- return entry.mobj;
- }
-
- String className = desc.getClassName();
- final Class cl = RMIClassLoader.loadClass(desc.getLocation(),
- className);
- final Thread t = Thread.currentThread();
- final ClassLoader savedCcl = t.getContextClassLoader();
- final ClassLoader ccl =
- covers(cl.getClassLoader(), savedCcl) ?
- cl.getClassLoader() : savedCcl;
-
- Remote impl = null;
-
- /*
- * Fix for 4164971: allow non-public activatable class
- * and/or constructor, create the activatable object in a
- * privileged block
- */
- try {
- PrivilegedExceptionAction action =
- new PrivilegedExceptionAction() {
- public Object run() throws InstantiationException,
- NoSuchMethodException, IllegalAccessException,
- InvocationTargetException, ActivationException
- {
- Object[] params = new Object[] {id, desc.getData()};
- Constructor constructor =
- cl.getDeclaredConstructor(paramTypes);
- constructor.setAccessible(true);
- try {
- /*
- * Fix for 4289544: make sure to set the
- * context class loader to be the class
- * loader of the impl class before
- * constructing that class.
- */
- t.setContextClassLoader(ccl);
- return constructor.newInstance(params);
- } finally {
- t.setContextClassLoader(savedCcl);
- }
- }
- };
-
- /*
- * The activatable object is created is in a doPrivileged
- * block to protect against user code which might have set
- * a global socket factory (in which case application code
- * would be on the stack).
- */
- impl = (Remote) (inheritGroupSubject ?
- Security.doPrivileged(action) :
- AccessController.doPrivileged(action));
-
- } catch (PrivilegedActionException pae) {
- throw pae.getException();
- }
-
- entry = new ActiveEntry(impl);
- synchronized (ActivationGroupImpl.class) {
- active.put(id, entry);
- }
- return entry.mobj;
- } catch (NoSuchMethodException e) {
- /* user forgot to provide activatable constructor? */
- throw new ActivationException(
- "activation constructor not defined", e);
- } catch (NoSuchMethodError e) {
- /* code recompiled and user forgot to provide
- * activatable constructor?
- */
- throw new ActivationException(
- "activation constructor not defined", e);
- } catch (InvocationTargetException e) {
- throw new ActivationException("exception constructing object",
- e.getTargetException());
- } catch (ActivationException e) {
- throw e;
- } catch (Exception e) {
- throw new ActivationException("unable to activate object", e);
- } finally {
- releaseLock(id);
- checkInactiveGroup();
- }
- }
-
- /**
- * Attempts to make the remote object that is associated with the
- * specified activation identifier, and that was exported as a JRMP
- * {@link java.rmi.activation.Activatable} object, inactive. This method
- * calls <code>Activatable.unexportObject</code> with the active remote
- * object and <code>false</code>, to unexport the object. 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 superclass <code>inactiveObject</code>
- * method is called with the same activation identifier, with the
- * <code>ActivationMonitor</code> constraints (if any) set as
- * contextual client constraints, and with the group's subject (if any)
- * set as the executing subject, and this method returns <code>true</code>.
- *
- * @param id the activation identifier
- * @return <code>true</code> if the object was successfully made
- * inactive; <code>false</code> otherwise
- * @throws UnknownObjectException if the object is not known to be
- * active (it may already be inactive)
- * @throws ActivationException if an activation error occurs
- * @throws InactiveGroupException if the group is inactive
- * @throws RemoteException if the remote call to the activation
- * monitor fails
- *
- * @throws SecurityException if a security manager exists and invoking
- * its {@link SecurityManager#checkPermission checkPermission} method
- * with the permission <code>{@link MonitorPermission}("java.rmi.activation.ActivationMonitor.inactiveObject")</code>
- * throws a <code>SecurityException</code>
- **/
- public boolean inactiveObject(final ActivationID id)
- throws ActivationException, RemoteException
- {
- SecurityManager security = System.getSecurityManager();
- if (security != null) {
- security.checkPermission(inactiveObjectPermission);
- }
- acquireLock(id);
- try {
- ActiveEntry entry;
- synchronized (ActivationGroupImpl.class) {
- if (state != ACTIVE) {
- throw new InactiveGroupException("group not active");
- }
- entry = (ActiveEntry) active.get(id);
- }
- if (entry == null) {
- // REMIND: should this be silent?
- throw new UnknownObjectException("object not active");
- }
-
- try {
- if (!Activatable.unexportObject(entry.impl, false)) {
- return false;
- }
- } catch (NoSuchObjectException allowUnexportedObjects) {
- }
-
- try {
- doAction(new PrivilegedExceptionAction() {
- public Object run() throws Exception {
- monitor.inactiveObject(id);
- return null;
- }
- });
- } catch (UnknownObjectException allowUnregisteredObjects) {
- }
-
- synchronized (ActivationGroupImpl.class) {
- active.remove(id);
- }
- } finally {
- releaseLock(id);
- checkInactiveGroup();
- }
-
- return true;
- }
-
- /**
- * 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
- * superclass <code>inactiveObject</code> method is called with the
- * activation identifier, with the <code>ActivationMonitor</code>
- * constraints (if any) set as contextual client constraints, and with
- * the group's subject (if any) set as the executing subject, and this
- * method returns <code>true</code>.
- *
- * @param id the 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 UnknownObjectException if the object is not known to be
- * active (it may already be inactive)
- * @throws ActivationException if an activation error occurs
- * @throws InactiveGroupException if the group is inactive
- * @throws RemoteException if the remote call to the activation monitor
- * fails
- * @throws SecurityException if a security manager exists and invoking
- * its {@link SecurityManager#checkPermission checkPermission} method
- * with the permission <code>{@link MonitorPermission}("java.rmi.activation.ActivationMonitor.inactiveObject")</code>
- * throws a <code>SecurityException</code>
- **/
- public boolean inactiveObject(final ActivationID id, Exporter exporter)
- throws ActivationException, RemoteException
- {
- SecurityManager security = System.getSecurityManager();
- if (security != null) {
- security.checkPermission(inactiveObjectPermission);
- }
- acquireLock(id);
- try {
- ActiveEntry entry;
- synchronized (ActivationGroupImpl.class) {
- if (state != ACTIVE) {
- throw new InactiveGroupException("group not active");
- }
- entry = (ActiveEntry) active.get(id);
- }
- if (entry == null) {
- // REMIND: should this be silent?
- throw new UnknownObjectException("object not active");
- }
-
- if (!exporter.unexport(false)) {
- return false;
- }
-
- try {
- doAction(new PrivilegedExceptionAction() {
- public Object run() throws Exception {
- monitor.inactiveObject(id);
- return null;
- }
- });
- } catch (UnknownObjectException allowUnregisteredObjects) {
- }
-
- synchronized (ActivationGroupImpl.class) {
- active.remove(id);
- }
- } finally {
- releaseLock(id);
- checkInactiveGroup();
- }
-
- return true;
- }
-
- /*
- * Determines if the group has become inactive and if so,
- * marks it as such, notifies the daemon, and unexports the group.
- */
- private static void checkInactiveGroup() {
- synchronized (ActivationGroupImpl.class) {
- if (state == ACTIVE) {
- if (!active.isEmpty() || !lockedIDs.isEmpty()) {
- return;
- }
- state = INACTIVE;
- } else if (state == INACTIVE) {
- return;
- } else if (state == CREATED) {
- state = UNUSED;
- } else {
- if (login != null) {
- try {
- login.logout();
- } catch (LoginException e) {
- }
- login = null;
- }
- state = UNUSED;
- return;
- }
- }
- try {
- doAction(new PrivilegedExceptionAction() {
- public Object run() throws Exception {
- monitor.inactiveGroup(groupID, incarnation);
- return null;
- }
- });
- } catch (Exception ignoreDeactivateFailure) {
- }
- Runnable action = new Runnable() {
- public void run() {
- long stop = System.currentTimeMillis() + unexportTimeout;
- // allow a failing newInstance call to finish first
- boolean force = false;
- while (!exporter.unexport(force)) {
- long rem = stop - System.currentTimeMillis();
- if (rem <= 0) {
- force = true;
- } else {
- try {
- Thread.sleep(Math.min(rem, unexportWait));
- } catch (InterruptedException e) {
- }
- }
- }
- if (login != null) {
- try {
- login.logout();
- } catch (LoginException e) {
- }
- }
- }
- };
- if (state == UNUSED) {
- action.run();
- } else {
- Executor systemThreadPool =
- (Executor) AccessController.doPrivileged(
- (login == null) ?
- (PrivilegedAction) new GetThreadPoolAction(false) :
- new PrivilegedAction() {
- public Object run() {
- return Subject.doAsPrivileged(
- login.getSubject(),
- new GetThreadPoolAction(false),
- null);
- }
- });
- systemThreadPool.execute(action, "UnexportGroup");
- }
- }
-
- /**
- * Marks the object as active in this virtual machine, and calls the
- * superclass <code>activeObject</code> method with the same arguments,
- * with the <code>ActivationMonitor</code> constraints (if any) set as
- * contextual client constraints, and with the group's subject (if any)
- * set as the executing subject. Any <code>RemoteException</code>
- * thrown by this call is caught and ignored. If the object is already
- * marked as active in this virtual machine, this method simply
- * returns.
- *
- * @param id the activation identifier
- * @param impl the active remote object
- * @throws UnknownObjectException if no object is registered under
- * the specified activation identifier
- * @throws ActivationException if an activation error occurs
- * @throws InactiveGroupException if the group is inactive
- * @throws SecurityException if a security manager exists and invoking
- * its {@link SecurityManager#checkPermission checkPermission} method
- * with the permission <code>{@link MonitorPermission}("java.rmi.activation.ActivationMonitor.activeObject")</code>
- * throws a <code>SecurityException</code>
- **/
- public void activeObject(final ActivationID id, Remote impl)
- throws ActivationException
- {
- SecurityManager security = System.getSecurityManager();
- if (security != null) {
- security.checkPermission(activeObjectPermission);
- }
- final ActiveEntry entry = new ActiveEntry(impl);
- acquireLock(id);
- try {
- synchronized (ActivationGroupImpl.class) {
- if (state != ACTIVE) {
- throw new InactiveGroupException("group not active");
- }
- if (active.containsKey(id)) {
- return;
- }
- active.put(id, entry);
- }
- // created new entry, so inform monitor of active object
- try {
- doAction(new PrivilegedExceptionAction() {
- public Object run() throws Exception {
- monitor.activeObject(id, entry.mobj);
- return null;
- }
- });
- } catch (RemoteException ignore) {
- // daemon can still find it by calling newInstance
- }
- } finally {
- releaseLock(id);
- checkInactiveGroup();
- }
- }
-
- /**
- * Execute the specified action on behalf of the server subject without
- * requiring the caller to have doAsPrivileged permission.
- */
- private static Object doAction(final PrivilegedExceptionAction action)
- throws ActivationException, RemoteException
- {
- try {
- if (login == null) {
- return AccessController.doPrivileged(action);
- } else {
- return AccessController.doPrivileged(
- new PrivilegedExceptionAction() {
- public Object run() throws Exception {
- try {
- return Subject.doAsPrivileged(
- login.getSubject(), action, null);
- } catch (PrivilegedActionException e) {
- throw e.getException();
- }
- }
- });
- }
- } catch (PrivilegedActionException e) {
- Exception ex = e.getException();
- if (ex instanceof RemoteException) {
- throw (RemoteException) ex;
- } else if (ex instanceof ActivationException) {
- throw (ActivationException) ex;
- } else {
- throw new ActivationException("unexpected failure", ex);
- }
- }
- }
-
- /**
- * Entry in table for active object.
- */
- private static class ActiveEntry {
- Remote impl;
- MarshalledObject mobj;
-
- ActiveEntry(Remote impl) throws ActivationException {
- this.impl = impl;
- try {
- Object proxy ;
- if (impl instanceof ProxyAccessor) {
- proxy = ((ProxyAccessor) impl).getProxy();
- if (proxy == null) {
- throw new ActivationException(
- "ProxyAccessor.getProxy returned null");
- }
- } else {
- proxy = impl;
- }
- this.mobj = new MarshalledObject(proxy);
- } catch (IOException e) {
- throw new ActivationException(
- "failed to marshal remote object", e);
- }
- }
- }
-}
+/*
+ * 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 com.sun.jini.phoenix;
+
+import java.rmi.MarshalledObject;
+import java.rmi.RemoteException;
+import java.rmi.activation.ActivationException;
+import java.rmi.activation.ActivationGroupDesc;
+import java.rmi.activation.ActivationGroupID;
+
+/**
+ * The default activation group implementation for phoenix. Instances of
+ * this class are configurable through a {@link Configuration}, as detailed
+ * further below, and provide the necessary support to allow exporter-based
+ * remote objects to go inactive. Instances of this class support the
+ * creation of remote objects through the normal activatable constructor;
+ * an activatable remote object must either implement the {@link
+ * ProxyAccessor} interface to return a suitable proxy for the remote
+ * object, or the remote object must itself be serializable and marshalling
+ * the object must produce a suitable proxy for the remote object.
+ *
+ * <p>An instance of this class can be configured by specifying an
+ * {@link ActivationGroupData} instance containing configuration options
+ * as the initialization data for the activation group. Typically
+ * this is accomplished indirectly, by setting the
+ * <code>groupConfig</code> configuration entry for
+ * phoenix itself. The following entries are obtained from the configuration,
+ * all for the component named <code>com.sun.jini.phoenix</code>:
+ *
+ * <table summary="Describes the loginContext configuration entry"
+ * border="0" cellpadding="2">
+ * <tr valign="top">
+ * <th scope="col" summary="layout"> <font size="+1">•</font>
+ * <th scope="col" align="left" colspan="2"> <font size="+1"><code>
+ * loginContext</code></font>
+ * <tr valign="top"> <td>   <th scope="row" align="right">
+ * Type: <td> <code>{@link javax.security.auth.login.LoginContext}</code>
+ * <tr valign="top"> <td>   <th scope="row" align="right">
+ * Default: <td> <code>null</code>
+ * <tr valign="top"> <td>   <th scope="row" align="right">
+ * Description: <td> JAAS login context
+ * </table>
+ *
+ * <table summary="Describes the inheritGroupSubject configuration entry"
+ * border="0" cellpadding="2">
+ * <tr valign="top">
+ * <th scope="col" summary="layout"> <font size="+1">•</font>
+ * <th scope="col" align="left" colspan="2"> <font size="+1"><code>
+ * inheritGroupSubject</code></font>
+ * <tr valign="top"> <td>   <th scope="row" align="right">
+ * Type: <td> <code>boolean</code>
+ * <tr valign="top"> <td>   <th scope="row" align="right">
+ * Default: <td> <code>false</code>
+ * <tr valign="top"> <td>   <th scope="row" align="right">
+ * Description: <td> if <code>true</code>, group subject is inherited
+ * when an activatable object is created
+ * </table>
+ *
+ * <table summary="Describes the instantiatorExporter configuration entry"
+ * border="0" cellpadding="2">
+ * <tr valign="top">
+ * <th scope="col" summary="layout"> <font size="+1">•</font>
+ * <th scope="col" align="left" colspan="2"> <font size="+1"><code>
+ * instantiatorExporter</code></font>
+ * <tr valign="top"> <td>   <th scope="row" align="right">
+ * Type: <td> <code>{@link net.jini.export.Exporter}</code>
+ * <tr valign="top"> <td>   <th scope="row" align="right">
+ * Default: <td> retains existing JRMP export of instantiator
+ * <tr valign="top"> <td>   <th scope="row" align="right">
+ * Description: <td> {@link java.rmi.activation.ActivationInstantiator}
+ * exporter
+ * </table>
+ *
+ * <table summary="Describes the monitorPreparer configuration entry"
+ * border="0" cellpadding="2">
+ * <tr valign="top">
+ * <th scope="col" summary="layout"> <font size="+1">•</font>
+ * <th scope="col" align="left" colspan="2"> <font size="+1"><code>
+ * monitorPreparer</code></font>
+ * <tr valign="top"> <td>   <th scope="row" align="right">
+ * Type: <td> <code>{@link net.jini.security.ProxyPreparer}</code>
+ * <tr valign="top"> <td>   <th scope="row" align="right">
+ * Default: <td> <code>new {@link
+ * net.jini.security.BasicProxyPreparer}()</code>
+ * <tr valign="top"> <td>   <th scope="row" align="right">
+ * Description: <td> {@link java.rmi.activation.ActivationMonitor}
+ * proxy preparer
+ * </table>
+ *
+ * <table summary="Describes the systemPreparer configuration entry"
+ * border="0" cellpadding="2">
+ * <tr valign="top">
+ * <th scope="col" summary="layout"> <font size="+1">•</font>
+ * <th scope="col" align="left" colspan="2"> <font size="+1"><code>
+ * systemPreparer</code></font>
+ * <tr valign="top"> <td>   <th scope="row" align="right">
+ * Type: <td> <code>{@link net.jini.security.ProxyPreparer}</code>
+ * <tr valign="top"> <td>   <th scope="row" align="right">
+ * Default: <td> <code>new {@link
+ * net.jini.security.BasicProxyPreparer}()</code>
+ * <tr valign="top"> <td>   <th scope="row" align="right">
+ * Description: <td> {@link java.rmi.activation.ActivationSystem}
+ * proxy preparer
+ * </table>
+ *
+ * <table summary="Describes the unexportTimeout configuration entry"
+ * border="0" cellpadding="2">
+ * <tr valign="top">
+ * <th scope="col" summary="layout"> <font size="+1">•</font>
+ * <th scope="col" align="left" colspan="2"> <font size="+1"><code>
+ * unexportTimeout</code></font>
+ * <tr valign="top"> <td>   <th scope="row" align="right">
+ * Type: <td> <code>int</code>
+ * <tr valign="top"> <td>   <th scope="row" align="right">
+ * Default: <td> <code>60000</code>
+ * <tr valign="top"> <td>   <th scope="row" align="right">
+ * Description: <td> maximum time in milliseconds to wait for
+ * in-progress calls to finish before forcibly unexporting the
+ * group when going inactive
+ * </table>
+ *
+ * <table summary="Describes the unexportWait configuration entry"
+ * border="0" cellpadding="2">
+ * <tr valign="top">
+ * <th scope="col" summary="layout"> <font size="+1">•</font>
+ * <th scope="col" align="left" colspan="2"> <font size="+1"><code>
+ * unexportWait</code></font>
+ * <tr valign="top"> <td>   <th scope="row" align="right">
+ * Type: <td> <code>int</code>
+ * <tr valign="top"> <td>   <th scope="row" align="right">
+ * Default: <td> <code>10</code>
+ * <tr valign="top"> <td>   <th scope="row" align="right">
+ * Description: <td> milliseconds to wait between unexport attempts
+ * when going inactive
+ * </table>
+ *
+ * <p>This class depends on its {@link #createGroup createGroup} method being
+ * called to initialize the activation group. As such, this class cannot be
+ * used in conjunction with the standard <code>rmid</code>.
+ *
+ * @author Sun Microsystems, Inc.
+ *
+ * @since 2.0
+ **/
+public class ActivationGroupImpl extends AbstractActivationGroup {
+
+ /**
+ * Creates an {@link java.rmi.activation.ActivationGroup} instance and
+ * returns it. An {@link ActivationGroupData} instance is extracted from
+ * the initialization data, and a {@link Configuration} is obtained by
+ * calling
+ * {@link net.jini.config.ConfigurationProvider#getInstance
+ * Configuration.Provider.getInstance} with the configuration options from
+ * that instance. A {@link LoginContext} is obtained from the
+ * <code>loginContext</code> configuration entry, if one exists; if the
+ * value is not <code>null</code>, a login is performed on that context,
+ * and the resulting {@link Subject} (set to be read-only) is used as the
+ * subject when executing the rest of this method. The subject is also
+ * used for all subsequent remote calls by this class to the
+ * {@link ActivationMonitor}. The {@link ActivationSystem} proxy
+ * (obtained from the <code>ActivationGroupID</code>) is passed to the
+ * {@link ProxyPreparer} given by the <code>systemPreparer</code>
+ * configuration entry, if one exists; a new
+ * <code>ActivationGroupID</code> is constructed with the resulting proxy.
+ * An {@link Exporter} instance is obtained from the
+ * <code>instantiatorExporter</code> configuration entry, if one exists;
+ * this exporter will be used (in the constructor of this class) to export
+ * the group. A <code>ProxyPreparer</code> instance is obtained from the
+ * <code>monitorPreparer</code> configuration entry, if one exists; this
+ * preparer will be used (in the constructor of this class) to prepare the
+ * <code>ActivationMonitor</code>. A call is then made to
+ * {@link ActivationGroup#createGroup ActivationGroup.createGroup} with
+ * the new group identifier, the activation group descriptor, and the
+ * group incarnation number, and the result of that call is returned.
+ *
+ * @param id the activation group identifier
+ * @param desc the activation group descriptor
+ * @param incarnation the group's incarnation number (zero on initial
+ * creation)
+ * @return the created activation group
+ * @throws ActivationException if a group already exists or if an
+ * exception occurs during group creation
+ */
+ public static synchronized
+ java.rmi.activation.ActivationGroup createGroup(
+ final ActivationGroupID id,
+ final ActivationGroupDesc desc,
+ final long incarnation)
+ throws ActivationException
+ {
+ return AbstractActivationGroup.createGroup(id, desc, incarnation);
+ }
+
+ /**
+ * Creates an instance with the specified group identifier and
+ * initialization data. This constructor must be called indirectly,
+ * via {@link #createGroup createGroup}. By default, this instance
+ * automatically exports itself as a {@link UnicastRemoteObject}. (This
+ * is a limitation of the existing activation system design.) If an
+ * {@link Exporter} was obtained by {@link #createGroup createGroup},
+ * then this instance is unexported from the JRMP runtime and re-exported
+ * using that exporter. (Any incoming remote calls received on the
+ * original JRMP export before this instance can be unexported will be
+ * refused with a security exception thrown.) The
+ * {@link ActivationSystem#activeGroup activeGroup} method of the
+ * activation system proxy (in the group identifier) is called to
+ * make the group active. The returned {@link ActivationMonitor} proxy
+ * is passed to the corresponding {@link ProxyPreparer} obtained by
+ * <code>createGroup</code>. Note that after this constructor returns,
+ * {@link ActivationGroup#createGroup ActivationGroup.createGroup} will
+ * also call <code>activeGroup</code> (so the activation system must
+ * accept idempotent calls to that method), but the
+ * <code>ActivationMonitor</code> proxy returned by that call will not be
+ * used.
+ *
+ * @param id the activation group identifier
+ * @param data group initialization data (ignored)
+ * @throws RemoteException if the group could not be exported or
+ * made active, or proxy preparation fails
+ * @throws ActivationException if the constructor was not called
+ * indirectly from <code>createGroup</code>
+ */
+ public ActivationGroupImpl(ActivationGroupID id, MarshalledObject data)
+ throws ActivationException, RemoteException
+ {
+ super(id, data);
+ export();
+ }
+
+}