Imported GNU Classpath 0.90
Imported GNU Classpath 0.90
* scripts/makemake.tcl: LocaleData.java moved to gnu/java/locale.
* sources.am: Regenerated.
* gcj/javaprims.h: Regenerated.
* Makefile.in: Regenerated.
* gcj/Makefile.in: Regenerated.
* include/Makefile.in: Regenerated.
* testsuite/Makefile.in: Regenerated.
* gnu/java/lang/VMInstrumentationImpl.java: New override.
* gnu/java/net/local/LocalSocketImpl.java: Likewise.
* gnu/classpath/jdwp/VMMethod.java: Likewise.
* gnu/classpath/jdwp/VMVirtualMachine.java: Update to latest
interface.
* java/lang/Thread.java: Add UncaughtExceptionHandler.
* java/lang/reflect/Method.java: Implements GenericDeclaration and
isSynthetic(),
* java/lang/reflect/Field.java: Likewise.
* java/lang/reflect/Constructor.java
* java/lang/Class.java: Implements Type, GenericDeclaration,
getSimpleName() and getEnclosing*() methods.
* java/lang/Class.h: Add new public methods.
* java/lang/Math.java: Add signum(), ulp() and log10().
* java/lang/natMath.cc (log10): New function.
* java/security/VMSecureRandom.java: New override.
* java/util/logging/Logger.java: Updated to latest classpath
version.
* java/util/logging/LogManager.java: New override.
From-SVN: r113887
This commit is contained in:
@@ -0,0 +1,406 @@
|
||||
/* ActivationSystemTransient.java -- The transient RMI object 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.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.Activator;
|
||||
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, Activator
|
||||
{
|
||||
/**
|
||||
* Maps group identifiers into group descriptions.
|
||||
*/
|
||||
protected final BidiTable groupDescs;
|
||||
|
||||
/**
|
||||
* Maps object identifiers into object activation descriptions
|
||||
*/
|
||||
protected final BidiTable descriptions;
|
||||
|
||||
/**
|
||||
* Maps group identifiers into already activated groups.
|
||||
*/
|
||||
protected transient final Map groupInstantiators = new Hashtable();
|
||||
|
||||
/**
|
||||
* The cache of the activated objects, maps activation ids to remote
|
||||
* object stubs.
|
||||
*/
|
||||
protected transient final 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.
|
||||
*/
|
||||
public static boolean debug = false;
|
||||
|
||||
|
||||
/**
|
||||
* Creates the group which uses the given maps to store the data.
|
||||
*/
|
||||
protected ActivationSystemTransient(BidiTable objectDescriptions,
|
||||
BidiTable groupDescriptiopns)
|
||||
{
|
||||
descriptions = objectDescriptions;
|
||||
groupDescs = groupDescriptiopns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the group with transient maps.
|
||||
*/
|
||||
protected ActivationSystemTransient()
|
||||
{
|
||||
this (new BidiTable(), new BidiTable());
|
||||
}
|
||||
|
||||
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("Activating unknown object "+
|
||||
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("Activating 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("No desc for "+
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls .shutdown on all bidirectional tables (has no effect if these
|
||||
* table are not persistent).
|
||||
*/
|
||||
public void shutdown() throws RemoteException
|
||||
{
|
||||
descriptions.shutdown();
|
||||
groupDescs.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/* 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.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
protected Map k2v;
|
||||
|
||||
/**
|
||||
* Maps values to keys (in reverse)
|
||||
*/
|
||||
protected Map v2k;
|
||||
|
||||
/**
|
||||
* Create a new table that is ready to use.
|
||||
*/
|
||||
public BidiTable()
|
||||
{
|
||||
k2v = new HashMap();
|
||||
v2k = new HashMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance where the hashtable fields are not initialised
|
||||
* (called from derivatives that intialise hashtables in they own way.
|
||||
*
|
||||
* @param flags currently used to mark the different constructor only.
|
||||
*/
|
||||
protected BidiTable(int flags)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get key by value
|
||||
*/
|
||||
public synchronized Object getKey(Object value)
|
||||
{
|
||||
return v2k.get(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put key-value pair.
|
||||
*/
|
||||
public synchronized void put(Object key, Object value)
|
||||
{
|
||||
k2v.put(key, value);
|
||||
v2k.put(value, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value from key
|
||||
*/
|
||||
public synchronized Object get(Object key)
|
||||
{
|
||||
return k2v.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the key-value pair by key
|
||||
*/
|
||||
public synchronized 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 synchronized boolean containsKey(Object key)
|
||||
{
|
||||
return k2v.containsKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called before exit and may be used to write the database
|
||||
* to the disk. The default method does nothing.
|
||||
*/
|
||||
public synchronized void shutdown()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size.
|
||||
*/
|
||||
public synchronized int size()
|
||||
{
|
||||
return k2v.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key collection.
|
||||
*/
|
||||
public synchronized Object[] keys()
|
||||
{
|
||||
Collection keys = k2v.keySet();
|
||||
Object[] k = new Object[keys.size()];
|
||||
|
||||
Iterator iter = keys.iterator();
|
||||
for (int i = 0; i < k.length; i++)
|
||||
k[i] = iter.next();
|
||||
|
||||
return k;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
/* 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. The
|
||||
* activation always occurs in the current jre.
|
||||
*
|
||||
* @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
|
||||
{
|
||||
if (ActivationSystemTransient.debug)
|
||||
System.out.println("Instantiating "+desc.getClassName());
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/* 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.registry.LocateRegistry;
|
||||
import java.rmi.registry.Registry;
|
||||
|
||||
/**
|
||||
* Finds and returns the default activation system for this jre.
|
||||
*
|
||||
* @author Audrius Meskauskas (audriusa@bioinformatics.org)
|
||||
*/
|
||||
public abstract class DefaultActivationSystem
|
||||
{
|
||||
/**
|
||||
* The activation system (assigned if once found).
|
||||
*/
|
||||
static ActivationSystem system;
|
||||
|
||||
/**
|
||||
* The default activation registry port.
|
||||
*/
|
||||
static int ACTIVATION_REGISTRY_PORT;
|
||||
|
||||
/**
|
||||
* The name of the activation system registry port property.
|
||||
*/
|
||||
static String AS_PORT_PROPERTY = "java.rmi.activation.port";
|
||||
|
||||
/**
|
||||
* The defalut name of the activation system in the activation registry.
|
||||
*/
|
||||
static String ACTIVATION_SYSTEM_NAME = "java.rmi.activation.ActivationSystem";
|
||||
|
||||
/**
|
||||
* Get the activation system, default for this jre. If no external activation
|
||||
* system exists, the internal activation system will be activated. This
|
||||
* internal system is limited in capabilities and should be used exclusively
|
||||
* for automated testing, to avoid necessity of starting rmi daemon during
|
||||
* testing process.
|
||||
*/
|
||||
public static ActivationSystem get()
|
||||
{
|
||||
if (system == null)
|
||||
try
|
||||
{
|
||||
// Obtain the port:
|
||||
String asr = System.getProperty("java.rmi.activation.port");
|
||||
|
||||
if (asr != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
ACTIVATION_REGISTRY_PORT = Integer.parseInt(asr);
|
||||
if (ACTIVATION_REGISTRY_PORT <= 0)
|
||||
throw new InternalError("Invalid " + asr + " value, "
|
||||
+ ACTIVATION_REGISTRY_PORT);
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
throw new InternalError("Unable to parse " + asr
|
||||
+ " to integer");
|
||||
}
|
||||
}
|
||||
else
|
||||
ACTIVATION_REGISTRY_PORT = ActivationSystem.SYSTEM_PORT;
|
||||
|
||||
// Expect the naming service running first.
|
||||
// The local host may want to use the shared registry
|
||||
Registry r = LocateRegistry.getRegistry(ACTIVATION_REGISTRY_PORT);
|
||||
ActivationSystem system = (ActivationSystem) r.lookup(ACTIVATION_SYSTEM_NAME);
|
||||
return system;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
system = ActivationSystemTransient.getInstance();
|
||||
}
|
||||
|
||||
return system;
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ exception statement from your version. */
|
||||
|
||||
package gnu.java.rmi.dgc;
|
||||
|
||||
import gnu.java.rmi.server.UnicastServer;
|
||||
import gnu.java.rmi.server.UnicastServerRef;
|
||||
|
||||
import java.rmi.RemoteException;
|
||||
@@ -46,7 +47,8 @@ import java.rmi.dgc.Lease;
|
||||
import java.rmi.dgc.VMID;
|
||||
import java.rmi.server.ObjID;
|
||||
import java.rmi.server.RMISocketFactory;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Collection;
|
||||
import java.util.TimerTask;
|
||||
|
||||
/**
|
||||
* The DGC implementation is used for the server side during the distributed
|
||||
@@ -67,15 +69,68 @@ public class DGCImpl
|
||||
* UnicastRemoteObject must exportObject automatically.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Use the serial version UID for interoperability.
|
||||
*/
|
||||
private static final long serialVersionUID = 1;
|
||||
|
||||
/**
|
||||
* Protects the array of object Id's for the scheduled period of time
|
||||
* (lease). After the time expires, the protector is automatically discarded,
|
||||
* making the references unprotected and hence applicable for the garbage
|
||||
* collection.
|
||||
*/
|
||||
class RefProtector extends TimerTask
|
||||
{
|
||||
/**
|
||||
* The corresponding server references to protect. Each Id may contain
|
||||
* multiple references that are stored to collection.
|
||||
*/
|
||||
Collection[] references;
|
||||
|
||||
/**
|
||||
* Create the new instance of the reference protector that protects the
|
||||
* given array of ids and exists for the given period of time.
|
||||
*
|
||||
* @param ids the ids to protect.
|
||||
*/
|
||||
RefProtector(ObjID[] ids, long timeToLive)
|
||||
{
|
||||
references = new Collection[ids.length];
|
||||
for (int i = 0; i < ids.length; i++)
|
||||
{
|
||||
references[i] = UnicastServer.getExported(ids[i]);
|
||||
}
|
||||
|
||||
// Schedule the existence.
|
||||
LeaseRenewingTask.timer.schedule(this, timeToLive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Break all links, ensuring easy collection of the references by the gc.
|
||||
*/
|
||||
public void run()
|
||||
{
|
||||
for (int i = 0; i < references.length; i++)
|
||||
{
|
||||
references[i].clear();
|
||||
references[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This defauld lease value is used if the lease value, passed to the
|
||||
* {@link #dirty} is equal to zero.
|
||||
*/
|
||||
static final long LEASE_VALUE = 600000L;
|
||||
|
||||
// leaseCache caches a LeaseRecord associated with a vmid
|
||||
Hashtable leaseCache = new Hashtable();
|
||||
|
||||
|
||||
/**
|
||||
* Create the new DGC implementation.
|
||||
*
|
||||
* @throws RemoteException if the super constructor throws or the
|
||||
* socket factory fails.
|
||||
*/
|
||||
public DGCImpl() throws RemoteException
|
||||
{
|
||||
super(new ObjID(ObjID.DGC_ID), 0, RMISocketFactory.getSocketFactory());
|
||||
@@ -92,26 +147,20 @@ public class DGCImpl
|
||||
*/
|
||||
public Lease dirty(ObjID[] ids, long sequenceNum, Lease lease)
|
||||
throws RemoteException
|
||||
{
|
||||
VMID vmid = lease.getVMID();
|
||||
if (vmid == null)
|
||||
vmid = new VMID();
|
||||
|
||||
{
|
||||
// We do not fill in VMID because in this implementation it is not used.
|
||||
long leaseValue = lease.getValue();
|
||||
|
||||
// Grant the maximal default lease time if the passed value is zero.
|
||||
if (leaseValue <= 0)
|
||||
leaseValue = LEASE_VALUE;
|
||||
|
||||
lease = new Lease(vmid, leaseValue);
|
||||
LeaseRecord lr = (LeaseRecord) leaseCache.get(vmid);
|
||||
if (lr != null)
|
||||
lr.reset(leaseValue);
|
||||
else
|
||||
{
|
||||
lr = new LeaseRecord(vmid, leaseValue, ids);
|
||||
leaseCache.put(vmid, lr);
|
||||
}
|
||||
|
||||
return (lease);
|
||||
// Create (and shedule of the given existence) the new reference
|
||||
// protector.
|
||||
new RefProtector(ids, leaseValue);
|
||||
|
||||
lease = new Lease(lease.getVMID(), leaseValue);
|
||||
return lease;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,65 +179,4 @@ public class DGCImpl
|
||||
// TODO implement
|
||||
}
|
||||
|
||||
/**
|
||||
* LeaseRecord associates a vmid to expireTime.
|
||||
*/
|
||||
static class LeaseRecord
|
||||
{
|
||||
/**
|
||||
* The lease id.
|
||||
*/
|
||||
final VMID vmid;
|
||||
|
||||
/**
|
||||
* The lease expiration time.
|
||||
*/
|
||||
long expireTime;
|
||||
|
||||
/**
|
||||
* The array of ObjeID's that must be protected from being garbage
|
||||
* collected.
|
||||
*/
|
||||
final ObjID [] objects;
|
||||
|
||||
/**
|
||||
* Create the new lease record.
|
||||
*
|
||||
* @param vmid lease id.
|
||||
* @param leaseValue lease value
|
||||
*/
|
||||
LeaseRecord(VMID vmid, long leaseValue, ObjID [] an_objects)
|
||||
{
|
||||
this.vmid = vmid;
|
||||
reset(leaseValue);
|
||||
objects = an_objects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prolong the expiration time till current time + passed value
|
||||
*
|
||||
* @param leaseValue the value after that (since the current moment)
|
||||
* the lease should expire in the future.
|
||||
*/
|
||||
void reset(long leaseValue)
|
||||
{
|
||||
long l = System.currentTimeMillis();
|
||||
expireTime = l + leaseValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the lease has been expired.
|
||||
*
|
||||
* @return true if the lease has been expired, false if it is still valid.
|
||||
*/
|
||||
boolean isExpired()
|
||||
{
|
||||
long l = System.currentTimeMillis();
|
||||
if (l > expireTime)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // End of LeaseRecord
|
||||
|
||||
} // End of DGCImpl
|
||||
|
||||
@@ -0,0 +1,234 @@
|
||||
/* LeaseRenewingTask.java -- The task to renew the lease.
|
||||
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.dgc;
|
||||
|
||||
import gnu.java.rmi.server.UnicastRef;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.rmi.dgc.Lease;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
* The task to renew the lease to some object reference. The UnicastRef
|
||||
* being renewed is stored as a weak reference. So the presence of the
|
||||
* sheduled task does not prevent it from being garbage collected. If the
|
||||
* reference has not been garbage collected, the task is resheduled after
|
||||
* the lease is renewed.
|
||||
*
|
||||
* @author Audrius Meskauskas (Audriusa@Bioinformatics.org)
|
||||
*/
|
||||
public class LeaseRenewingTask
|
||||
{
|
||||
/**
|
||||
* The sheduled timer task to call the renew() method.
|
||||
*/
|
||||
class LeaseTimerTask extends TimerTask
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
renew();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The default requested lease duration time (one minute by default).
|
||||
*/
|
||||
public static long REQUEST_LEASE_DURATION = 60000;
|
||||
|
||||
/**
|
||||
* The reference to the UnicastRef that must renew its lease until not
|
||||
* garbage collected. The different members of this list may point to the
|
||||
* different instances of the UnicastRef's, but these references are
|
||||
* pointing to the same remote object (they .equals() returns
|
||||
* true when comparing with each other). Using LinkedList to make
|
||||
* frequent deletions from the middle easy.
|
||||
*/
|
||||
LinkedList ref = new LinkedList();
|
||||
|
||||
/**
|
||||
* The granted (or supposed) lease.
|
||||
*/
|
||||
Lease lease = new Lease(null, REQUEST_LEASE_DURATION);
|
||||
|
||||
/**
|
||||
* The timer, shared by all lease renewing tasks. The same instance is also
|
||||
* used for the reference protector discarding in DGCImpl.
|
||||
*/
|
||||
static Timer timer = new Timer(true);
|
||||
|
||||
/**
|
||||
* Maps the UnicastRef to its renewing task.
|
||||
*/
|
||||
static WeakHashMap existingTasks = new WeakHashMap();
|
||||
|
||||
/**
|
||||
* Creates the lease renewing task that renews the lease of the given
|
||||
* UnicastRef until it is not collected. This constructor requests the lease
|
||||
* value from the server and schedules the lease renewal action.
|
||||
*
|
||||
* @param renewIt the reference that must be renewed.
|
||||
*/
|
||||
public LeaseRenewingTask(UnicastRef renewIt)
|
||||
{
|
||||
lease = notifyDGC(renewIt);
|
||||
if (lease != null)
|
||||
{
|
||||
schedule(lease);
|
||||
ref.add(new WeakReference(renewIt));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule periodic leases for the given UnicastRef reference.
|
||||
*
|
||||
* @param renewIt the reference, for that the leases must be scheduled.
|
||||
*/
|
||||
public static void scheduleLeases(UnicastRef renewIt)
|
||||
{
|
||||
// No need to schedule leases for null.
|
||||
if (renewIt == null)
|
||||
return;
|
||||
try {
|
||||
synchronized (existingTasks)
|
||||
{
|
||||
// Check maybe the task for refreshing this remote object already
|
||||
// exists.
|
||||
LeaseRenewingTask task = (LeaseRenewingTask) existingTasks.get(renewIt);
|
||||
|
||||
if (task != null)
|
||||
{
|
||||
// Extend the reference list only. The scheduling must be
|
||||
// alredy done with the previous lease.
|
||||
synchronized (task.ref)
|
||||
{
|
||||
task.ref.add(new WeakReference(renewIt));
|
||||
}
|
||||
}
|
||||
else
|
||||
existingTasks.put(renewIt, new LeaseRenewingTask(renewIt));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
InternalError ierr = new InternalError("Lease for "+renewIt);
|
||||
ierr.initCause(ex);
|
||||
throw ierr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shedule the renewing call, taking into consideration that the following
|
||||
* lease was granted.
|
||||
*
|
||||
* @param lease the lease that was granted.
|
||||
*/
|
||||
public void schedule(Lease lease)
|
||||
{
|
||||
long value = lease.getValue();
|
||||
|
||||
// Shedule a 10 % earlier because some time is needed for the message
|
||||
// to reach the server.
|
||||
long reduced = (value * 90)/100;
|
||||
if (reduced == 0)
|
||||
reduced = value;
|
||||
|
||||
timer.schedule(new LeaseTimerTask(), reduced);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renew the lease.
|
||||
*/
|
||||
public void renew()
|
||||
{
|
||||
Object renewIt = null;
|
||||
// Iterate throw the list of associated references. If all are
|
||||
// discarded, there is no need to renew.
|
||||
synchronized (ref)
|
||||
{
|
||||
Iterator iter = ref.iterator();
|
||||
WeakReference w;
|
||||
while (iter.hasNext() && renewIt == null)
|
||||
{
|
||||
w = (WeakReference) iter.next();
|
||||
renewIt = w.get();
|
||||
if (renewIt == null)
|
||||
// Discard the weak reference if its target has been garbage
|
||||
// collected.
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
|
||||
if (renewIt!=null)
|
||||
{
|
||||
Lease lease = notifyDGC( (UnicastRef) renewIt);
|
||||
|
||||
// Schedule the next renewing session.
|
||||
if (lease!=null)
|
||||
schedule(lease);
|
||||
}
|
||||
{
|
||||
// All references collected - discard this entry.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify DGC that we still hold this reference.
|
||||
*
|
||||
* @param renewIt the reference we still have (must not be null).
|
||||
*/
|
||||
public Lease notifyDGC(UnicastRef renewIt)
|
||||
{
|
||||
try
|
||||
{
|
||||
return renewIt.notifyDGC(lease);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Failed to notify.
|
||||
// TODO Take some relevant action in the case if we failed
|
||||
// to notify the remote object owner.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
/* ActivatableRef.java -- 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.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.activation.ActivationException;
|
||||
import java.rmi.activation.ActivationID;
|
||||
import java.rmi.server.ObjID;
|
||||
import java.rmi.server.RMIClientSocketFactory;
|
||||
import java.rmi.server.RemoteObject;
|
||||
import java.rmi.server.RemoteObjectInvocationHandler;
|
||||
import java.rmi.server.RemoteRef;
|
||||
|
||||
/**
|
||||
* The activatable reference works like UnicastRef, but if the remote object
|
||||
* appears to be not accessible, it tries to reactivate it before reporting
|
||||
* any errors. Apart the fields of the UnicastRef, the activatable reference
|
||||
* contains the ActivationID that is used for this activation.
|
||||
*
|
||||
* @author Audrius Meskauskas (Audriusa@Bioinformatics.org)
|
||||
*/
|
||||
public class ActivatableRef extends UnicastRef
|
||||
{
|
||||
/**
|
||||
* Use serial version UID for iteroperability
|
||||
*/
|
||||
private static final long serialVersionUID = 1;
|
||||
|
||||
/**
|
||||
* The activation id.
|
||||
*/
|
||||
ActivationID actId;
|
||||
|
||||
/**
|
||||
* Delegate call to the superclass.
|
||||
*/
|
||||
public ActivatableRef()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate call to the superclass.
|
||||
*/
|
||||
public ActivatableRef(ObjID objid, String host, int port,
|
||||
RMIClientSocketFactory csf)
|
||||
{
|
||||
super(objid, host, port, csf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate call to the superclass.
|
||||
*/
|
||||
public ActivatableRef(ObjID objid)
|
||||
{
|
||||
super(objid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the referencing class.
|
||||
*/
|
||||
public String getRefClass(ObjectOutput out)
|
||||
{
|
||||
return "ActivatableRef";
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the content from the input stream.
|
||||
*/
|
||||
public void readExternal(ObjectInput in) throws IOException,
|
||||
ClassNotFoundException
|
||||
{
|
||||
super.readExternal(in);
|
||||
actId = (ActivationID) in.readObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the content to the output stream.
|
||||
*/
|
||||
public void writeExternal(ObjectOutput out) throws IOException
|
||||
{
|
||||
super.writeExternal(out);
|
||||
out.writeObject(actId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the remote method on the given object and try to activate the object
|
||||
* if it is not reacheable with the current manager.
|
||||
*/
|
||||
protected Object invokeCommon(Remote obj, Method method, Object[] params,
|
||||
int opnum, long hash) throws Exception
|
||||
{
|
||||
UnicastConnection conn;
|
||||
try
|
||||
{
|
||||
conn = manager.getConnection();
|
||||
}
|
||||
catch (IOException e1)
|
||||
{
|
||||
// Connection failed: try to activate.
|
||||
Remote reactivated = actId.activate(false);
|
||||
|
||||
if (reactivated instanceof RemoteObject)
|
||||
{
|
||||
RemoteRef ref = ((RemoteObject) reactivated).getRef();
|
||||
manager = ((UnicastRef) ref).manager;
|
||||
}
|
||||
else if (Proxy.isProxyClass(reactivated.getClass()))
|
||||
{
|
||||
RemoteObjectInvocationHandler hander =
|
||||
(RemoteObjectInvocationHandler)
|
||||
Proxy.getInvocationHandler(reactivated);
|
||||
|
||||
RemoteRef ref = hander.getRef();
|
||||
manager = ((UnicastRef) ref).manager;
|
||||
}
|
||||
else
|
||||
throw new ActivationException("Activating into unsupported class "
|
||||
+ reactivated.getClass());
|
||||
|
||||
try
|
||||
{
|
||||
conn = manager.getConnection();
|
||||
}
|
||||
catch (IOException e2)
|
||||
{
|
||||
throw new RemoteException("connection failed to host: "
|
||||
+ manager.serverName, e1);
|
||||
}
|
||||
}
|
||||
return invokeCommon(conn, obj, method, params, opnum, hash);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
/* 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.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.activation.ActivationID;
|
||||
import java.rmi.server.ObjID;
|
||||
import java.rmi.server.RMIServerSocketFactory;
|
||||
import java.rmi.server.RemoteStub;
|
||||
import java.rmi.server.Skeleton;
|
||||
|
||||
/**
|
||||
* 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.detail = 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export object and ensure it is present in the server activation table as
|
||||
* well.
|
||||
*
|
||||
* @param aClass the class being exported, must implement Remote.
|
||||
*/
|
||||
public Remote exportClass(Class aClass) throws RemoteException
|
||||
{
|
||||
if (!Remote.class.isAssignableFrom(aClass))
|
||||
throw new InternalError(aClass.getName()+" must implement Remote");
|
||||
|
||||
String ignoreStubs;
|
||||
|
||||
ClassLoader loader =aClass.getClassLoader();
|
||||
|
||||
// Stubs are always searched for the bootstrap classes that may have
|
||||
// obsolete pattern and may still need also skeletons.
|
||||
if (loader==null)
|
||||
ignoreStubs = "false";
|
||||
else
|
||||
ignoreStubs = System.getProperty("java.rmi.server.ignoreStubClasses",
|
||||
"false");
|
||||
|
||||
if (! ignoreStubs.equals("true"))
|
||||
{
|
||||
// Find and install the stub
|
||||
Class cls = aClass;
|
||||
|
||||
// where ist the _Stub? (check superclasses also)
|
||||
Class expCls = expCls = findStubSkelClass(cls);
|
||||
|
||||
if (expCls != null)
|
||||
{
|
||||
stub = (RemoteStub) getHelperClass(expCls, "_Stub");
|
||||
// Find and install the skeleton (if there is one)
|
||||
skel = (Skeleton) getHelperClass(expCls, "_Skel");
|
||||
}
|
||||
}
|
||||
|
||||
if (stub == null)
|
||||
stub = createProxyStub(aClass, this);
|
||||
|
||||
// Build hash of methods which may be called.
|
||||
buildMethodHash(aClass, true);
|
||||
|
||||
UnicastServer.registerActivatable(this);
|
||||
return stub;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the referencing class.
|
||||
*/
|
||||
public String getRefClass(ObjectOutput out)
|
||||
{
|
||||
return "ActivatableRef";
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the content from the input stream.
|
||||
*/
|
||||
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
|
||||
{
|
||||
super.readExternal(in);
|
||||
actId = (ActivationID) in.readObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the content to the output stream.
|
||||
*/
|
||||
public void writeExternal(ObjectOutput out) throws IOException
|
||||
{
|
||||
super.writeExternal(out);
|
||||
out.writeObject(actId);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -77,8 +77,8 @@ public class CombinedClassLoader extends ClassLoader
|
||||
while (iter.hasNext())
|
||||
{
|
||||
cl = iter.next();
|
||||
if (!sLoaders.contains(cl))
|
||||
sLoaders.add(iter.next());
|
||||
if (cl!=null && !sLoaders.contains(cl))
|
||||
sLoaders.add(cl);
|
||||
}
|
||||
|
||||
loaders = new ClassLoader[sLoaders.size()];
|
||||
@@ -96,7 +96,7 @@ public class CombinedClassLoader extends ClassLoader
|
||||
{
|
||||
try
|
||||
{
|
||||
return findClass(name);
|
||||
return loaders[i].loadClass(name);
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
@@ -106,20 +106,6 @@ public class CombinedClassLoader extends ClassLoader
|
||||
return super.findClass(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the library with the given name
|
||||
*/
|
||||
protected String findLibrary(String name)
|
||||
{
|
||||
for (int i = 0; i < loaders.length; i++)
|
||||
{
|
||||
String lib = findLibrary(name);
|
||||
if (lib != null)
|
||||
return lib;
|
||||
}
|
||||
return super.findLibrary(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find resource with the given name.
|
||||
*/
|
||||
@@ -127,7 +113,7 @@ public class CombinedClassLoader extends ClassLoader
|
||||
{
|
||||
for (int i = 0; i < loaders.length; i++)
|
||||
{
|
||||
URL resource = findResource(name);
|
||||
URL resource = loaders[i].getResource(name);
|
||||
if (resource != null)
|
||||
return resource;
|
||||
}
|
||||
@@ -141,7 +127,7 @@ public class CombinedClassLoader extends ClassLoader
|
||||
{
|
||||
for (int i = 0; i < loaders.length; i++)
|
||||
{
|
||||
Enumeration resource = findResources(name);
|
||||
Enumeration resource = loaders[i].getResources(name);
|
||||
if (resource != null)
|
||||
return resource;
|
||||
}
|
||||
|
||||
@@ -310,6 +310,14 @@ private UnicastConnection getClientConnection() throws IOException {
|
||||
return (conn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the string representation, describing the connection.
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
return serverName+":"+serverPort+" ("+serverobj+")";
|
||||
}
|
||||
|
||||
/**
|
||||
* Discard a connection when we're done with it - maybe it can be
|
||||
* recycled.
|
||||
@@ -443,4 +451,12 @@ public boolean equals(Object obj) {
|
||||
return (false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the string representation, describing the connection.
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
return host+":"+port+" ("+other+")";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* UnicastRef.java --
|
||||
Copyright (c) 1996, 1997, 1998, 1999, 2002, 2005
|
||||
Copyright (c) 1996, 1997, 1998, 1999, 2002, 2005, 2006
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
@@ -36,8 +36,11 @@ 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 gnu.java.rmi.dgc.LeaseRenewingTask;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -50,6 +53,7 @@ import java.lang.reflect.Method;
|
||||
import java.rmi.ConnectException;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.dgc.Lease;
|
||||
import java.rmi.server.ObjID;
|
||||
import java.rmi.server.Operation;
|
||||
import java.rmi.server.RMIClientSocketFactory;
|
||||
@@ -59,221 +63,462 @@ import java.rmi.server.RemoteRef;
|
||||
import java.rmi.server.UID;
|
||||
|
||||
public class UnicastRef
|
||||
implements RemoteRef, ProtocolConstants {
|
||||
implements RemoteRef, ProtocolConstants
|
||||
{
|
||||
|
||||
public ObjID objid;
|
||||
UnicastConnectionManager manager;
|
||||
/**
|
||||
* Use serial version UID for iteroperability
|
||||
*/
|
||||
private static final long serialVersionUID = 1;
|
||||
|
||||
/**
|
||||
* Used by serialization, and let subclass capable of having default constructor
|
||||
*/
|
||||
// must be public otherwise java.rmi.RemoteObject cannot instantiate this class
|
||||
// -- iP
|
||||
public UnicastRef() {
|
||||
}
|
||||
public ObjID objid;
|
||||
|
||||
public UnicastRef(ObjID objid, String host, int port, RMIClientSocketFactory csf) {
|
||||
this(objid);
|
||||
manager = UnicastConnectionManager.getInstance(host, port, csf);
|
||||
}
|
||||
UnicastConnectionManager manager;
|
||||
|
||||
public UnicastRef(ObjID objid) {
|
||||
this.objid = objid;
|
||||
}
|
||||
/**
|
||||
* Used by serialization, and let subclass capable of having default
|
||||
* constructor
|
||||
*/
|
||||
// must be public otherwise java.rmi.RemoteObject cannot instantiate this
|
||||
// class
|
||||
// -- iP
|
||||
public UnicastRef()
|
||||
{
|
||||
}
|
||||
|
||||
public Object invoke(Remote obj, Method method, Object[] params, long opnum) throws Exception {
|
||||
// Check if client and server are in the same VM, then local call can be used to
|
||||
public UnicastRef(ObjID objid, String host, int port,
|
||||
RMIClientSocketFactory csf)
|
||||
{
|
||||
this(objid);
|
||||
manager = UnicastConnectionManager.getInstance(host, port, csf);
|
||||
}
|
||||
|
||||
public UnicastRef(ObjID objid)
|
||||
{
|
||||
this.objid = objid;
|
||||
}
|
||||
|
||||
public Object invoke(Remote obj, Method method, Object[] params, long opnum)
|
||||
throws Exception
|
||||
{
|
||||
// Check if client and server are in the same VM, then local call can be
|
||||
// used to
|
||||
// replace remote call, but it's somewhat violating remote semantic.
|
||||
Object svrobj = manager.serverobj;
|
||||
|
||||
// Make sure that the server object is compatible. It could be loaded from a different
|
||||
|
||||
// Make sure that the server object is compatible. It could be loaded from a
|
||||
// different
|
||||
// classloader --iP
|
||||
if(svrobj != null && method.getDeclaringClass().isInstance(svrobj)){
|
||||
//local call
|
||||
Object ret = null;
|
||||
try{
|
||||
ret = method.invoke(svrobj, params);
|
||||
}catch(InvocationTargetException e){
|
||||
throw (Exception)e.getTargetException();
|
||||
}
|
||||
//System.out.println("\n\n ***** local call: " + method + "\nreturn: " + ret + "\n\n");
|
||||
return ret;
|
||||
}
|
||||
//System.out.println("***************** remote call:" + manager.serverPort);
|
||||
return (invokeCommon(obj, method, params, -1, opnum));
|
||||
}
|
||||
if (svrobj != null && method.getDeclaringClass().isInstance(svrobj))
|
||||
{
|
||||
// local call
|
||||
Object ret = null;
|
||||
try
|
||||
{
|
||||
ret = method.invoke(svrobj, params);
|
||||
}
|
||||
catch (InvocationTargetException e)
|
||||
{
|
||||
throw (Exception) e.getTargetException();
|
||||
}
|
||||
// System.out.println("\n\n ***** local call: " + method + "\nreturn: "
|
||||
// + ret + "\n\n");
|
||||
return ret;
|
||||
}
|
||||
// System.out.println("***************** remote call:" +
|
||||
// manager.serverPort);
|
||||
return (invokeCommon(obj, method, params, - 1, opnum));
|
||||
}
|
||||
|
||||
private Object invokeCommon(Remote obj, Method method, Object[] params, int opnum, long hash) throws Exception {
|
||||
UnicastConnection conn;
|
||||
try {
|
||||
conn = manager.getConnection();
|
||||
}
|
||||
catch (IOException e1) {
|
||||
throw new RemoteException("connection failed to host: " + manager.serverName, e1);
|
||||
}
|
||||
/**
|
||||
* The ordinary number of the DGC messages.
|
||||
*/
|
||||
static long dgcSequence;
|
||||
|
||||
ObjectOutputStream out;
|
||||
DataOutputStream dout;
|
||||
try {
|
||||
dout = conn.getDataOutputStream();
|
||||
dout.writeByte(MESSAGE_CALL);
|
||||
/**
|
||||
* The DGC object id, also serves as a synchronization target to increment the
|
||||
* dgcSequence safely.
|
||||
*/
|
||||
static final ObjID dgcId = new ObjID(ObjID.DGC_ID);
|
||||
|
||||
out = conn.startObjectOutputStream(); // (re)start ObjectOutputStream
|
||||
|
||||
objid.write(out);
|
||||
out.writeInt(opnum);
|
||||
out.writeLong(hash);
|
||||
|
||||
// must handle primitive class and their wrapper classes
|
||||
Class clss[] = method.getParameterTypes();
|
||||
for(int i = 0; i < clss.length; i++)
|
||||
((RMIObjectOutputStream)out).writeValue(params[i], clss[i]);
|
||||
ObjID[] this_id;
|
||||
|
||||
out.flush();
|
||||
}
|
||||
catch (IOException e2) {
|
||||
throw new RemoteException("call failed: ", e2);
|
||||
}
|
||||
/**
|
||||
* The number of the method "dirty" in the DGC.
|
||||
*/
|
||||
static int DIRTY = 1;
|
||||
|
||||
int returncode;
|
||||
Object returnval;
|
||||
DataInputStream din;
|
||||
ObjectInputStream in;
|
||||
UID ack;
|
||||
try {
|
||||
din = conn.getDataInputStream();
|
||||
|
||||
if ((returncode = din.readUnsignedByte()) != MESSAGE_CALL_ACK) {
|
||||
conn.disconnect();
|
||||
throw new RemoteException("Call not acked:" + returncode);
|
||||
}
|
||||
/**
|
||||
* The DGC interface hash code.
|
||||
*/
|
||||
static final long dgcInterfaceHash = - 669196253586618813L;
|
||||
|
||||
in = conn.startObjectInputStream(); // (re)start ObjectInputStream
|
||||
returncode = in.readUnsignedByte();
|
||||
ack = UID.read(in);
|
||||
/**
|
||||
* Notify the DGC of the remote side that we still hold this object.
|
||||
*/
|
||||
public Lease notifyDGC(Lease lease) throws Exception
|
||||
{
|
||||
long seq;
|
||||
synchronized (dgcId)
|
||||
{
|
||||
seq = dgcSequence++;
|
||||
}
|
||||
|
||||
Class cls = method.getReturnType();
|
||||
if (this_id == null)
|
||||
this_id = new ObjID[] { objid };
|
||||
|
||||
if (returncode == RETURN_NACK) {
|
||||
returnval = in.readObject(); // get Exception
|
||||
|
||||
} else if(cls == Void.TYPE) {
|
||||
returnval = null;
|
||||
// in.readObject() // not required! returntype 'void' means no field is returned.
|
||||
} else {
|
||||
returnval = ((RMIObjectInputStream)in).readValue(cls); // get returnvalue
|
||||
}
|
||||
} catch (IOException e3) {
|
||||
//for debug: e3.printStackTrace();
|
||||
throw new RemoteException("call return failed: ", e3);
|
||||
}
|
||||
|
||||
/* if DGCAck is necessary??
|
||||
//According to RMI wire protocol, send a DGCAck
|
||||
// to indicate receiving return value
|
||||
dout.writeByte(MESSAGE_DGCACK);
|
||||
ack.write(dout);
|
||||
out.flush();
|
||||
*/
|
||||
|
||||
manager.discardConnection(conn);
|
||||
|
||||
if (returncode != RETURN_ACK && returnval != null) {
|
||||
if (returncode == RETURN_NACK) throw (Exception)returnval;
|
||||
else throw new RemoteException("unexpected returncode: " + returncode);
|
||||
}
|
||||
|
||||
return (returnval);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public RemoteCall newCall(RemoteObject obj, Operation[] op, int opnum, long hash) throws RemoteException {
|
||||
UnicastConnection conn;
|
||||
|
||||
try {
|
||||
conn = manager.getConnection();
|
||||
}
|
||||
catch (IOException e1) {
|
||||
throw new ConnectException("connection failed to host: " + manager.serverName, e1);
|
||||
}
|
||||
try
|
||||
{
|
||||
conn = manager.getConnection();
|
||||
}
|
||||
catch (IOException e1)
|
||||
{
|
||||
throw new RemoteException("connection failed to host: "
|
||||
+ manager.serverName, e1);
|
||||
}
|
||||
|
||||
//obj: useless?
|
||||
ObjectOutputStream out;
|
||||
DataOutputStream dout;
|
||||
try
|
||||
{
|
||||
dout = conn.getDataOutputStream();
|
||||
dout.writeByte(MESSAGE_CALL);
|
||||
|
||||
return (new UnicastRemoteCall(conn, objid, opnum, hash));
|
||||
}
|
||||
out = conn.startObjectOutputStream(); // (re)start ObjectOutputStream
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public void invoke(RemoteCall call) throws Exception {
|
||||
UnicastRemoteCall c = (UnicastRemoteCall)call;
|
||||
call.executeCall();
|
||||
}
|
||||
dgcId.write(out);
|
||||
// The number of the operation is 1 ("dirty")
|
||||
out.writeInt(DIRTY);
|
||||
out.writeLong(dgcInterfaceHash);
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public void done(RemoteCall call) throws RemoteException {
|
||||
UnicastRemoteCall c = (UnicastRemoteCall)call;
|
||||
try{
|
||||
c.done();
|
||||
} catch(IOException e){}
|
||||
RMIObjectOutputStream rout = (RMIObjectOutputStream) out;
|
||||
|
||||
rout.writeValue(this_id, this_id.getClass());
|
||||
rout.writeLong(seq);
|
||||
rout.writeValue(lease, lease.getClass());
|
||||
|
||||
out.flush();
|
||||
}
|
||||
catch (IOException e2)
|
||||
{
|
||||
throw new RemoteException("DGC call failed: ", e2);
|
||||
}
|
||||
|
||||
int returncode;
|
||||
Object returnval;
|
||||
DataInputStream din;
|
||||
ObjectInputStream in;
|
||||
UID ack;
|
||||
try
|
||||
{
|
||||
din = conn.getDataInputStream();
|
||||
|
||||
if ((returncode = din.readUnsignedByte()) != MESSAGE_CALL_ACK)
|
||||
{
|
||||
conn.disconnect();
|
||||
throw new RemoteException("DGC Call not acked:" + returncode);
|
||||
}
|
||||
|
||||
in = conn.startObjectInputStream(); // (re)start ObjectInputStream
|
||||
returncode = in.readUnsignedByte();
|
||||
ack = UID.read(in);
|
||||
|
||||
if (returncode == RETURN_NACK)
|
||||
{
|
||||
returnval = in.readObject(); // get Exception
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
returnval = ((RMIObjectInputStream) in).readValue(Lease.class);
|
||||
}
|
||||
}
|
||||
catch (IOException e3)
|
||||
{
|
||||
throw new RemoteException("DGC call return failed: ", e3);
|
||||
}
|
||||
|
||||
manager.discardConnection(conn);
|
||||
|
||||
if (returncode != RETURN_ACK && returnval != null)
|
||||
{
|
||||
if (returncode == RETURN_NACK)
|
||||
throw (Exception) returnval;
|
||||
else
|
||||
throw new RemoteException("DGC unexpected returncode: " + returncode);
|
||||
}
|
||||
|
||||
return (Lease) returnval;
|
||||
}
|
||||
/**
|
||||
* Invoke the remote method on the given object. This part is overridden by
|
||||
* the activatable objects.
|
||||
*/
|
||||
protected Object invokeCommon(Remote obj, Method method, Object[] params,
|
||||
int opnum, long hash) throws Exception
|
||||
{
|
||||
UnicastConnection conn;
|
||||
try
|
||||
{
|
||||
conn = manager.getConnection();
|
||||
return invokeCommon(conn, obj, method, params, opnum, hash);
|
||||
}
|
||||
catch (IOException e1)
|
||||
{
|
||||
throw new RemoteException("connection failed to host: "
|
||||
+ manager.serverName, e1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the remote method on the given object when connection is already
|
||||
* established.
|
||||
*/
|
||||
protected Object invokeCommon(UnicastConnection conn, Remote obj,
|
||||
Method method, Object[] params, int opnum,
|
||||
long hash) throws Exception
|
||||
{
|
||||
ObjectOutputStream out;
|
||||
DataOutputStream dout;
|
||||
try
|
||||
{
|
||||
dout = conn.getDataOutputStream();
|
||||
dout.writeByte(MESSAGE_CALL);
|
||||
|
||||
out = conn.startObjectOutputStream(); // (re)start ObjectOutputStream
|
||||
|
||||
objid.write(out);
|
||||
out.writeInt(opnum);
|
||||
out.writeLong(hash);
|
||||
|
||||
// must handle primitive class and their wrapper classes
|
||||
Class clss[] = method.getParameterTypes();
|
||||
for (int i = 0; i < clss.length; i++)
|
||||
((RMIObjectOutputStream) out).writeValue(params[i], clss[i]);
|
||||
|
||||
out.flush();
|
||||
}
|
||||
catch (IOException e2)
|
||||
{
|
||||
throw new RemoteException("call failed: ", e2);
|
||||
}
|
||||
|
||||
int returncode;
|
||||
Object returnval;
|
||||
DataInputStream din;
|
||||
ObjectInputStream in;
|
||||
UID ack;
|
||||
try
|
||||
{
|
||||
din = conn.getDataInputStream();
|
||||
|
||||
if ((returncode = din.readUnsignedByte()) != MESSAGE_CALL_ACK)
|
||||
{
|
||||
conn.disconnect();
|
||||
throw new RemoteException("Call not acked:" + returncode);
|
||||
}
|
||||
|
||||
in = conn.startObjectInputStream(); // (re)start ObjectInputStream
|
||||
returncode = in.readUnsignedByte();
|
||||
ack = UID.read(in);
|
||||
|
||||
Class cls = method.getReturnType();
|
||||
|
||||
if (returncode == RETURN_NACK)
|
||||
{
|
||||
returnval = in.readObject(); // get Exception
|
||||
|
||||
}
|
||||
else if (cls == Void.TYPE)
|
||||
{
|
||||
returnval = null;
|
||||
// in.readObject() // not required! returntype 'void' means no field
|
||||
// is returned.
|
||||
}
|
||||
else
|
||||
{
|
||||
returnval = ((RMIObjectInputStream) in).readValue(cls); // get
|
||||
// returnvalue
|
||||
}
|
||||
}
|
||||
catch (IOException e3)
|
||||
{
|
||||
// for debug: e3.printStackTrace();
|
||||
throw new RemoteException("call return failed: ", e3);
|
||||
}
|
||||
|
||||
/*
|
||||
* if DGCAck is necessary?? //According to RMI wire protocol, send a DGCAck //
|
||||
* to indicate receiving return value dout.writeByte(MESSAGE_DGCACK);
|
||||
* ack.write(dout); out.flush();
|
||||
*/
|
||||
|
||||
manager.discardConnection(conn);
|
||||
|
||||
if (returncode != RETURN_ACK && returnval != null)
|
||||
{
|
||||
if (returncode == RETURN_NACK)
|
||||
throw (Exception) returnval;
|
||||
else
|
||||
throw new RemoteException("unexpected returncode: " + returncode);
|
||||
}
|
||||
|
||||
return (returnval);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public RemoteCall newCall(RemoteObject obj, Operation[] op, int opnum,
|
||||
long hash) throws RemoteException
|
||||
{
|
||||
UnicastConnection conn;
|
||||
|
||||
try
|
||||
{
|
||||
conn = manager.getConnection();
|
||||
}
|
||||
catch (IOException e1)
|
||||
{
|
||||
throw new ConnectException("connection failed to host: "
|
||||
+ manager.serverName, e1);
|
||||
}
|
||||
|
||||
// obj: useless?
|
||||
|
||||
return (new UnicastRemoteCall(conn, objid, opnum, hash));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public void invoke(RemoteCall call) throws Exception
|
||||
{
|
||||
UnicastRemoteCall c = (UnicastRemoteCall) call;
|
||||
call.executeCall();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public void done(RemoteCall call) throws RemoteException
|
||||
{
|
||||
UnicastRemoteCall c = (UnicastRemoteCall) call;
|
||||
try
|
||||
{
|
||||
c.done();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
}
|
||||
UnicastConnection conn = c.getConnection();
|
||||
manager.discardConnection(conn);
|
||||
}
|
||||
manager.discardConnection(conn);
|
||||
}
|
||||
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
if (manager == null) {
|
||||
throw new IOException("no connection");
|
||||
}
|
||||
manager.write(out);
|
||||
objid.write(out);
|
||||
// This byte is somewhat confusing when interoperating with JDK
|
||||
out.writeByte(0); //RETURN_ACK);
|
||||
}
|
||||
public void writeExternal(ObjectOutput out) throws IOException
|
||||
{
|
||||
if (manager == null)
|
||||
{
|
||||
throw new IOException("no connection");
|
||||
}
|
||||
manager.write(out);
|
||||
objid.write(out);
|
||||
// This byte is somewhat confusing when interoperating with JDK
|
||||
out.writeByte(0); // RETURN_ACK);
|
||||
}
|
||||
|
||||
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
|
||||
manager = UnicastConnectionManager.read(in);
|
||||
objid = ObjID.read(in);
|
||||
byte ack = in.readByte();
|
||||
// This byte is somewhat confusing when interoperating with JDK
|
||||
if (ack != RETURN_ACK && ack != 0/*jdk ack value*/) {
|
||||
throw new IOException("no ack found");
|
||||
}
|
||||
}
|
||||
public void readExternal(ObjectInput in) throws IOException,
|
||||
ClassNotFoundException
|
||||
{
|
||||
manager = UnicastConnectionManager.read(in);
|
||||
objid = ObjID.read(in);
|
||||
byte ack = in.readByte();
|
||||
// This byte is somewhat confusing when interoperating with JDK
|
||||
if (ack != RETURN_ACK && ack != 0/* jdk ack value */)
|
||||
{
|
||||
throw new IOException("no ack found");
|
||||
}
|
||||
|
||||
public boolean remoteEquals(RemoteRef ref) {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
// Notify the DGC of the remote side that we hold the reference to the
|
||||
// received object. Do not notify if the client and server are on the
|
||||
// same virtual machine.
|
||||
if (manager.serverobj == null)
|
||||
LeaseRenewingTask.scheduleLeases(this);
|
||||
}
|
||||
|
||||
public int remoteHashCode() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
public boolean remoteEquals(RemoteRef ref)
|
||||
{
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public String getRefClass(ObjectOutput out) {
|
||||
return ("UnicastRef");
|
||||
}
|
||||
public int remoteHashCode()
|
||||
{
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public String remoteToString() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
public String getRefClass(ObjectOutput out)
|
||||
{
|
||||
return ("UnicastRef");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the string representing the remote reference information.
|
||||
*/
|
||||
public String remoteToString()
|
||||
{
|
||||
if (manager!=null)
|
||||
return manager.toString();
|
||||
else
|
||||
return "null manager";
|
||||
}
|
||||
|
||||
public void dump(UnicastConnection conn) {
|
||||
try {
|
||||
DataInputStream din = conn.getDataInputStream();
|
||||
for (;;) {
|
||||
int b = din.readUnsignedByte();
|
||||
System.out.print(Integer.toHexString(b));
|
||||
if (b >= 32 && b < 128) {
|
||||
System.out.print(": " + (char)b);
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
catch (IOException _) {
|
||||
}
|
||||
}
|
||||
public void dump(UnicastConnection conn)
|
||||
{
|
||||
try
|
||||
{
|
||||
DataInputStream din = conn.getDataInputStream();
|
||||
for (;;)
|
||||
{
|
||||
int b = din.readUnsignedByte();
|
||||
System.out.print(Integer.toHexString(b));
|
||||
if (b >= 32 && b < 128)
|
||||
{
|
||||
System.out.print(": " + (char) b);
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
catch (IOException _)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this UnicastRef points to the object as the passed UnicastRef.
|
||||
* Both the object Id and manager must be the same.
|
||||
*
|
||||
* @return true if the passed reference points to the same remote object as
|
||||
* this reference, false otherwise.
|
||||
*/
|
||||
public boolean equals(Object other)
|
||||
{
|
||||
if (other instanceof UnicastRef)
|
||||
{
|
||||
UnicastRef r = (UnicastRef) other;
|
||||
return r.manager.equals(manager) && r.objid.equals(objid);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the hash code of this UnicastRef, combining hash code of the manager
|
||||
* with hash code of the object id.
|
||||
*/
|
||||
public int hashCode()
|
||||
{
|
||||
return manager.hashCode() ^ objid.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ exception statement from your version. */
|
||||
package gnu.java.rmi.server;
|
||||
|
||||
import gnu.java.rmi.dgc.DGCImpl;
|
||||
import gnu.java.util.WeakIdentityHashMap;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -49,122 +50,272 @@ 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.Map;
|
||||
import java.util.Hashtable;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
public class UnicastServer
|
||||
implements ProtocolConstants {
|
||||
implements ProtocolConstants
|
||||
{
|
||||
|
||||
static private Hashtable objects = new Hashtable(); //mapping OBJID to server ref
|
||||
static private Map refcache = Collections.synchronizedMap(new IdentityHashMap()); //mapping obj itself to server ref
|
||||
static private DGCImpl dgc;
|
||||
/**
|
||||
* Mapping OBJID to server ref by .equals().
|
||||
*/
|
||||
static private Map objects = Collections.synchronizedMap(new WeakHashMap());
|
||||
|
||||
public static void exportObject(UnicastServerRef obj) {
|
||||
startDGC();
|
||||
objects.put(obj.objid, obj);
|
||||
refcache.put(obj.myself, obj);
|
||||
obj.manager.startServer();
|
||||
}
|
||||
/**
|
||||
* 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();
|
||||
objects.put(obj.objid, obj);
|
||||
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);
|
||||
}
|
||||
|
||||
// FIX ME: I haven't handle force parameter
|
||||
public static boolean unexportObject(UnicastServerRef obj, boolean force) {
|
||||
objects.remove(obj.objid);
|
||||
refcache.remove(obj.myself);
|
||||
obj.manager.stopServer();
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Get the server references to the object, previously exported via this
|
||||
* server. As the identity map is scanned, more than one reference may match
|
||||
* this Id.
|
||||
*
|
||||
* @param id the id of the exported object
|
||||
* @return the server reference to this object, null if none.
|
||||
*/
|
||||
public static Collection getExported(Object id)
|
||||
{
|
||||
synchronized (objects)
|
||||
{
|
||||
ArrayList list = new ArrayList();
|
||||
Iterator iter = objects.entrySet().iterator();
|
||||
Map.Entry e;
|
||||
Object key;
|
||||
while (iter.hasNext())
|
||||
{
|
||||
e = (Map.Entry) iter.next();
|
||||
key = e.getKey();
|
||||
if (key != null && key.equals(id))
|
||||
list.add(e.getValue());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
public static UnicastServerRef getExportedRef(Remote remote){
|
||||
return (UnicastServerRef)refcache.get(remote);
|
||||
}
|
||||
private static synchronized void startDGC()
|
||||
{
|
||||
if (dgc == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
dgc = new DGCImpl();
|
||||
// Changed DGCImpl to inherit UnicastServerRef directly
|
||||
// ((UnicastServerRef)dgc.getRef()).exportObject(dgc);
|
||||
dgc.exportObject(dgc);
|
||||
}
|
||||
catch (RemoteException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static synchronized void startDGC() {
|
||||
if (dgc == null) {
|
||||
try {
|
||||
dgc = new DGCImpl();
|
||||
// Changed DGCImpl to inherit UnicastServerRef directly
|
||||
//((UnicastServerRef)dgc.getRef()).exportObject(dgc);
|
||||
dgc.exportObject(dgc);
|
||||
}
|
||||
catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void dispatch(UnicastConnection conn) throws Exception
|
||||
{
|
||||
switch (conn.getDataInputStream().readUnsignedByte())
|
||||
{
|
||||
case MESSAGE_CALL:
|
||||
incomingMessageCall(conn);
|
||||
break;
|
||||
case MESSAGE_PING:
|
||||
// jdk sends a ping before each method call -> answer it!
|
||||
DataOutputStream out = conn.getDataOutputStream();
|
||||
out.writeByte(MESSAGE_PING_ACK);
|
||||
out.flush();
|
||||
break;
|
||||
default:
|
||||
throw new Exception("bad method type");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is invoked when the remote call is received. The method
|
||||
* dispatches the call to the responsible object, connected to this
|
||||
* server via UnicastServerReference.
|
||||
*/
|
||||
private static void incomingMessageCall(UnicastConnection conn)
|
||||
throws IOException
|
||||
{
|
||||
ObjectInputStream in = conn.startObjectInputStream(); // (re)start
|
||||
// ObjectInputStream
|
||||
|
||||
public static void dispatch(UnicastConnection conn) throws Exception {
|
||||
switch (conn.getDataInputStream().readUnsignedByte()) {
|
||||
case MESSAGE_CALL:
|
||||
incomingMessageCall(conn);
|
||||
break;
|
||||
case MESSAGE_PING:
|
||||
// jdk sends a ping before each method call -> answer it!
|
||||
DataOutputStream out = conn.getDataOutputStream();
|
||||
out.writeByte(MESSAGE_PING_ACK);
|
||||
out.flush();
|
||||
break;
|
||||
default:
|
||||
throw new Exception("bad method type");
|
||||
}
|
||||
}
|
||||
ObjID objid = ObjID.read(in);
|
||||
int method = in.readInt();
|
||||
long hash = in.readLong();
|
||||
|
||||
private static void incomingMessageCall(UnicastConnection conn) throws IOException {
|
||||
ObjectInputStream in = conn.startObjectInputStream(); // (re)start ObjectInputStream
|
||||
// System.out.println("ObjID: " + objid + ", method: " + method + ", hash: "
|
||||
// + hash);
|
||||
|
||||
ObjID objid = ObjID.read(in);
|
||||
int method = in.readInt();
|
||||
long hash = in.readLong();
|
||||
// Use the objid to locate the relevant UnicastServerRef
|
||||
UnicastServerRef uref = (UnicastServerRef) objects.get(objid);
|
||||
Object returnval;
|
||||
int returncode = RETURN_ACK;
|
||||
// returnval is from Method.invoke(), so we must check the return class to
|
||||
// see
|
||||
// if it's primitive type
|
||||
Class returncls = null;
|
||||
if (uref != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Dispatch the call to it.
|
||||
returnval = uref.incomingMessageCall(conn, method, hash);
|
||||
returncls = uref.getMethodReturnType(method, hash);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
returnval = e;
|
||||
returncode = RETURN_NACK;
|
||||
}
|
||||
catch (Error e)
|
||||
{
|
||||
returnval = new ServerError(
|
||||
"Server error, ObjID: " + objid +
|
||||
", method: " + method + ", hash: "+ hash, e);
|
||||
returncode = RETURN_NACK;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
returnval = new NoSuchObjectException("ObjID: " + objid);
|
||||
returncode = RETURN_NACK;
|
||||
}
|
||||
|
||||
//System.out.println("ObjID: " + objid + ", method: " + method + ", hash: " + hash);
|
||||
conn.getDataOutputStream().writeByte(MESSAGE_CALL_ACK);
|
||||
|
||||
// Use the objid to locate the relevant UnicastServerRef
|
||||
UnicastServerRef uref = (UnicastServerRef)objects.get(objid);
|
||||
Object returnval;
|
||||
int returncode = RETURN_ACK;
|
||||
// returnval is from Method.invoke(), so we must check the return class to see
|
||||
// if it's primitive type
|
||||
Class returncls = null;
|
||||
if (uref != null) {
|
||||
try {
|
||||
// Dispatch the call to it.
|
||||
returnval = uref.incomingMessageCall(conn, method, hash);
|
||||
returncls = uref.getMethodReturnType(method, hash);
|
||||
}
|
||||
catch (Exception e) {
|
||||
returnval = e;
|
||||
returncode = RETURN_NACK;
|
||||
}
|
||||
catch (Error e) {
|
||||
returnval = new ServerError ("An Error is thrown while processing the invocation on the server", e);
|
||||
returncode = RETURN_NACK;
|
||||
}
|
||||
}
|
||||
else {
|
||||
returnval = new NoSuchObjectException("");
|
||||
returncode = RETURN_NACK;
|
||||
}
|
||||
ObjectOutputStream out = conn.startObjectOutputStream(); // (re)start
|
||||
// ObjectOutputStream
|
||||
|
||||
conn.getDataOutputStream().writeByte(MESSAGE_CALL_ACK);
|
||||
out.writeByte(returncode);
|
||||
(new UID()).write(out);
|
||||
|
||||
ObjectOutputStream out = conn.startObjectOutputStream(); // (re)start ObjectOutputStream
|
||||
// System.out.println("returnval=" + returnval + " returncls=" + returncls);
|
||||
|
||||
out.writeByte(returncode);
|
||||
(new UID()).write(out);
|
||||
if (returnval != null && returncls != null)
|
||||
((RMIObjectOutputStream) out).writeValue(returnval, returncls);
|
||||
|
||||
//System.out.println("returnval=" + returnval + " returncls=" + returncls);
|
||||
// 1.1/1.2 void return type detection:
|
||||
else if (! (returnval instanceof RMIVoidValue || returncls == Void.TYPE))
|
||||
out.writeObject(returnval);
|
||||
|
||||
if(returnval != null && returncls != null)
|
||||
((RMIObjectOutputStream)out).writeValue(returnval, returncls);
|
||||
|
||||
// 1.1/1.2 void return type detection:
|
||||
else if (!(returnval instanceof RMIVoidValue || returncls == Void.TYPE))
|
||||
out.writeObject(returnval);
|
||||
|
||||
out.flush();
|
||||
}
|
||||
out.flush();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
@@ -80,18 +84,18 @@ public class UnicastServerRef
|
||||
/**
|
||||
* The skeleton (if any), associated with the exported remote object.
|
||||
*/
|
||||
private Skeleton skel;
|
||||
protected Skeleton skel;
|
||||
|
||||
/**
|
||||
* The stub, associated with the exported remote object (may be proxy class).
|
||||
*/
|
||||
private Remote stub;
|
||||
protected Remote stub;
|
||||
|
||||
/**
|
||||
* The method table (RMI hash code to method) of the methods of the
|
||||
* exported object.
|
||||
*/
|
||||
private Hashtable methods = new Hashtable();
|
||||
protected Hashtable methods = new Hashtable();
|
||||
|
||||
/**
|
||||
* Used by serialization.
|
||||
@@ -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;
|
||||
@@ -202,7 +205,7 @@ public class UnicastServerRef
|
||||
*
|
||||
* @return the class having stub defined, null if none.
|
||||
*/
|
||||
private Class findStubSkelClass(Class startCls)
|
||||
protected Class findStubSkelClass(Class startCls)
|
||||
{
|
||||
Class cls = startCls;
|
||||
|
||||
@@ -242,7 +245,7 @@ public class UnicastServerRef
|
||||
* @return the instantiated instance of the helper class or null if the
|
||||
* helper class cannot be found or instantiated.
|
||||
*/
|
||||
private Object getHelperClass(Class cls, String type)
|
||||
protected Object getHelperClass(Class cls, String type)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -310,7 +313,7 @@ public class UnicastServerRef
|
||||
* @param build if true, the class methods are added to the table. If
|
||||
* false, they are removed from the table.
|
||||
*/
|
||||
private void buildMethodHash(Class cls, boolean build)
|
||||
protected void buildMethodHash(Class cls, boolean build)
|
||||
{
|
||||
Method[] meths = cls.getMethods();
|
||||
for (int i = 0; i < meths.length; i++)
|
||||
@@ -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
|
||||
{
|
||||
@@ -353,7 +360,8 @@ public class UnicastServerRef
|
||||
// meth);
|
||||
if (meth == null)
|
||||
{
|
||||
throw new NoSuchMethodException();
|
||||
throw new NoSuchMethodException(
|
||||
myself.getClass().getName()+" hash "+hash);
|
||||
}
|
||||
|
||||
ObjectInputStream in = conn.getObjectInputStream();
|
||||
@@ -413,9 +421,8 @@ public class UnicastServerRef
|
||||
else
|
||||
{
|
||||
if (skel == null)
|
||||
{
|
||||
throw new NoSuchMethodException();
|
||||
}
|
||||
throw new NoSuchMethodException("JDK 1.1 call - Skeleton required");
|
||||
|
||||
UnicastRemoteCall call = new UnicastRemoteCall(conn);
|
||||
skel.dispatch(myself, call, method, hash);
|
||||
if (! call.isReturnValue())
|
||||
|
||||
Reference in New Issue
Block a user