1 /* 2 * Copyright (c) 1997, 2013, 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 java.security.PrivilegedAction; 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 * {@link SecurityManager} 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 * {@link SecurityManager}, 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 * @throws UnsupportedOperationException if and only if activation is 137 * not supported by this implementation 138 * @since 1.2 139 */ 140 protected ActivationGroup(ActivationGroupID groupID) 141 throws RemoteException 142 { 143 // call super constructor to export the object 144 super(); 145 this.groupID = groupID; 146 } 147 148 /** 149 * The group's <code>inactiveObject</code> method is called 150 * indirectly via a call to the <code>Activatable.inactive</code> 151 * method. A remote object implementation must call 152 * <code>Activatable</code>'s <code>inactive</code> method when 153 * that object deactivates (the object deems that it is no longer 154 * active). If the object does not call 155 * <code>Activatable.inactive</code> when it deactivates, the 156 * object will never be garbage collected since the group keeps 157 * strong references to the objects it creates. 158 * 159 * <p>The group's <code>inactiveObject</code> method unexports the 160 * remote object from the RMI runtime so that the object can no 161 * longer receive incoming RMI calls. An object will only be unexported 162 * if the object has no pending or executing calls. 163 * The subclass of <code>ActivationGroup</code> must override this 164 * method and unexport the object. 165 * 166 * <p>After removing the object from the RMI runtime, the group 167 * must inform its <code>ActivationMonitor</code> (via the monitor's 168 * <code>inactiveObject</code> method) that the remote object is 169 * not currently active so that the remote object will be 170 * re-activated by the activator upon a subsequent activation 171 * request. 172 * 173 * <p>This method simply informs the group's monitor that the object 174 * is inactive. It is up to the concrete subclass of ActivationGroup 175 * to fulfill the additional requirement of unexporting the object. <p> 176 * 177 * @param id the object's activation identifier 178 * @return true if the object was successfully deactivated; otherwise 179 * returns false. 180 * @exception UnknownObjectException if object is unknown (may already 181 * be inactive) 182 * @exception RemoteException if call informing monitor fails 183 * @exception ActivationException if group is inactive 184 * @since 1.2 185 */ 186 public boolean inactiveObject(ActivationID id) 187 throws ActivationException, UnknownObjectException, RemoteException 188 { 189 getMonitor().inactiveObject(id); 190 return true; 191 } 192 193 /** 194 * The group's <code>activeObject</code> method is called when an 195 * object is exported (either by <code>Activatable</code> object 196 * construction or an explicit call to 197 * <code>Activatable.exportObject</code>. The group must inform its 198 * <code>ActivationMonitor</code> that the object is active (via 199 * the monitor's <code>activeObject</code> method) if the group 200 * hasn't already done so. 201 * 202 * @param id the object's identifier 203 * @param obj the remote object implementation 204 * @exception UnknownObjectException if object is not registered 205 * @exception RemoteException if call informing monitor fails 206 * @exception ActivationException if group is inactive 207 * @since 1.2 208 */ 209 public abstract void activeObject(ActivationID id, Remote obj) 210 throws ActivationException, UnknownObjectException, RemoteException; 211 212 /** 213 * Create and set the activation group for the current VM. The 214 * activation group can only be set if it is not currently set. 215 * An activation group is set using the <code>createGroup</code> 216 * method when the <code>Activator</code> initiates the 217 * re-creation of an activation group in order to carry out 218 * incoming <code>activate</code> requests. A group must first be 219 * registered with the <code>ActivationSystem</code> before it can 220 * be created via this method. 221 * 222 * <p>The group class specified by the 223 * <code>ActivationGroupDesc</code> must be a concrete subclass of 224 * <code>ActivationGroup</code> and have a public constructor that 225 * takes two arguments: the <code>ActivationGroupID</code> for the 226 * group and the <code>MarshalledObject</code> containing the 227 * group's initialization data (obtained from the 228 * <code>ActivationGroupDesc</code>. 229 * 230 * <p>If the group class name specified in the 231 * <code>ActivationGroupDesc</code> is <code>null</code>, then 232 * this method will behave as if the group descriptor contained 233 * the name of the default activation group implementation class. 234 * 235 * <p>Note that if your application creates its own custom 236 * activation group, a security manager must be set for that 237 * group. Otherwise objects cannot be activated in the group. 238 * {@link SecurityManager} is set by default. 239 * 240 * <p>If a security manager is already set in the group VM, this 241 * method first calls the security manager's 242 * <code>checkSetFactory</code> method. This could result in a 243 * <code>SecurityException</code>. If your application needs to 244 * set a different security manager, you must ensure that the 245 * policy file specified by the group's 246 * <code>ActivationGroupDesc</code> grants the group the necessary 247 * permissions to set a new security manager. (Note: This will be 248 * necessary if your group downloads and sets a security manager). 249 * 250 * <p>After the group is created, the 251 * <code>ActivationSystem</code> is informed that the group is 252 * active by calling the <code>activeGroup</code> method which 253 * returns the <code>ActivationMonitor</code> for the group. The 254 * application need not call <code>activeGroup</code> 255 * independently since it is taken care of by this method. 256 * 257 * <p>Once a group is created, subsequent calls to the 258 * <code>currentGroupID</code> method will return the identifier 259 * for this group until the group becomes inactive. 260 * 261 * @param id the activation group's identifier 262 * @param desc the activation group's descriptor 263 * @param incarnation the group's incarnation number (zero on group's 264 * initial creation) 265 * @return the activation group for the VM 266 * @exception ActivationException if group already exists or if error 267 * occurs during group creation 268 * @exception SecurityException if permission to create group is denied. 269 * (Note: The default implementation of the security manager 270 * <code>checkSetFactory</code> 271 * method requires the RuntimePermission "setFactory") 272 * @exception UnsupportedOperationException if and only if activation is 273 * not supported by this implementation 274 * @see SecurityManager#checkSetFactory 275 * @since 1.2 276 */ 277 public static synchronized 278 ActivationGroup createGroup(ActivationGroupID id, 279 final ActivationGroupDesc desc, 280 long incarnation) 281 throws ActivationException 282 { 283 SecurityManager security = System.getSecurityManager(); 284 if (security != null) 285 security.checkSetFactory(); 286 287 if (currGroup != null) 288 throw new ActivationException("group already exists"); 289 290 if (canCreate == false) 291 throw new ActivationException("group deactivated and " + 292 "cannot be recreated"); 293 294 try { 295 // load group's class 296 String groupClassName = desc.getClassName(); 297 Class<? extends ActivationGroup> cl; 298 Class<? extends ActivationGroup> defaultGroupClass = 299 sun.rmi.server.ActivationGroupImpl.class; 300 if (groupClassName == null || // see 4252236 301 groupClassName.equals(defaultGroupClass.getName())) 302 { 303 cl = defaultGroupClass; 304 } else { 305 Class<?> cl0; 306 try { 307 cl0 = RMIClassLoader.loadClass(desc.getLocation(), 308 groupClassName); 309 } catch (Exception ex) { 310 throw new ActivationException( 311 "Could not load group implementation class", ex); 312 } 313 if (ActivationGroup.class.isAssignableFrom(cl0)) { 314 cl = cl0.asSubclass(ActivationGroup.class); 315 } else { 316 throw new ActivationException("group not correct class: " + 317 cl0.getName()); 318 } 319 } 320 321 // create group 322 Constructor<? extends ActivationGroup> constructor = 323 cl.getConstructor(ActivationGroupID.class, 324 MarshalledObject.class); 325 ActivationGroup newGroup = 326 constructor.newInstance(id, desc.getData()); 327 currSystem = id.getSystem(); 328 newGroup.incarnation = incarnation; 329 newGroup.monitor = 330 currSystem.activeGroup(id, newGroup, incarnation); 331 currGroup = newGroup; 332 currGroupID = id; 333 canCreate = false; 334 } catch (InvocationTargetException e) { 335 e.getTargetException().printStackTrace(); 336 throw new ActivationException("exception in group constructor", 337 e.getTargetException()); 338 339 } catch (ActivationException e) { 340 throw e; 341 342 } catch (Exception e) { 343 throw new ActivationException("exception creating group", e); 344 } 345 346 return currGroup; 347 } 348 349 /** 350 * Returns the current activation group's identifier. Returns null 351 * if no group is currently active for this VM. 352 * @exception UnsupportedOperationException if and only if activation is 353 * not supported by this implementation 354 * @return the activation group's identifier 355 * @since 1.2 356 */ 357 public static synchronized ActivationGroupID 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 internalCurrentGroupID() 373 throws ActivationException 374 { 375 if (currGroupID == null) 376 throw new ActivationException("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 * @exception UnsupportedOperationException if and only if activation is 404 * not supported by this implementation 405 * @see #getSystem 406 * @see SecurityManager#checkSetFactory 407 * @since 1.2 408 */ 409 public static synchronized void setSystem(ActivationSystem system) 410 throws ActivationException 411 { 412 SecurityManager security = System.getSecurityManager(); 413 if (security != null) 414 security.checkSetFactory(); 415 416 if (currSystem != null) 417 throw new ActivationException("activation system already set"); 418 419 currSystem = system; 420 } 421 422 /** 423 * Returns the activation system for the VM. The activation system 424 * may be set by the <code>setSystem</code> method. If the 425 * activation system is not set via the <code>setSystem</code> 426 * method, then the <code>getSystem</code> method attempts to 427 * obtain a reference to the <code>ActivationSystem</code> by 428 * looking up the name "java.rmi.activation.ActivationSystem" in 429 * the Activator's registry. By default, the port number used to 430 * look up the activation system is defined by 431 * <code>ActivationSystem.SYSTEM_PORT</code>. This port can be 432 * overridden by setting the property 433 * <code>java.rmi.activation.port</code>. 434 * 435 * @return the activation system for the VM/group 436 * @exception ActivationException if activation system cannot be 437 * obtained or is not bound 438 * (means that it is not running) 439 * @exception UnsupportedOperationException if and only if activation is 440 * not supported by this implementation 441 * @see #setSystem 442 * @since 1.2 443 */ 444 public static synchronized ActivationSystem getSystem() 445 throws ActivationException 446 { 447 if (currSystem == null) { 448 try { 449 int port = AccessController.doPrivileged((PrivilegedAction<Integer>) () -> 450 Integer.getInteger("java.rmi.activation.port", ActivationSystem.SYSTEM_PORT)); 451 currSystem = (ActivationSystem) 452 Naming.lookup("//:" + port + 453 "/java.rmi.activation.ActivationSystem"); 454 } catch (Exception e) { 455 throw new ActivationException( 456 "unable to obtain ActivationSystem", e); 457 } 458 } 459 return currSystem; 460 } 461 462 /** 463 * This protected method is necessary for subclasses to 464 * make the <code>activeObject</code> callback to the group's 465 * monitor. The call is simply forwarded to the group's 466 * <code>ActivationMonitor</code>. 467 * 468 * @param id the object's identifier 469 * @param mobj a marshalled object containing the remote object's stub 470 * @exception UnknownObjectException if object is not registered 471 * @exception RemoteException if call informing monitor fails 472 * @exception ActivationException if an activation error occurs 473 * @since 1.2 474 */ 475 protected void activeObject(ActivationID id, 476 MarshalledObject<? extends Remote> mobj) 477 throws ActivationException, UnknownObjectException, RemoteException 478 { 479 getMonitor().activeObject(id, mobj); 480 } 481 482 /** 483 * This protected method is necessary for subclasses to 484 * make the <code>inactiveGroup</code> callback to the group's 485 * monitor. The call is simply forwarded to the group's 486 * <code>ActivationMonitor</code>. Also, the current group 487 * for the VM is set to null. 488 * 489 * @exception UnknownGroupException if group is not registered 490 * @exception RemoteException if call informing monitor fails 491 * @since 1.2 492 */ 493 protected void inactiveGroup() 494 throws UnknownGroupException, RemoteException 495 { 496 try { 497 getMonitor().inactiveGroup(groupID, incarnation); 498 } finally { 499 destroyGroup(); 500 } 501 } 502 503 /** 504 * Returns the monitor for the activation group. 505 */ 506 private ActivationMonitor getMonitor() throws RemoteException { 507 synchronized (ActivationGroup.class) { 508 if (monitor != null) { 509 return monitor; 510 } 511 } 512 throw new RemoteException("monitor not received"); 513 } 514 515 /** 516 * Destroys the current group. 517 */ 518 private static synchronized void destroyGroup() { 519 currGroup = null; 520 currGroupID = null; 521 // NOTE: don't set currSystem to null since it may be needed 522 } 523 524 /** 525 * Returns the current group for the VM. 526 * @exception ActivationException if current group is null (not active) 527 */ 528 static synchronized ActivationGroup currentGroup() 529 throws ActivationException 530 { 531 if (currGroup == null) { 532 throw new ActivationException("group is not active"); 533 } 534 return currGroup; 535 } 536 537 }