POAManagerImpl.java revision 667:d0315150c39d
1/*
2 * Copyright (c) 1997, 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.Iterator;
29import java.util.Collections;
30import java.util.Set;
31import java.util.HashSet;
32
33import org.omg.CORBA.LocalObject;
34import org.omg.CORBA.CompletionStatus ;
35
36import org.omg.PortableServer.POAManager;
37import org.omg.PortableServer.POAManagerPackage.State;
38import org.omg.PortableServer.POA;
39
40import org.omg.PortableInterceptor.DISCARDING ;
41import org.omg.PortableInterceptor.ACTIVE ;
42import org.omg.PortableInterceptor.HOLDING ;
43import org.omg.PortableInterceptor.INACTIVE ;
44import org.omg.PortableInterceptor.NON_EXISTENT ;
45
46import com.sun.corba.se.spi.protocol.PIHandler ;
47
48import com.sun.corba.se.impl.logging.POASystemException ;
49
50import com.sun.corba.se.impl.orbutil.ORBUtility ;
51import com.sun.corba.se.impl.transport.ManagedLocalsThread;
52
53/** POAManagerImpl is the implementation of the POAManager interface.
54 *  Its public methods are activate(), hold_requests(), discard_requests()
55 *  and deactivate().
56 */
57
58public class POAManagerImpl extends org.omg.CORBA.LocalObject implements
59    POAManager
60{
61    private final POAFactory factory ;  // factory which contains global state
62                                        // for all POAManagers
63    private PIHandler pihandler ;       // for adapterManagerStateChanged
64    private State state;                // current state of this POAManager
65    private Set poas = new HashSet(4) ; // all poas controlled by this POAManager
66    private int nInvocations=0;         // Number of invocations in progress
67    private int nWaiters=0;             // Number of threads waiting for
68                                        // invocations to complete
69    private int myId = 0 ;              // This POAManager's ID
70    private boolean debug ;
71    private boolean explicitStateChange ; // initially false, set true as soon as
72                                        // one of activate, hold_request,
73                                        // discard_request, or deactivate is called.
74
75    private String stateToString( State state )
76    {
77        switch (state.value()) {
78            case State._HOLDING : return "State[HOLDING]" ;
79            case State._ACTIVE : return "State[ACTIVE]" ;
80            case State._DISCARDING : return "State[DISCARDING]" ;
81            case State._INACTIVE : return "State[INACTIVE]" ;
82        }
83
84        return "State[UNKNOWN]" ;
85    }
86
87    public String toString()
88    {
89        return "POAManagerImpl[myId=" + myId +
90            " state=" + stateToString(state) +
91            " nInvocations=" + nInvocations +
92            " nWaiters=" + nWaiters + "]" ;
93    }
94
95    POAFactory getFactory()
96    {
97        return factory ;
98    }
99
100    PIHandler getPIHandler()
101    {
102        return pihandler ;
103    }
104
105    private void countedWait()
106    {
107        try {
108            if (debug) {
109                ORBUtility.dprint( this, "Calling countedWait on POAManager " +
110                    this + " nWaiters=" + nWaiters ) ;
111            }
112
113            nWaiters++ ;
114            wait();
115        } catch ( java.lang.InterruptedException ex ) {
116            // NOP
117        } finally {
118            nWaiters-- ;
119
120            if (debug) {
121                ORBUtility.dprint( this, "Exiting countedWait on POAManager " +
122                    this + " nWaiters=" + nWaiters ) ;
123            }
124        }
125    }
126
127    private void notifyWaiters()
128    {
129        if (debug) {
130            ORBUtility.dprint( this, "Calling notifyWaiters on POAManager " +
131                this + " nWaiters=" + nWaiters ) ;
132        }
133
134        if (nWaiters >0)
135            notifyAll() ;
136    }
137
138    public int getManagerId()
139    {
140        return myId ;
141    }
142
143    POAManagerImpl( POAFactory factory, PIHandler pihandler )
144    {
145        this.factory = factory ;
146        factory.addPoaManager(this);
147        this.pihandler = pihandler ;
148        myId = factory.newPOAManagerId() ;
149        state = State.HOLDING;
150        debug = factory.getORB().poaDebugFlag ;
151        explicitStateChange = false ;
152
153        if (debug) {
154            ORBUtility.dprint( this, "Creating POAManagerImpl " + this ) ;
155        }
156    }
157
158    synchronized void addPOA(POA poa)
159    {
160        // XXX This is probably not the correct error
161        if (state.value() == State._INACTIVE) {
162            POASystemException wrapper = factory.getWrapper();
163            throw wrapper.addPoaInactive( CompletionStatus.COMPLETED_NO ) ;
164        }
165
166        poas.add(poa);
167    }
168
169    synchronized void removePOA(POA poa)
170    {
171        poas.remove(poa);
172        if ( poas.isEmpty() ) {
173            factory.removePoaManager(this);
174        }
175    }
176
177    public short getORTState()
178    {
179        switch (state.value()) {
180            case State._HOLDING    : return HOLDING.value ;
181            case State._ACTIVE     : return ACTIVE.value ;
182            case State._INACTIVE   : return INACTIVE.value ;
183            case State._DISCARDING : return DISCARDING.value ;
184            default                : return NON_EXISTENT.value ;
185        }
186    }
187
188/****************************************************************************
189 * The following four public methods are used to change the POAManager's state.
190 *
191 * A note on the design of synchronization code:
192 * There are 4 places where a thread would need to wait for a condition:
193 *      - in hold_requests, discard_requests, deactivate, enter
194 * There are 5 places where a thread notifies a condition:
195 *      - in activate, hold_requests, discard_requests, deactivate, exit
196 *
197 * Since each notify needs to awaken waiters in several of the 4 places,
198 * and since wait() in Java has the nice property of releasing the lock
199 * on its monitor before sleeping, it seemed simplest to have just one
200 * monitor object: "this". Thus all notifies will awaken all waiters.
201 * On waking up, each waiter verifies that the condition it was waiting
202 * for is satisfied, otherwise it goes back into a wait().
203 *
204 ****************************************************************************/
205
206    /**
207     * <code>activate</code>
208     * <b>Spec: pages 3-14 thru 3-18</b>
209     */
210    public synchronized void activate()
211        throws org.omg.PortableServer.POAManagerPackage.AdapterInactive
212    {
213        explicitStateChange = true ;
214
215        if (debug) {
216            ORBUtility.dprint( this,
217                "Calling activate on POAManager " + this ) ;
218        }
219
220        try {
221            if ( state.value() == State._INACTIVE )
222                throw new org.omg.PortableServer.POAManagerPackage.AdapterInactive();
223
224            // set the state to ACTIVE
225            state = State.ACTIVE;
226
227            pihandler.adapterManagerStateChanged( myId, getORTState() ) ;
228
229            // Notify any invocations that were waiting because the previous
230            // state was HOLDING, as well as notify any threads that were waiting
231            // inside hold_requests() or discard_requests().
232            notifyWaiters();
233        } finally {
234            if (debug) {
235                ORBUtility.dprint( this,
236                    "Exiting activate on POAManager " + this ) ;
237            }
238        }
239    }
240
241    /**
242     * <code>hold_requests</code>
243     * <b>Spec: pages 3-14 thru 3-18</b>
244     */
245    public synchronized void hold_requests(boolean wait_for_completion)
246        throws org.omg.PortableServer.POAManagerPackage.AdapterInactive
247    {
248        explicitStateChange = true ;
249
250        if (debug) {
251            ORBUtility.dprint( this,
252                "Calling hold_requests on POAManager " + this ) ;
253        }
254
255        try {
256            if ( state.value() == State._INACTIVE )
257                throw new org.omg.PortableServer.POAManagerPackage.AdapterInactive();
258            // set the state to HOLDING
259            state  = State.HOLDING;
260
261            pihandler.adapterManagerStateChanged( myId, getORTState() ) ;
262
263            // Notify any threads that were waiting in the wait() inside
264            // discard_requests. This will cause discard_requests to return
265            // (which is in conformance with the spec).
266            notifyWaiters();
267
268            if ( wait_for_completion ) {
269                while ( state.value() == State._HOLDING && nInvocations > 0 ) {
270                    countedWait() ;
271                }
272            }
273        } finally {
274            if (debug) {
275                ORBUtility.dprint( this,
276                    "Exiting hold_requests on POAManager " + this ) ;
277            }
278        }
279    }
280
281    /**
282     * <code>discard_requests</code>
283     * <b>Spec: pages 3-14 thru 3-18</b>
284     */
285    public synchronized void discard_requests(boolean wait_for_completion)
286        throws org.omg.PortableServer.POAManagerPackage.AdapterInactive
287    {
288        explicitStateChange = true ;
289
290        if (debug) {
291            ORBUtility.dprint( this,
292                "Calling hold_requests on POAManager " + this ) ;
293        }
294
295        try {
296            if ( state.value() == State._INACTIVE )
297                throw new org.omg.PortableServer.POAManagerPackage.AdapterInactive();
298
299            // set the state to DISCARDING
300            state = State.DISCARDING;
301
302            pihandler.adapterManagerStateChanged( myId, getORTState() ) ;
303
304            // Notify any invocations that were waiting because the previous
305            // state was HOLDING. Those invocations will henceforth be rejected with
306            // a TRANSIENT exception. Also notify any threads that were waiting
307            // inside hold_requests().
308            notifyWaiters();
309
310            if ( wait_for_completion ) {
311                while ( state.value() == State._DISCARDING && nInvocations > 0 ) {
312                    countedWait() ;
313                }
314            }
315        } finally {
316            if (debug) {
317                ORBUtility.dprint( this,
318                    "Exiting hold_requests on POAManager " + this ) ;
319            }
320        }
321    }
322
323    /**
324     * <code>deactivate</code>
325     * <b>Spec: pages 3-14 thru 3-18</b>
326     * Note: INACTIVE is a permanent state.
327     */
328
329    public void deactivate(boolean etherealize_objects, boolean wait_for_completion)
330        throws org.omg.PortableServer.POAManagerPackage.AdapterInactive
331    {
332        explicitStateChange = true ;
333
334        try {
335            synchronized( this ) {
336                if (debug) {
337                    ORBUtility.dprint( this,
338                        "Calling deactivate on POAManager " + this ) ;
339                }
340
341                if ( state.value() == State._INACTIVE )
342                    throw new org.omg.PortableServer.POAManagerPackage.AdapterInactive();
343
344                state = State.INACTIVE;
345
346                pihandler.adapterManagerStateChanged( myId, getORTState() ) ;
347
348                // Notify any invocations that were waiting because the previous
349                // state was HOLDING. Those invocations will then be rejected with
350                // an OBJ_ADAPTER exception. Also notify any threads that were waiting
351                // inside hold_requests() or discard_requests().
352                notifyWaiters();
353            }
354
355            POAManagerDeactivator deactivator = new POAManagerDeactivator( this,
356                etherealize_objects, debug ) ;
357
358            if (wait_for_completion)
359                deactivator.run() ;
360            else {
361                Thread thr = new ManagedLocalsThread(deactivator) ;
362                thr.start() ;
363            }
364        } finally {
365            synchronized(this) {
366                if (debug) {
367                    ORBUtility.dprint( this,
368                        "Exiting deactivate on POAManager " + this ) ;
369                }
370            }
371        }
372    }
373
374    private class POAManagerDeactivator implements Runnable
375    {
376        private boolean etherealize_objects ;
377        private POAManagerImpl pmi ;
378        private boolean debug ;
379
380        POAManagerDeactivator( POAManagerImpl pmi, boolean etherealize_objects,
381            boolean debug )
382        {
383            this.etherealize_objects = etherealize_objects ;
384            this.pmi = pmi ;
385            this.debug = debug ;
386        }
387
388        public void run()
389        {
390            try {
391                synchronized (pmi) {
392                    if (debug) {
393                        ORBUtility.dprint( this,
394                            "Calling run with etherealize_objects=" +
395                            etherealize_objects + " pmi=" + pmi ) ;
396                    }
397
398                    while ( pmi.nInvocations > 0 ) {
399                        countedWait() ;
400                    }
401                }
402
403                if (etherealize_objects) {
404                    Iterator iterator = null ;
405
406                    // Make sure that poas cannot change while we copy it!
407                    synchronized (pmi) {
408                        if (debug) {
409                            ORBUtility.dprint( this,
410                                "run: Preparing to etherealize with pmi=" +
411                                pmi ) ;
412                        }
413
414                        iterator = (new HashSet(pmi.poas)).iterator();
415                    }
416
417                    while (iterator.hasNext()) {
418                        // Each RETAIN+USE_SERVANT_MGR poa
419                        // must call etherealize for all its objects
420                        ((POAImpl)iterator.next()).etherealizeAll();
421                    }
422
423                    synchronized (pmi) {
424                        if (debug) {
425                            ORBUtility.dprint( this,
426                                "run: removing POAManager and clearing poas " +
427                                "with pmi=" + pmi ) ;
428                        }
429
430                        factory.removePoaManager(pmi);
431                        poas.clear();
432                    }
433                }
434            } finally {
435                if (debug) {
436                    synchronized (pmi) {
437                        ORBUtility.dprint( this, "Exiting run" ) ;
438                    }
439                }
440            }
441        }
442    }
443
444    /**
445     * Added according to the spec CORBA V2.3; this returns the
446     * state of the POAManager
447     */
448
449    public org.omg.PortableServer.POAManagerPackage.State get_state () {
450        return state;
451    }
452
453/****************************************************************************
454 * The following methods are used on the invocation path.
455 ****************************************************************************/
456
457    // called from POA.find_POA before calling
458    // AdapterActivator.unknown_adapter.
459    synchronized void checkIfActive()
460    {
461        try {
462            if (debug) {
463                ORBUtility.dprint( this,
464                    "Calling checkIfActive for POAManagerImpl " + this ) ;
465            }
466
467            checkState();
468        } finally {
469            if (debug) {
470                ORBUtility.dprint( this,
471                    "Exiting checkIfActive for POAManagerImpl " + this ) ;
472            }
473        }
474    }
475
476    private void checkState()
477    {
478        while ( state.value() != State._ACTIVE ) {
479            switch ( state.value() ) {
480                case State._HOLDING:
481                    while ( state.value() == State._HOLDING ) {
482                        countedWait() ;
483                    }
484                    break;
485
486                case State._DISCARDING:
487                    throw factory.getWrapper().poaDiscarding() ;
488
489                case State._INACTIVE:
490                    throw factory.getWrapper().poaInactive() ;
491            }
492        }
493    }
494
495    synchronized void enter()
496    {
497        try {
498            if (debug) {
499                ORBUtility.dprint( this,
500                    "Calling enter for POAManagerImpl " + this ) ;
501            }
502
503            checkState();
504            nInvocations++;
505        } finally {
506            if (debug) {
507                ORBUtility.dprint( this,
508                    "Exiting enter for POAManagerImpl " + this ) ;
509            }
510        }
511    }
512
513    synchronized void exit()
514    {
515        try {
516            if (debug) {
517                ORBUtility.dprint( this,
518                    "Calling exit for POAManagerImpl " + this ) ;
519            }
520
521            nInvocations--;
522
523            if ( nInvocations == 0 ) {
524                // This notifies any threads that were in the
525                // wait_for_completion loop in hold/discard/deactivate().
526                notifyWaiters();
527            }
528        } finally {
529            if (debug) {
530                ORBUtility.dprint( this,
531                    "Exiting exit for POAManagerImpl " + this ) ;
532            }
533        }
534    }
535
536    /** Activate the POAManager if no explicit state change has ever been
537     * previously invoked.
538     */
539    public synchronized void implicitActivation()
540    {
541        if (!explicitStateChange)
542            try {
543                activate() ;
544            } catch (org.omg.PortableServer.POAManagerPackage.AdapterInactive ai) {
545                // ignore the exception.
546            }
547    }
548}
549