/* * Copyright (c) 1997, 2004, 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 org.jboss.com.sun.corba.se.impl.oa.poa; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import org.jboss.com.sun.corba.se.impl.logging.POASystemException; import org.jboss.com.sun.corba.se.impl.orbutil.ORBUtility; import org.jboss.com.sun.corba.se.spi.protocol.PIHandler; import org.omg.CORBA.CompletionStatus; import org.omg.PortableInterceptor.ACTIVE; import org.omg.PortableInterceptor.DISCARDING; import org.omg.PortableInterceptor.HOLDING; import org.omg.PortableInterceptor.INACTIVE; import org.omg.PortableInterceptor.NON_EXISTENT; import org.omg.PortableServer.POA; import org.omg.PortableServer.POAManager; import org.omg.PortableServer.POAManagerPackage.State; /** * 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 static final long serialVersionUID = 5295604954267836516L; 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<POA> poas = new HashSet<POA>(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(). * ****************************************************************************/ /** * <code>activate</code> <b>Spec: pages 3-14 thru 3-18</b> */ 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); } } } /** * <code>hold_requests</code> <b>Spec: pages 3-14 thru 3-18</b> */ 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); } } } /** * <code>discard_requests</code> <b>Spec: pages 3-14 thru 3-18</b> */ 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); } } } /** * <code>deactivate</code> <b>Spec: pages 3-14 thru 3-18</b> 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<POA> 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<POA>(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. } } }