1. /*
  2. * @(#)ActivationGroup.java 1.33 00/02/02
  3. *
  4. * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package java.rmi.activation;
  11. import java.lang.reflect.Constructor;
  12. import java.net.URL;
  13. import java.net.MalformedURLException;
  14. import java.rmi.MarshalledObject;
  15. import java.rmi.Naming;
  16. import java.rmi.activation.UnknownGroupException;
  17. import java.rmi.activation.UnknownObjectException;
  18. import java.rmi.Remote;
  19. import java.rmi.RemoteException;
  20. import java.rmi.server.UnicastRemoteObject;
  21. import java.rmi.server.RMIClassLoader;
  22. import java.security.PrivilegedExceptionAction;
  23. import java.security.PrivilegedActionException;
  24. import sun.security.action.GetIntegerAction;
  25. /**
  26. * An <code>ActivationGroup</code> is responsible for creating new
  27. * instances of "activatable" objects in its group, informing its
  28. * <code>ActivationMonitor</code> when either: its object's become
  29. * active or inactive, or the group as a whole becomes inactive. <p>
  30. *
  31. * An <code>ActivationGroup</code> is <i>initially</i> created in one
  32. * of several ways: <ul>
  33. * <li>as a side-effect of creating an <code>ActivationDesc</code>
  34. * (using its first constructor) for the first activatable
  35. * object in the group, or
  36. * <li>via the <code>ActivationGroup.createGroup</code> method
  37. * <li>as a side-effect of activating the first object in a group
  38. * whose <code>ActivationGroupDesc</code> was only registered.</ul><p>
  39. *
  40. * Only the activator can <i>recreate</i> an
  41. * <code>ActivationGroup</code>. The activator spawns, as needed, a
  42. * separate VM (as a child process, for example) for each registered
  43. * activation group and directs activation requests to the appropriate
  44. * group. It is implementation specific how VMs are spawned. An
  45. * activation group is created via the
  46. * <code>ActivationGroup.createGroup</code> static method. The
  47. * <code>createGroup</code> method has two requirements on the group
  48. * to be created: 1) the group must be a concrete subclass of
  49. * <code>ActivationGroup</code>, and 2) the group must have a
  50. * constructor that takes two arguments:
  51. *
  52. * <ul>
  53. * <li> the group's <code>ActivationGroupID</code>, and
  54. * <li> the group's initialization data (in a
  55. * <code>java.rmi.MarshalledObject</code>)</ul><p>
  56. *
  57. * When created, the default implementation of
  58. * <code>ActivationGroup</code> will override the system properties
  59. * with the properties requested when its
  60. * <code>ActivationGroupDesc</code> was created, and will set a
  61. * <code>java.rmi.RMISecurityManager</code> as the default system
  62. * security manager. If your application requires specific properties
  63. * to be set when objects are activated in the group, the application
  64. * should create a special <code>Properties</code> object containing
  65. * these properties, then create an <code>ActivationGroupDesc</code>
  66. * with the <code>Properties</code> object, and use
  67. * <code>ActivationGroup.createGroup</code> before creating any
  68. * <code>ActivationDesc</code>s (before the default
  69. * <code>ActivationGroupDesc</code> is created). If your application
  70. * requires the use of a security manager other than
  71. * <code>java.rmi.RMISecurityManager</code>, in the
  72. * ActivativationGroupDescriptor properties list you can set
  73. * <code>java.security.manager</code> property to the name of the security
  74. * manager you would like to install.
  75. *
  76. * @author Ann Wollrath
  77. * @version 1.33, 02/02/00
  78. * @see ActivationInstantiator
  79. * @see ActivationGroupDesc
  80. * @see ActivationGroupID
  81. * @since 1.2
  82. */
  83. public abstract class ActivationGroup
  84. extends UnicastRemoteObject
  85. implements ActivationInstantiator
  86. {
  87. /**
  88. * @serial the group's identifier
  89. */
  90. private ActivationGroupID groupID;
  91. /**
  92. * @serial the group's monitor
  93. */
  94. private ActivationMonitor monitor;
  95. /**
  96. * @serial the group's incarnation number
  97. */
  98. private long incarnation;
  99. /** the current activation group for this VM */
  100. private static ActivationGroup currGroup;
  101. /** the current group's identifier */
  102. private static ActivationGroupID currGroupID;
  103. /** the current group's activation system */
  104. private static ActivationSystem currSystem;
  105. /** used to control a group being created only once */
  106. private static boolean canCreate = true;
  107. /** formal parameters for constructing an activation group */
  108. private static Class[] groupConstrParams = {
  109. ActivationGroupID.class, MarshalledObject.class
  110. };
  111. /** indicate compatibility with the Java 2 SDK v1.2 version of class */
  112. private static final long serialVersionUID = -7696947875314805420L;
  113. /**
  114. * Constructs and exports an activation group as a UnicastRemoteObject
  115. * so that a client can invoke its newInstance method.
  116. *
  117. * @param groupID the group's identifier
  118. * @exception RemoteException if group could not be exported
  119. * @since 1.2
  120. */
  121. protected ActivationGroup(ActivationGroupID groupID)
  122. throws RemoteException
  123. {
  124. // call super constructor to export the object
  125. super();
  126. this.groupID = groupID;
  127. }
  128. /**
  129. * The group's <code>inactiveObject</code> method is called
  130. * indirectly via a call to the <code>Activatable.inactive</code>
  131. * method. A remote object implementation must call
  132. * <code>Activatable</code>'s <code>inactive</code> method when
  133. * that object deactivates (the object deems that it is no longer
  134. * active). If the object does not call
  135. * <code>Activatable.inactive</code> when it deactivates, the
  136. * object will never be garbage collected since the group keeps
  137. * strong references to the objects it creates. <p>
  138. *
  139. * <p>The group's <code>inactiveObject</code> method unexports the
  140. * remote object from the RMI runtime so that the object can no
  141. * longer receive incoming RMI calls. An object will only be unexported
  142. * if the object has no pending or executing calls.
  143. * The subclass of <code>ActivationGroup</code> must override this
  144. * method and unexport the object. <p>
  145. *
  146. * <p>After removing the object from the RMI runtime, the group
  147. * must inform its <code>ActivationMonitor</code> (via the monitor's
  148. * <code>inactiveObject</code> method) that the remote object is
  149. * not currently active so that the remote object will be
  150. * re-activated by the activator upon a subsequent activation
  151. * request.<p>
  152. *
  153. * <p>This method simply informs the group's monitor that the object
  154. * is inactive. It is up to the concrete subclass of ActivationGroup
  155. * to fulfill the additional requirement of unexporting the object. <p>
  156. *
  157. * @param id the object's activation identifier
  158. * @return true if the object was successfully deactivated; otherwise
  159. * returns false.
  160. * @exception UnknownObjectException if object is unknown (may already
  161. * be inactive)
  162. * @exception RemoteException if call informing monitor fails
  163. * @exception ActivationException if group is inactive
  164. * @since 1.2
  165. */
  166. public boolean inactiveObject(ActivationID id)
  167. throws ActivationException, UnknownObjectException, RemoteException
  168. {
  169. monitor.inactiveObject(id);
  170. return true;
  171. }
  172. /**
  173. * The group's <code>activeObject</code> method is called when an
  174. * object is exported (either by <code>Activatable</code> object
  175. * construction or an explicit call to
  176. * <code>Activatable.exportObject</code>. The group must inform its
  177. * <code>ActivationMonitor</code> that the object is active (via
  178. * the monitor's <code>activeObject</code> method) if the group
  179. * hasn't already done so.
  180. *
  181. * @param id the object's identifier
  182. * @param obj the remote object implementation
  183. * @exception UnknownObjectException if object is not registered
  184. * @exception RemoteException if call informing monitor fails
  185. * @exception ActivationException if group is inactive
  186. * @since 1.2
  187. */
  188. public abstract void activeObject(ActivationID id, Remote obj)
  189. throws ActivationException, UnknownObjectException, RemoteException;
  190. /**
  191. * Create and set the activation group for the current VM. The
  192. * activation group can only be set if it is not currently set.
  193. * An activation group is set using the <code>createGroup</code>
  194. * method when the <code>Activator</code> initiates the
  195. * re-creation of an activation group in order to carry out
  196. * incoming <code>activate</code> requests. A group must first be
  197. * registered with the <code>ActivationSystem</code> before it can
  198. * be created via this method.
  199. *
  200. * <p>The group class specified by the
  201. * <code>ActivationGroupDesc</code> must be a concrete subclass of
  202. * <code>ActivationGroup</code> and have a public constructor that
  203. * takes two arguments: the <code>ActivationGroupID</code> for the
  204. * group and the <code>MarshalledObject</code> containing the
  205. * group's initialization data (obtained from the
  206. * <code>ActivationGroupDesc</code>.
  207. *
  208. * <p>If the group class name specified in the
  209. * <code>ActivationGroupDesc</code> is <code>null</code>, then
  210. * this method will behave as if the group descriptor contained
  211. * the name of the default activation group implementation class.
  212. *
  213. * <p>Note that if your application creates its own custom
  214. * activation group, a security manager must be set for that
  215. * group. Otherwise objects cannot be activated in the group.
  216. * <code>java.rmi.RMISecurityManager</code> is set by default.
  217. *
  218. * <p>If a security manager is already set in the group VM, this
  219. * method first calls the security manager's
  220. * <code>checkSetFactory</code> method. This could result in a
  221. * <code>SecurityException</code>. If your application needs to
  222. * set a different security manager, you must ensure that the
  223. * policy file specified by the group's
  224. * <code>ActivationGroupDesc</code> grants the group the necessary
  225. * permissions to set a new security manager. (Note: This will be
  226. * necessary if your group downloads and sets a security manager).
  227. *
  228. * <p>After the group is created, the
  229. * <code>ActivationSystem</code> is informed that the group is
  230. * active by calling the <code>activeGroup</code> method which
  231. * returns the <code>ActivationMonitor</code> for the group. The
  232. * application need not call <code>activeGroup</code>
  233. * independently since it is taken care of by this method.
  234. *
  235. * <p>Once a group is created, subsequent calls to the
  236. * <code>currentGroupID</code> method will return the identifier
  237. * for this group until the group becomes inactive.
  238. *
  239. * @param id the activation group's identifier
  240. * @param desc the activation group's descriptor
  241. * @param incarnation the group's incarnation number (zero on group's
  242. * initial creation)
  243. * @return the activation group for the VM
  244. * @exception ActivationException if group already exists or if error
  245. * occurs during group creation
  246. * @exception SecurityException if permission to create group is denied.
  247. * (Note: The default implementation of the security manager
  248. * <code>checkSetFactory</code>
  249. * method requires the RuntimePermission "setFactory")
  250. * @see SecurityManager#checkSetFactory
  251. * @since 1.2
  252. */
  253. public static synchronized
  254. ActivationGroup createGroup(ActivationGroupID id,
  255. final ActivationGroupDesc desc,
  256. long incarnation)
  257. throws ActivationException
  258. {
  259. SecurityManager security = System.getSecurityManager();
  260. if (security != null)
  261. security.checkSetFactory();
  262. if (currGroup != null)
  263. throw new ActivationException("group already exists");
  264. if (canCreate == false)
  265. throw new ActivationException("group deactivated and " +
  266. "cannot be recreated");
  267. try {
  268. try {
  269. // load group's class
  270. String groupClassName = desc.getClassName();
  271. /*
  272. * Fix for 4252236: resolution of the default
  273. * activation group implementation name should be
  274. * delayed until now.
  275. */
  276. if (groupClassName == null) {
  277. groupClassName = sun.rmi.server.ActivationGroupImpl.
  278. class.getName();
  279. }
  280. final String className = groupClassName;
  281. /*
  282. * Fix for 4170955: Because the default group
  283. * implementation is a sun.* class, the group class
  284. * needs to be loaded in a privileged block of code.
  285. */
  286. Class cl;
  287. try {
  288. cl = (Class) java.security.AccessController.
  289. doPrivileged(new PrivilegedExceptionAction() {
  290. public Object run() throws ClassNotFoundException,
  291. MalformedURLException
  292. {
  293. return RMIClassLoader.
  294. loadClass(desc.getLocation(), className);
  295. }
  296. });
  297. } catch (PrivilegedActionException pae) {
  298. throw new ActivationException("Could not load default group " +
  299. "implementation class",
  300. pae.getException());
  301. }
  302. // create group
  303. Constructor constructor = cl.getConstructor(groupConstrParams);
  304. Object[] params = new Object[] { id, desc.getData() };
  305. Object obj = constructor.newInstance(params);
  306. if (obj instanceof ActivationGroup) {
  307. currGroup = (ActivationGroup)obj;
  308. currGroupID = id;
  309. currSystem = id.getSystem();
  310. currGroup.incarnation = incarnation;
  311. currGroup.monitor =
  312. currSystem.activeGroup(id, currGroup, incarnation);
  313. canCreate = false;
  314. } else {
  315. throw new ActivationException("group not correct class: " +
  316. obj.getClass().getName());
  317. }
  318. } catch (java.lang.reflect.InvocationTargetException e) {
  319. e.getTargetException().printStackTrace();
  320. throw new ActivationException("exception in group constructor",
  321. e.getTargetException());
  322. } catch (ActivationException e) {
  323. throw e;
  324. } catch (Exception e) {
  325. throw new ActivationException("exception creating group", e);
  326. }
  327. } catch (ActivationException e) {
  328. destroyGroup();
  329. canCreate = true;
  330. throw e;
  331. }
  332. return currGroup;
  333. }
  334. /**
  335. * Returns the current activation group's identifier. Returns null
  336. * if no group is currently active for this VM.
  337. * @return the activation group's identifier
  338. * @since 1.2
  339. */
  340. public static synchronized ActivationGroupID currentGroupID() {
  341. return currGroupID;
  342. }
  343. /**
  344. * Returns the activation group identifier for the VM. If an
  345. * activation group does not exist for this VM, a default
  346. * activation group is created. A group can be created only once,
  347. * so if a group has already become active and deactivated.
  348. *
  349. * @return the activation group identifier
  350. * @exception ActivationException if error occurs during group
  351. * creation, if security manager is not set, or if the group
  352. * has already been created and deactivated.
  353. */
  354. static synchronized ActivationGroupID internalCurrentGroupID()
  355. throws ActivationException
  356. {
  357. if (currGroupID == null)
  358. throw new ActivationException("nonexistent group");
  359. return currGroupID;
  360. }
  361. /**
  362. * Set the activation system for the VM. The activation system can
  363. * only be set it if no group is currently active. If the activation
  364. * system is not set via this call, then the <code>getSystem</code>
  365. * method attempts to obtain a reference to the
  366. * <code>ActivationSystem</code> by looking up the name
  367. * "java.rmi.activation.ActivationSystem" in the Activator's
  368. * registry. By default, the port number used to look up the
  369. * activation system is defined by
  370. * <code>ActivationSystem.SYSTEM_PORT</code>. This port can be overridden
  371. * by setting the property <code>java.rmi.activation.port</code>.
  372. *
  373. * <p>If there is a security manager, this method first
  374. * calls the security manager's <code>checkSetFactory</code> method.
  375. * This could result in a SecurityException.
  376. *
  377. * @param system remote reference to the <code>ActivationSystem</code>
  378. * @exception ActivationException if activation system is already set
  379. * @exception SecurityException if permission to set the activation system is denied.
  380. * (Note: The default implementation of the security manager
  381. * <code>checkSetFactory</code>
  382. * method requires the RuntimePermission "setFactory")
  383. * @see SecurityManager#checkSetFactory
  384. * @since 1.2
  385. */
  386. public static synchronized void setSystem(ActivationSystem system)
  387. throws ActivationException
  388. {
  389. SecurityManager security = System.getSecurityManager();
  390. if (security != null)
  391. security.checkSetFactory();
  392. if (currSystem != null)
  393. throw new ActivationException("activation system already set");
  394. currSystem = system;
  395. }
  396. /**
  397. * Returns the activation system for the VM. The activation system
  398. * may be set by the <code>setSystem</code> method. If the
  399. * activation system is not set via the <code>setSystem</code>
  400. * method, then the <code>getSystem</code> method attempts to
  401. * obtain a reference to the <code>ActivationSystem</code> by
  402. * looking up the name "java.rmi.activation.ActivationSystem" in
  403. * the Activator's registry. By default, the port number used to
  404. * look up the activation system is defined by
  405. * <code>ActivationSystem.SYSTEM_PORT</code>. This port can be
  406. * overridden by setting the property
  407. * <code>java.rmi.activation.port</code>.
  408. *
  409. * @return the activation system for the VM/group
  410. * @exception ActivationException if activation system cannot be
  411. * obtained or is not bound
  412. * (means that it is not running)
  413. * @since 1.2
  414. */
  415. public static synchronized ActivationSystem getSystem()
  416. throws ActivationException
  417. {
  418. if (currSystem == null) {
  419. try {
  420. int port;
  421. port = ((Integer)java.security.AccessController.doPrivileged(
  422. new GetIntegerAction("java.rmi.activation.port",
  423. ActivationSystem.SYSTEM_PORT))).intValue();
  424. currSystem = (ActivationSystem)
  425. Naming.lookup("//:" + port +
  426. "/java.rmi.activation.ActivationSystem");
  427. } catch (Exception e) {
  428. throw new ActivationException("ActivationSystem not running",
  429. e);
  430. }
  431. }
  432. return currSystem;
  433. }
  434. /**
  435. * This protected method is necessary for subclasses to
  436. * make the <code>activeObject</code> callback to the group's
  437. * monitor. The call is simply forwarded to the group's
  438. * <code>ActivationMonitor</code>.
  439. *
  440. * @param id the object's identifier
  441. * @param mobj a marshalled object containing the remote object's stub
  442. * @exception UnknownObjectException if object is not registered
  443. * @exception RemoteException if call informing monitor fails
  444. * @exception ActivationException if an activation error occurs
  445. * @since 1.2
  446. */
  447. protected void activeObject(ActivationID id, MarshalledObject mobj)
  448. throws ActivationException, UnknownObjectException, RemoteException
  449. {
  450. monitor.activeObject(id, mobj);
  451. }
  452. /**
  453. * This protected method is necessary for subclasses to
  454. * make the <code>inactiveGroup</code> callback to the group's
  455. * monitor. The call is simply forwarded to the group's
  456. * <code>ActivationMonitor</code>. Also, the current group
  457. * for the VM is set to null.
  458. *
  459. * @exception UnknownGroupException if group is not registered
  460. * @exception RemoteException if call informing monitor fails
  461. * @since 1.2
  462. */
  463. protected void inactiveGroup()
  464. throws UnknownGroupException, RemoteException
  465. {
  466. try {
  467. monitor.inactiveGroup(groupID, incarnation);
  468. } finally {
  469. destroyGroup();
  470. }
  471. }
  472. /**
  473. * Destroys the current group.
  474. */
  475. private static synchronized void destroyGroup() {
  476. currGroup = null;
  477. currGroupID = null;
  478. // NOTE: don't set currSystem to null since it may be needed
  479. }
  480. /**
  481. * Returns the current group for the VM.
  482. * @exception ActivationException if current group is null (not active)
  483. */
  484. static synchronized ActivationGroup currentGroup()
  485. throws ActivationException
  486. {
  487. if (currGroup == null) {
  488. throw new ActivationException("group is not active");
  489. }
  490. return currGroup;
  491. }
  492. }