1 /* UnicastServerRef.java --
2 Copyright (c) 1996, 1997, 1998, 1999, 2002, 2003, 2004, 2006
3 Free Software Foundation, Inc.
5 This file is part of GNU Classpath.
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING. If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library. Thus, the terms and
24 conditions of the GNU General Public License cover the whole
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module. An independent module is a module which is not derived from
34 or based on this library. If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so. If you do not wish to do so, delete this
37 exception statement from your version. */
40 package gnu
.java
.rmi
.server
;
42 import java
.io
.ObjectInputStream
;
43 import java
.lang
.reflect
.Constructor
;
44 import java
.lang
.reflect
.InvocationTargetException
;
45 import java
.lang
.reflect
.Method
;
46 import java
.lang
.reflect
.Proxy
;
47 import java
.rmi
.Remote
;
48 import java
.rmi
.RemoteException
;
49 import java
.rmi
.server
.ObjID
;
50 import java
.rmi
.server
.RMIServerSocketFactory
;
51 import java
.rmi
.server
.RemoteObjectInvocationHandler
;
52 import java
.rmi
.server
.RemoteRef
;
53 import java
.rmi
.server
.RemoteServer
;
54 import java
.rmi
.server
.RemoteStub
;
55 import java
.rmi
.server
.ServerNotActiveException
;
56 import java
.rmi
.server
.Skeleton
;
57 import java
.util
.HashSet
;
58 import java
.util
.Hashtable
;
59 import java
.util
.Iterator
;
62 * This class connects the local, remotely available (exported) object to
63 * the local RMI server that accepts the remote calls.
65 public class UnicastServerRef
70 * Use GNU Classpath v 0.20 SVUID for interoperability
72 private static final long serialVersionUID
= - 5585608108300801246L;
75 * The class array, defining parameters of the jdk 1.2 RMI stub constructor.
77 private static final Class
[] stubprototype
= new Class
[] { RemoteRef
.class };
80 * The exported remote object itself.
82 Remote myself
; // save the remote object itself
85 * The skeleton (if any), associated with the exported remote object.
87 protected Skeleton skel
;
90 * The stub, associated with the exported remote object (may be proxy class).
92 protected Remote stub
;
95 * The method table (RMI hash code to method) of the methods of the
98 protected Hashtable methods
= new Hashtable();
101 * Used by serialization.
107 public UnicastServerRef(ObjID id
, int port
, RMIServerSocketFactory ssf
)
108 throws RemoteException
111 manager
= UnicastConnectionManager
.getInstance(port
, ssf
);
115 * Export the object and return its remote stub. The method tries to locate
116 * existing stubs and skeletons. If this fails, the method instantiates the
119 * Stubs and skeletons are always ignored (even if present) if the
120 * java.rmi.server.ignoreStubClasses property is set to true.
122 * @param obj the object being exported.
123 * @return the stub (existing class or proxy) of the exported object.
124 * @throws RemoteException if the export failed due any reason
126 public Remote
exportObject(Remote obj
) throws RemoteException
131 // Save it to server manager, to let client calls in the same VM to
133 manager
.serverobj
= obj
;
137 ClassLoader loader
=obj
.getClass().getClassLoader();
139 // Stubs are always searched for the bootstrap classes that may have
140 // obsolete pattern and may still need also skeletons.
142 ignoreStubs
= "false";
144 ignoreStubs
= System
.getProperty("java.rmi.server.ignoreStubClasses",
147 if (! ignoreStubs
.equals("true"))
149 // Find and install the stub
150 Class cls
= obj
.getClass();
152 // where ist the _Stub? (check superclasses also)
153 Class expCls
= expCls
= findStubSkelClass(cls
);
157 stub
= (RemoteStub
) getHelperClass(expCls
, "_Stub");
158 // Find and install the skeleton (if there is one)
159 skel
= (Skeleton
) getHelperClass(expCls
, "_Skel");
164 stub
= createProxyStub(obj
.getClass(), this);
166 // Build hash of methods which may be called.
167 buildMethodHash(obj
.getClass(), true);
170 UnicastServer
.exportObject(this);
177 * Get the stub (actual class or proxy) of the exported remote object.
179 * @return the remote stub (null if exportObject has not been called).
181 public Remote
getStub()
187 * Unexport the object (remove methods from the method hashcode table
188 * and call UnicastServer.unexportObject.
190 * @param obj the object being unexported
191 * @param force passed to the UnicastServer.unexportObject.
192 * @return value, returned by the UnicastServer.unexportObject.
194 public boolean unexportObject(Remote obj
, boolean force
)
196 // Remove all hashes of methods which may be called.
197 buildMethodHash(obj
.getClass(), false);
198 return UnicastServer
.unexportObject(this, force
);
202 * Return the class in the hierarchy for that the stub class is defined.
203 * The Subs/Skels might not there for the actual class, but maybe for one of
206 * @return the class having stub defined, null if none.
208 protected Class
findStubSkelClass(Class startCls
)
210 Class cls
= startCls
;
216 String stubClassname
= cls
.getName() + "_Stub";
217 ClassLoader cl
= cls
.getClassLoader();
218 Class scls
= cl
== null ? Class
.forName(stubClassname
)
219 : cl
.loadClass(stubClassname
);
220 return cls
; // found it
222 catch (ClassNotFoundException e
)
224 Class superCls
= cls
.getSuperclass();
226 || superCls
== java
.rmi
.server
.UnicastRemoteObject
.class)
236 * Get the helper (assisting) class with the given type.
238 * @param cls the class, for that the helper class is requested. This class
239 * and the requested helper class must share the same class loader.
241 * @param type the type of the assisting helper. The only currently supported
242 * non deprecated value is "_Stub" (load jdk 1.1 or 1.2 RMI stub). Another
243 * (deprecated) value is "_Skel" (load skeleton).
245 * @return the instantiated instance of the helper class or null if the
246 * helper class cannot be found or instantiated.
248 protected Object
getHelperClass(Class cls
, String type
)
252 String classname
= cls
.getName();
253 ClassLoader cl
= cls
.getClassLoader();
254 Class scls
= cl
== null ? Class
.forName(classname
+ type
)
255 : cl
.loadClass(classname
+ type
);
256 if (type
.equals("_Stub"))
261 Constructor con
= scls
.getConstructor(stubprototype
);
262 return (con
.newInstance(new Object
[] { this }));
264 catch (NoSuchMethodException e
)
267 catch (InstantiationException e
)
270 catch (IllegalAccessException e
)
273 catch (IllegalArgumentException e
)
276 catch (InvocationTargetException e
)
280 RemoteStub stub
= (RemoteStub
) scls
.newInstance();
281 UnicastRemoteStub
.setStubRef(stub
, this);
287 return (scls
.newInstance());
290 catch (ClassNotFoundException e
)
293 catch (InstantiationException e
)
296 catch (IllegalAccessException e
)
302 public String
getClientHost() throws ServerNotActiveException
304 return RemoteServer
.getClientHost();
308 * Build the method has code table and put it into {@link #methods}
309 * (mapping RMI hashcode tos method). The same method is used to remove
312 * @param cls the class for that the method table is built.
313 * @param build if true, the class methods are added to the table. If
314 * false, they are removed from the table.
316 protected void buildMethodHash(Class cls
, boolean build
)
318 Method
[] meths
= cls
.getMethods();
319 for (int i
= 0; i
< meths
.length
; i
++)
321 /* Don't need to include any java.xxx related stuff */
322 if (meths
[i
].getDeclaringClass().getName().startsWith("java."))
326 long hash
= RMIHashes
.getMethodHash(meths
[i
]);
328 methods
.put(new Long(hash
), meths
[i
]);
330 methods
.remove(new Long(hash
));
331 // System.out.println("meth = " + meths[i] + ", hash = " + hash);
335 Class
getMethodReturnType(int method
, long hash
) throws Exception
339 Method meth
= (Method
) methods
.get(new Long(hash
));
340 return meth
.getReturnType();
347 * This method is called from the {@link UnicastServer#incomingMessageCall}
348 * to deliver the remote call to this object.
350 public Object
incomingMessageCall(UnicastConnection conn
, int method
,
351 long hash
) throws Exception
353 // System.out.println("method = " + method + ", hash = " + hash);
354 // If method is -1 then this is JDK 1.2 RMI - so use the hash
355 // to locate the method
358 Method meth
= (Method
) methods
.get(new Long(hash
));
359 // System.out.println("class = " + myself.getClass() + ", meth = " +
363 throw new NoSuchMethodException(
364 myself
.getClass().getName()+" hash "+hash
);
367 ObjectInputStream in
= conn
.getObjectInputStream();
368 int nrargs
= meth
.getParameterTypes().length
;
369 Object
[] args
= new Object
[nrargs
];
370 for (int i
= 0; i
< nrargs
; i
++)
373 * For debugging purposes - we don't handle CodeBases quite right so
374 * we don't always find the stubs. This lets us know that.
378 // need to handle primitive types
379 args
[i
] = ((RMIObjectInputStream
) in
)
380 .readValue(meth
.getParameterTypes()[i
]);
389 //We must reinterpret the exception thrown by meth.invoke()
390 //return (meth.invoke(myself, args));
394 ret
= meth
.invoke(myself
, args
);
396 catch (InvocationTargetException e
)
398 Throwable cause
= e
.getTargetException();
399 if (cause
instanceof Exception
)
401 throw (Exception
) cause
;
403 else if (cause
instanceof Error
)
410 "The remote method threw a java.lang.Throwable that"+
411 " is neither java.lang.Exception nor java.lang.Error.",
417 // Otherwise this is JDK 1.1 style RMI - we find the skeleton
418 // and invoke it using the method number. We wrap up our
419 // connection system in a UnicastRemoteCall so it appears in a
420 // way the Skeleton can handle.
424 throw new NoSuchMethodException("JDK 1.1 call - Skeleton required");
426 UnicastRemoteCall call
= new UnicastRemoteCall(conn
);
427 skel
.dispatch(myself
, call
, method
, hash
);
428 if (! call
.isReturnValue())
429 return RMIVoidValue
.INSTANCE
;
431 return (call
.returnValue());
436 * Create the 1.2 proxy stub in the case when the pre-generated stub is not
437 * available of the system is explicitly instructed to use proxy stubs.
439 * @param stubFor the class for that the proxy class must be constructed.
440 * @param reference the remote reference, used to find the given object
442 * @return the applicable proxy stub.
444 * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
446 Remote
createProxyStub(Class stubFor
, RemoteRef reference
)
448 // Collect all interfaces, implemented by stubFor and derived from
449 // Remote (also Remote itself):
450 HashSet interfaces
= new HashSet();
456 intfs
= c
.getInterfaces();
457 for (int i
= 0; i
< intfs
.length
; i
++)
459 if (Remote
.class.isAssignableFrom(intfs
[i
]))
460 interfaces
.add(intfs
[i
]);
462 c
= c
.getSuperclass();
465 intfs
= new Class
[interfaces
.size()];
466 Iterator it
= interfaces
.iterator();
468 for (int i
= 0; i
< intfs
.length
; i
++)
469 intfs
[i
] = (Class
) it
.next();
471 RemoteObjectInvocationHandler handler
=
472 new RemoteObjectInvocationHandler(reference
);
475 Proxy
.newProxyInstance(stubFor
.getClassLoader(), intfs
, handler
);
477 return (Remote
) proxy
;