KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > rmi > activation > ActivationGroup


1 /*
2  * @(#)ActivationGroup.java 1.44 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.rmi.activation;
9
10 import java.lang.reflect.Constructor JavaDoc;
11
12 import java.net.URL JavaDoc;
13 import java.net.MalformedURLException JavaDoc;
14 import java.rmi.MarshalledObject JavaDoc;
15 import java.rmi.Naming JavaDoc;
16 import java.rmi.activation.UnknownGroupException JavaDoc;
17 import java.rmi.activation.UnknownObjectException JavaDoc;
18 import java.rmi.Remote JavaDoc;
19 import java.rmi.RemoteException JavaDoc;
20 import java.rmi.server.UnicastRemoteObject JavaDoc;
21 import java.rmi.server.RMIClassLoader JavaDoc;
22 import java.security.PrivilegedExceptionAction JavaDoc;
23 import java.security.PrivilegedActionException JavaDoc;
24
25 import sun.security.action.GetIntegerAction;
26
27 /**
28  * An <code>ActivationGroup</code> is responsible for creating new
29  * instances of "activatable" objects in its group, informing its
30  * <code>ActivationMonitor</code> when either: its object's become
31  * active or inactive, or the group as a whole becomes inactive. <p>
32  *
33  * An <code>ActivationGroup</code> is <i>initially</i> created in one
34  * of several ways: <ul>
35  * <li>as a side-effect of creating an <code>ActivationDesc</code>
36  * without an explicit <code>ActivationGroupID</code> for the
37  * first activatable object in the group, or
38  * <li>via the <code>ActivationGroup.createGroup</code> method
39  * <li>as a side-effect of activating the first object in a group
40  * whose <code>ActivationGroupDesc</code> was only registered.</ul><p>
41  *
42  * Only the activator can <i>recreate</i> an
43  * <code>ActivationGroup</code>. The activator spawns, as needed, a
44  * separate VM (as a child process, for example) for each registered
45  * activation group and directs activation requests to the appropriate
46  * group. It is implementation specific how VMs are spawned. An
47  * activation group is created via the
48  * <code>ActivationGroup.createGroup</code> static method. The
49  * <code>createGroup</code> method has two requirements on the group
50  * to be created: 1) the group must be a concrete subclass of
51  * <code>ActivationGroup</code>, and 2) the group must have a
52  * constructor that takes two arguments:
53  *
54  * <ul>
55  * <li> the group's <code>ActivationGroupID</code>, and
56  * <li> the group's initialization data (in a
57  * <code>java.rmi.MarshalledObject</code>)</ul><p>
58  *
59  * When created, the default implementation of
60  * <code>ActivationGroup</code> will override the system properties
61  * with the properties requested when its
62  * <code>ActivationGroupDesc</code> was created, and will set a
63  * <code>java.rmi.RMISecurityManager</code> as the default system
64  * security manager. If your application requires specific properties
65  * to be set when objects are activated in the group, the application
66  * should create a special <code>Properties</code> object containing
67  * these properties, then create an <code>ActivationGroupDesc</code>
68  * with the <code>Properties</code> object, and use
69  * <code>ActivationGroup.createGroup</code> before creating any
70  * <code>ActivationDesc</code>s (before the default
71  * <code>ActivationGroupDesc</code> is created). If your application
72  * requires the use of a security manager other than
73  * <code>java.rmi.RMISecurityManager</code>, in the
74  * ActivativationGroupDescriptor properties list you can set
75  * <code>java.security.manager</code> property to the name of the security
76  * manager you would like to install.
77  *
78  * @author Ann Wollrath
79  * @version 1.44, 03/12/19
80  * @see ActivationInstantiator
81  * @see ActivationGroupDesc
82  * @see ActivationGroupID
83  * @since 1.2
84  */

85 public abstract class ActivationGroup
86     extends UnicastRemoteObject JavaDoc
87     implements ActivationInstantiator JavaDoc
88 {
89     /**
90      * @serial the group's identifier
91      */

92     private ActivationGroupID JavaDoc groupID;
93
94     /**
95      * @serial the group's monitor
96      */

97     private ActivationMonitor JavaDoc monitor;
98
99     /**
100      * @serial the group's incarnation number
101      */

102     private long incarnation;
103
104     /** the current activation group for this VM */
105     private static ActivationGroup JavaDoc currGroup;
106     /** the current group's identifier */
107     private static ActivationGroupID JavaDoc currGroupID;
108     /** the current group's activation system */
109     private static ActivationSystem JavaDoc currSystem;
110     /** used to control a group being created only once */
111     private static boolean canCreate = true;
112     /** formal parameters for constructing an activation group */
113     private static Class JavaDoc[] groupConstrParams = {
114     ActivationGroupID JavaDoc.class, MarshalledObject JavaDoc.class
115     };
116     
117     /** indicate compatibility with the Java 2 SDK v1.2 version of class */
118     private static final long serialVersionUID = -7696947875314805420L;
119     
120     /**
121      * Constructs an activation group with the given activation group
122      * identifier. The group is exported as a
123      * <code>java.rmi.server.UnicastRemoteObject</code>.
124      *
125      * @param groupID the group's identifier
126      * @throws RemoteException if this group could not be exported
127      * @since 1.2
128      */

129     protected ActivationGroup(ActivationGroupID JavaDoc groupID)
130     throws RemoteException JavaDoc
131     {
132     // call super constructor to export the object
133
super();
134     this.groupID = groupID;
135     }
136
137     /**
138      * The group's <code>inactiveObject</code> method is called
139      * indirectly via a call to the <code>Activatable.inactive</code>
140      * method. A remote object implementation must call
141      * <code>Activatable</code>'s <code>inactive</code> method when
142      * that object deactivates (the object deems that it is no longer
143      * active). If the object does not call
144      * <code>Activatable.inactive</code> when it deactivates, the
145      * object will never be garbage collected since the group keeps
146      * strong references to the objects it creates. <p>
147      *
148      * <p>The group's <code>inactiveObject</code> method unexports the
149      * remote object from the RMI runtime so that the object can no
150      * longer receive incoming RMI calls. An object will only be unexported
151      * if the object has no pending or executing calls.
152      * The subclass of <code>ActivationGroup</code> must override this
153      * method and unexport the object. <p>
154      *
155      * <p>After removing the object from the RMI runtime, the group
156      * must inform its <code>ActivationMonitor</code> (via the monitor's
157      * <code>inactiveObject</code> method) that the remote object is
158      * not currently active so that the remote object will be
159      * re-activated by the activator upon a subsequent activation
160      * request.<p>
161      *
162      * <p>This method simply informs the group's monitor that the object
163      * is inactive. It is up to the concrete subclass of ActivationGroup
164      * to fulfill the additional requirement of unexporting the object. <p>
165      *
166      * @param id the object's activation identifier
167      * @return true if the object was successfully deactivated; otherwise
168      * returns false.
169      * @exception UnknownObjectException if object is unknown (may already
170      * be inactive)
171      * @exception RemoteException if call informing monitor fails
172      * @exception ActivationException if group is inactive
173      * @since 1.2
174      */

175     public boolean inactiveObject(ActivationID JavaDoc id)
176     throws ActivationException JavaDoc, UnknownObjectException JavaDoc, RemoteException JavaDoc
177     {
178     getMonitor().inactiveObject(id);
179     return true;
180     }
181
182     /**
183      * The group's <code>activeObject</code> method is called when an
184      * object is exported (either by <code>Activatable</code> object
185      * construction or an explicit call to
186      * <code>Activatable.exportObject</code>. The group must inform its
187      * <code>ActivationMonitor</code> that the object is active (via
188      * the monitor's <code>activeObject</code> method) if the group
189      * hasn't already done so.
190      *
191      * @param id the object's identifier
192      * @param obj the remote object implementation
193      * @exception UnknownObjectException if object is not registered
194      * @exception RemoteException if call informing monitor fails
195      * @exception ActivationException if group is inactive
196      * @since 1.2
197      */

198     public abstract void activeObject(ActivationID JavaDoc id, Remote JavaDoc obj)
199     throws ActivationException JavaDoc, UnknownObjectException JavaDoc, RemoteException JavaDoc;
200
201     /**
202      * Create and set the activation group for the current VM. The
203      * activation group can only be set if it is not currently set.
204      * An activation group is set using the <code>createGroup</code>
205      * method when the <code>Activator</code> initiates the
206      * re-creation of an activation group in order to carry out
207      * incoming <code>activate</code> requests. A group must first be
208      * registered with the <code>ActivationSystem</code> before it can
209      * be created via this method.
210      *
211      * <p>The group class specified by the
212      * <code>ActivationGroupDesc</code> must be a concrete subclass of
213      * <code>ActivationGroup</code> and have a public constructor that
214      * takes two arguments: the <code>ActivationGroupID</code> for the
215      * group and the <code>MarshalledObject</code> containing the
216      * group's initialization data (obtained from the
217      * <code>ActivationGroupDesc</code>.
218      *
219      * <p>If the group class name specified in the
220      * <code>ActivationGroupDesc</code> is <code>null</code>, then
221      * this method will behave as if the group descriptor contained
222      * the name of the default activation group implementation class.
223      *
224      * <p>Note that if your application creates its own custom
225      * activation group, a security manager must be set for that
226      * group. Otherwise objects cannot be activated in the group.
227      * <code>java.rmi.RMISecurityManager</code> is set by default.
228      *
229      * <p>If a security manager is already set in the group VM, this
230      * method first calls the security manager's
231      * <code>checkSetFactory</code> method. This could result in a
232      * <code>SecurityException</code>. If your application needs to
233      * set a different security manager, you must ensure that the
234      * policy file specified by the group's
235      * <code>ActivationGroupDesc</code> grants the group the necessary
236      * permissions to set a new security manager. (Note: This will be
237      * necessary if your group downloads and sets a security manager).
238      *
239      * <p>After the group is created, the
240      * <code>ActivationSystem</code> is informed that the group is
241      * active by calling the <code>activeGroup</code> method which
242      * returns the <code>ActivationMonitor</code> for the group. The
243      * application need not call <code>activeGroup</code>
244      * independently since it is taken care of by this method.
245      *
246      * <p>Once a group is created, subsequent calls to the
247      * <code>currentGroupID</code> method will return the identifier
248      * for this group until the group becomes inactive.
249      *
250      * @param id the activation group's identifier
251      * @param desc the activation group's descriptor
252      * @param incarnation the group's incarnation number (zero on group's
253      * initial creation)
254      * @return the activation group for the VM
255      * @exception ActivationException if group already exists or if error
256      * occurs during group creation
257      * @exception SecurityException if permission to create group is denied.
258      * (Note: The default implementation of the security manager
259      * <code>checkSetFactory</code>
260      * method requires the RuntimePermission "setFactory")
261      * @see SecurityManager#checkSetFactory
262      * @since 1.2
263      */

264     public static synchronized
265     ActivationGroup JavaDoc createGroup(ActivationGroupID JavaDoc id,
266                     final ActivationGroupDesc JavaDoc desc,
267                     long incarnation)
268         throws ActivationException JavaDoc
269     {
270     SecurityManager JavaDoc security = System.getSecurityManager();
271     if (security != null)
272         security.checkSetFactory();
273         
274     if (currGroup != null)
275         throw new ActivationException JavaDoc("group already exists");
276     
277     if (canCreate == false)
278         throw new ActivationException JavaDoc("group deactivated and " +
279                       "cannot be recreated");
280
281     try {
282         // load group's class
283
String JavaDoc groupClassName = desc.getClassName();
284
285         /*
286          * Fix for 4252236: resolution of the default
287          * activation group implementation name should be
288          * delayed until now.
289          */

290         if (groupClassName == null) {
291         groupClassName = sun.rmi.server.ActivationGroupImpl.class.getName();
292         }
293         
294         final String JavaDoc className = groupClassName;
295         
296         /*
297          * Fix for 4170955: Because the default group
298          * implementation is a sun.* class, the group class
299          * needs to be loaded in a privileged block of code.
300          */

301         Class JavaDoc cl;
302         try {
303         cl = (Class JavaDoc) java.security.AccessController.
304             doPrivileged(new PrivilegedExceptionAction JavaDoc() {
305             public Object JavaDoc run() throws ClassNotFoundException JavaDoc,
306                 MalformedURLException JavaDoc
307                 {
308                 return RMIClassLoader.
309                     loadClass(desc.getLocation(), className);
310                 }
311             });
312         } catch (PrivilegedActionException JavaDoc pae) {
313         throw new ActivationException JavaDoc("Could not load default group " +
314                           "implementation class",
315                           pae.getException());
316         }
317         
318         // create group
319
Constructor JavaDoc constructor = cl.getConstructor(groupConstrParams);
320         Object JavaDoc[] params = new Object JavaDoc[] { id, desc.getData() };
321
322         Object JavaDoc obj = constructor.newInstance(params);
323         if (obj instanceof ActivationGroup JavaDoc) {
324         ActivationGroup JavaDoc newGroup = (ActivationGroup JavaDoc) obj;
325         currSystem = id.getSystem();
326         newGroup.incarnation = incarnation;
327         newGroup.monitor =
328             currSystem.activeGroup(id, newGroup, incarnation);
329         currGroup = newGroup;
330         currGroupID = id;
331         canCreate = false;
332         } else {
333         throw new ActivationException JavaDoc("group not correct class: " +
334                           obj.getClass().getName());
335         }
336     } catch (java.lang.reflect.InvocationTargetException JavaDoc e) {
337         e.getTargetException().printStackTrace();
338         throw new ActivationException JavaDoc("exception in group constructor",
339                           e.getTargetException());
340         
341     } catch (ActivationException JavaDoc e) {
342         throw e;
343         
344     } catch (Exception JavaDoc e) {
345         throw new ActivationException JavaDoc("exception creating group", e);
346     }
347     
348     return currGroup;
349     }
350
351     /**
352      * Returns the current activation group's identifier. Returns null
353      * if no group is currently active for this VM.
354      * @return the activation group's identifier
355      * @since 1.2
356      */

357     public static synchronized ActivationGroupID JavaDoc currentGroupID() {
358     return currGroupID;
359     }
360
361     /**
362      * Returns the activation group identifier for the VM. If an
363      * activation group does not exist for this VM, a default
364      * activation group is created. A group can be created only once,
365      * so if a group has already become active and deactivated.
366      *
367      * @return the activation group identifier
368      * @exception ActivationException if error occurs during group
369      * creation, if security manager is not set, or if the group
370      * has already been created and deactivated.
371      */

372     static synchronized ActivationGroupID JavaDoc internalCurrentGroupID()
373     throws ActivationException JavaDoc
374     {
375     if (currGroupID == null)
376         throw new ActivationException JavaDoc("nonexistent group");
377
378     return currGroupID;
379     }
380
381     /**
382      * Set the activation system for the VM. The activation system can
383      * only be set it if no group is currently active. If the activation
384      * system is not set via this call, then the <code>getSystem</code>
385      * method attempts to obtain a reference to the
386      * <code>ActivationSystem</code> by looking up the name
387      * "java.rmi.activation.ActivationSystem" in the Activator's
388      * registry. By default, the port number used to look up the
389      * activation system is defined by
390      * <code>ActivationSystem.SYSTEM_PORT</code>. This port can be overridden
391      * by setting the property <code>java.rmi.activation.port</code>.
392      *
393      * <p>If there is a security manager, this method first
394      * calls the security manager's <code>checkSetFactory</code> method.
395      * This could result in a SecurityException.
396      *
397      * @param system remote reference to the <code>ActivationSystem</code>
398      * @exception ActivationException if activation system is already set
399      * @exception SecurityException if permission to set the activation system is denied.
400      * (Note: The default implementation of the security manager
401      * <code>checkSetFactory</code>
402      * method requires the RuntimePermission "setFactory")
403      * @see #getSystem
404      * @see SecurityManager#checkSetFactory
405      * @since 1.2
406      */

407     public static synchronized void setSystem(ActivationSystem JavaDoc system)
408     throws ActivationException JavaDoc
409     {
410     SecurityManager JavaDoc security = System.getSecurityManager();
411     if (security != null)
412         security.checkSetFactory();
413     
414     if (currSystem != null)
415         throw new ActivationException JavaDoc("activation system already set");
416
417     currSystem = system;
418     }
419
420     /**
421      * Returns the activation system for the VM. The activation system
422      * may be set by the <code>setSystem</code> method. If the
423      * activation system is not set via the <code>setSystem</code>
424      * method, then the <code>getSystem</code> method attempts to
425      * obtain a reference to the <code>ActivationSystem</code> by
426      * looking up the name "java.rmi.activation.ActivationSystem" in
427      * the Activator's registry. By default, the port number used to
428      * look up the activation system is defined by
429      * <code>ActivationSystem.SYSTEM_PORT</code>. This port can be
430      * overridden by setting the property
431      * <code>java.rmi.activation.port</code>.
432      *
433      * @return the activation system for the VM/group
434      * @exception ActivationException if activation system cannot be
435      * obtained or is not bound
436      * (means that it is not running)
437      * @see #setSystem
438      * @since 1.2
439      */

440     public static synchronized ActivationSystem JavaDoc getSystem()
441     throws ActivationException JavaDoc
442     {
443     if (currSystem == null) {
444         try {
445         int port;
446         port = ((Integer JavaDoc)java.security.AccessController.doPrivileged(
447                     new GetIntegerAction("java.rmi.activation.port",
448                      ActivationSystem.SYSTEM_PORT))).intValue();
449         currSystem = (ActivationSystem JavaDoc)
450             Naming.lookup("//:" + port +
451                   "/java.rmi.activation.ActivationSystem");
452         } catch (Exception JavaDoc e) {
453         throw new ActivationException JavaDoc(
454             "unable to obtain ActivationSystem", e);
455         }
456     }
457     return currSystem;
458     }
459
460     /**
461      * This protected method is necessary for subclasses to
462      * make the <code>activeObject</code> callback to the group's
463      * monitor. The call is simply forwarded to the group's
464      * <code>ActivationMonitor</code>.
465      *
466      * @param id the object's identifier
467      * @param mobj a marshalled object containing the remote object's stub
468      * @exception UnknownObjectException if object is not registered
469      * @exception RemoteException if call informing monitor fails
470      * @exception ActivationException if an activation error occurs
471      * @since 1.2
472      */

473     protected void activeObject(ActivationID JavaDoc id, MarshalledObject JavaDoc mobj)
474     throws ActivationException JavaDoc, UnknownObjectException JavaDoc, RemoteException JavaDoc
475     {
476     getMonitor().activeObject(id, mobj);
477     }
478
479     /**
480      * This protected method is necessary for subclasses to
481      * make the <code>inactiveGroup</code> callback to the group's
482      * monitor. The call is simply forwarded to the group's
483      * <code>ActivationMonitor</code>. Also, the current group
484      * for the VM is set to null.
485      *
486      * @exception UnknownGroupException if group is not registered
487      * @exception RemoteException if call informing monitor fails
488      * @since 1.2
489      */

490     protected void inactiveGroup()
491     throws UnknownGroupException JavaDoc, RemoteException JavaDoc
492     {
493     try {
494         getMonitor().inactiveGroup(groupID, incarnation);
495     } finally {
496         destroyGroup();
497     }
498     }
499
500     /**
501      * Returns the monitor for the activation group.
502      */

503     private ActivationMonitor JavaDoc getMonitor() throws RemoteException JavaDoc {
504     synchronized (ActivationGroup JavaDoc.class) {
505         if (monitor != null) {
506         return monitor;
507         }
508     }
509     throw new RemoteException JavaDoc("monitor not received");
510     }
511     
512     /**
513      * Destroys the current group.
514      */

515     private static synchronized void destroyGroup() {
516     currGroup = null;
517     currGroupID = null;
518     // NOTE: don't set currSystem to null since it may be needed
519
}
520
521     /**
522      * Returns the current group for the VM.
523      * @exception ActivationException if current group is null (not active)
524      */

525     static synchronized ActivationGroup JavaDoc currentGroup()
526     throws ActivationException JavaDoc
527     {
528     if (currGroup == null) {
529         throw new ActivationException JavaDoc("group is not active");
530     }
531     return currGroup;
532     }
533     
534 }
535
Popular Tags