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