/* * 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.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import org.jboss.com.sun.corba.se.impl.ior.ObjectAdapterIdArray; import org.jboss.com.sun.corba.se.impl.ior.POAObjectKeyTemplate; import org.jboss.com.sun.corba.se.impl.orbutil.ORBConstants; import org.jboss.com.sun.corba.se.impl.orbutil.ORBUtility; import org.jboss.com.sun.corba.se.impl.orbutil.concurrent.CondVar; import org.jboss.com.sun.corba.se.impl.orbutil.concurrent.ReentrantMutex; import org.jboss.com.sun.corba.se.impl.orbutil.concurrent.Sync; import org.jboss.com.sun.corba.se.impl.orbutil.concurrent.SyncUtil; import org.jboss.com.sun.corba.se.spi.copyobject.CopierManager; import org.jboss.com.sun.corba.se.spi.copyobject.ObjectCopierFactory; import org.jboss.com.sun.corba.se.spi.ior.IOR; import org.jboss.com.sun.corba.se.spi.ior.IORFactories; import org.jboss.com.sun.corba.se.spi.ior.IORTemplateList; import org.jboss.com.sun.corba.se.spi.ior.ObjectAdapterId; import org.jboss.com.sun.corba.se.spi.ior.ObjectId; import org.jboss.com.sun.corba.se.spi.ior.ObjectKeyTemplate; import org.jboss.com.sun.corba.se.spi.ior.TaggedProfile; import org.jboss.com.sun.corba.se.spi.oa.OADestroyed; import org.jboss.com.sun.corba.se.spi.oa.OAInvocationInfo; import org.jboss.com.sun.corba.se.spi.oa.ObjectAdapterBase; import org.jboss.com.sun.corba.se.spi.orb.ORB; import org.jboss.com.sun.corba.se.spi.protocol.ForwardException; import org.omg.CORBA.Policy; import org.omg.CORBA.SystemException; import org.omg.PortableInterceptor.NON_EXISTENT; import org.omg.PortableInterceptor.ObjectReferenceFactory; import org.omg.PortableInterceptor.ObjectReferenceTemplate; import org.omg.PortableServer.AdapterActivator; import org.omg.PortableServer.ForwardRequest; import org.omg.PortableServer.IdAssignmentPolicy; import org.omg.PortableServer.IdAssignmentPolicyValue; import org.omg.PortableServer.IdUniquenessPolicy; import org.omg.PortableServer.IdUniquenessPolicyValue; import org.omg.PortableServer.ImplicitActivationPolicy; import org.omg.PortableServer.ImplicitActivationPolicyValue; import org.omg.PortableServer.LifespanPolicy; import org.omg.PortableServer.LifespanPolicyValue; import org.omg.PortableServer.POA; import org.omg.PortableServer.POAManager; import org.omg.PortableServer.RequestProcessingPolicy; import org.omg.PortableServer.RequestProcessingPolicyValue; import org.omg.PortableServer.Servant; import org.omg.PortableServer.ServantManager; import org.omg.PortableServer.ServantRetentionPolicy; import org.omg.PortableServer.ServantRetentionPolicyValue; import org.omg.PortableServer.ThreadPolicy; import org.omg.PortableServer.ThreadPolicyValue; import org.omg.PortableServer.POAPackage.AdapterAlreadyExists; import org.omg.PortableServer.POAPackage.AdapterNonExistent; import org.omg.PortableServer.POAPackage.InvalidPolicy; import org.omg.PortableServer.POAPackage.NoServant; import org.omg.PortableServer.POAPackage.ObjectAlreadyActive; import org.omg.PortableServer.POAPackage.ObjectNotActive; import org.omg.PortableServer.POAPackage.ServantAlreadyActive; import org.omg.PortableServer.POAPackage.ServantNotActive; import org.omg.PortableServer.POAPackage.WrongAdapter; import org.omg.PortableServer.POAPackage.WrongPolicy; /** * POAImpl is the implementation of the Portable Object Adapter. It contains an implementation of the POA interfaces * specified in COBRA 2.3.1 chapter 11 (formal/99-10-07). This implementation is moving to comply with CORBA 3.0 due to * the many clarifications that have been made to the POA semantics since CORBA 2.3.1. Specific comments have been added * where 3.0 applies, but note that we do not have the new 3.0 APIs yet. */ public class POAImpl extends ObjectAdapterBase implements POA { private static final long serialVersionUID = 1806031312673382020L; private boolean debug; /* * POA creation takes place in 2 stages: first, the POAImpl constructor is called, then the initialize method is * called. This separation is needed because an AdapterActivator does not know the POAManager or the policies when * the unknown_adapter method is invoked. However, the POA must be created before the unknown_adapter method is * invoked, so that the parent knows when concurrent attempts are made to create the same POA. Calling the POAImpl * constructor results in a new POA in state STATE_START. Calling initialize( POAManager, Policies ) results in * state STATE_RUN. Calling destroy results in STATE_DESTROY, which marks the beginning of POA destruction. */ // Notes on concurrency. // The POA requires careful design for concurrency management to correctly implement the specification and avoid // deadlocks. The order of acquiring locks must respect the following locking hierarchy: // // 1. Lock POAs before POAManagers // 2. Lock a POA before locking its child POA // // Also note that there are 3 separate conditions on which threads may wait in the POA, as defined by invokeCV, // beingDestroyedCV, and adapterActivatorCV. This means that (for this reason as well as others) we cannot simply // use the standard Java synchronized primitive. // This implementation uses a modified version of Doug Lea's util.concurrent (version 1.3.0) that supports reentrant // mutexes to handle the locking. This will all be replaced by the new JSR 166 concurrency primitives in J2SE 1.5 // and later once the ORB moves to J2SE 1.5. // POA state constants // // Note that ordering is important here: we must have the state defined in this order so that ordered comparison is // possible. DO NOT CHANGE THE VALUES OF THE STATE CONSTANTS!!! In particular, the initialization related states // must be lower than STATE_RUN. // // POA is created in STATE_START // // Valid state transitions: // // START to INIT after find_POA constructor call // START to RUN after initialize completes // INIT to INIT_DONE after initialize completes // INIT to DESTROYED after failed unknown_adapter // INIT_DONE to RUN after successful unknown_adapter // STATE_RUN to STATE_DESTROYING after start of destruction // STATE_DESTROYING to STATE_DESTROYED after destruction completes. private static final int STATE_START = 0; // constructor complete private static final int STATE_INIT = 1; // waiting for adapter activator private static final int STATE_INIT_DONE = 2; // adapter activator called create_POA private static final int STATE_RUN = 3; // initialized and running private static final int STATE_DESTROYING = 4; // being destroyed private static final int STATE_DESTROYED = 5; // destruction complete private String stateToString() { switch (state) { case STATE_START : return "START"; case STATE_INIT : return "INIT"; case STATE_INIT_DONE : return "INIT_DONE"; case STATE_RUN : return "RUN"; case STATE_DESTROYING : return "DESTROYING"; case STATE_DESTROYED : return "DESTROYED"; default : return "UNKNOWN(" + state + ")"; } } // Current state of the POA private int state; // The POA request handler that performs all policy specific operations Note that POAImpl handles all // synchronization, so mediator is (mostly) unsynchronized. private POAPolicyMediator mediator; // Representation of object adapter ID private int numLevels; // counts depth of tree. Root = 1. private ObjectAdapterId poaId; // the actual object adapter ID for this POA private String name; // the name of this POA private POAManagerImpl manager; // This POA's POAManager private int uniquePOAId; // ID for this POA that is unique relative to the POAFactory, which has the same lifetime // as the ORB. private POAImpl parent; // The POA that created this POA. private Map<String, POA> children; // Map from name to POA of POAs created by // this POA. private AdapterActivator activator; private int invocationCount; // pending invocations on this POA. // Data used to control POA concurrency // XXX revisit for JSR 166 // Master lock for all POA synchronization. See lock and unlock. // package private for access by AOMEntry. Sync poaMutex; // Wait on this CV for AdapterActivator upcalls to complete private CondVar adapterActivatorCV; // Wait on this CV for all active invocations to complete private CondVar invokeCV; // Wait on this CV for the destroy method to complete doing its work private CondVar beingDestroyedCV; // thread local variable to store a boolean to detect deadlock in // POA.destroy(). protected ThreadLocal<Object> isDestroying; // This includes the most important information for debugging // POA problems. public String toString() { return "POA[" + poaId.toString() + ", uniquePOAId=" + uniquePOAId + ", state=" + stateToString() + ", invocationCount=" + invocationCount + "]"; } // package private for mediator implementations. boolean getDebug() { return debug; } // package private for access to servant to POA map static POAFactory getPOAFactory(ORB orb) { return (POAFactory) orb.getRequestDispatcherRegistry().getObjectAdapterFactory(ORBConstants.TRANSIENT_SCID); } // package private so that POAFactory can access it. static POAImpl makeRootPOA(ORB orb) { POAManagerImpl poaManager = new POAManagerImpl(getPOAFactory(orb), orb.getPIHandler()); POAImpl result = new POAImpl(ORBConstants.ROOT_POA_NAME, null, orb, STATE_START); result.initialize(poaManager, Policies.rootPOAPolicies); return result; } // package private so that POAPolicyMediatorBase can access it. int getPOAId() { return uniquePOAId; } // package private so that POAPolicyMediator can access it. void lock() { SyncUtil.acquire(poaMutex); if (debug) { ORBUtility.dprint(this, "LOCKED poa " + this); } } // package private so that POAPolicyMediator can access it. void unlock() { if (debug) { ORBUtility.dprint(this, "UNLOCKED poa " + this); } poaMutex.release(); } // package private so that DelegateImpl can access it. Policies getPolicies() { return mediator.getPolicies(); } // Note that the parent POA must be locked when this constructor is called. private POAImpl(String name, POAImpl parent, ORB orb, int initialState) { super(orb); debug = orb.poaDebugFlag; if (debug) { ORBUtility.dprint(this, "Creating POA with name=" + name + " parent=" + parent); } this.state = initialState; this.name = name; this.parent = parent; children = new HashMap<String, POA>(); activator = null; // This was done in initialize, but I moved it here to get better searchability when tracing. uniquePOAId = getPOAFactory(orb).newPOAId(); if (parent == null) { // This is the root POA, which counts as 1 level numLevels = 1; } else { // My level is one more than that of my parent numLevels = parent.numLevels + 1; parent.children.put(name, this); } // Get an array of all of the POA names in order to // create the poaid. String[] names = new String[numLevels]; POAImpl poaImpl = this; int ctr = numLevels - 1; while (poaImpl != null) { names[ctr--] = poaImpl.name; poaImpl = poaImpl.parent; } poaId = new ObjectAdapterIdArray(names); invocationCount = 0; poaMutex = new ReentrantMutex(orb.poaConcurrencyDebugFlag); adapterActivatorCV = new CondVar(poaMutex, orb.poaConcurrencyDebugFlag); invokeCV = new CondVar(poaMutex, orb.poaConcurrencyDebugFlag); beingDestroyedCV = new CondVar(poaMutex, orb.poaConcurrencyDebugFlag); isDestroying = new ThreadLocal<Object>() { protected Object initialValue() { return Boolean.FALSE; } }; } // The POA lock must be held when this method is called. private void initialize(POAManagerImpl manager, Policies policies) { if (debug) { ORBUtility.dprint(this, "Initializing poa " + this + " with POAManager=" + manager + " policies=" + policies); } this.manager = manager; manager.addPOA(this); mediator = POAPolicyMediatorFactory.create(policies, this); // Construct the object key template int serverid = mediator.getServerId(); int scid = mediator.getScid(); String orbId = getORB().getORBData().getORBId(); ObjectKeyTemplate oktemp = new POAObjectKeyTemplate(getORB(), scid, serverid, orbId, poaId); if (debug) { ORBUtility.dprint(this, "Initializing poa: oktemp=" + oktemp); } // Note that parent == null if this is the root POA. This was used to avoid executing interceptors on the // RootPOA. That is no longer necessary. boolean objectAdapterCreated = true; // parent != null ; // XXX extract codebase from policies and pass into initializeTemplate after the codebase policy change is // finalized. initializeTemplate(oktemp, objectAdapterCreated, policies, null, // codebase null, // manager id oktemp.getObjectAdapterId()); if (state == STATE_START) state = STATE_RUN; else if (state == STATE_INIT) state = STATE_INIT_DONE; else throw lifecycleWrapper().illegalPoaStateTrans(); } // The poaMutex must be held when this method is called private boolean waitUntilRunning() { if (debug) { ORBUtility.dprint(this, "Calling waitUntilRunning on poa " + this); } while (state < STATE_RUN) { try { adapterActivatorCV.await(); } catch (InterruptedException exc) { // NO-OP } } if (debug) { ORBUtility.dprint(this, "Exiting waitUntilRunning on poa " + this); } // Note that a POA could be destroyed while in STATE_INIT due to a failure in the AdapterActivator upcall. return (state == STATE_RUN); } // This method checks that the AdapterActivator finished the initialization of a POA activated in find_POA. This is // determined by checking the state of the POA. If the state is STATE_INIT, the AdapterActivator did not complete // the inialization. In this case, we destroy the POA that was partially created and return false. Otherwise, we // return true. In any case, we must wake up all threads waiting for the adapter activator, either to continue their // invocations, or to return errors to their client. // // The poaMutex must NOT be held when this method is called. private boolean destroyIfNotInitDone() { try { lock(); if (debug) { ORBUtility.dprint(this, "Calling destroyIfNotInitDone on poa " + this); } boolean success = (state == STATE_INIT_DONE); if (success) state = STATE_RUN; else { // Don't just use destroy, because the check for deadlock is too general, and can prevent this from // functioning properly. DestroyThread destroyer = new DestroyThread(false, debug); destroyer.doIt(this, true); } return success; } finally { adapterActivatorCV.broadcast(); if (debug) { ORBUtility.dprint(this, "Exiting destroyIfNotInitDone on poa " + this); } unlock(); } } private byte[] internalReferenceToId(org.omg.CORBA.Object reference) throws WrongAdapter { IOR ior = ORBUtility.getIOR(reference); IORTemplateList thisTemplate = ior.getIORTemplates(); ObjectReferenceFactory orf = getCurrentFactory(); IORTemplateList poaTemplate = IORFactories.getIORTemplateList(orf); if (!poaTemplate.isEquivalent(thisTemplate)) throw new WrongAdapter(); // Extract the ObjectId from the first TaggedProfile in the IOR. If ior was created in this POA, the same ID was // used for every profile through the profile templates in the currentFactory, so we will get the same result // from any profile. Iterator<Object> iter = ior.iterator(); if (!iter.hasNext()) throw iorWrapper().noProfilesInIor(); TaggedProfile prof = (TaggedProfile) (iter.next()); ObjectId oid = prof.getObjectId(); return oid.getId(); } // Converted from anonymous class to local class so that we can call performDestroy() directly. static class DestroyThread extends Thread { private boolean wait; private boolean etherealize; private boolean debug; private POAImpl thePoa; public DestroyThread(boolean etherealize, boolean debug) { this.etherealize = etherealize; this.debug = debug; } public void doIt(POAImpl thePoa, boolean wait) { if (debug) { ORBUtility.dprint(this, "Calling DestroyThread.doIt(thePOA=" + thePoa + " wait=" + wait + " etherealize=" + etherealize); } this.thePoa = thePoa; this.wait = wait; if (wait) { run(); } else { // Catch exceptions since setDaemon can cause a security exception to be thrown under netscape in the // Applet mode try { setDaemon(true); } catch (Exception e) { } start(); } } public void run() { Set<ObjectReferenceTemplate> destroyedPOATemplates = new HashSet<ObjectReferenceTemplate>(); performDestroy(thePoa, destroyedPOATemplates); Iterator<ObjectReferenceTemplate> iter = destroyedPOATemplates.iterator(); ObjectReferenceTemplate[] orts = new ObjectReferenceTemplate[destroyedPOATemplates.size()]; int index = 0; while (iter.hasNext()) orts[index++] = iter.next(); thePoa.getORB().getPIHandler().adapterStateChanged(orts, NON_EXISTENT.value); } // Returns true if destruction must be completed, false if not, which means that another thread is already // destroying poa. private boolean prepareForDestruction(POAImpl poa, Set<ObjectReferenceTemplate> destroyedPOATemplates) { POAImpl[] childPoas = null; // Note that we do not synchronize on this, since this is the PerformDestroy instance, not the POA. try { poa.lock(); if (debug) { ORBUtility.dprint(this, "Calling performDestroy on poa " + poa); } if (poa.state <= STATE_RUN) { poa.state = STATE_DESTROYING; } else { // destroy may be called multiple times, and each call is allowed to proceed with its own setting of // the wait flag, but the etherealize value is used from the first call to destroy. Also all // children should be destroyed before the parent POA. If the poa is already destroyed, we can just // return. If the poa has started destruction, but not completed, and wait is true, we need to wait // until destruction is complete, then just return. if (wait) while (poa.state != STATE_DESTROYED) { try { poa.beingDestroyedCV.await(); } catch (InterruptedException exc) { // NO-OP } } return false; } poa.isDestroying.set(Boolean.TRUE); // Make a copy since we can't hold the lock while destroying the children, and an iterator is not // deletion-safe. childPoas = poa.children.values().toArray(new POAImpl[0]); } finally { poa.unlock(); } // We are not holding the POA mutex here to avoid holding it while destroying the POA's children, since this // may involve upcalls to etherealize methods. for (int ctr = 0; ctr < childPoas.length; ctr++) { performDestroy(childPoas[ctr], destroyedPOATemplates); } return true; } public void performDestroy(POAImpl poa, Set<ObjectReferenceTemplate> destroyedPOATemplates) { if (!prepareForDestruction(poa, destroyedPOATemplates)) return; // NOTE: If we are here, poa is in STATE_DESTROYING state. All other state checks are taken care of in // prepareForDestruction. No other threads may either be starting new invocations by calling enter or // starting to destroy poa. There may still be pending invocations. POAImpl parent = poa.parent; boolean isRoot = parent == null; try { // Note that we must lock the parent before the child. The parent lock is required (if poa is not the // root) to safely remove poa from parent's children Map. if (!isRoot) parent.lock(); try { poa.lock(); completeDestruction(poa, parent, destroyedPOATemplates); } finally { poa.unlock(); if (isRoot) // We have just destroyed the root POA, so we need to make sure that the next call to // resolve_initial_reference( "RootPOA" ) will recreate a valid root POA. poa.manager.getFactory().registerRootPOA(); } } finally { if (!isRoot) { parent.unlock(); poa.parent = null; } } } private void completeDestruction(POAImpl poa, POAImpl parent, Set<ObjectReferenceTemplate> destroyedPOATemplates) { if (debug) { ORBUtility.dprint(this, "Calling completeDestruction on poa " + poa); } try { while (poa.invocationCount != 0) { try { poa.invokeCV.await(); } catch (InterruptedException ex) { // NO-OP } } if (poa.mediator != null) { if (etherealize) poa.mediator.etherealizeAll(); poa.mediator.clearAOM(); } if (poa.manager != null) poa.manager.removePOA(poa); if (parent != null) parent.children.remove(poa.name); destroyedPOATemplates.add(poa.getAdapterTemplate()); } catch (Throwable thr) { if (thr instanceof ThreadDeath) throw (ThreadDeath) thr; poa.lifecycleWrapper().unexpectedException(thr, poa.toString()); } finally { poa.state = STATE_DESTROYED; poa.beingDestroyedCV.broadcast(); poa.isDestroying.set(Boolean.FALSE); if (debug) { ORBUtility.dprint(this, "Exiting completeDestruction on poa " + poa); } } } } void etherealizeAll() { try { lock(); if (debug) { ORBUtility.dprint(this, "Calling etheralizeAll on poa " + this); } mediator.etherealizeAll(); } finally { if (debug) { ORBUtility.dprint(this, "Exiting etheralizeAll on poa " + this); } unlock(); } } // ******************************************************************* // Public POA API // ******************************************************************* /** * <code>create_POA</code> <b>Section 3.3.8.2</b> */ public POA create_POA(String name, POAManager theManager, Policy[] policies) throws AdapterAlreadyExists, InvalidPolicy { try { lock(); if (debug) { ORBUtility.dprint(this, "Calling create_POA(name=" + name + " theManager=" + theManager + " policies=" + policies + ") on poa " + this); } // We cannot create children of a POA that is (being) destroyed. sThis has been added to the CORBA 3.0 spec. if (state > STATE_RUN) throw omgLifecycleWrapper().createPoaDestroy(); POAImpl poa = (POAImpl) (children.get(name)); if (poa == null) { poa = new POAImpl(name, this, getORB(), STATE_START); } try { poa.lock(); if (debug) { ORBUtility.dprint(this, "Calling create_POA: new poa is " + poa); } if ((poa.state != STATE_START) && (poa.state != STATE_INIT)) throw new AdapterAlreadyExists(); POAManagerImpl newManager = (POAManagerImpl) theManager; if (newManager == null) newManager = new POAManagerImpl(manager.getFactory(), manager.getPIHandler()); int defaultCopierId = getORB().getCopierManager().getDefaultId(); Policies POAPolicies = new Policies(policies, defaultCopierId); poa.initialize(newManager, POAPolicies); return poa; } finally { poa.unlock(); } } finally { unlock(); } } /** * <code>find_POA</code> <b>Section 3.3.8.3</b> */ public POA find_POA(String name, boolean activate) throws AdapterNonExistent { POAImpl found = null; AdapterActivator act = null; lock(); if (debug) { ORBUtility.dprint(this, "Calling find_POA(name=" + name + " activate=" + activate + ") on poa " + this); } found = (POAImpl) children.get(name); if (found != null) { if (debug) { ORBUtility.dprint(this, "Calling find_POA: found poa " + found); } try { found.lock(); // Do not hold the parent POA lock while waiting for child to complete initialization. unlock(); // Make sure that the child has completed its initialization, if it was created by an AdapterActivator, // otherwise throw a standard TRANSIENT exception with minor code 4 (see CORBA 3.0 11.3.9.3, in // reference to unknown_adapter) if (!found.waitUntilRunning()) throw omgLifecycleWrapper().poaDestroyed(); // Note that found may be in state DESTROYING or DESTROYED at this point. That's OK, since destruction // could start at any time. } finally { found.unlock(); } } else { try { if (debug) { ORBUtility.dprint(this, "Calling find_POA: no poa found"); } if (activate && (activator != null)) { // Create a child, but don't initialize it. The newly created POA will be in state STATE_START, // which will cause other calls to find_POA that are creating the same POA to block on the // waitUntilRunning call above. Initialization must be completed by a call to create_POA inside the // unknown_adapter upcall. Note that this.poaMutex must be held here so that this.children can be // safely updated. The state is set to STATE_INIT so that initialize can make the correct state // transition when create_POA is called inside the AdapterActivator. This avoids activating the new // POA too soon by transitioning to STATE_RUN after unknown_adapter returns. found = new POAImpl(name, this, getORB(), STATE_INIT); if (debug) { ORBUtility.dprint(this, "Calling find_POA: created poa " + found); } act = activator; } else { throw new AdapterNonExistent(); } } finally { unlock(); } } // assert (found != null) // assert not holding this.poaMutex OR found.poaMutex // We must not hold either this.poaMutex or found.poaMutex here while waiting for intialization of found to // complete to prevent possible deadlocks. if (act != null) { boolean status = false; boolean adapterResult = false; if (debug) { ORBUtility.dprint(this, "Calling find_POA: calling AdapterActivator"); } try { // Prevent more than one thread at a time from executing in act in case act is shared between multiple // POAs. synchronized (act) { status = act.unknown_adapter(this, name); } } catch (SystemException exc) { throw omgLifecycleWrapper().adapterActivatorException(exc, name, poaId.toString()); } catch (Throwable thr) { // ignore most non-system exceptions, but log them for diagnostic purposes. lifecycleWrapper().unexpectedException(thr, this.toString()); if (thr instanceof ThreadDeath) throw (ThreadDeath) thr; } finally { // At this point, we have completed adapter activation. Whether this was successful or not, we must call // destroyIfNotInitDone so that calls to enter() and create_POA() that are waiting can execute again. // Failing to do this will cause the system to hang in complex tests. adapterResult = found.destroyIfNotInitDone(); } if (status) { if (!adapterResult) throw omgLifecycleWrapper().adapterActivatorException(name, poaId.toString()); } else { if (debug) { ORBUtility.dprint(this, "Calling find_POA: AdapterActivator returned false"); } // OMG Issue 3740 is resolved to throw AdapterNonExistent if unknown_adapter() returns false. throw new AdapterNonExistent(); } } return found; } /** * <code>destroy</code> <b>Section 3.3.8.4</b> */ public void destroy(boolean etherealize, boolean wait_for_completion) { // This is to avoid deadlock if (wait_for_completion && getORB().isDuringDispatch()) { throw lifecycleWrapper().destroyDeadlock(); } DestroyThread destroyer = new DestroyThread(etherealize, debug); destroyer.doIt(this, wait_for_completion); } /** * <code>create_thread_policy</code> <b>Section 3.3.8.5</b> */ public ThreadPolicy create_thread_policy(ThreadPolicyValue value) { return new ThreadPolicyImpl(value); } /** * <code>create_lifespan_policy</code> <b>Section 3.3.8.5</b> */ public LifespanPolicy create_lifespan_policy(LifespanPolicyValue value) { return new LifespanPolicyImpl(value); } /** * <code>create_id_uniqueness_policy</code> <b>Section 3.3.8.5</b> */ public IdUniquenessPolicy create_id_uniqueness_policy(IdUniquenessPolicyValue value) { return new IdUniquenessPolicyImpl(value); } /** * <code>create_id_assignment_policy</code> <b>Section 3.3.8.5</b> */ public IdAssignmentPolicy create_id_assignment_policy(IdAssignmentPolicyValue value) { return new IdAssignmentPolicyImpl(value); } /** * <code>create_implicit_activation_policy</code> <b>Section 3.3.8.5</b> */ public ImplicitActivationPolicy create_implicit_activation_policy(ImplicitActivationPolicyValue value) { return new ImplicitActivationPolicyImpl(value); } /** * <code>create_servant_retention_policy</code> <b>Section 3.3.8.5</b> */ public ServantRetentionPolicy create_servant_retention_policy(ServantRetentionPolicyValue value) { return new ServantRetentionPolicyImpl(value); } /** * <code>create_request_processing_policy</code> <b>Section 3.3.8.5</b> */ public RequestProcessingPolicy create_request_processing_policy(RequestProcessingPolicyValue value) { return new RequestProcessingPolicyImpl(value); } /** * <code>the_name</code> <b>Section 3.3.8.6</b> */ public String the_name() { try { lock(); return name; } finally { unlock(); } } /** * <code>the_parent</code> <b>Section 3.3.8.7</b> */ public POA the_parent() { try { lock(); return parent; } finally { unlock(); } } /** * <code>the_children</code> */ public org.omg.PortableServer.POA[] the_children() { try { lock(); Collection<POA> coll = children.values(); int size = coll.size(); POA[] result = new POA[size]; int index = 0; Iterator<POA> iter = coll.iterator(); while (iter.hasNext()) { POA poa = iter.next(); result[index++] = poa; } return result; } finally { unlock(); } } /** * <code>the_POAManager</code> <b>Section 3.3.8.8</b> */ public POAManager the_POAManager() { try { lock(); return manager; } finally { unlock(); } } /** * <code>the_activator</code> <b>Section 3.3.8.9</b> */ public AdapterActivator the_activator() { try { lock(); return activator; } finally { unlock(); } } /** * <code>the_activator</code> <b>Section 3.3.8.9</b> */ public void the_activator(AdapterActivator activator) { try { lock(); if (debug) { ORBUtility.dprint(this, "Calling the_activator on poa " + this + " activator=" + activator); } this.activator = activator; } finally { unlock(); } } /** * <code>get_servant_manager</code> <b>Section 3.3.8.10</b> */ public ServantManager get_servant_manager() throws WrongPolicy { try { lock(); return mediator.getServantManager(); } finally { unlock(); } } /** * <code>set_servant_manager</code> <b>Section 3.3.8.10</b> */ public void set_servant_manager(ServantManager servantManager) throws WrongPolicy { try { lock(); if (debug) { ORBUtility.dprint(this, "Calling set_servant_manager on poa " + this + " servantManager=" + servantManager); } mediator.setServantManager(servantManager); } finally { unlock(); } } /** * <code>get_servant</code> <b>Section 3.3.8.12</b> */ public Servant get_servant() throws NoServant, WrongPolicy { try { lock(); return mediator.getDefaultServant(); } finally { unlock(); } } /** * <code>set_servant</code> <b>Section 3.3.8.13</b> */ public void set_servant(Servant defaultServant) throws WrongPolicy { try { lock(); if (debug) { ORBUtility.dprint(this, "Calling set_servant on poa " + this + " defaultServant=" + defaultServant); } mediator.setDefaultServant(defaultServant); } finally { unlock(); } } /** * <code>activate_object</code> <b>Section 3.3.8.14</b> */ public byte[] activate_object(Servant servant) throws ServantAlreadyActive, WrongPolicy { try { lock(); if (debug) { ORBUtility.dprint(this, "Calling activate_object on poa " + this + " (servant=" + servant + ")"); } // Allocate a new system-generated object-id. This will throw WrongPolicy if not SYSTEM_ID policy. byte[] id = mediator.newSystemId(); try { mediator.activateObject(id, servant); } catch (ObjectAlreadyActive oaa) { // This exception can not occur in this case, since id is always brand new. } return id; } finally { if (debug) { ORBUtility.dprint(this, "Exiting activate_object on poa " + this); } unlock(); } } /** * <code>activate_object_with_id</code> <b>Section 3.3.8.15</b> */ public void activate_object_with_id(byte[] id, Servant servant) throws ObjectAlreadyActive, ServantAlreadyActive, WrongPolicy { try { lock(); if (debug) { ORBUtility.dprint(this, "Calling activate_object_with_id on poa " + this + " (servant=" + servant + " id=" + id + ")"); } // Clone the id to avoid possible errors due to aliasing (e.g. the client passes the id in and then changes // it later). byte[] idClone = id.clone(); mediator.activateObject(idClone, servant); } finally { if (debug) { ORBUtility.dprint(this, "Exiting activate_object_with_id on poa " + this); } unlock(); } } /** * <code>deactivate_object</code> <b>3.3.8.16</b> */ public void deactivate_object(byte[] id) throws ObjectNotActive, WrongPolicy { try { lock(); if (debug) { ORBUtility.dprint(this, "Calling deactivate_object on poa " + this + " (id=" + id + ")"); } mediator.deactivateObject(id); } finally { if (debug) { ORBUtility.dprint(this, "Exiting deactivate_object on poa " + this); } unlock(); } } /** * <code>create_reference</code> <b>3.3.8.17</b> */ public org.omg.CORBA.Object create_reference(String repId) throws WrongPolicy { try { lock(); if (debug) { ORBUtility.dprint(this, "Calling create_reference(repId=" + repId + ") on poa " + this); } return makeObject(repId, mediator.newSystemId()); } finally { unlock(); } } /** * <code>create_reference_with_id</code> <b>3.3.8.18</b> */ public org.omg.CORBA.Object create_reference_with_id(byte[] oid, String repId) { try { lock(); if (debug) { ORBUtility.dprint(this, "Calling create_reference_with_id(oid=" + oid + " repId=" + repId + ") on poa " + this); } // Clone the id to avoid possible errors due to aliasing (e.g. the client passes the id in and then changes // it later). byte[] idClone = oid.clone(); return makeObject(repId, idClone); } finally { unlock(); } } /** * <code>servant_to_id</code> <b>3.3.8.19</b> */ public byte[] servant_to_id(Servant servant) throws ServantNotActive, WrongPolicy { try { lock(); if (debug) { ORBUtility.dprint(this, "Calling servant_to_id(servant=" + servant + ") on poa " + this); } return mediator.servantToId(servant); } finally { unlock(); } } /** * <code>servant_to_reference</code> <b>3.3.8.20</b> */ public org.omg.CORBA.Object servant_to_reference(Servant servant) throws ServantNotActive, WrongPolicy { try { lock(); if (debug) { ORBUtility.dprint(this, "Calling servant_to_reference(servant=" + servant + ") on poa " + this); } byte[] oid = mediator.servantToId(servant); String repId = servant._all_interfaces(this, oid)[0]; return create_reference_with_id(oid, repId); } finally { unlock(); } } /** * <code>reference_to_servant</code> <b>3.3.8.21</b> */ public Servant reference_to_servant(org.omg.CORBA.Object reference) throws ObjectNotActive, WrongPolicy, WrongAdapter { try { lock(); if (debug) { ORBUtility.dprint(this, "Calling reference_to_servant(reference=" + reference + ") on poa " + this); } if (state >= STATE_DESTROYING) { throw lifecycleWrapper().adapterDestroyed(); } // reference_to_id should throw WrongAdapter if the objref was not created by this POA byte[] id = internalReferenceToId(reference); return mediator.idToServant(id); } finally { unlock(); } } /** * <code>reference_to_id</code> <b>3.3.8.22</b> */ public byte[] reference_to_id(org.omg.CORBA.Object reference) throws WrongAdapter, WrongPolicy { try { lock(); if (debug) { ORBUtility.dprint(this, "Calling reference_to_id(reference=" + reference + ") on poa " + this); } if (state >= STATE_DESTROYING) { throw lifecycleWrapper().adapterDestroyed(); } return internalReferenceToId(reference); } finally { unlock(); } } /** * <code>id_to_servant</code> <b>3.3.8.23</b> */ public Servant id_to_servant(byte[] id) throws ObjectNotActive, WrongPolicy { try { lock(); if (debug) { ORBUtility.dprint(this, "Calling id_to_servant(id=" + id + ") on poa " + this); } if (state >= STATE_DESTROYING) { throw lifecycleWrapper().adapterDestroyed(); } return mediator.idToServant(id); } finally { unlock(); } } /** * <code>id_to_reference</code> <b>3.3.8.24</b> */ public org.omg.CORBA.Object id_to_reference(byte[] id) throws ObjectNotActive, WrongPolicy { try { lock(); if (debug) { ORBUtility.dprint(this, "Calling id_to_reference(id=" + id + ") on poa " + this); } if (state >= STATE_DESTROYING) { throw lifecycleWrapper().adapterDestroyed(); } Servant s = mediator.idToServant(id); String repId = s._all_interfaces(this, id)[0]; return makeObject(repId, id); } finally { unlock(); } } /** * <code>id</code> <b>11.3.8.26 in ptc/00-08-06</b> */ public byte[] id() { try { lock(); return getAdapterId(); } finally { unlock(); } } // *************************************************************** // Implementation of ObjectAdapter interface // *************************************************************** public Policy getEffectivePolicy(int type) { return mediator.getPolicies().get_effective_policy(type); } public int getManagerId() { return manager.getManagerId(); } public short getState() { return manager.getORTState(); } public String[] getInterfaces(java.lang.Object servant, byte[] objectId) { Servant serv = (Servant) servant; return serv._all_interfaces(this, objectId); } protected ObjectCopierFactory getObjectCopierFactory() { int copierId = mediator.getPolicies().getCopierId(); CopierManager cm = getORB().getCopierManager(); return cm.getObjectCopierFactory(copierId); } public void enter() throws OADestroyed { try { lock(); if (debug) { ORBUtility.dprint(this, "Calling enter on poa " + this); } // Avoid deadlock if this is the thread that is processing the POA.destroy because this is the only thread // that can notify waiters on beingDestroyedCV. This can happen if an etherealize upcall invokes a method on // a colocated object served by this POA. while ((state == STATE_DESTROYING) && (isDestroying.get() == Boolean.FALSE)) { try { beingDestroyedCV.await(); } catch (InterruptedException ex) { // NO-OP } } if (!waitUntilRunning()) throw new OADestroyed(); invocationCount++; } finally { if (debug) { ORBUtility.dprint(this, "Exiting enter on poa " + this); } unlock(); } manager.enter(); } public void exit() { try { lock(); if (debug) { ORBUtility.dprint(this, "Calling exit on poa " + this); } invocationCount--; if ((invocationCount == 0) && (state == STATE_DESTROYING)) { invokeCV.broadcast(); } } finally { if (debug) { ORBUtility.dprint(this, "Exiting exit on poa " + this); } unlock(); } manager.exit(); } public void getInvocationServant(OAInvocationInfo info) { try { lock(); if (debug) { ORBUtility.dprint(this, "Calling getInvocationServant on poa " + this); } java.lang.Object servant = null; try { servant = mediator.getInvocationServant(info.id(), info.getOperation()); } catch (ForwardRequest freq) { throw new ForwardException(getORB(), freq.forward_reference); } info.setServant(servant); } finally { if (debug) { ORBUtility.dprint(this, "Exiting getInvocationServant on poa " + this); } unlock(); } } public org.omg.CORBA.Object getLocalServant(byte[] objectId) { return null; } /** * Called from the subcontract to let this POA cleanup after an invocation. Note: If getServant was called, then * returnServant MUST be called, even in the case of exceptions. This may be called multiple times for a single * request. */ public void returnServant() { try { lock(); if (debug) { ORBUtility.dprint(this, "Calling returnServant on poa " + this); } mediator.returnServant(); } catch (Throwable thr) { if (debug) { ORBUtility.dprint(this, "Exception " + thr + " in returnServant on poa " + this); } if (thr instanceof Error) throw (Error) thr; else if (thr instanceof RuntimeException) throw (RuntimeException) thr; } finally { if (debug) { ORBUtility.dprint(this, "Exiting returnServant on poa " + this); } unlock(); } } }