/*
* @(#)POAManagerImpl.java 1.22 04/06/21
*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package com.sun.corba.se.impl.oa.poa;
import java.util.Iterator;
import java.util.Collections;
import java.util.Set;
import java.util.HashSet;
import org.omg.CORBA.LocalObject;
import org.omg.CORBA.CompletionStatus ;
import org.omg.PortableServer.POAManager;
import org.omg.PortableServer.POAManagerPackage.State;
import org.omg.PortableServer.POA;
import org.omg.PortableInterceptor.DISCARDING ;
import org.omg.PortableInterceptor.ACTIVE ;
import org.omg.PortableInterceptor.HOLDING ;
import org.omg.PortableInterceptor.INACTIVE ;
import org.omg.PortableInterceptor.NON_EXISTENT ;
import com.sun.corba.se.spi.protocol.PIHandler ;
import com.sun.corba.se.impl.logging.POASystemException ;
import com.sun.corba.se.impl.orbutil.ORBUtility ;
/** POAManagerImpl is the implementation of the POAManager interface.
* Its public methods are activate(), hold_requests(), discard_requests()
* and deactivate().
*/
public class POAManagerImpl extends org.omg.CORBA.LocalObject implements
POAManager
{
private final POAFactory factory ; // factory which contains global state
// for all POAManagers
private PIHandler pihandler ; // for adapterManagerStateChanged
private State state; // current state of this POAManager
private Set poas = new HashSet(4) ; // all poas controlled by this POAManager
private int nInvocations=0; // Number of invocations in progress
private int nWaiters=0; // Number of threads waiting for
// invocations to complete
private int myId = 0 ; // This POAManager's ID
private boolean debug ;
private boolean explicitStateChange ; // initially false, set true as soon as
// one of activate, hold_request,
// discard_request, or deactivate is called.
private String stateToString( State state )
{
switch (state.value()) {
case State._HOLDING : return "State[HOLDING]" ;
case State._ACTIVE : return "State[ACTIVE]" ;
case State._DISCARDING : return "State[DISCARDING]" ;
case State._INACTIVE : return "State[INACTIVE]" ;
}
return "State[UNKNOWN]" ;
}
public String toString()
{
return "POAManagerImpl[myId=" + myId +
" state=" + stateToString(state) +
" nInvocations=" + nInvocations +
" nWaiters=" + nWaiters + "]" ;
}
POAFactory getFactory()
{
return factory ;
}
PIHandler getPIHandler()
{
return pihandler ;
}
private void countedWait()
{
try {
if (debug) {
ORBUtility.dprint( this, "Calling countedWait on POAManager " +
this + " nWaiters=" + nWaiters ) ;
}
nWaiters++ ;
wait();
} catch ( java.lang.InterruptedException ex ) {
// NOP
} finally {
nWaiters-- ;
if (debug) {
ORBUtility.dprint( this, "Exiting countedWait on POAManager " +
this + " nWaiters=" + nWaiters ) ;
}
}
}
private void notifyWaiters()
{
if (debug) {
ORBUtility.dprint( this, "Calling notifyWaiters on POAManager " +
this + " nWaiters=" + nWaiters ) ;
}
if (nWaiters >0)
notifyAll() ;
}
public int getManagerId()
{
return myId ;
}
POAManagerImpl( POAFactory factory, PIHandler pihandler )
{
this.factory = factory ;
factory.addPoaManager(this);
this.pihandler = pihandler ;
myId = factory.newPOAManagerId() ;
state = State.HOLDING;
debug = factory.getORB().poaDebugFlag ;
explicitStateChange = false ;
if (debug) {
ORBUtility.dprint( this, "Creating POAManagerImpl " + this ) ;
}
}
synchronized void addPOA(POA poa)
{
// XXX This is probably not the correct error
if (state.value() == State._INACTIVE) {
POASystemException wrapper = factory.getWrapper();
throw wrapper.addPoaInactive( CompletionStatus.COMPLETED_NO ) ;
}
poas.add(poa);
}
synchronized void removePOA(POA poa)
{
poas.remove(poa);
if ( poas.isEmpty() ) {
factory.removePoaManager(this);
}
}
public short getORTState()
{
switch (state.value()) {
case State._HOLDING : return HOLDING.value ;
case State._ACTIVE : return ACTIVE.value ;
case State._INACTIVE : return INACTIVE.value ;
case State._DISCARDING : return DISCARDING.value ;
default : return NON_EXISTENT.value ;
}
}
/****************************************************************************
* The following four public methods are used to change the POAManager's state.
*
* A note on the design of synchronization code:
* There are 4 places where a thread would need to wait for a condition:
* - in hold_requests, discard_requests, deactivate, enter
* There are 5 places where a thread notifies a condition:
* - in activate, hold_requests, discard_requests, deactivate, exit
*
* Since each notify needs to awaken waiters in several of the 4 places,
* and since wait() in Java has the nice property of releasing the lock
* on its monitor before sleeping, it seemed simplest to have just one
* monitor object: "this". Thus all notifies will awaken all waiters.
* On waking up, each waiter verifies that the condition it was waiting
* for is satisfied, otherwise it goes back into a wait().
*
****************************************************************************/
/**
* activate
* Spec: pages 3-14 thru 3-18
*/
public synchronized void activate()
throws org.omg.PortableServer.POAManagerPackage.AdapterInactive
{
explicitStateChange = true ;
if (debug) {
ORBUtility.dprint( this,
"Calling activate on POAManager " + this ) ;
}
try {
if ( state.value() == State._INACTIVE )
throw new org.omg.PortableServer.POAManagerPackage.AdapterInactive();
// set the state to ACTIVE
state = State.ACTIVE;
pihandler.adapterManagerStateChanged( myId, getORTState() ) ;
// Notify any invocations that were waiting because the previous
// state was HOLDING, as well as notify any threads that were waiting
// inside hold_requests() or discard_requests().
notifyWaiters();
} finally {
if (debug) {
ORBUtility.dprint( this,
"Exiting activate on POAManager " + this ) ;
}
}
}
/**
* hold_requests
* Spec: pages 3-14 thru 3-18
*/
public synchronized void hold_requests(boolean wait_for_completion)
throws org.omg.PortableServer.POAManagerPackage.AdapterInactive
{
explicitStateChange = true ;
if (debug) {
ORBUtility.dprint( this,
"Calling hold_requests on POAManager " + this ) ;
}
try {
if ( state.value() == State._INACTIVE )
throw new org.omg.PortableServer.POAManagerPackage.AdapterInactive();
// set the state to HOLDING
state = State.HOLDING;
pihandler.adapterManagerStateChanged( myId, getORTState() ) ;
// Notify any threads that were waiting in the wait() inside
// discard_requests. This will cause discard_requests to return
// (which is in conformance with the spec).
notifyWaiters();
if ( wait_for_completion ) {
while ( state.value() == State._HOLDING && nInvocations > 0 ) {
countedWait() ;
}
}
} finally {
if (debug) {
ORBUtility.dprint( this,
"Exiting hold_requests on POAManager " + this ) ;
}
}
}
/**
* discard_requests
* Spec: pages 3-14 thru 3-18
*/
public synchronized void discard_requests(boolean wait_for_completion)
throws org.omg.PortableServer.POAManagerPackage.AdapterInactive
{
explicitStateChange = true ;
if (debug) {
ORBUtility.dprint( this,
"Calling hold_requests on POAManager " + this ) ;
}
try {
if ( state.value() == State._INACTIVE )
throw new org.omg.PortableServer.POAManagerPackage.AdapterInactive();
// set the state to DISCARDING
state = State.DISCARDING;
pihandler.adapterManagerStateChanged( myId, getORTState() ) ;
// Notify any invocations that were waiting because the previous
// state was HOLDING. Those invocations will henceforth be rejected with
// a TRANSIENT exception. Also notify any threads that were waiting
// inside hold_requests().
notifyWaiters();
if ( wait_for_completion ) {
while ( state.value() == State._DISCARDING && nInvocations > 0 ) {
countedWait() ;
}
}
} finally {
if (debug) {
ORBUtility.dprint( this,
"Exiting hold_requests on POAManager " + this ) ;
}
}
}
/**
* deactivate
* Spec: pages 3-14 thru 3-18
* Note: INACTIVE is a permanent state.
*/
public void deactivate(boolean etherealize_objects, boolean wait_for_completion)
throws org.omg.PortableServer.POAManagerPackage.AdapterInactive
{
explicitStateChange = true ;
try {
synchronized( this ) {
if (debug) {
ORBUtility.dprint( this,
"Calling deactivate on POAManager " + this ) ;
}
if ( state.value() == State._INACTIVE )
throw new org.omg.PortableServer.POAManagerPackage.AdapterInactive();
state = State.INACTIVE;
pihandler.adapterManagerStateChanged( myId, getORTState() ) ;
// Notify any invocations that were waiting because the previous
// state was HOLDING. Those invocations will then be rejected with
// an OBJ_ADAPTER exception. Also notify any threads that were waiting
// inside hold_requests() or discard_requests().
notifyWaiters();
}
POAManagerDeactivator deactivator = new POAManagerDeactivator( this,
etherealize_objects, debug ) ;
if (wait_for_completion)
deactivator.run() ;
else {
Thread thr = new Thread(deactivator) ;
thr.start() ;
}
} finally {
synchronized(this) {
if (debug) {
ORBUtility.dprint( this,
"Exiting deactivate on POAManager " + this ) ;
}
}
}
}
private class POAManagerDeactivator implements Runnable
{
private boolean etherealize_objects ;
private POAManagerImpl pmi ;
private boolean debug ;
POAManagerDeactivator( POAManagerImpl pmi, boolean etherealize_objects,
boolean debug )
{
this.etherealize_objects = etherealize_objects ;
this.pmi = pmi ;
this.debug = debug ;
}
public void run()
{
try {
synchronized (pmi) {
if (debug) {
ORBUtility.dprint( this,
"Calling run with etherealize_objects=" +
etherealize_objects + " pmi=" + pmi ) ;
}
while ( pmi.nInvocations > 0 ) {
countedWait() ;
}
}
if (etherealize_objects) {
Iterator iterator = null ;
// Make sure that poas cannot change while we copy it!
synchronized (pmi) {
if (debug) {
ORBUtility.dprint( this,
"run: Preparing to etherealize with pmi=" +
pmi ) ;
}
iterator = (new HashSet(pmi.poas)).iterator();
}
while (iterator.hasNext()) {
// Each RETAIN+USE_SERVANT_MGR poa
// must call etherealize for all its objects
((POAImpl)iterator.next()).etherealizeAll();
}
synchronized (pmi) {
if (debug) {
ORBUtility.dprint( this,
"run: removing POAManager and clearing poas " +
"with pmi=" + pmi ) ;
}
factory.removePoaManager(pmi);
poas.clear();
}
}
} finally {
if (debug) {
synchronized (pmi) {
ORBUtility.dprint( this, "Exiting run" ) ;
}
}
}
}
}
/**
* Added according to the spec CORBA V2.3; this returns the
* state of the POAManager
*/
public org.omg.PortableServer.POAManagerPackage.State get_state () {
return state;
}
/****************************************************************************
* The following methods are used on the invocation path.
****************************************************************************/
// called from POA.find_POA before calling
// AdapterActivator.unknown_adapter.
synchronized void checkIfActive()
{
try {
if (debug) {
ORBUtility.dprint( this,
"Calling checkIfActive for POAManagerImpl " + this ) ;
}
checkState();
} finally {
if (debug) {
ORBUtility.dprint( this,
"Exiting checkIfActive for POAManagerImpl " + this ) ;
}
}
}
private void checkState()
{
while ( state.value() != State._ACTIVE ) {
switch ( state.value() ) {
case State._HOLDING:
while ( state.value() == State._HOLDING ) {
countedWait() ;
}
break;
case State._DISCARDING:
throw factory.getWrapper().poaDiscarding() ;
case State._INACTIVE:
throw factory.getWrapper().poaInactive() ;
}
}
}
synchronized void enter()
{
try {
if (debug) {
ORBUtility.dprint( this,
"Calling enter for POAManagerImpl " + this ) ;
}
checkState();
nInvocations++;
} finally {
if (debug) {
ORBUtility.dprint( this,
"Exiting enter for POAManagerImpl " + this ) ;
}
}
}
synchronized void exit()
{
try {
if (debug) {
ORBUtility.dprint( this,
"Calling exit for POAManagerImpl " + this ) ;
}
nInvocations--;
if ( nInvocations == 0 ) {
// This notifies any threads that were in the
// wait_for_completion loop in hold/discard/deactivate().
notifyWaiters();
}
} finally {
if (debug) {
ORBUtility.dprint( this,
"Exiting exit for POAManagerImpl " + this ) ;
}
}
}
/** Activate the POAManager if no explicit state change has ever been
* previously invoked.
*/
public synchronized void implicitActivation()
{
if (!explicitStateChange)
try {
activate() ;
} catch (org.omg.PortableServer.POAManagerPackage.AdapterInactive ai) {
// ignore the exception.
}
}
}