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 
  26 package com.sun.corba.se.impl.oa.poa;
  27 
  28 import java.util.Iterator;
  29 import java.util.Collections;
  30 import java.util.Set;
  31 import java.util.HashSet;
  32 
  33 import org.omg.CORBA.LocalObject;
  34 import org.omg.CORBA.CompletionStatus ;
  35 
  36 import org.omg.PortableServer.POAManager;
  37 import org.omg.PortableServer.POAManagerPackage.State;
  38 import org.omg.PortableServer.POA;
  39 
  40 import org.omg.PortableInterceptor.DISCARDING ;
  41 import org.omg.PortableInterceptor.ACTIVE ;
  42 import org.omg.PortableInterceptor.HOLDING ;
  43 import org.omg.PortableInterceptor.INACTIVE ;
  44 import org.omg.PortableInterceptor.NON_EXISTENT ;
  45 
  46 import com.sun.corba.se.spi.protocol.PIHandler ;
  47 
  48 import com.sun.corba.se.impl.logging.POASystemException ;
  49 
  50 import 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 
  57 public 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 sun.misc.ManagedLocalsThread(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 }