POAPolicyMediatorImpl_R_USM.java revision 758:bb6bf34f121f
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 ;
52
53/** Implementation of POARequesHandler that provides policy specific
54 * operations on the POA.
55 */
56public class POAPolicyMediatorImpl_R_USM extends POAPolicyMediatorBase_R {
57    protected ServantActivator activator ;
58
59    POAPolicyMediatorImpl_R_USM( Policies policies, POAImpl poa )
60    {
61        // assert policies.retainServants()
62        super( policies, poa ) ;
63        activator = null ;
64
65        if (!policies.useServantManager())
66            throw poa.invocationWrapper().policyMediatorBadPolicyInFactory() ;
67    }
68
69    /* This handles a rather subtle bug (4939892).  The problem is that
70     * enter will wait on the entry if it is being etherealized.  When the
71     * deferred state transition completes, the entry is no longer in the
72     * AOM, and so we need to get a new entry, otherwise activator.incarnate
73     * will be called twice, once for the old entry, and again when a new
74     * entry is created.  This fix also required extending the FSM StateEngine
75     * to allow actions to throw exceptions, and adding a new state in the
76     * AOMEntry FSM to detect this condition.
77     */
78    private AOMEntry enterEntry( ActiveObjectMap.Key key )
79    {
80        AOMEntry result = null ;
81        boolean failed ;
82        do {
83            failed = false ;
84            result = activeObjectMap.get(key) ;
85
86            try {
87                result.enter() ;
88            } catch (Exception exc) {
89                failed = true ;
90            }
91        } while (failed) ;
92
93        return result ;
94    }
95
96    protected java.lang.Object internalGetServant( byte[] id,
97        String operation ) throws ForwardRequest
98    {
99        if (poa.getDebug()) {
100            ORBUtility.dprint( this,
101                "Calling POAPolicyMediatorImpl_R_USM.internalGetServant " +
102                "for poa " + poa + " operation=" + operation ) ;
103        }
104
105        try {
106            ActiveObjectMap.Key key = new ActiveObjectMap.Key( id ) ;
107            AOMEntry entry = enterEntry(key) ;
108            java.lang.Object servant = activeObjectMap.getServant( entry ) ;
109            if (servant != null) {
110                if (poa.getDebug()) {
111                    ORBUtility.dprint( this,
112                        "internalGetServant: servant already activated" ) ;
113                }
114
115                return servant ;
116            }
117
118            if (activator == null) {
119                if (poa.getDebug()) {
120                    ORBUtility.dprint( this,
121                        "internalGetServant: no servant activator in POA" ) ;
122                }
123
124                entry.incarnateFailure() ;
125                throw poa.invocationWrapper().poaNoServantManager() ;
126            }
127
128            // Drop the POA lock during the incarnate call and
129            // re-acquire it afterwards.  The entry state machine
130            // prevents more than one thread from executing the
131            // incarnate method at a time within the same POA.
132            try {
133                if (poa.getDebug()) {
134                    ORBUtility.dprint( this,
135                        "internalGetServant: upcall to incarnate" ) ;
136                }
137
138                poa.unlock() ;
139
140                servant = activator.incarnate(id, poa);
141
142                if (servant == null)
143                    servant = new NullServantImpl(
144                        poa.omgInvocationWrapper().nullServantReturned() ) ;
145            } catch (ForwardRequest freq) {
146                if (poa.getDebug()) {
147                    ORBUtility.dprint( this,
148                        "internalGetServant: incarnate threw ForwardRequest" ) ;
149                }
150
151                throw freq ;
152            } catch (SystemException exc) {
153                if (poa.getDebug()) {
154                    ORBUtility.dprint( this,
155                        "internalGetServant: incarnate threw SystemException " + exc ) ;
156                }
157
158                throw exc ;
159            } catch (Throwable exc) {
160                if (poa.getDebug()) {
161                    ORBUtility.dprint( this,
162                        "internalGetServant: incarnate threw Throwable " + exc ) ;
163                }
164
165                throw poa.invocationWrapper().poaServantActivatorLookupFailed(
166                    exc ) ;
167            } finally {
168                poa.lock() ;
169
170                // servant == null means incarnate threw an exception,
171                // while servant instanceof NullServant means incarnate returned a
172                // null servant.  Either case is an incarnate failure to the
173                // entry state machine.
174                if ((servant == null) || (servant instanceof NullServant)) {
175                    if (poa.getDebug()) {
176                        ORBUtility.dprint( this,
177                            "internalGetServant: incarnate failed" ) ;
178                    }
179
180                    // XXX Does the AOM leak in this case? Yes,
181                    // but the problem is hard to fix.  There may be
182                    // a number of threads waiting for the state to change
183                    // from INCARN to something else, which is VALID or
184                    // INVALID, depending on the incarnate result.
185                    // The activeObjectMap.get() call above creates an
186                    // ActiveObjectMap.Entry if one does not already exist,
187                    // and stores it in the keyToEntry map in the AOM.
188                    entry.incarnateFailure() ;
189                } else {
190                    // here check for unique_id policy, and if the servant
191                    // is already registered for a different ID, then throw
192                    // OBJ_ADAPTER exception, else activate it. Section 11.3.5.1
193                    // 99-10-07.pdf
194                    if (isUnique) {
195                        // check if the servant already is associated with some id
196                        if (activeObjectMap.contains((Servant)servant)) {
197                            if (poa.getDebug()) {
198                                ORBUtility.dprint( this,
199                                    "internalGetServant: servant already assigned to ID" ) ;
200                            }
201
202                            entry.incarnateFailure() ;
203                            throw poa.invocationWrapper().poaServantNotUnique() ;
204                        }
205                    }
206
207                    if (poa.getDebug()) {
208                        ORBUtility.dprint( this,
209                            "internalGetServant: incarnate complete" ) ;
210                    }
211
212                    entry.incarnateComplete() ;
213                    activateServant(key, entry, (Servant)servant);
214                }
215            }
216
217            return servant ;
218        } finally {
219            if (poa.getDebug()) {
220                ORBUtility.dprint( this,
221                    "Exiting POAPolicyMediatorImpl_R_USM.internalGetServant " +
222                    "for poa " + poa ) ;
223            }
224        }
225    }
226
227    public void returnServant()
228    {
229        OAInvocationInfo info = orb.peekInvocationInfo();
230        byte[] id = info.id() ;
231        ActiveObjectMap.Key key = new ActiveObjectMap.Key( id ) ;
232        AOMEntry entry = activeObjectMap.get( key ) ;
233        entry.exit() ;
234    }
235
236    public void etherealizeAll()
237    {
238        if (activator != null)  {
239            Set keySet = activeObjectMap.keySet() ;
240
241            // Copy the elements in the set to an array to avoid
242            // changes in the set due to concurrent modification
243            ActiveObjectMap.Key[] keys =
244                (ActiveObjectMap.Key[])keySet.toArray(
245                    new ActiveObjectMap.Key[ keySet.size() ] ) ;
246
247            for (int ctr=0; ctr<keySet.size(); ctr++) {
248                ActiveObjectMap.Key key = keys[ctr] ;
249                AOMEntry entry = activeObjectMap.get( key ) ;
250                Servant servant = activeObjectMap.getServant( entry ) ;
251                if (servant != null) {
252                    boolean remainingActivations =
253                        activeObjectMap.hasMultipleIDs(entry) ;
254
255                    // Here we etherealize in the thread that called this
256                    // method, rather than etherealizing in a new thread
257                    // as in the deactivate case.  We still inform the
258                    // entry state machine so that only one thread at a
259                    // time can call the etherealize method.
260                    entry.startEtherealize( null ) ;
261                    try {
262                        poa.unlock() ;
263                        try {
264                            activator.etherealize(key.id, poa, servant, true,
265                                remainingActivations);
266                        } catch (Exception exc) {
267                            // ignore all exceptions
268                        }
269                    } finally {
270                        poa.lock() ;
271                        entry.etherealizeComplete() ;
272                    }
273                }
274            }
275        }
276    }
277
278    public ServantManager getServantManager() throws WrongPolicy
279    {
280        return activator;
281    }
282
283    public void setServantManager(
284        ServantManager servantManager ) throws WrongPolicy
285    {
286        if (activator != null)
287            throw poa.invocationWrapper().servantManagerAlreadySet() ;
288
289        if (servantManager instanceof ServantActivator)
290            activator = (ServantActivator)servantManager;
291        else
292            throw poa.invocationWrapper().servantManagerBadType() ;
293    }
294
295    public Servant getDefaultServant() throws NoServant, WrongPolicy
296    {
297        throw new WrongPolicy();
298    }
299
300    public void setDefaultServant( Servant servant ) throws WrongPolicy
301    {
302        throw new WrongPolicy();
303    }
304
305    class Etherealizer extends Thread {
306        private POAPolicyMediatorImpl_R_USM mediator ;
307        private ActiveObjectMap.Key key ;
308        private AOMEntry entry ;
309        private Servant servant ;
310        private boolean debug ;
311
312
313        public Etherealizer( POAPolicyMediatorImpl_R_USM mediator,
314            ActiveObjectMap.Key key, AOMEntry entry, Servant servant,
315            boolean debug )
316        {
317            super(null, null, "PAO-Etherealizer-Thread", 0, false);
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