/* * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package 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(null, deactivator, "Deactivator-Thread", 0, false) ; 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. } } }