1. /*
  2. * @(#)POAManagerImpl.java 1.18 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.corba.se.internal.POA;
  8. import java.util.*;
  9. import org.omg.CORBA.TRANSIENT;
  10. import org.omg.CORBA.OBJ_ADAPTER;
  11. import org.omg.CORBA.CompletionStatus;
  12. import org.omg.CORBA.LocalObject;
  13. import org.omg.PortableServer.POAManager;
  14. import org.omg.PortableServer.POAManagerPackage.State;
  15. import org.omg.PortableServer.POA;
  16. /** POAManagerImpl is the implementation of the POAManager interface.
  17. * Its public methods are activate(), hold_requests(), discard_requests()
  18. * and deactivate().
  19. *
  20. * A note on deadlocks: Since Java allows threads to acquire the same
  21. * monitor multiple times, there will not be a deadlock on circular calls
  22. * to synchronized methods (i.e. if a POAManager instance method calls an
  23. * object which calls another method on this same POAManager instance).
  24. * However, there is one "legal" deadlock which can occur: see the note
  25. * in the enter() method.
  26. */
  27. public class POAManagerImpl extends org.omg.CORBA.LocalObject implements POAManager
  28. {
  29. // POAManager states
  30. private static final State HOLDING = State.HOLDING;
  31. private static final State ACTIVE = State.ACTIVE;
  32. private static final State DISCARDING = State.DISCARDING;
  33. private static final State INACTIVE = State.INACTIVE;
  34. POAORB orb;
  35. private State state; // current state of this
  36. private Set poas = Collections.synchronizedSet(new HashSet(4)); // all poas controlled by this
  37. // Number of invocations in progress
  38. int nInvocations=0;
  39. // Number of threads waiting for invocations to complete
  40. int nWaiters=0;
  41. private void countedWait()
  42. {
  43. try {
  44. nWaiters++ ;
  45. wait();
  46. } catch ( java.lang.InterruptedException ex ) {
  47. // NOP
  48. } finally {
  49. nWaiters-- ;
  50. }
  51. }
  52. private void notifyWaiters()
  53. {
  54. if (nWaiters >0)
  55. notifyAll() ;
  56. }
  57. public POAManagerImpl(POAORB orb)
  58. {
  59. this.orb = orb;
  60. state = HOLDING;
  61. }
  62. synchronized void addPOA(POA poa)
  63. {
  64. poas.add(poa);
  65. orb.addPoaManager(this);
  66. }
  67. synchronized void removePOA(POA poa)
  68. {
  69. poas.remove(poa);
  70. if ( poas.isEmpty() ) {
  71. orb.removePoaManager(this);
  72. }
  73. }
  74. /****************************************************************************
  75. * The following four public methods are used to change the POAManager's state.
  76. *
  77. * A note on the design of synchronization code:
  78. * There are 4 places where a thread would need to wait for a condition:
  79. * - in hold_requests, discard_requests, deactivate, enter
  80. * There are 5 places where a thread notifies a condition:
  81. * - in activate, hold_requests, discard_requests, deactivate, exit
  82. * Since each notify needs to awaken waiters in several of the 4 places,
  83. * and since wait() in Java has the nice property of releasing the lock
  84. * on its monitor before sleeping, it seemed simplest to have just one
  85. * monitor object: "this". Thus all notifies will awaken all waiters.
  86. * On waking up, each waiter verifies that the condition it was waiting
  87. * for is satisfied, otherwise it goes back into a wait().
  88. *
  89. ****************************************************************************/
  90. /**
  91. * <code>activate</code>
  92. * <b>Spec: pages 3-14 thru 3-18</b>
  93. */
  94. public synchronized void activate()
  95. throws org.omg.PortableServer.POAManagerPackage.AdapterInactive
  96. {
  97. if ( state.value() == State._INACTIVE )
  98. throw new org.omg.PortableServer.POAManagerPackage.AdapterInactive();
  99. // set the state to ACTIVE
  100. state = ACTIVE;
  101. // Notify any invocations that were waiting because the previous
  102. // state was HOLDING, as well as notify any threads that were waiting
  103. // inside hold_requests() or discard_requests().
  104. notifyWaiters();
  105. }
  106. /**
  107. * <code>hold_requests</code>
  108. * <b>Spec: pages 3-14 thru 3-18</b>
  109. */
  110. public synchronized void hold_requests(boolean wait_for_completion)
  111. throws org.omg.PortableServer.POAManagerPackage.AdapterInactive
  112. {
  113. if ( state.value() == State._INACTIVE )
  114. throw new org.omg.PortableServer.POAManagerPackage.AdapterInactive();
  115. // set the state to HOLDING
  116. state = HOLDING;
  117. // Notify any threads that were waiting in the wait() inside
  118. // discard_requests. This will cause discard_requests to return
  119. // (which is in conformance with the spec).
  120. notifyWaiters();
  121. if ( wait_for_completion ) {
  122. while ( state.value() == State._HOLDING && nInvocations > 0 ) {
  123. countedWait() ;
  124. }
  125. }
  126. }
  127. /**
  128. * <code>discard_requests</code>
  129. * <b>Spec: pages 3-14 thru 3-18</b>
  130. */
  131. public synchronized void discard_requests(boolean wait_for_completion)
  132. throws org.omg.PortableServer.POAManagerPackage.AdapterInactive
  133. {
  134. if ( state.value() == State._INACTIVE )
  135. throw new org.omg.PortableServer.POAManagerPackage.AdapterInactive();
  136. // set the state to DISCARDING
  137. state = DISCARDING;
  138. // Notify any invocations that were waiting because the previous
  139. // state was HOLDING. Those invocations will henceforth be rejected with
  140. // a TRANSIENT exception. Also notify any threads that were waiting
  141. // inside hold_requests().
  142. notifyWaiters();
  143. if ( wait_for_completion ) {
  144. while ( state.value() == State._DISCARDING && nInvocations > 0 ) {
  145. countedWait() ;
  146. }
  147. }
  148. }
  149. /**
  150. * <code>deactivate</code>
  151. * <b>Spec: pages 3-14 thru 3-18</b>
  152. * Note: INACTIVE is a permanent state.
  153. */
  154. public synchronized void deactivate(boolean etherealize_objects, boolean wait_for_completion)
  155. throws org.omg.PortableServer.POAManagerPackage.AdapterInactive
  156. {
  157. if ( state.value() == State._INACTIVE )
  158. throw new org.omg.PortableServer.POAManagerPackage.AdapterInactive();
  159. state = INACTIVE;
  160. // Notify any invocations that were waiting because the previous
  161. // state was HOLDING. Those invocations will then be rejected with
  162. // an OBJ_ADAPTER exception. Also notify any threads that were waiting
  163. // inside hold_requests() or discard_requests().
  164. notifyWaiters();
  165. if ( wait_for_completion ) {
  166. while ( nInvocations > 0 ) {
  167. countedWait() ;
  168. }
  169. }
  170. if ( etherealize_objects ) {
  171. if ( wait_for_completion ) {
  172. // stefanb 12/00: Why was this condition reversed? Spawning new threads means NOT to wait!
  173. etherealizePOAs();
  174. } else {
  175. new Thread() {
  176. public void run() {
  177. POAManagerImpl.this.etherealizePOAs();
  178. }
  179. }.start();
  180. }
  181. } else {
  182. orb.removePoaManager(this);
  183. // remove all POAs from poas, so that they can be GC'ed.
  184. poas.clear();
  185. }
  186. }
  187. /**
  188. * Added according to the spec CORBA V2.3; this returns the
  189. * state of the POAManager
  190. */
  191. public org.omg.PortableServer.POAManagerPackage.State get_state () {
  192. return state;
  193. }
  194. void etherealizePOAs() {
  195. Iterator iterator = (new HashSet(poas)).iterator();
  196. while (iterator.hasNext()) {
  197. // if this is a RETAIN+USE_SERVANT_MGR poa
  198. // then it must call etherealize for all its objects
  199. ((POAImpl)iterator.next()).etherealizeAll();
  200. }
  201. orb.removePoaManager(this);
  202. poas.clear();
  203. }
  204. /****************************************************************************
  205. * The following methods are used on the invocation path.
  206. ****************************************************************************/
  207. // called from POA.find_POA before calling
  208. // AdapterActivator.unknown_adapter.
  209. synchronized void checkIfActive()
  210. {
  211. checkState();
  212. }
  213. private void checkState()
  214. {
  215. while ( state.value() != State._ACTIVE ) {
  216. switch ( state.value() ) {
  217. case State._HOLDING:
  218. while ( state.value() == State._HOLDING ) {
  219. countedWait() ;
  220. }
  221. break;
  222. case State._DISCARDING:
  223. throw new TRANSIENT(MinorCodes.POA_DISCARDING,
  224. CompletionStatus.COMPLETED_NO);
  225. case State._INACTIVE:
  226. throw new OBJ_ADAPTER(MinorCodes.POA_INACTIVE,
  227. CompletionStatus.COMPLETED_NO);
  228. }
  229. }
  230. }
  231. synchronized void enter()
  232. {
  233. checkState();
  234. nInvocations++;
  235. }
  236. synchronized void exit()
  237. {
  238. nInvocations--;
  239. if ( nInvocations == 0 ) {
  240. // This notifies any threads that were in the
  241. // wait_for_completion loop in hold/discard/deactivate().
  242. notifyWaiters();
  243. }
  244. }
  245. }