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