/*
* Copyright (c) 2002, 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.Set;
import org.jboss.com.sun.corba.se.impl.oa.NullServantImpl;
import org.jboss.com.sun.corba.se.impl.oa.poa.ActiveObjectMap.Key;
import org.jboss.com.sun.corba.se.impl.orbutil.ORBUtility;
import org.jboss.com.sun.corba.se.spi.oa.NullServant;
import org.jboss.com.sun.corba.se.spi.oa.OAInvocationInfo;
import org.omg.CORBA.SystemException;
import org.omg.PortableServer.ForwardRequest;
import org.omg.PortableServer.Servant;
import org.omg.PortableServer.ServantActivator;
import org.omg.PortableServer.ServantManager;
import org.omg.PortableServer.POAPackage.NoServant;
import org.omg.PortableServer.POAPackage.ObjectNotActive;
import org.omg.PortableServer.POAPackage.WrongPolicy;
/**
* Implementation of POARequesHandler that provides policy specific operations on the POA.
*/
public class POAPolicyMediatorImpl_R_USM extends POAPolicyMediatorBase_R
{
protected ServantActivator activator;
POAPolicyMediatorImpl_R_USM(Policies policies, POAImpl poa)
{
// assert policies.retainServants()
super(policies, poa);
activator = null;
if (!policies.useServantManager())
throw poa.invocationWrapper().policyMediatorBadPolicyInFactory();
}
/*
* This handles a rather subtle bug (4939892). The problem is that enter will wait on the entry if it is being
* etherealized. When the deferred state transition completes, the entry is no longer in the AOM, and so we need to
* get a new entry, otherwise activator.incarnate will be called twice, once for the old entry, and again when a new
* entry is created. This fix also required extending the FSM StateEngine to allow actions to throw exceptions, and
* adding a new state in the AOMEntry FSM to detect this condition.
*/
private AOMEntry enterEntry(ActiveObjectMap.Key key)
{
AOMEntry result = null;
boolean failed;
do
{
failed = false;
result = activeObjectMap.get(key);
try
{
result.enter();
}
catch (Exception exc)
{
failed = true;
}
}
while (failed);
return result;
}
protected Object internalGetServant(byte[] id, String operation) throws ForwardRequest
{
if (poa.getDebug())
{
ORBUtility.dprint(this, "Calling POAPolicyMediatorImpl_R_USM.internalGetServant " + "for poa " + poa
+ " operation=" + operation);
}
try
{
ActiveObjectMap.Key key = new ActiveObjectMap.Key(id);
AOMEntry entry = enterEntry(key);
Object servant = activeObjectMap.getServant(entry);
if (servant != null)
{
if (poa.getDebug())
{
ORBUtility.dprint(this, "internalGetServant: servant already activated");
}
return servant;
}
if (activator == null)
{
if (poa.getDebug())
{
ORBUtility.dprint(this, "internalGetServant: no servant activator in POA");
}
entry.incarnateFailure();
throw poa.invocationWrapper().poaNoServantManager();
}
// Drop the POA lock during the incarnate call and re-acquire it afterwards. The entry state machine
// prevents more than one thread from executing the incarnate method at a time within the same POA.
try
{
if (poa.getDebug())
{
ORBUtility.dprint(this, "internalGetServant: upcall to incarnate");
}
poa.unlock();
servant = activator.incarnate(id, poa);
if (servant == null)
servant = new NullServantImpl(poa.omgInvocationWrapper().nullServantReturned());
}
catch (ForwardRequest freq)
{
if (poa.getDebug())
{
ORBUtility.dprint(this, "internalGetServant: incarnate threw ForwardRequest");
}
throw freq;
}
catch (SystemException exc)
{
if (poa.getDebug())
{
ORBUtility.dprint(this, "internalGetServant: incarnate threw SystemException " + exc);
}
throw exc;
}
catch (Throwable exc)
{
if (poa.getDebug())
{
ORBUtility.dprint(this, "internalGetServant: incarnate threw Throwable " + exc);
}
throw poa.invocationWrapper().poaServantActivatorLookupFailed(exc);
}
finally
{
poa.lock();
// servant == null means incarnate threw an exception, while servant instanceof NullServant means
// incarnate returned a null servant. Either case is an incarnate failure to the entry state machine.
if ((servant == null) || (servant instanceof NullServant))
{
if (poa.getDebug())
{
ORBUtility.dprint(this, "internalGetServant: incarnate failed");
}
// XXX Does the AOM leak in this case? Yes, but the problem is hard to fix. There may be a number of
// threads waiting for the state to change from INCARN to something else, which is VALID or INVALID,
// depending on the incarnate result. The activeObjectMap.get() call above creates an
// ActiveObjectMap.Entry if one does not already exist, and stores it in the keyToEntry map in the
// AOM.
entry.incarnateFailure();
}
else
{
// here check for unique_id policy, and if the servant is already registered for a different ID,
// then throw OBJ_ADAPTER exception, else activate it. Section 11.3.5.1 99-10-07.pdf
if (isUnique)
{
// check if the servant already is associated with some id
if (activeObjectMap.contains((Servant) servant))
{
if (poa.getDebug())
{
ORBUtility.dprint(this, "internalGetServant: servant already assigned to ID");
}
entry.incarnateFailure();
throw poa.invocationWrapper().poaServantNotUnique();
}
}
if (poa.getDebug())
{
ORBUtility.dprint(this, "internalGetServant: incarnate complete");
}
entry.incarnateComplete();
activateServant(key, entry, (Servant) servant);
}
}
return servant;
}
finally
{
if (poa.getDebug())
{
ORBUtility.dprint(this, "Exiting POAPolicyMediatorImpl_R_USM.internalGetServant " + "for poa " + poa);
}
}
}
public void returnServant()
{
OAInvocationInfo info = orb.peekInvocationInfo();
byte[] id = info.id();
ActiveObjectMap.Key key = new ActiveObjectMap.Key(id);
AOMEntry entry = activeObjectMap.get(key);
entry.exit();
}
public void etherealizeAll()
{
if (activator != null)
{
Set<Key> keySet = activeObjectMap.keySet();
// Copy the elements in the set to an array to avoid changes in the set due to concurrent modification
ActiveObjectMap.Key[] keys = keySet.toArray(new ActiveObjectMap.Key[keySet.size()]);
for (int ctr = 0; ctr < keySet.size(); ctr++)
{
ActiveObjectMap.Key key = keys[ctr];
AOMEntry entry = activeObjectMap.get(key);
Servant servant = activeObjectMap.getServant(entry);
if (servant != null)
{
boolean remainingActivations = activeObjectMap.hasMultipleIDs(entry);
// Here we etherealize in the thread that called this method, rather than etherealizing in a new
// thread as in the deactivate case. We still inform the entry state machine so that only one thread
// at a time can call the etherealize method.
entry.startEtherealize(null);
try
{
poa.unlock();
try
{
activator.etherealize(key.id, poa, servant, true, remainingActivations);
}
catch (Exception exc)
{
// ignore all exceptions
}
}
finally
{
poa.lock();
entry.etherealizeComplete();
}
}
}
}
}
public ServantManager getServantManager() throws WrongPolicy
{
return activator;
}
public void setServantManager(ServantManager servantManager) throws WrongPolicy
{
if (activator != null)
throw poa.invocationWrapper().servantManagerAlreadySet();
if (servantManager instanceof ServantActivator)
activator = (ServantActivator) servantManager;
else
throw poa.invocationWrapper().servantManagerBadType();
}
public Servant getDefaultServant() throws NoServant, WrongPolicy
{
throw new WrongPolicy();
}
public void setDefaultServant(Servant servant) throws WrongPolicy
{
throw new WrongPolicy();
}
class Etherealizer extends Thread
{
private POAPolicyMediatorImpl_R_USM mediator;
private ActiveObjectMap.Key key;
private AOMEntry entry;
private Servant servant;
private boolean debug;
public Etherealizer(POAPolicyMediatorImpl_R_USM mediator, ActiveObjectMap.Key key, AOMEntry entry,
Servant servant, boolean debug)
{
this.mediator = mediator;
this.key = key;
this.entry = entry;
this.servant = servant;
this.debug = debug;
}
public void run()
{
if (debug)
{
ORBUtility.dprint(this, "Calling Etherealizer.run on key " + key);
}
try
{
try
{
mediator.activator.etherealize(key.id, mediator.poa, servant, false,
mediator.activeObjectMap.hasMultipleIDs(entry));
}
catch (Exception exc)
{
// ignore all exceptions
}
try
{
mediator.poa.lock();
entry.etherealizeComplete();
mediator.activeObjectMap.remove(key);
POAManagerImpl pm = (POAManagerImpl) mediator.poa.the_POAManager();
POAFactory factory = pm.getFactory();
factory.unregisterPOAForServant(mediator.poa, servant);
}
finally
{
mediator.poa.unlock();
}
}
finally
{
if (debug)
{
ORBUtility.dprint(this, "Exiting Etherealizer.run");
}
}
}
}
public void deactivateHelper(ActiveObjectMap.Key key, AOMEntry entry, Servant servant) throws ObjectNotActive,
WrongPolicy
{
if (activator == null)
throw poa.invocationWrapper().poaNoServantManager();
Etherealizer eth = new Etherealizer(this, key, entry, servant, poa.getDebug());
entry.startEtherealize(eth);
}
public Servant idToServant(byte[] id) throws WrongPolicy, ObjectNotActive
{
ActiveObjectMap.Key key = new ActiveObjectMap.Key(id);
AOMEntry entry = activeObjectMap.get(key);
Servant servant = activeObjectMap.getServant(entry);
if (servant != null)
return servant;
else
throw new ObjectNotActive();
}
}