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