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