/* * Copyright 2002-2004 Sun Microsystems, Inc. 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. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ package com.sun.corba.se.impl.oa.poa ; import java.util.Set ; import org.omg.CORBA.SystemException ; import org.omg.PortableServer.ServantActivator ; import org.omg.PortableServer.Servant ; import org.omg.PortableServer.ServantManager ; import org.omg.PortableServer.ForwardRequest ; import org.omg.PortableServer.POAPackage.WrongPolicy ; import org.omg.PortableServer.POAPackage.ObjectNotActive ; import org.omg.PortableServer.POAPackage.ServantNotActive ; import org.omg.PortableServer.POAPackage.ObjectAlreadyActive ; import org.omg.PortableServer.POAPackage.ServantAlreadyActive ; import org.omg.PortableServer.POAPackage.NoServant ; import com.sun.corba.se.impl.orbutil.concurrent.SyncUtil ; import com.sun.corba.se.impl.orbutil.ORBUtility ; import com.sun.corba.se.impl.orbutil.ORBConstants ; import com.sun.corba.se.impl.oa.NullServantImpl ; import com.sun.corba.se.impl.javax.rmi.CORBA.Util ; import com.sun.corba.se.spi.oa.OAInvocationInfo ; import com.sun.corba.se.spi.oa.NullServant ; /** 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 java.lang.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) ; java.lang.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 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 = (ActiveObjectMap.Key[])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() ; } }