/*
* 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();
}
}
}