blob: 0698aafef43249efe6f9b4ca777655d53379c98b [file] [log] [blame]
/*
* 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 com.sun.corba.se.impl.oa.poa;
import java.util.Collection ;
import java.util.Set ;
import java.util.HashSet ;
import java.util.Map ;
import java.util.HashMap ;
import java.util.Iterator ;
import org.omg.CORBA.Policy ;
import org.omg.CORBA.SystemException ;
import org.omg.PortableServer.POA ;
import org.omg.PortableServer.Servant ;
import org.omg.PortableServer.POAManager ;
import org.omg.PortableServer.AdapterActivator ;
import org.omg.PortableServer.ServantManager ;
import org.omg.PortableServer.ForwardRequest ;
import org.omg.PortableServer.ThreadPolicy;
import org.omg.PortableServer.LifespanPolicy;
import org.omg.PortableServer.IdUniquenessPolicy;
import org.omg.PortableServer.IdAssignmentPolicy;
import org.omg.PortableServer.ImplicitActivationPolicy;
import org.omg.PortableServer.ServantRetentionPolicy;
import org.omg.PortableServer.RequestProcessingPolicy;
import org.omg.PortableServer.ThreadPolicyValue ;
import org.omg.PortableServer.LifespanPolicyValue ;
import org.omg.PortableServer.IdUniquenessPolicyValue ;
import org.omg.PortableServer.IdAssignmentPolicyValue ;
import org.omg.PortableServer.ImplicitActivationPolicyValue ;
import org.omg.PortableServer.ServantRetentionPolicyValue ;
import org.omg.PortableServer.RequestProcessingPolicyValue ;
import org.omg.PortableServer.POAPackage.AdapterAlreadyExists ;
import org.omg.PortableServer.POAPackage.AdapterNonExistent ;
import org.omg.PortableServer.POAPackage.InvalidPolicy ;
import org.omg.PortableServer.POAPackage.WrongPolicy ;
import org.omg.PortableServer.POAPackage.WrongAdapter ;
import org.omg.PortableServer.POAPackage.NoServant ;
import org.omg.PortableServer.POAPackage.ServantAlreadyActive ;
import org.omg.PortableServer.POAPackage.ObjectAlreadyActive ;
import org.omg.PortableServer.POAPackage.ServantNotActive ;
import org.omg.PortableServer.POAPackage.ObjectNotActive ;
import org.omg.PortableInterceptor.ObjectReferenceFactory ;
import org.omg.PortableInterceptor.ObjectReferenceTemplate ;
import org.omg.PortableInterceptor.NON_EXISTENT ;
import org.omg.IOP.TAG_INTERNET_IOP ;
import com.sun.corba.se.spi.copyobject.CopierManager ;
import com.sun.corba.se.spi.copyobject.ObjectCopier ;
import com.sun.corba.se.spi.copyobject.ObjectCopierFactory ;
import com.sun.corba.se.spi.oa.OADestroyed ;
import com.sun.corba.se.spi.oa.OAInvocationInfo ;
import com.sun.corba.se.spi.oa.ObjectAdapter ;
import com.sun.corba.se.spi.oa.ObjectAdapterBase ;
import com.sun.corba.se.spi.oa.ObjectAdapterFactory ;
import com.sun.corba.se.spi.ior.ObjectKeyTemplate ;
import com.sun.corba.se.spi.ior.ObjectId ;
import com.sun.corba.se.spi.ior.ObjectAdapterId ;
import com.sun.corba.se.spi.ior.IOR ;
import com.sun.corba.se.spi.ior.IORFactories ;
import com.sun.corba.se.spi.ior.IORTemplate ;
import com.sun.corba.se.spi.ior.IORTemplateList ;
import com.sun.corba.se.spi.ior.TaggedProfile ;
import com.sun.corba.se.spi.ior.iiop.IIOPProfile ;
import com.sun.corba.se.spi.ior.iiop.IIOPAddress ;
import com.sun.corba.se.spi.ior.iiop.IIOPFactories ;
import com.sun.corba.se.spi.orb.ORB ;
import com.sun.corba.se.spi.protocol.ForwardException ;
import com.sun.corba.se.spi.transport.SocketOrChannelAcceptor;
import com.sun.corba.se.impl.ior.POAObjectKeyTemplate ;
import com.sun.corba.se.impl.ior.ObjectAdapterIdArray ;
import com.sun.corba.se.impl.orbutil.ORBUtility;
import com.sun.corba.se.impl.orbutil.ORBConstants;
import com.sun.corba.se.impl.orbutil.concurrent.Sync ;
import com.sun.corba.se.impl.orbutil.concurrent.SyncUtil ;
import com.sun.corba.se.impl.orbutil.concurrent.ReentrantMutex ;
import com.sun.corba.se.impl.orbutil.concurrent.CondVar ;
/**
* 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 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 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 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();
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 () {
protected java.lang.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 iff 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 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 destroyedPOATemplates = new HashSet() ;
performDestroy( thePoa, destroyedPOATemplates );
Iterator iter = destroyedPOATemplates.iterator() ;
ObjectReferenceTemplate[] orts = new ObjectReferenceTemplate[
destroyedPOATemplates.size() ] ;
int index = 0 ;
while (iter.hasNext())
orts[ index++ ] = (ObjectReferenceTemplate)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 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 = (POAImpl[])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 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 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.
// This 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 coll = children.values() ;
int size = coll.size() ;
POA[] result = new POA[ size ] ;
int index = 0 ;
Iterator iter = coll.iterator() ;
while (iter.hasNext()) {
POA 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 = (byte[])(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 = (byte[])(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() ;
}
}
}