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