ObjectInputStream.java (resolveProxyClass): New method from Classpath.
* java/io/ObjectInputStream.java (resolveProxyClass): New method from Classpath. * Makefile.in: Rebuilt. * Makefile.am (rmi_java_source_files): Added new files. * gnu/java/rmi/RMIMarshalledObjectInputStream.java, gnu/java/rmi/RMIMarshalledObjectOutputStream.java, gnu/java/rmi/server/ConnectionRunnerPool.java: New files from Classpath. * gnu/java/rmi/dgc/DGCImpl.java, gnu/java/rmi/dgc/DGCImpl_Skel.java, gnu/java/rmi/dgc/DGCImpl_Stub.java, gnu/java/rmi/registry/RegistryImpl_Skel.java, gnu/java/rmi/registry/RegistryImpl_Stub.java, gnu/java/rmi/server/RMIHashes.java, gnu/java/rmi/server/RMIObjectInputStream.java, gnu/java/rmi/server/RMIObjectOutputStream.java, gnu/java/rmi/server/UnicastConnection.java, gnu/java/rmi/server/UnicastConnectionManager.java, gnu/java/rmi/server/UnicastRef.java, gnu/java/rmi/server/UnicastServer.java, gnu/java/rmi/server/UnicastServerRef.java, java/rmi/MarshalledObject.java, java/rmi/server/RMIClassLoader.java, java/rmi/server/RemoteObject.java, java/rmi/server/UnicastRemoteObject.java, java/security/SecureClassLoader.java: Merged from Classpath. From-SVN: r57675
This commit is contained in:
parent
e3e3815b7f
commit
d74732f5cd
28 changed files with 1175 additions and 156 deletions
154
libjava/gnu/java/rmi/server/ConnectionRunnerPool.java
Normal file
154
libjava/gnu/java/rmi/server/ConnectionRunnerPool.java
Normal file
|
@ -0,0 +1,154 @@
|
|||
/* gnu.java.rmi.server.ConnectionRunnerPool
|
||||
Copyright (C) 2002 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., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 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.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
//Should I generalize this class?
|
||||
|
||||
class ConnectionRunnerPool
|
||||
{
|
||||
|
||||
public static
|
||||
class ConnectionRunner extends Thread{
|
||||
private UnicastConnection conn;
|
||||
private volatile boolean exiting = false;
|
||||
|
||||
public ConnectionRunner(ThreadGroup group, String id){
|
||||
super(group, id);
|
||||
}
|
||||
|
||||
public synchronized void run(){
|
||||
while(!exiting){
|
||||
if(conn == null)
|
||||
try{
|
||||
wait();
|
||||
}catch(InterruptedException e){
|
||||
continue;
|
||||
}
|
||||
else{
|
||||
conn.run();
|
||||
conn = null;
|
||||
synchronized(ConnectionRunnerPool.class){
|
||||
freelist.add(this);
|
||||
if(freelist.size() == 1)
|
||||
ConnectionRunnerPool.class.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void dispatch(UnicastConnection conn){
|
||||
this.conn = conn;
|
||||
notify();
|
||||
}
|
||||
|
||||
void exit(){
|
||||
exiting = true;
|
||||
if(conn != null)
|
||||
try{
|
||||
join(500);
|
||||
}catch(InterruptedException e){}
|
||||
interrupt();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static int size = 5;
|
||||
private static int max_size = 10;
|
||||
|
||||
private static ArrayList freelist;
|
||||
|
||||
private static ThreadGroup group = new ThreadGroup("pool");
|
||||
|
||||
static {
|
||||
ConnectionRunner[] pools = new ConnectionRunner[size];
|
||||
for(int i = 0; i < pools.length; i++){
|
||||
pools[i] = new ConnectionRunner(group, new Integer(i).toString());
|
||||
pools[i].setContextClassLoader(Thread.currentThread().getContextClassLoader());
|
||||
pools[i].start();
|
||||
}
|
||||
freelist = new ArrayList(Arrays.asList(pools));
|
||||
}
|
||||
|
||||
public static void setSize(int size_){
|
||||
size = size_;
|
||||
}
|
||||
|
||||
public static void setMaxSize(int size){
|
||||
max_size = size;
|
||||
}
|
||||
|
||||
private synchronized static ConnectionRunner getConnectionRunner()
|
||||
{
|
||||
if(freelist.size() == 0){
|
||||
if(size < max_size){
|
||||
++size;
|
||||
ConnectionRunner a = new ConnectionRunner(group, new Integer(size).toString());
|
||||
a.start();
|
||||
freelist.add(a);
|
||||
}else
|
||||
while(freelist.size() == 0)
|
||||
try{
|
||||
ConnectionRunnerPool.class.wait();
|
||||
}catch(InterruptedException e){}
|
||||
}
|
||||
|
||||
// always let the first in pool most busy or other scheduling plan??
|
||||
ConnectionRunner a = (ConnectionRunner)freelist.get(0);
|
||||
freelist.remove(a);
|
||||
return a;
|
||||
}
|
||||
|
||||
public static void dispatchConnection(UnicastConnection conn)
|
||||
{
|
||||
ConnectionRunner r = getConnectionRunner();
|
||||
r.dispatch(conn);
|
||||
}
|
||||
|
||||
public static void exit()
|
||||
{
|
||||
Thread[] list = new Thread[group.activeCount()];
|
||||
group.enumerate(list);
|
||||
for(int i = 0; i < list.length; i++)
|
||||
((ConnectionRunner)list[i]).exit();
|
||||
}
|
||||
|
||||
}
|
|
@ -39,13 +39,56 @@ package gnu.java.rmi.server;
|
|||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.Class;
|
||||
import gnu.java.security.provider.SHA;
|
||||
import gnu.java.io.NullOutputStream;
|
||||
import gnu.java.lang.reflect.TypeSignature;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.DigestOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
public class RMIHashes
|
||||
{
|
||||
//There're other places using DigestOutputStream to generate hash in classpath, but I think the way I used
|
||||
//here is more efficient, anyway, you can switch to DigestOutputStream by doing like "//or:" comments say.
|
||||
|
||||
//or:add this statement: private static final NullOutputStream nullOutputStream = new NullOutputStream ();
|
||||
public static long getMethodHash(Method meth)
|
||||
{
|
||||
return meth.hashCode ();
|
||||
//Object Serialization Spec 8.3
|
||||
try
|
||||
{
|
||||
MessageDigest md = MessageDigest.getInstance ("SHA");
|
||||
//or:remove this statement: DigestOutputStream digest_out = new DigestOutputStream (nullOutputStream, md);
|
||||
ByteArrayOutputStream digest_out = new ByteArrayOutputStream();
|
||||
DataOutputStream data_out = new DataOutputStream (digest_out);
|
||||
|
||||
StringBuffer sbuf = new StringBuffer();
|
||||
sbuf.append(meth.getName());
|
||||
sbuf.append('(');
|
||||
Class params[] = meth.getParameterTypes();
|
||||
for(int i = 0; i < params.length; i++)
|
||||
sbuf.append(TypeSignature.getEncodingOfClass(params[i]));
|
||||
sbuf.append(')');
|
||||
Class rcls = meth.getReturnType();
|
||||
if(rcls != Void.TYPE)
|
||||
sbuf.append(TypeSignature.getEncodingOfClass(rcls));
|
||||
else
|
||||
sbuf.append('V');
|
||||
|
||||
data_out.writeUTF (sbuf.toString());
|
||||
data_out.flush();
|
||||
data_out.close ();
|
||||
|
||||
md.update(digest_out.toByteArray()); //or:remove this statement
|
||||
byte[] sha = md.digest ();
|
||||
long result = 0;
|
||||
int len = sha.length < 8 ? sha.length : 8;
|
||||
for (int i=0; i < len; i++)
|
||||
result += (long)(sha[i] & 0xFF) << (8 * i);
|
||||
return result;
|
||||
}catch(Exception _){
|
||||
return -1L;
|
||||
}
|
||||
}
|
||||
|
||||
public static long getInterfaceHash(Class clazz)
|
||||
|
@ -53,3 +96,4 @@ public class RMIHashes
|
|||
return clazz.hashCode ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,8 @@ import java.io.IOException;
|
|||
import java.net.URL;
|
||||
import java.net.MalformedURLException;
|
||||
import java.rmi.server.RMIClassLoader;
|
||||
import java.lang.ClassNotFoundException;
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
public class RMIObjectInputStream
|
||||
extends ObjectInputStream {
|
||||
|
@ -56,20 +58,80 @@ public RMIObjectInputStream(InputStream strm, UnicastConnectionManager man) thro
|
|||
enableResolveObject(true);
|
||||
}
|
||||
|
||||
public RMIObjectInputStream(InputStream strm) throws IOException {
|
||||
this(strm, UnicastConnectionManager.getInstance(0, null));
|
||||
}
|
||||
|
||||
protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
|
||||
//System.out.println("Resolving class: " + desc.getName());
|
||||
String annotation = (String)readObject();
|
||||
if (annotation == null) {
|
||||
return (super.resolveClass(desc));
|
||||
String annotation = (String)getAnnotation();
|
||||
try{
|
||||
return super.resolveClass(desc);
|
||||
}catch(ClassNotFoundException _){};
|
||||
|
||||
try {
|
||||
if(annotation == null)
|
||||
return (RMIClassLoader.loadClass(desc.getName()));
|
||||
else
|
||||
return (RMIClassLoader.loadClass(annotation, desc.getName()));
|
||||
}
|
||||
else {
|
||||
try {
|
||||
return (RMIClassLoader.loadClass(new URL(annotation), desc.getName()));
|
||||
}
|
||||
catch (MalformedURLException _) {
|
||||
throw new ClassNotFoundException(desc.getName());
|
||||
}
|
||||
catch (MalformedURLException _) {
|
||||
throw new ClassNotFoundException(desc.getName());
|
||||
}
|
||||
}
|
||||
|
||||
//Separate it for override by MarshalledObject
|
||||
protected Object getAnnotation()
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
return readObject();
|
||||
}
|
||||
|
||||
protected Class resolveProxyClass(String intfs[])
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
String annotation = (String)getAnnotation();
|
||||
try{
|
||||
return super.resolveProxyClass(intfs);
|
||||
}catch(ClassNotFoundException _){};
|
||||
|
||||
Class clss[] = new Class[intfs.length];
|
||||
if(annotation == null)
|
||||
clss[0] = RMIClassLoader.loadClass(intfs[0]);
|
||||
else
|
||||
clss[0] = RMIClassLoader.loadClass(annotation, intfs[0]);
|
||||
//assume all interfaces can be loaded by the same classloader
|
||||
ClassLoader loader = clss[0].getClassLoader();
|
||||
if(loader == null)
|
||||
for(int i = 1; i < intfs.length; i++)
|
||||
clss[i] = Class.forName(intfs[i]);
|
||||
else
|
||||
for(int i = 1; i < intfs.length; i++)
|
||||
clss[i] = loader.loadClass(intfs[i]);
|
||||
return Proxy.getProxyClass(loader, clss);
|
||||
}
|
||||
|
||||
protected Object readValue(Class valueClass) throws IOException, ClassNotFoundException {
|
||||
if(valueClass.isPrimitive()){
|
||||
if(valueClass == Boolean.TYPE)
|
||||
return new Boolean(readBoolean());
|
||||
if(valueClass == Byte.TYPE)
|
||||
return new Byte(readByte());
|
||||
if(valueClass == Character.TYPE)
|
||||
return new Character(readChar());
|
||||
if(valueClass == Short.TYPE)
|
||||
return new Short(readShort());
|
||||
if(valueClass == Integer.TYPE)
|
||||
return new Integer(readInt());
|
||||
if(valueClass == Long.TYPE)
|
||||
return new Long(readLong());
|
||||
if(valueClass == Float.TYPE)
|
||||
return new Float(readFloat());
|
||||
if(valueClass == Double.TYPE)
|
||||
return new Double(readDouble());
|
||||
else
|
||||
throw new Error("Unsupported primitive class: " + valueClass);
|
||||
} else
|
||||
return readObject();
|
||||
}
|
||||
|
||||
}
|
|
@ -41,17 +41,74 @@ import java.io.ObjectOutputStream;
|
|||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.rmi.server.RMIClassLoader;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.server.RemoteStub;
|
||||
import java.rmi.server.ObjID;
|
||||
|
||||
public class RMIObjectOutputStream
|
||||
extends ObjectOutputStream {
|
||||
|
||||
public RMIObjectOutputStream(OutputStream strm) throws IOException {
|
||||
super(strm);
|
||||
enableReplaceObject(true);
|
||||
}
|
||||
|
||||
//Separate it for override by MarshalledObject
|
||||
protected void setAnnotation(String annotation) throws IOException{
|
||||
writeObject(annotation);
|
||||
}
|
||||
|
||||
protected void annotateClass(Class cls) throws IOException {
|
||||
//System.out.println("Annotating class: " + cls);
|
||||
writeObject(RMIClassLoader.getClassAnnotation(cls));
|
||||
setAnnotation(RMIClassLoader.getClassAnnotation(cls));
|
||||
}
|
||||
|
||||
protected void annotateProxyClass(Class cls)
|
||||
throws IOException
|
||||
{
|
||||
annotateClass(cls);
|
||||
}
|
||||
|
||||
protected Object replaceObject(Object obj)
|
||||
throws IOException
|
||||
{
|
||||
if((obj instanceof Remote) && !(obj instanceof RemoteStub)){
|
||||
UnicastServerRef ref = new UnicastServerRef(new ObjID(), 0, null);
|
||||
try{
|
||||
return ref.exportObject((Remote)obj);
|
||||
}catch(Exception e){}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
protected void writeValue(Object value, Class valueClass) throws IOException{
|
||||
if(valueClass.isPrimitive()){
|
||||
if(valueClass == Boolean.TYPE)
|
||||
writeBoolean(((Boolean)value).booleanValue());
|
||||
else
|
||||
if(valueClass == Byte.TYPE)
|
||||
writeByte(((Byte)value).byteValue());
|
||||
else
|
||||
if(valueClass == Character.TYPE)
|
||||
writeChar(((Character)value).charValue());
|
||||
else
|
||||
if(valueClass == Short.TYPE)
|
||||
writeShort(((Short)value).shortValue());
|
||||
else
|
||||
if(valueClass == Integer.TYPE)
|
||||
writeInt(((Integer)value).intValue());
|
||||
else
|
||||
if(valueClass == Long.TYPE)
|
||||
writeLong(((Long)value).longValue());
|
||||
else
|
||||
if(valueClass == Float.TYPE)
|
||||
writeFloat(((Float)value).floatValue());
|
||||
else
|
||||
if(valueClass == Double.TYPE)
|
||||
writeDouble(((Double)value).doubleValue());
|
||||
else
|
||||
throw new Error("Unsupported primitive class: " + valueClass);
|
||||
} else
|
||||
writeObject(value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -44,6 +44,8 @@ import java.io.DataInputStream;
|
|||
import java.io.DataOutputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.ObjectOutput;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.IOException;
|
||||
|
@ -65,9 +67,10 @@ UnicastConnection(UnicastConnectionManager man, Socket sock) {
|
|||
}
|
||||
|
||||
void acceptConnection() throws IOException {
|
||||
//System.out.println("Accepting connection on " + lport);
|
||||
din = new DataInputStream(sock.getInputStream());
|
||||
dout = new DataOutputStream(sock.getOutputStream());
|
||||
//System.out.println("Accepting connection on " + sock);
|
||||
//Use BufferedXXXStream would be more efficient
|
||||
din = new DataInputStream(new BufferedInputStream(sock.getInputStream()));
|
||||
dout = new DataOutputStream(new BufferedOutputStream(sock.getOutputStream()));
|
||||
|
||||
int sig = din.readInt();
|
||||
if (sig != PROTOCOL_HEADER) {
|
||||
|
@ -85,6 +88,7 @@ void acceptConnection() throws IOException {
|
|||
// Send my hostname and port
|
||||
dout.writeUTF(manager.serverName);
|
||||
dout.writeInt(manager.serverPort);
|
||||
dout.flush();
|
||||
|
||||
// Read their hostname and port
|
||||
String rhost = din.readUTF();
|
||||
|
@ -94,15 +98,16 @@ void acceptConnection() throws IOException {
|
|||
}
|
||||
|
||||
void makeConnection(int protocol) throws IOException {
|
||||
dout = new DataOutputStream(sock.getOutputStream());
|
||||
din = new DataInputStream(sock.getInputStream());
|
||||
//Use BufferedXXXStream would be more efficient
|
||||
din = new DataInputStream(new BufferedInputStream(sock.getInputStream()));
|
||||
dout = new DataOutputStream(new BufferedOutputStream(sock.getOutputStream()));
|
||||
|
||||
// Send header
|
||||
dout.writeInt(PROTOCOL_HEADER);
|
||||
dout.writeShort(PROTOCOL_VERSION);
|
||||
dout.writeByte(protocol);
|
||||
dout.flush();
|
||||
|
||||
dout.flush();
|
||||
|
||||
if (protocol != SINGLE_OP_PROTOCOL) {
|
||||
// Get back ack.
|
||||
int ack = din.readUnsignedByte();
|
||||
|
@ -117,6 +122,7 @@ void makeConnection(int protocol) throws IOException {
|
|||
// Send them my endpoint
|
||||
dout.writeUTF(manager.serverName);
|
||||
dout.writeInt(manager.serverPort);
|
||||
dout.flush();
|
||||
}
|
||||
// Okay, ready to roll ...
|
||||
}
|
||||
|
@ -144,13 +150,15 @@ ObjectOutputStream getObjectOutputStream() throws IOException {
|
|||
}
|
||||
|
||||
void disconnect() {
|
||||
oin = null;
|
||||
oout = null;
|
||||
try {
|
||||
sock.close();
|
||||
if(oout != null)
|
||||
oout.close();
|
||||
}
|
||||
catch (IOException _) {
|
||||
}
|
||||
}
|
||||
|
||||
oin = null;
|
||||
oout = null;
|
||||
din = null;
|
||||
dout = null;
|
||||
sock = null;
|
||||
|
|
|
@ -57,9 +57,12 @@ public class UnicastConnectionManager
|
|||
implements Runnable, ProtocolConstants {
|
||||
|
||||
private static String localhost;
|
||||
// use different maps for server/client type UnicastConnectionManager
|
||||
private static Hashtable servers = new Hashtable();
|
||||
private static Hashtable clients = new Hashtable();
|
||||
|
||||
private Thread serverThread;
|
||||
// make serverThread volatile for poll
|
||||
private volatile Thread serverThread;
|
||||
private ServerSocket ssock;
|
||||
String serverName;
|
||||
int serverPort;
|
||||
|
@ -68,7 +71,9 @@ private RMIClientSocketFactory clientFactory;
|
|||
|
||||
static {
|
||||
try {
|
||||
localhost = InetAddress.getLocalHost().getHostName();
|
||||
//Use host address instead of host name to avoid name resolving issues
|
||||
//localhost = InetAddress.getLocalHost().getHostName();
|
||||
localhost = InetAddress.getLocalHost().getHostAddress();
|
||||
}
|
||||
catch (UnknownHostException _) {
|
||||
localhost = "localhost";
|
||||
|
@ -112,11 +117,16 @@ public static synchronized UnicastConnectionManager getInstance(String host, int
|
|||
if (csf == null) {
|
||||
csf = RMISocketFactory.getSocketFactory();
|
||||
}
|
||||
// change host name to host address to avoid name resolving issues
|
||||
try{
|
||||
host = InetAddress.getByName(host).getHostAddress();
|
||||
}catch(Exception _){}
|
||||
|
||||
TripleKey key = new TripleKey(host, port, csf);
|
||||
UnicastConnectionManager man = (UnicastConnectionManager)servers.get(key);
|
||||
UnicastConnectionManager man = (UnicastConnectionManager)clients.get(key);
|
||||
if (man == null) {
|
||||
man = new UnicastConnectionManager(host, port, csf);
|
||||
servers.put(key, man);
|
||||
clients.put(key, man);
|
||||
}
|
||||
return (man);
|
||||
}
|
||||
|
@ -198,18 +208,34 @@ public void startServer() {
|
|||
serverThread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop a server on this manager
|
||||
*/
|
||||
public void stopServer() {
|
||||
synchronized(this) {
|
||||
if(serverThread != null){
|
||||
serverThread = null;
|
||||
try{
|
||||
ssock.close();
|
||||
}catch(Exception _){}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Server thread for connection manager.
|
||||
*/
|
||||
public void run() {
|
||||
for (;;) {
|
||||
for (;serverThread != null;) { // if serverThread==null, then exit thread
|
||||
try {
|
||||
//System.out.println("Waiting for connection on " + serverPort);
|
||||
UnicastConnection conn = getServerConnection();
|
||||
(new Thread(conn)).start();
|
||||
// use a thread pool to improve performance
|
||||
// (new Thread(conn)).start();
|
||||
ConnectionRunnerPool.dispatchConnection(conn);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
// e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,6 +107,7 @@ private Object invokeCommon(Remote obj, Method method, Object[] params, int opnu
|
|||
objid.write(out);
|
||||
out.writeInt(opnum);
|
||||
out.writeLong(hash);
|
||||
/*
|
||||
if (params != null) {
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
if (params[i] instanceof UnicastRemoteObject) {
|
||||
|
@ -117,6 +118,11 @@ private Object invokeCommon(Remote obj, Method method, Object[] params, int opnu
|
|||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
// 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();
|
||||
}
|
||||
|
@ -139,12 +145,25 @@ private Object invokeCommon(Remote obj, Method method, Object[] params, int opnu
|
|||
|
||||
returncode = in.readUnsignedByte();
|
||||
ack = UID.read(in);
|
||||
returnval = in.readObject();
|
||||
//returnval = in.readObject();
|
||||
Class cls = method.getReturnType();
|
||||
if(cls == Void.TYPE){
|
||||
returnval = null;
|
||||
}else
|
||||
returnval = ((RMIObjectInputStream)in).readValue(cls);
|
||||
}
|
||||
catch (IOException e3) {
|
||||
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) {
|
||||
|
@ -183,13 +202,16 @@ public void writeExternal(ObjectOutput out) throws IOException {
|
|||
}
|
||||
manager.write(out);
|
||||
objid.write(out);
|
||||
out.writeByte(RETURN_ACK);
|
||||
// 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);
|
||||
if (in.readByte() != RETURN_ACK) {
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,6 +65,13 @@ public static void exportObject(UnicastServerRef obj) {
|
|||
obj.manager.startServer();
|
||||
}
|
||||
|
||||
// FIX ME: I haven't handle force parameter
|
||||
public static boolean unexportObject(UnicastServerRef obj, boolean force) {
|
||||
objects.remove(obj.objid);
|
||||
obj.manager.stopServer();
|
||||
return true;
|
||||
}
|
||||
|
||||
private static synchronized void startDGC() {
|
||||
if (dgc == null) {
|
||||
try {
|
||||
|
@ -100,10 +107,14 @@ private static void incomingMessageCall(UnicastConnection conn) throws IOExcepti
|
|||
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;
|
||||
|
@ -121,7 +132,10 @@ private static void incomingMessageCall(UnicastConnection conn) throws IOExcepti
|
|||
|
||||
out.writeByte(returncode);
|
||||
(new UID()).write(out);
|
||||
out.writeObject(returnval);
|
||||
if(returnval != null && returncls != null)
|
||||
((RMIObjectOutputStream)out).writeValue(returnval, returncls);
|
||||
else
|
||||
out.writeObject(returnval);
|
||||
|
||||
out.flush();
|
||||
}
|
||||
|
|
|
@ -66,14 +66,15 @@ import java.io.ObjectOutputStream;
|
|||
import java.util.Hashtable;
|
||||
|
||||
public class UnicastServerRef
|
||||
extends UnicastRef {
|
||||
extends UnicastRef
|
||||
implements ServerRef{ //SHOULD implement ServerRef
|
||||
|
||||
final static private Class[] stubprototype = new Class[] { RemoteRef.class };
|
||||
|
||||
Remote myself;
|
||||
private Skeleton skel;
|
||||
private RemoteStub stub;
|
||||
private Hashtable methods;
|
||||
private Hashtable methods = new Hashtable();
|
||||
|
||||
public UnicastServerRef(ObjID id, int port, RMIServerSocketFactory ssf) {
|
||||
super(id);
|
||||
|
@ -95,7 +96,7 @@ public RemoteStub exportObject(Remote obj) throws RemoteException {
|
|||
skel = (Skeleton)getHelperClass(cls, "_Skel");
|
||||
|
||||
// Build hash of methods which may be called.
|
||||
buildMethodHash(obj.getClass());
|
||||
buildMethodHash(obj.getClass(), true);
|
||||
|
||||
// Export it.
|
||||
UnicastServer.exportObject(this);
|
||||
|
@ -104,10 +105,25 @@ public RemoteStub exportObject(Remote obj) throws RemoteException {
|
|||
return (stub);
|
||||
}
|
||||
|
||||
public RemoteStub exportObject(Remote remote, Object obj)
|
||||
throws RemoteException
|
||||
{
|
||||
//FIX ME
|
||||
return exportObject(remote);
|
||||
}
|
||||
|
||||
|
||||
public boolean unexportObject(Remote obj, boolean force) throws RemoteException {
|
||||
// Remove all hashes of methods which may be called.
|
||||
buildMethodHash(obj.getClass(), false);
|
||||
return UnicastServer.unexportObject(this, force);
|
||||
}
|
||||
|
||||
private Object getHelperClass(Class cls, String type) {
|
||||
try {
|
||||
String classname = cls.getName();
|
||||
Class scls = Class.forName(classname + type);
|
||||
String classname = cls.getName();
|
||||
ClassLoader cl = cls.getClassLoader(); //DONT use "Class scls = Class.forName(classname + type);"
|
||||
Class scls = cl.loadClass(classname + type);
|
||||
if (type.equals("_Stub")) {
|
||||
try {
|
||||
// JDK 1.2 stubs
|
||||
|
@ -147,8 +163,7 @@ public String getClientHost() throws ServerNotActiveException {
|
|||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
private void buildMethodHash(Class cls) {
|
||||
methods = new Hashtable();
|
||||
private void buildMethodHash(Class cls, boolean build) {
|
||||
Method[] meths = cls.getMethods();
|
||||
for (int i = 0; i < meths.length; i++) {
|
||||
/* Don't need to include any java.xxx related stuff */
|
||||
|
@ -156,11 +171,23 @@ private void buildMethodHash(Class cls) {
|
|||
continue;
|
||||
}
|
||||
long hash = RMIHashes.getMethodHash(meths[i]);
|
||||
methods.put(new Long (hash), meths[i]);
|
||||
if(build)
|
||||
methods.put(new Long (hash), meths[i]);
|
||||
else
|
||||
methods.remove(new Long (hash));
|
||||
//System.out.println("meth = " + meths[i] + ", hash = " + hash);
|
||||
}
|
||||
}
|
||||
|
||||
Class getMethodReturnType(int method, long hash) throws Exception
|
||||
{
|
||||
if (method == -1) {
|
||||
Method meth = (Method)methods.get(new Long (hash));
|
||||
return meth.getReturnType();
|
||||
}else
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object incomingMessageCall(UnicastConnection conn, int method, long hash) throws Exception {
|
||||
//System.out.println("method = " + method + ", hash = " + hash);
|
||||
// If method is -1 then this is JDK 1.2 RMI - so use the hash
|
||||
|
@ -189,7 +216,15 @@ public Object incomingMessageCall(UnicastConnection conn, int method, long hash)
|
|||
throw t;
|
||||
}
|
||||
}
|
||||
return (meth.invoke(myself, args));
|
||||
//We must reinterpret the exception thrown by meth.invoke()
|
||||
//return (meth.invoke(myself, args));
|
||||
Object ret = null;
|
||||
try{
|
||||
ret = meth.invoke(myself, args);
|
||||
}catch(InvocationTargetException e){
|
||||
throw (Exception)(e.getTargetException());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
// Otherwise this is JDK 1.1 style RMI - we find the skeleton
|
||||
// and invoke it using the method number. We wrap up our
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue