POAManagerImpl.java revision 758:bb6bf34f121f
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 ; 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(null, deactivator, "POA-Deactivator-Thread", 0, false) ; 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