diff options
| author | Audrius Meskauskas <audriusa@Bioinformatics.org> | 2006-03-17 12:19:25 +0000 |
|---|---|---|
| committer | Audrius Meskauskas <audriusa@Bioinformatics.org> | 2006-03-17 12:19:25 +0000 |
| commit | 616d94e82c815801ba158e5e3731aa53905bbf1e (patch) | |
| tree | d3f3e62aa4e814263450fce60d5b76223c0d85ab /gnu/java | |
| parent | 6c99d6627576eafb4301a1f3822afa2840c67369 (diff) | |
| download | classpath-616d94e82c815801ba158e5e3731aa53905bbf1e.tar.gz | |
2006-03-17 Audrius Meskauskas <AudriusA@Bioinformatics.org>
* java/rmi/activation/Activatable.java: Implemented.
java/rmi/activation/ActivationDesc.java: Implemented.
java/rmi/activation/ActivationGroup.java: Implemented.
java/rmi/activation/ActivationGroupDesc.java: Implemented.
java/rmi/activation/ActivationID.java: Implemented.
java/rmi/activation/ActivationSystem.java: Implemented.
* gnu/java/rmi/server/UnicastServerRef.java
(exportObject, incommingMessageCall): Documented.
* java/rmi/activation/package.html: Documented.
* java/rmi/server/ObjID.java (objNum, space): Made package
protected.
* gnu/java/rmi/server/UnicastServer.java: Rewritten.
* gnu/java/rmi/server/CombinedClassLoader.java (constructor):
Iteration bug fix.
* gnu/java/rmi/activation/ActivationSystemTransient.java: New file.
gnu/java/rmi/activation/BidiTable.java: New file.
gnu/java/rmi/activation/DefaultActivationGroup.java: New file.
gnu/java/rmi/activation/DefaultActivationSystem.java: New file.
gnu/java/rmi/server/ActivatableServerRef.java: New file.
Diffstat (limited to 'gnu/java')
| -rw-r--r-- | gnu/java/rmi/activation/ActivationSystemTransient.java | 389 | ||||
| -rw-r--r-- | gnu/java/rmi/activation/BidiTable.java | 111 | ||||
| -rw-r--r-- | gnu/java/rmi/activation/DefaultActivationGroup.java | 155 | ||||
| -rw-r--r-- | gnu/java/rmi/activation/DefaultActivationSystem.java | 57 | ||||
| -rw-r--r-- | gnu/java/rmi/server/ActivatableServerRef.java | 146 | ||||
| -rw-r--r-- | gnu/java/rmi/server/CombinedClassLoader.java | 2 | ||||
| -rw-r--r-- | gnu/java/rmi/server/UnicastServer.java | 93 | ||||
| -rw-r--r-- | gnu/java/rmi/server/UnicastServerRef.java | 13 |
8 files changed, 958 insertions, 8 deletions
diff --git a/gnu/java/rmi/activation/ActivationSystemTransient.java b/gnu/java/rmi/activation/ActivationSystemTransient.java new file mode 100644 index 000000000..810dbb2af --- /dev/null +++ b/gnu/java/rmi/activation/ActivationSystemTransient.java @@ -0,0 +1,389 @@ +/* DefaultActivationSystem.java -- FIXME: briefly describe file purpose + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.rmi.activation; + +import java.rmi.MarshalledObject; +import java.rmi.RemoteException; +import java.rmi.activation.ActivationDesc; +import java.rmi.activation.ActivationException; +import java.rmi.activation.ActivationGroup; +import java.rmi.activation.ActivationGroupDesc; +import java.rmi.activation.ActivationGroupID; +import java.rmi.activation.ActivationID; +import java.rmi.activation.ActivationInstantiator; +import java.rmi.activation.ActivationMonitor; +import java.rmi.activation.ActivationSystem; +import java.rmi.activation.UnknownGroupException; +import java.rmi.activation.UnknownObjectException; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; + +/** + * Provides the default transient activation system. + * + * @author Audrius Meskauskas (audriusa@bioinformatics.org) + */ +public class ActivationSystemTransient + extends DefaultActivationSystem + implements ActivationSystem, ActivationMonitor +{ + /** + * Maps group identifiers into group descriptions. + */ + BidiTable groupDescs = new BidiTable(); + + /** + * Maps object identifiers into object activation descriptions + */ + BidiTable descriptions = new BidiTable(); + + /** + * Maps group descriptions into group object instantiators. + */ + Map groupInstantiators = new Hashtable(); + + /** + * The cache of the activated objects, maps activation ids to remote + * object stubs. + */ + Map activatedObjects = new HashMap(); + + /** + * The object incarnation counter. + */ + static long groupIncarnations = 0; + + /** + * The singleton of this activation system + */ + static ActivationSystem singleton; + + /** + * Set to true to print the event messages to console. + */ + static boolean debug = true; + + /** + * This group should not be instantiated outside the group code. + */ + private ActivationSystemTransient() + { + } + + public static ActivationSystem getInstance() + { + if (singleton == null) + singleton = new ActivationSystemTransient(); + return singleton; + } + + /** + * Activate the given object (try cache first if force = false) + */ + public MarshalledObject activate(ActivationID id, boolean force) + throws ActivationException, UnknownObjectException, RemoteException + { + if (! force) + { + synchronized (activatedObjects) + { + MarshalledObject object = (MarshalledObject) activatedObjects.get(id); + if (object != null) + return object; + } + } + + ActivationDesc desc = (ActivationDesc) descriptions.get(id); + if (desc == null) + throw new UnknownObjectException(id == null ? "null" : id.toString()); + + ActivationInstantiator group = + (ActivationInstantiator) groupInstantiators.get(desc.getGroupID()); + + if (group == null) + { + // The group is not active - must be activated. + ActivationGroupID gid = desc.getGroupID(); + ActivationGroupDesc adesc = (ActivationGroupDesc) groupDescs.get(gid); + + if (adesc == null) + throw new UnknownGroupException("Unknown group, " + gid + " for " + + id+" this "+this); + + synchronized (ActivationSystemTransient.class) + { + groupIncarnations++; + } + + group = ActivationGroup.createGroup(gid, adesc, groupIncarnations); + activeGroup(gid, group, groupIncarnations); + } + + MarshalledObject object = group.newInstance(id, desc); + + synchronized (activatedObjects) + { + activatedObjects.put(id, object); + } + return object; + } + + /** + * Returns the activation monitor (THIS) and remebers the instantiator, used + * by that group. + */ + public ActivationMonitor activeGroup(ActivationGroupID id, + ActivationInstantiator group, + long incarnation) + throws UnknownGroupException, ActivationException, RemoteException + { + groupInstantiators.put(id, group); + return this; + } + + /** + * Get the activation descriptor for the given activation id. + * + * @return the activation descriptor, never null. + * @throws UnknownObjectException if such object is unknown. + */ + public ActivationDesc getActivationDesc(ActivationID id) + throws ActivationException, UnknownObjectException, RemoteException + { + ActivationDesc desc = (ActivationDesc) descriptions.get(id); + if (desc == null) + throw new UnknownObjectException(id == null ? "null" : id.toString()); + return desc; + } + + /** + * Get the descriptor of the given activation group. + * + * @return the activation group descriptor, never null. + * @throws UnknownGroupException if such group is unknown + */ + public ActivationGroupDesc getActivationGroupDesc(ActivationGroupID groupId) + throws ActivationException, UnknownGroupException, RemoteException + { + ActivationGroupDesc desc = (ActivationGroupDesc) groupDescs.get(groupId); + if (desc == null) + throw new UnknownGroupException(groupId == null ? "null" + : groupId.toString()); + return desc; + } + + /** + * Create the activation group id and put this id-descriptor combination into + * the group map. The new ID will only be created if this description has not + * already been registered, otherwise the id of the registered description + * will be returned. + */ + public ActivationGroupID registerGroup(ActivationGroupDesc groupDesc) + throws ActivationException, RemoteException + { + ActivationGroupID id = (ActivationGroupID) groupDescs.getKey(groupDesc); + if (id == null) + { + id = new ActivationGroupID(this); + groupDescs.put(id, groupDesc); + } + if (debug) + System.out.println("Register group " + id +":"+groupDesc+" this "+this); + + return id; + } + + /** + * Create the object activation id and put this id-descriptor combination into + * the group map. The new ID will only be created if this description has not + * already been registered, otherwise the id of the registered description + * will be returned. + */ + public ActivationID registerObject(ActivationDesc desc) + throws ActivationException, UnknownGroupException, RemoteException + { + ActivationID id = (ActivationID) descriptions.getKey(desc); + if (id == null) + { + id = new ActivationID(this); + descriptions.put(id, desc); + } + + if (debug) + System.out.println("Register object " + id +":"+desc+" this "+this); + + return id; + } + + /** + * Replace the activation descriptor, return the previous descriptor. + */ + public ActivationDesc setActivationDesc(ActivationID id, ActivationDesc desc) + throws ActivationException, UnknownObjectException, + UnknownGroupException, RemoteException + { + ActivationDesc prev = getActivationDesc(id); + descriptions.put(id, desc); + return prev; + } + + /** + * Replace the activation group descriptor, return the previous descriptor. + */ + public ActivationGroupDesc setActivationGroupDesc( + ActivationGroupID groupId, + ActivationGroupDesc groupDesc) + throws ActivationException, UnknownGroupException, RemoteException + { + ActivationGroupDesc prev = getActivationGroupDesc(groupId); + groupDescs.put(groupId, groupDesc); + return prev; + } + + /** + * No action. + */ + public void shutdown() throws RemoteException + { + // Nothing to do. + } + + /** + * Remove the group from the group map + */ + public void unregisterGroup(ActivationGroupID groupId) throws ActivationException, + UnknownGroupException, RemoteException + { + if (! groupDescs.containsKey(groupId)) + throw new UnknownGroupException("Unknown group "+groupId); + + groupDescs.removeKey(groupId); + groupInstantiators.remove(groupId); + } + + /** + * Remove the object id from the active object and description maps. + */ + public void unregisterObject(ActivationID id) throws ActivationException, + UnknownObjectException, RemoteException + { + if (! descriptions.containsKey(id)) + throw new UnknownObjectException("Unregistering unknown object"); + descriptions.removeKey(id); + + synchronized (activatedObjects) + { + activatedObjects.remove(id); + } + } + + /** + * Put the object into active object map. + */ + public void activeObject(ActivationID id, MarshalledObject obj) + throws UnknownObjectException, RemoteException + { + if (! descriptions.containsKey(id)) + throw new UnknownObjectException("Activating unknown object "+ + id+" this "+this); + try + { + synchronized (activatedObjects) + { + activatedObjects.put(id, obj.get()); + } + } + catch (RemoteException e) + { + throw e; + } + catch (Exception e) + { + UnknownObjectException un = new UnknownObjectException( + "Cannot get Remote for MarshalledObject of "+id); + un.detail = e; + throw un; + } + } + + /** + * Check if the group is known. Remove all active objects, belonging to + * that group, from the active object cache. + */ + public void inactiveGroup(ActivationGroupID groupId, long incarnation) + throws UnknownGroupException, RemoteException + { + if (! groupInstantiators.containsKey(groupId)) + throw new UnknownGroupException("Inactivating unkwnon group"); + + groupInstantiators.remove(groupId); + + // Remove all members of this group from the cache. + synchronized (activatedObjects) + { + Iterator iter = activatedObjects.keySet().iterator(); + ActivationID id; + ActivationDesc desc; + while (iter.hasNext()) + { + id = (ActivationID) iter.next(); + desc = (ActivationDesc) descriptions.get(id); + if (desc.getGroupID().equals(groupId)) + activatedObjects.remove(id); + } + } + } + + /** + * Removes this id from the active object cache. + */ + public void inactiveObject(ActivationID id) throws UnknownObjectException, + RemoteException + { + if (! descriptions.containsKey(id)) + throw new UnknownObjectException("Inactivating unknown object"); + + synchronized (activatedObjects) + { + activatedObjects.remove(id); + } + } +} diff --git a/gnu/java/rmi/activation/BidiTable.java b/gnu/java/rmi/activation/BidiTable.java new file mode 100644 index 000000000..0a8d895f3 --- /dev/null +++ b/gnu/java/rmi/activation/BidiTable.java @@ -0,0 +1,111 @@ +/* BidiHasthable.java -- Bidirectional hash table. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.rmi.activation; + +import java.util.Hashtable; + +/** + * The bidirectional hash table, maps both a to b and b to a. + * + * @author Audrius Meskauskas (audriusa@bioinformatics.org) + */ +public class BidiTable +{ + /** + * Use serialVerionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * Maps keys to values + */ + Hashtable k2v = new Hashtable(); + + /** + * Maps values to keys (in reverse) + */ + Hashtable v2k = new Hashtable(); + + /** + * Get key by value + */ + Object getKey(Object value) + { + return v2k.get(value); + } + + /** + * Put key-value pair. + */ + public void put(Object key, Object value) + { + k2v.put(key, value); + v2k.put(value, key); + } + + /** + * Get value from key + */ + public Object get(Object key) + { + return k2v.get(key); + } + + /** + * Remove the key-value pair by key + */ + public void removeKey(Object key) + { + Object value = k2v.get(key); + if (value!=null) + { + k2v.remove(key); + v2k.remove(value); + } + } + + /** + * Check if the table contains this key. + */ + public boolean containsKey(Object key) + { + return k2v.containsKey(key); + } + +} diff --git a/gnu/java/rmi/activation/DefaultActivationGroup.java b/gnu/java/rmi/activation/DefaultActivationGroup.java new file mode 100644 index 000000000..95c5a4139 --- /dev/null +++ b/gnu/java/rmi/activation/DefaultActivationGroup.java @@ -0,0 +1,155 @@ +/* DefaultActivationGroup.java -- Default activation group. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.rmi.activation; + +import gnu.java.rmi.server.ActivatableServerRef; +import gnu.java.rmi.server.UnicastServer; + +import java.lang.reflect.Constructor; +import java.rmi.MarshalledObject; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.activation.ActivationDesc; +import java.rmi.activation.ActivationException; +import java.rmi.activation.ActivationGroup; +import java.rmi.activation.ActivationGroupID; +import java.rmi.activation.ActivationID; +import java.rmi.activation.UnknownObjectException; + +/** + * The default activation group class. This activation group assumes that + * all classes are accessible via current thread context class loader. + * The remote class loading is not supported for security reasons. + * + * @author Audrius Meskauskas (audriusa@Bioinformatics.org) + */ +public class DefaultActivationGroup + extends ActivationGroup +{ + /** + * Use the serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * Used during the group creation (required constructor). + */ + static final Class[] cConstructorTypes = new Class[] + { + ActivationID.class, + MarshalledObject.class + }; + + + /** + * Create the new default activation group. + * + * @param id the group activation id. + * @param data may contain the group initialization data (unused and can be + * null) + * @throws RemoteException if the super constructor does + */ + public DefaultActivationGroup(ActivationGroupID id, MarshalledObject data) + throws RemoteException + { + super(id); + } + + + /** + * May be overridden and used as a hook. This method is called each time + * the new object is instantiated. + */ + public void activeObject(ActivationID id, Remote obj) + throws ActivationException, UnknownObjectException, RemoteException + { + // Nothing to do (the monitor is already notified in newInstance) + } + + /** + * Create the new instance of the object, using the class name and location + * information, stored in the passed descriptor. The method expects the object + * class to have the two parameter constructor, the first parameter being the + * {@link ActivationID} and the second the {@link MarshalledObject}. + * + * @param id the object activation id + * @param desc the activation descriptor, providing the information, necessary + * to create and activate the object + * @return the marshalled object, containing the exported stub of the created + * object + * @throws ActivationException if the activation fails due any reason + */ + public MarshalledObject newInstance(ActivationID id, ActivationDesc desc) + throws ActivationException, RemoteException + { + try + { + Remote object; + Class objectClass; + + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + objectClass = loader.loadClass(desc.getClassName()); + Constructor constructor = objectClass.getConstructor(cConstructorTypes); + object = (Remote) constructor.newInstance( + new Object[] { id, desc.getData() }); + + // Make the object accessible and create the stub. + ActivatableServerRef ref = UnicastServer.getActivatableRef(id); + Remote stub = ref.exportObject(object); + + MarshalledObject marsh = new MarshalledObject(stub); + + // Notify the activation monitor. + activeObject(id, marsh); + + // Make call to the hook that may be overridden. + activeObject(id, stub); + + return marsh; + } + catch (Exception e) + { + ActivationException acex = new ActivationException( + "Unable to activate "+ desc.getClassName() + + " from "+ desc.getLocation(), e); + throw acex; + } + } + +} diff --git a/gnu/java/rmi/activation/DefaultActivationSystem.java b/gnu/java/rmi/activation/DefaultActivationSystem.java new file mode 100644 index 000000000..75fb45160 --- /dev/null +++ b/gnu/java/rmi/activation/DefaultActivationSystem.java @@ -0,0 +1,57 @@ +/* DefaultActivationSystem.java -- Default RMI activation system + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.rmi.activation; + +import java.rmi.activation.ActivationSystem; +import java.rmi.activation.Activator; + +/** + * The default activation system for this jre. + * + * @author Audrius Meskauskas (audriusa@bioinformatics.org) + */ +public abstract class DefaultActivationSystem + implements ActivationSystem, Activator +{ + /** + * The singleton instance of the default activation system. + */ + public static final ActivationSystem singleton + = ActivationSystemTransient.getInstance(); +} diff --git a/gnu/java/rmi/server/ActivatableServerRef.java b/gnu/java/rmi/server/ActivatableServerRef.java new file mode 100644 index 000000000..6463f40d2 --- /dev/null +++ b/gnu/java/rmi/server/ActivatableServerRef.java @@ -0,0 +1,146 @@ +/* ActivatableServerRef.java -- The activatable server reference + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.rmi.server; + +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.activation.ActivationID; +import java.rmi.server.ObjID; +import java.rmi.server.RMIServerSocketFactory; + +/** + * The activatable server reference works like UnicastServerReference, but it + * additionally activates the associated object on demand, during the first + * incoming call. When UnicastServerReference takes the working reference, + * the ActivatableServerRef takes the activation id instead. + * + * @author Audrius Meskauskas (Audriusa@Bioinformatics.org) + */ +public class ActivatableServerRef extends UnicastServerRef +{ + /** + * Use SVUID for interoperability + */ + private static final long serialVersionUID = 1; + + /** + * The object activation id. + */ + public ActivationID actId; + + /** + * Used by serialization only + */ + public ActivatableServerRef() + { + super(); + } + + /** + * Create the new activatable server reference that will activate object on + * the first call using the given activation id. + */ + public ActivatableServerRef(ObjID id, ActivationID anId, int aPort, + RMIServerSocketFactory ssFactory) + throws RemoteException + { + super(id, aPort, ssFactory); + actId = anId; + + // The object ID will be placed in the object map and should deliver + // incoming call to {@link #incommingMessageCall}. The object itself + // is currently null. + UnicastServer.exportActivatableObject(this); + } + + /** + * Inactivate the object (stop the server). + */ + public void inactivate() + { + manager.stopServer(); + } + + /** + * Activate the object (normally during the first call). + */ + protected void activate() throws RemoteException + { + try + { + Remote self = actId.activate(false); + + // This will call UnicastServer.exportObject, replacing null by + // the activated object (self) in the object map. + exportObject(self); + } + catch (RemoteException rex) + { + throw rex; + } + catch (Exception exc) + { + RemoteException rx = new RemoteException("Activation failed."); + rx.initCause(exc); + throw rx; + } + } + + /** + * If the object is not active, activate it first. + */ + public Object incomingMessageCall(UnicastConnection conn, int method, + long hash) throws Exception + { + if (myself == null) + activate(); + return super.incomingMessageCall(conn, method, hash); + } + + /** + * Export object and ensure it is present in the server activation table + * as well. + */ + public Remote exportObject(Remote obj) throws RemoteException + { + Remote r = super.exportObject(obj); + UnicastServer.registerActivatable(this); + return r; + } +} diff --git a/gnu/java/rmi/server/CombinedClassLoader.java b/gnu/java/rmi/server/CombinedClassLoader.java index 0a2d3baff..efffda4c6 100644 --- a/gnu/java/rmi/server/CombinedClassLoader.java +++ b/gnu/java/rmi/server/CombinedClassLoader.java @@ -78,7 +78,7 @@ public class CombinedClassLoader extends ClassLoader { cl = iter.next(); if (!sLoaders.contains(cl)) - sLoaders.add(iter.next()); + sLoaders.add(cl); } loaders = new ClassLoader[sLoaders.size()]; diff --git a/gnu/java/rmi/server/UnicastServer.java b/gnu/java/rmi/server/UnicastServer.java index 94aafc5d1..3b06984aa 100644 --- a/gnu/java/rmi/server/UnicastServer.java +++ b/gnu/java/rmi/server/UnicastServer.java @@ -50,11 +50,14 @@ import java.rmi.NoSuchObjectException; import java.rmi.Remote; import java.rmi.RemoteException; import java.rmi.ServerError; +import java.rmi.activation.ActivationException; +import java.rmi.activation.ActivationID; import java.rmi.server.ObjID; import java.rmi.server.UID; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import java.util.WeakHashMap; @@ -72,9 +75,24 @@ public class UnicastServer * Mapping obj itself to server ref by identity. */ static private Map refcache = Collections.synchronizedMap(new WeakIdentityHashMap()); - + + /** + * Mapping the registered activatable objects into they server references. + */ + public static Map actIds = new Hashtable(); + + /** + * The reference to the local distributed garbage collector. + */ static private DGCImpl dgc; - + + /** + * Connect this server reference to the server, allowing the local + * implementation, associated with this object, to receive remote calls. + * + * @param obj the server reference, encloses the (usually local) remote + * object. + */ public static void exportObject(UnicastServerRef obj) { startDGC(); @@ -82,16 +100,83 @@ public class UnicastServer refcache.put(obj.myself, obj); obj.manager.startServer(); } - + + /** + * Register the activatable object into the table of the activatable + * objects. + */ + public static void registerActivatable(ActivatableServerRef ref) + { + actIds.put(ref.actId, ref); + } + + /** + * Export tha activatable object. The object id is placed into the map, + * but the object itself not. This is enough to deliver call to + * the ref.incomingMessageCall where the object will be instantiated, + * if not present. + */ + public static void exportActivatableObject(ActivatableServerRef ref) + { + startDGC(); + objects.put(ref.objid, ref); + ref.manager.startServer(); + actIds.put(ref.actId, ref); + } + + + /** + * Get the activatable server reference that is handling activation of the + * given activation id. + */ + public static ActivatableServerRef getActivatableRef(ActivationID id) + throws ActivationException + { + ActivatableServerRef ref = (ActivatableServerRef) actIds.get(id); + if (ref == null) + throw new ActivationException(id + " was not registered with this server"); + return ref; + } + + /** + * Unregister the previously registered activatable server reference. + */ + public static void unregisterActivatable(ActivationID id) + { + actIds.remove(id); + } + // FIX ME: I haven't handle force parameter + /** + * Remove the given server reference. The remote object, associated with + * this reference, will no longer receive remote calls via this server. + */ public static boolean unexportObject(UnicastServerRef obj, boolean force) { objects.remove(obj.objid); refcache.remove(obj.myself); obj.manager.stopServer(); + + if (obj instanceof ActivatableServerRef) + { + ActivationID id = ((ActivatableServerRef) obj).actId; + unregisterActivatable(id); + } return true; } - + + /** + * Get the exported reference of the given Remote. The identity map is used, + * the non-null value will only be returned if exactly the passed remote + * is part of the registered UnicastServerRef. + * + * @param remote the Remote that is connected to this server via + * {@link UnicastServerRef}. + * + * @return the UnicastServerRef that is used to connect the passed + * remote with this server or null, if this Remote is not connected + * to this server. + */ public static UnicastServerRef getExportedRef(Remote remote) { return (UnicastServerRef) refcache.get(remote); diff --git a/gnu/java/rmi/server/UnicastServerRef.java b/gnu/java/rmi/server/UnicastServerRef.java index dcb12a53b..577dae157 100644 --- a/gnu/java/rmi/server/UnicastServerRef.java +++ b/gnu/java/rmi/server/UnicastServerRef.java @@ -58,6 +58,10 @@ import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; +/** + * This class connects the local, remotely available (exported) object to + * the local RMI server that accepts the remote calls. + */ public class UnicastServerRef extends UnicastRef { @@ -125,8 +129,7 @@ public class UnicastServerRef { myself = obj; // Save it to server manager, to let client calls in the same VM to - // issue - // local call + // issue local call manager.serverobj = obj; String ignoreStubs; @@ -339,7 +342,11 @@ public class UnicastServerRef else return null; } - + + /** + * This method is called from the {@link UnicastServer#incomingMessageCall} + * to deliver the remote call to this object. + */ public Object incomingMessageCall(UnicastConnection conn, int method, long hash) throws Exception { |
