Frames | No Frames |
1: /* Activatable.java -- A common ancestor for the activatable objects. 2: Copyright (c) 1996, 1997, 1998, 1999, 2004, 2006 3: Free Software Foundation, Inc. 4: 5: This file is part of GNU Classpath. 6: 7: GNU Classpath is free software; you can redistribute it and/or modify 8: it under the terms of the GNU General Public License as published by 9: the Free Software Foundation; either version 2, or (at your option) 10: any later version. 11: 12: GNU Classpath is distributed in the hope that it will be useful, but 13: WITHOUT ANY WARRANTY; without even the implied warranty of 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15: General Public License for more details. 16: 17: You should have received a copy of the GNU General Public License 18: along with GNU Classpath; see the file COPYING. If not, write to the 19: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 20: 02110-1301 USA. 21: 22: Linking this library statically or dynamically with other modules is 23: making a combined work based on this library. Thus, the terms and 24: conditions of the GNU General Public License cover the whole 25: combination. 26: 27: As a special exception, the copyright holders of this library give you 28: permission to link this library with independent modules to produce an 29: executable, regardless of the license terms of these independent 30: modules, and to copy and distribute the resulting executable under 31: terms of your choice, provided that you also meet, for each linked 32: independent module, the terms and conditions of the license of that 33: module. An independent module is a module which is not derived from 34: or based on this library. If you modify this library, you may extend 35: this exception to your version of the library, but you are not 36: obligated to do so. If you do not wish to do so, delete this 37: exception statement from your version. */ 38: 39: 40: package java.rmi.activation; 41: 42: import gnu.java.rmi.server.ActivatableServerRef; 43: import gnu.java.rmi.server.UnicastServer; 44: import gnu.java.rmi.server.UnicastServerRef; 45: 46: import java.lang.reflect.Field; 47: import java.rmi.MarshalledObject; 48: import java.rmi.NoSuchObjectException; 49: import java.rmi.Remote; 50: import java.rmi.RemoteException; 51: import java.rmi.server.ObjID; 52: import java.rmi.server.RMIClientSocketFactory; 53: import java.rmi.server.RMIServerSocketFactory; 54: import java.rmi.server.RemoteObject; 55: import java.rmi.server.RemoteServer; 56: import java.rmi.server.UnicastRemoteObject; 57: 58: /** 59: * A common ancestor for the implementations of the activatable objects. Such 60: * objects require persistent access over time and can be activated by the 61: * system. The derived classes also implements the needed interface of some 62: * remote object and usually have the two parameter constructor, the first 63: * parameter being the {@link ActivationID} and the second the 64: * {@link MarshalledObject}. Activatable is the main class that developers need 65: * to use to implement and manage activatable objects. It also contains methods 66: * for making activatable remote objects that are not derived from the 67: * Activatable class. 68: * 69: * @author Audrius Meskauskas (audriusa@bioinformatics.org) (from stub) 70: */ 71: public abstract class Activatable 72: extends RemoteServer 73: { 74: 75: /** 76: * Use SVUID for interoperability. 77: */ 78: static final long serialVersionUID = - 3120617863591563455L; 79: 80: /** 81: * The object activation id. 82: */ 83: final ActivationID id; 84: 85: /** 86: * This constructor is used to register export the object on the given port. A 87: * subclass of the Activatable class calls this constructor to register and 88: * export the object during initial construction. As a side-effect of 89: * activatable object construction, the remote object is both "registered" 90: * with the activation system and "exported" (on an anonymous port, if port is 91: * zero) to the RMI runtime so that it is available to accept incoming calls 92: * from clients. 93: * 94: * @param codebase the object code base url 95: * @param data the data, needed to activate the object. 96: * @param restart specifies reactivation mode after crash. If true, the object 97: * is activated when activator is restarted or the activation group 98: * is restarted. If false, the object is only activated on demand. 99: * This flag does has no effect during the normal operation (the 100: * object is normally activated on demand). 101: * @param port the port, on which the object will become available. The value 102: * 0 means anonymous port. 103: * @throws ActivationException if the activation failed 104: * @throws RemoteException if the remote call failed. 105: */ 106: protected Activatable(String codebase, MarshalledObject<?> data, 107: boolean restart, int port) throws ActivationException, 108: RemoteException 109: { 110: ActivationDesc descriptor = new ActivationDesc(getClass().getName(), 111: codebase, data, restart); 112: id = obtainId(descriptor); 113: exportObject(this, id, port); 114: } 115: 116: /** 117: * This constructor is used to register export the object on the given port, 118: * additionally specifying the socket factories. A subclass of the Activatable 119: * class calls this constructor to register and export the object during 120: * initial construction. 121: * 122: * @param codebase the object code base url 123: * @param data the data, needed to activate the object. 124: * @param restart specifies reactivation mode after crash. If true, the object 125: * is activated when activator is restarted or the activation group 126: * is restarted. If false, the object is only activated on demand. 127: * This flag does has no effect during the normal operation (the 128: * object is normally activated on demand). 129: * @param port the port, on which the object will become available. The value 130: * 0 means anonymous port. 131: * @param csf the client socket factory 132: * @param ssf the server socket factory 133: * @throws ActivationException if the activation failed 134: * @throws RemoteException if the remote call failed. 135: */ 136: protected Activatable(String codebase, MarshalledObject<?> data, 137: boolean restart, int port, RMIClientSocketFactory csf, 138: RMIServerSocketFactory ssf) throws ActivationException, 139: RemoteException 140: { 141: ActivationDesc descriptor = new ActivationDesc(getClass().getName(), 142: codebase, data, restart); 143: id = obtainId(descriptor); 144: exportObject(this, id, port); 145: } 146: 147: /** 148: * Creates the new instance of activatable with the given activation id and is 149: * listening at the given port. A subclass of the Activatable class calls this 150: * constructor when the object itself is activated via its special 151: * "activation" constructor with the two parameters ({@link ActivationID}, 152: * {@link MarshalledObject}). As a side effect, the object is exported and is 153: * available to accept incoming calls. 154: * 155: * @param anId the activation id 156: * @param port the port, on which the activatable will be listening 157: * @throws RemoteException if the activation failed. 158: */ 159: protected Activatable(ActivationID anId, int port) throws RemoteException 160: { 161: id = anId; 162: try 163: { 164: exportObject(this, anId, port); 165: } 166: catch (Exception e) 167: { 168: e.printStackTrace(); 169: RemoteException acex = 170: new RemoteException("cannot export Activatable", e); 171: throw acex; 172: } 173: } 174: 175: /** 176: * Creates the new instance of activatable with the given activation id and is 177: * listening at the given port, using the specified client and server sockets 178: * factories. A subclass of the Activatable class calls this 179: * constructor when the object itself is activated via its special 180: * "activation" constructor with the two parameters ({@link ActivationID}, 181: * {@link MarshalledObject}). As a side effect, the object is exported and is 182: * available to accept incoming calls. 183: * 184: * @param anId the activation id 185: * @param port the port, on which the activatable will be listening 186: * @param csf the client socket factory 187: * @param ssf the server socket factory 188: * 189: * @throws RemoteException if the remote call failed 190: */ 191: protected Activatable(ActivationID anId, int port, RMIClientSocketFactory csf, 192: RMIServerSocketFactory ssf) throws RemoteException 193: { 194: id = anId; 195: try 196: { 197: exportObject(this, anId, port, csf, ssf); 198: } 199: catch (Exception e) 200: { 201: RemoteException acex = new RemoteException(); 202: acex.initCause(e); 203: throw acex; 204: } 205: } 206: 207: /** 208: * Get the objects activation identifier. 209: * 210: * @return the object activation identifier 211: */ 212: protected ActivationID getID() 213: { 214: return id; 215: } 216: 217: /** 218: * Obtain the activation Id from the activation descriptor by registering 219: * within the current group. 220: */ 221: static ActivationID obtainId(ActivationDesc descriptor) 222: throws RemoteException, UnknownGroupException, ActivationException 223: { 224: ActivationGroupID id = descriptor.getGroupID(); 225: ActivationSystem system; 226: 227: if (id != null) 228: system = id.getSystem(); 229: else 230: system = ActivationGroup.currentGroupID().getSystem(); 231: return system.registerObject(descriptor); 232: } 233: 234: /** 235: * This method registers an activatable object. The object is expected to be 236: * on the anonymous port (null client and server socket factories). 237: * 238: * @param desc the object description. 239: * @return the remote stub for the activatable object (the first call on this 240: * stub will activate the object). 241: * @throws UnknownGroupException if the object group identifier is unknown 242: * @throws ActivationException if the activation system is not running 243: * @throws RemoteException if the remote call fails 244: */ 245: public static Remote register(ActivationDesc desc) 246: throws UnknownGroupException, ActivationException, RemoteException 247: { 248: ActivationID id = obtainId(desc); 249: try 250: { 251: return toStub( 252: id, 253: Thread.currentThread().getContextClassLoader().loadClass( 254: desc.getClassName())); 255: } 256: catch (ClassNotFoundException e) 257: { 258: throw new ActivationException("Class not found: "+desc.getClassName()); 259: } 260: } 261: 262: /** 263: * Inactivates and unexports the object. The subsequent calls will activate 264: * the object again. The object is not inactivated if it is currently 265: * executing calls. 266: * 267: * @param id the id of the object being inactivated 268: * @return true if the object has been inactivated, false if it has not been 269: * inactivated because of the running or pending calls. 270: * @throws UnknownObjectException if the object is unknown. 271: * @throws ActivationException if the object group is not active 272: * @throws RemoteException if the remote call fails 273: */ 274: public static boolean inactive(ActivationID id) 275: throws UnknownObjectException, ActivationException, RemoteException 276: { 277: if (id.group!=null) 278: id.group.inactiveObject(id); 279: return UnicastRemoteObject.unexportObject(id.activate(false), false); 280: } 281: 282: /** 283: * Unregister the object (the object will no longer be activable with that id) 284: * 285: * @param id the object id 286: * @throws UnknownObjectException if the id is unknown 287: * @throws ActivationException if the activation system is not running 288: * @throws RemoteException if the remote call fails. 289: */ 290: public static void unregister(ActivationID id) throws UnknownObjectException, 291: ActivationException, RemoteException 292: { 293: ActivationGroup.currentGroupId.getSystem().unregisterObject(id); 294: UnicastServer.unregisterActivatable(id); 295: } 296: 297: /** 298: * Register and export the object that activatable object that is not derived 299: * from the Activatable super class. It creates and registers the object 300: * activation descriptor. There is no need to call this method if the object 301: * extends Activable, as its work is done in the constructor 302: * {@link #Activatable(String, MarshalledObject, boolean, int)}. 303: * 304: * @param obj the object, that is exported, becoming available at the given 305: * port. 306: * @param location the object code location (codebase). 307: * @param data the data, needed to activate the object 308: * @param restart the restart mode 309: * @param port the port, where the object will be available 310: * 311: * @return the created object activation ID. 312: * 313: * @throws ActivationException if the activation group is not active 314: * @throws RemoteException if the registration or export fails 315: */ 316: public static ActivationID exportObject(Remote obj, String location, 317: MarshalledObject<?> data, 318: boolean restart, int port) 319: throws ActivationException, RemoteException 320: { 321: ActivationDesc descriptor = new ActivationDesc(obj.getClass().getName(), 322: location, data, restart); 323: ActivationID id = obtainId(descriptor); 324: Remote stub = exportObject(obj, id, port); 325: return id; 326: } 327: 328: /** 329: * Register and export the object that activatable object that is not derived 330: * from the Activatable super class. It creates and registers the object 331: * activation descriptor. There is no need to call this method if the object 332: * extends Activable, as its work is done in the constructor 333: * {@link #Activatable(String, MarshalledObject, boolean, int, RMIClientSocketFactory, RMIServerSocketFactory)} 334: * 335: * @param obj the object, that is exported, becoming available at the given 336: * port. 337: * @param location the object code location (codebase). 338: * @param data the data, needed to activate the object 339: * @param restart the restart mode 340: * @param port the port, where the object will be available 341: * @param csf the client socket factory 342: * @param ssf the server socket factory 343: * 344: * @return the created object activation ID. 345: * 346: * @throws ActivationException if the activation group is not active 347: * @throws RemoteException if the registration or export fails 348: */ 349: public static ActivationID exportObject(Remote obj, String location, 350: MarshalledObject data, 351: boolean restart, int port, 352: RMIClientSocketFactory csf, 353: RMIServerSocketFactory ssf) 354: throws ActivationException, RemoteException 355: { 356: ActivationDesc descriptor = new ActivationDesc(obj.getClass().getName(), 357: location, data, restart); 358: ActivationID id = obtainId(descriptor); 359: Remote stub = exportObject(obj, id, port, csf, ssf); 360: return id; 361: 362: } 363: 364: /** 365: * During activation, this exportObject method should be invoked explicitly by 366: * the activatable object, that does is not derived from the Activatable 367: * class. There is no need to call this method if the object extends 368: * Activable, as its work is done in the constructor 369: * {@link #Activatable(ActivationID, int)} 370: * 371: * @param obj the object 372: * @param id the known activation id 373: * @param port the object port 374: * 375: * @return the remote stub of the activatable object 376: * 377: * @throws RemoteException if the object export fails 378: */ 379: public static Remote exportObject(Remote obj, ActivationID id, int port) 380: throws RemoteException 381: { 382: Remote stub = export(id, obj, port, null); 383: return stub; 384: } 385: 386: /** 387: * During activation, this exportObject method should be invoked explicitly by 388: * the activatable object, that does is not derived from the Activatable 389: * class. There is no need to call this method if the object extends 390: * Activable, as its work is done in the constructor 391: * {@link #Activatable(ActivationID, int)} 392: * 393: * @param obj the object 394: * @param id the known activation id 395: * @param port the object port 396: * @param csf the client socket factory 397: * @param ssf the server socket factory 398: * 399: * @return the remote stub of the activatable object 400: * 401: * @throws RemoteException if the object export fails 402: */ 403: public static Remote exportObject(Remote obj, ActivationID id, int port, 404: RMIClientSocketFactory csf, 405: RMIServerSocketFactory ssf) 406: throws RemoteException 407: { 408: Remote stub = export(id, obj, port, ssf); 409: return stub; 410: 411: } 412: 413: /** 414: * Make the remote object unavailable for incoming calls. This method also 415: * unregisters the object, so it cannot be activated again by incoming call 416: * (unless registered). 417: * 418: * @param obj the object to unexport 419: * @param force if true, cancel all pending or running calls to that object 420: * (if false, the object with such calls is not unexported and false 421: * is returned by this method). 422: * @return if the object was successfully unexported, false otherwise 423: * @throws NoSuchObjectException if such object is not known 424: */ 425: public static boolean unexportObject(Remote obj, boolean force) 426: throws NoSuchObjectException 427: { 428: Object aref = UnicastServer.getExportedRef(obj); 429: 430: // Unregister it also (otherwise will be activated during the subsequent 431: // call. 432: if (aref instanceof ActivatableServerRef) 433: { 434: ActivatableServerRef aar = (ActivatableServerRef) aref; 435: UnicastServer.unregisterActivatable(aar.actId); 436: } 437: return UnicastRemoteObject.unexportObject(obj, force); 438: } 439: 440: static Remote exportObject(Remote obj, int port, 441: RMIServerSocketFactory serverSocketFactory) 442: throws RemoteException 443: { 444: UnicastServerRef sref = null; 445: if (obj instanceof RemoteObject) 446: sref = (UnicastServerRef) ((RemoteObject) obj).getRef(); 447: 448: if (sref == null) 449: sref = new UnicastServerRef(new ObjID(), port, serverSocketFactory); 450: 451: Remote stub = sref.exportObject(obj); 452: // addStub(obj, stub); 453: // TODO Need to change the place of the stub repository 454: return stub; 455: } 456: 457: /** 458: * Create and export the new remote object, making it available at the given 459: * port, using sockets, produced by the specified factories. 460: * 461: * @param port the port, on that the object should become available. Zero 462: * means anonymous port. 463: * @param serverSocketFactory the server socket factory 464: */ 465: private static Remote export(ActivationID id, Remote obj, int port, 466: RMIServerSocketFactory serverSocketFactory) 467: throws RemoteException 468: { 469: ActivatableServerRef sref = null; 470: sref = new ActivatableServerRef(makeId(id), id, port, serverSocketFactory); 471: return sref.exportObject(obj); 472: } 473: 474: /** 475: * Make the object ID from the activation ID. The same activation ID always 476: * produces the identical object id. 477: * 478: * @param aid the activation id 479: * 480: * @return the object id 481: */ 482: private static ObjID makeId(ActivationID aid) 483: { 484: ObjID id = new ObjID(0); 485: 486: // The fields of both ObjID and ActivationID must be package private, 487: // so we need to use the reflection to access them anyway. 488: // Probably other implementations use some very different approach. 489: 490: try 491: { 492: Field idUid = ObjID.class.getDeclaredField("space"); 493: Field aidUid = ActivationID.class.getDeclaredField("uid"); 494: 495: aidUid.setAccessible(true); 496: idUid.setAccessible(true); 497: 498: idUid.set(id, aidUid.get(aid)); 499: } 500: catch (Exception e) 501: { 502: InternalError ierr = new InternalError("Unable to set UID field"); 503: ierr.initCause(e); 504: throw ierr; 505: } 506: 507: return id; 508: } 509: 510: /** 511: * Connect the object to the UnicastServer (export), but not activate it. 512: * The object will be activated on the first call. 513: */ 514: static Remote toStub(ActivationID anId, Class stubFor) 515: { 516: try 517: { 518: ActivatableServerRef asr = 519: new ActivatableServerRef(makeId(anId), anId, 0, null); 520: UnicastServer.exportActivatableObject(asr); 521: return asr.exportClass(stubFor); 522: } 523: catch (RemoteException e) 524: { 525: InternalError ierr = new InternalError( 526: "Failed to obtain activatable stub"); 527: ierr.initCause(e); 528: throw ierr; 529: } 530: } 531: }