POAPolicyMediatorImpl_R_USM.java revision 667:d0315150c39d
1/*
2 * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.corba.se.impl.oa.poa ;
27
28import java.util.Set ;
29import org.omg.CORBA.SystemException ;
30
31import org.omg.PortableServer.ServantActivator ;
32import org.omg.PortableServer.Servant ;
33import org.omg.PortableServer.ServantManager ;
34import org.omg.PortableServer.ForwardRequest ;
35import org.omg.PortableServer.POAPackage.WrongPolicy ;
36import org.omg.PortableServer.POAPackage.ObjectNotActive ;
37import org.omg.PortableServer.POAPackage.ServantNotActive ;
38import org.omg.PortableServer.POAPackage.ObjectAlreadyActive ;
39import org.omg.PortableServer.POAPackage.ServantAlreadyActive ;
40import org.omg.PortableServer.POAPackage.NoServant ;
41
42import com.sun.corba.se.impl.orbutil.concurrent.SyncUtil ;
43import com.sun.corba.se.impl.orbutil.ORBUtility ;
44import com.sun.corba.se.impl.orbutil.ORBConstants ;
45
46import com.sun.corba.se.impl.oa.NullServantImpl ;
47
48import com.sun.corba.se.impl.javax.rmi.CORBA.Util ;
49
50import com.sun.corba.se.spi.oa.OAInvocationInfo ;
51import com.sun.corba.se.spi.oa.NullServant ;
52import com.sun.corba.se.impl.transport.ManagedLocalsThread;
53
54/** Implementation of POARequesHandler that provides policy specific
55 * operations on the POA.
56 */
57public class POAPolicyMediatorImpl_R_USM extends POAPolicyMediatorBase_R {
58    protected ServantActivator activator ;
59
60    POAPolicyMediatorImpl_R_USM( Policies policies, POAImpl poa )
61    {
62        // assert policies.retainServants()
63        super( policies, poa ) ;
64        activator = null ;
65
66        if (!policies.useServantManager())
67            throw poa.invocationWrapper().policyMediatorBadPolicyInFactory() ;
68    }
69
70    /* This handles a rather subtle bug (4939892).  The problem is that
71     * enter will wait on the entry if it is being etherealized.  When the
72     * deferred state transition completes, the entry is no longer in the
73     * AOM, and so we need to get a new entry, otherwise activator.incarnate
74     * will be called twice, once for the old entry, and again when a new
75     * entry is created.  This fix also required extending the FSM StateEngine
76     * to allow actions to throw exceptions, and adding a new state in the
77     * AOMEntry FSM to detect this condition.
78     */
79    private AOMEntry enterEntry( ActiveObjectMap.Key key )
80    {
81        AOMEntry result = null ;
82        boolean failed ;
83        do {
84            failed = false ;
85            result = activeObjectMap.get(key) ;
86
87            try {
88                result.enter() ;
89            } catch (Exception exc) {
90                failed = true ;
91            }
92        } while (failed) ;
93
94        return result ;
95    }
96
97    protected java.lang.Object internalGetServant( byte[] id,
98        String operation ) throws ForwardRequest
99    {
100        if (poa.getDebug()) {
101            ORBUtility.dprint( this,
102                "Calling POAPolicyMediatorImpl_R_USM.internalGetServant " +
103                "for poa " + poa + " operation=" + operation ) ;
104        }
105
106        try {
107            ActiveObjectMap.Key key = new ActiveObjectMap.Key( id ) ;
108            AOMEntry entry = enterEntry(key) ;
109            java.lang.Object servant = activeObjectMap.getServant( entry ) ;
110            if (servant != null) {
111                if (poa.getDebug()) {
112                    ORBUtility.dprint( this,
113                        "internalGetServant: servant already activated" ) ;
114                }
115
116                return servant ;
117            }
118
119            if (activator == null) {
120                if (poa.getDebug()) {
121                    ORBUtility.dprint( this,
122                        "internalGetServant: no servant activator in POA" ) ;
123                }
124
125                entry.incarnateFailure() ;
126                throw poa.invocationWrapper().poaNoServantManager() ;
127            }
128
129            // Drop the POA lock during the incarnate call and
130            // re-acquire it afterwards.  The entry state machine
131            // prevents more than one thread from executing the
132            // incarnate method at a time within the same POA.
133            try {
134                if (poa.getDebug()) {
135                    ORBUtility.dprint( this,
136                        "internalGetServant: upcall to incarnate" ) ;
137                }
138
139                poa.unlock() ;
140
141                servant = activator.incarnate(id, poa);
142
143                if (servant == null)
144                    servant = new NullServantImpl(
145                        poa.omgInvocationWrapper().nullServantReturned() ) ;
146            } catch (ForwardRequest freq) {
147                if (poa.getDebug()) {
148                    ORBUtility.dprint( this,
149                        "internalGetServant: incarnate threw ForwardRequest" ) ;
150                }
151
152                throw freq ;
153            } catch (SystemException exc) {
154                if (poa.getDebug()) {
155                    ORBUtility.dprint( this,
156                        "internalGetServant: incarnate threw SystemException " + exc ) ;
157                }
158
159                throw exc ;
160            } catch (Throwable exc) {
161                if (poa.getDebug()) {
162                    ORBUtility.dprint( this,
163                        "internalGetServant: incarnate threw Throwable " + exc ) ;
164                }
165
166                throw poa.invocationWrapper().poaServantActivatorLookupFailed(
167                    exc ) ;
168            } finally {
169                poa.lock() ;
170
171                // servant == null means incarnate threw an exception,
172                // while servant instanceof NullServant means incarnate returned a
173                // null servant.  Either case is an incarnate failure to the
174                // entry state machine.
175                if ((servant == null) || (servant instanceof NullServant)) {
176                    if (poa.getDebug()) {
177                        ORBUtility.dprint( this,
178                            "internalGetServant: incarnate failed" ) ;
179                    }
180
181                    // XXX Does the AOM leak in this case? Yes,
182                    // but the problem is hard to fix.  There may be
183                    // a number of threads waiting for the state to change
184                    // from INCARN to something else, which is VALID or
185                    // INVALID, depending on the incarnate result.
186                    // The activeObjectMap.get() call above creates an
187                    // ActiveObjectMap.Entry if one does not already exist,
188                    // and stores it in the keyToEntry map in the AOM.
189                    entry.incarnateFailure() ;
190                } else {
191                    // here check for unique_id policy, and if the servant
192                    // is already registered for a different ID, then throw
193                    // OBJ_ADAPTER exception, else activate it. Section 11.3.5.1
194                    // 99-10-07.pdf
195                    if (isUnique) {
196                        // check if the servant already is associated with some id
197                        if (activeObjectMap.contains((Servant)servant)) {
198                            if (poa.getDebug()) {
199                                ORBUtility.dprint( this,
200                                    "internalGetServant: servant already assigned to ID" ) ;
201                            }
202
203                            entry.incarnateFailure() ;
204                            throw poa.invocationWrapper().poaServantNotUnique() ;
205                        }
206                    }
207
208                    if (poa.getDebug()) {
209                        ORBUtility.dprint( this,
210                            "internalGetServant: incarnate complete" ) ;
211                    }
212
213                    entry.incarnateComplete() ;
214                    activateServant(key, entry, (Servant)servant);
215                }
216            }
217
218            return servant ;
219        } finally {
220            if (poa.getDebug()) {
221                ORBUtility.dprint( this,
222                    "Exiting POAPolicyMediatorImpl_R_USM.internalGetServant " +
223                    "for poa " + poa ) ;
224            }
225        }
226    }
227
228    public void returnServant()
229    {
230        OAInvocationInfo info = orb.peekInvocationInfo();
231        byte[] id = info.id() ;
232        ActiveObjectMap.Key key = new ActiveObjectMap.Key( id ) ;
233        AOMEntry entry = activeObjectMap.get( key ) ;
234        entry.exit() ;
235    }
236
237    public void etherealizeAll()
238    {
239        if (activator != null)  {
240            Set keySet = activeObjectMap.keySet() ;
241
242            // Copy the elements in the set to an array to avoid
243            // changes in the set due to concurrent modification
244            ActiveObjectMap.Key[] keys =
245                (ActiveObjectMap.Key[])keySet.toArray(
246                    new ActiveObjectMap.Key[ keySet.size() ] ) ;
247
248            for (int ctr=0; ctr<keySet.size(); ctr++) {
249                ActiveObjectMap.Key key = keys[ctr] ;
250                AOMEntry entry = activeObjectMap.get( key ) ;
251                Servant servant = activeObjectMap.getServant( entry ) ;
252                if (servant != null) {
253                    boolean remainingActivations =
254                        activeObjectMap.hasMultipleIDs(entry) ;
255
256                    // Here we etherealize in the thread that called this
257                    // method, rather than etherealizing in a new thread
258                    // as in the deactivate case.  We still inform the
259                    // entry state machine so that only one thread at a
260                    // time can call the etherealize method.
261                    entry.startEtherealize( null ) ;
262                    try {
263                        poa.unlock() ;
264                        try {
265                            activator.etherealize(key.id, poa, servant, true,
266                                remainingActivations);
267                        } catch (Exception exc) {
268                            // ignore all exceptions
269                        }
270                    } finally {
271                        poa.lock() ;
272                        entry.etherealizeComplete() ;
273                    }
274                }
275            }
276        }
277    }
278
279    public ServantManager getServantManager() throws WrongPolicy
280    {
281        return activator;
282    }
283
284    public void setServantManager(
285        ServantManager servantManager ) throws WrongPolicy
286    {
287        if (activator != null)
288            throw poa.invocationWrapper().servantManagerAlreadySet() ;
289
290        if (servantManager instanceof ServantActivator)
291            activator = (ServantActivator)servantManager;
292        else
293            throw poa.invocationWrapper().servantManagerBadType() ;
294    }
295
296    public Servant getDefaultServant() throws NoServant, WrongPolicy
297    {
298        throw new WrongPolicy();
299    }
300
301    public void setDefaultServant( Servant servant ) throws WrongPolicy
302    {
303        throw new WrongPolicy();
304    }
305
306    class Etherealizer extends ManagedLocalsThread {
307        private POAPolicyMediatorImpl_R_USM mediator ;
308        private ActiveObjectMap.Key key ;
309        private AOMEntry entry ;
310        private Servant servant ;
311        private boolean debug ;
312
313
314        public Etherealizer( POAPolicyMediatorImpl_R_USM mediator,
315            ActiveObjectMap.Key key, AOMEntry entry, Servant servant,
316            boolean debug )
317        {
318            this.mediator = mediator ;
319            this.key = key ;
320            this.entry = entry;
321            this.servant = servant;
322            this.debug = debug ;
323        }
324
325        public void run() {
326            if (debug) {
327                ORBUtility.dprint( this, "Calling Etherealizer.run on key " +
328                    key ) ;
329            }
330
331            try {
332                try {
333                    mediator.activator.etherealize( key.id, mediator.poa, servant,
334                        false, mediator.activeObjectMap.hasMultipleIDs( entry ) );
335                } catch (Exception exc) {
336                    // ignore all exceptions
337                }
338
339                try {
340                    mediator.poa.lock() ;
341
342                    entry.etherealizeComplete() ;
343                    mediator.activeObjectMap.remove( key ) ;
344
345                    POAManagerImpl pm = (POAManagerImpl)mediator.poa.the_POAManager() ;
346                    POAFactory factory = pm.getFactory() ;
347                    factory.unregisterPOAForServant( mediator.poa, servant);
348                } finally {
349                    mediator.poa.unlock() ;
350                }
351            } finally {
352                if (debug) {
353                    ORBUtility.dprint( this, "Exiting Etherealizer.run" ) ;
354                }
355            }
356        }
357    }
358
359    public void deactivateHelper( ActiveObjectMap.Key key, AOMEntry entry,
360        Servant servant ) throws ObjectNotActive, WrongPolicy
361    {
362        if (activator == null)
363            throw poa.invocationWrapper().poaNoServantManager() ;
364
365        Etherealizer eth = new Etherealizer( this, key, entry, servant, poa.getDebug() ) ;
366        entry.startEtherealize( eth ) ;
367    }
368
369    public Servant idToServant( byte[] id )
370        throws WrongPolicy, ObjectNotActive
371    {
372        ActiveObjectMap.Key key = new ActiveObjectMap.Key( id ) ;
373        AOMEntry entry = activeObjectMap.get(key);
374
375        Servant servant = activeObjectMap.getServant( entry ) ;
376        if (servant != null)
377            return servant ;
378        else
379            throw new ObjectNotActive() ;
380    }
381}
382