1 /* UnicastServerRef.java --
2 Copyright (c) 1996, 1997, 1998, 1999, 2002, 2003, 2004
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., 59 Temple Place, Suite 330, 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
.Method
;
45 import java
.lang
.reflect
.InvocationTargetException
;
46 import java
.rmi
.Remote
;
47 import java
.rmi
.RemoteException
;
48 import java
.rmi
.server
.RemoteStub
;
49 import java
.rmi
.server
.ObjID
;
50 import java
.rmi
.server
.ServerRef
;
51 import java
.rmi
.server
.RemoteServer
;
52 import java
.rmi
.server
.RemoteRef
;
53 import java
.rmi
.server
.ServerNotActiveException
;
54 import java
.rmi
.server
.RMIServerSocketFactory
;
55 import java
.rmi
.server
.Skeleton
;
56 import java
.util
.Hashtable
;
58 public class UnicastServerRef
60 implements ServerRef
{ //SHOULD implement ServerRef
62 final static private Class
[] stubprototype
= new Class
[] { RemoteRef
.class };
64 Remote myself
; //save the remote object itself
65 private Skeleton skel
;
66 private RemoteStub stub
;
67 private Hashtable methods
= new Hashtable();
70 * Used by serialization.
76 public UnicastServerRef(ObjID id
, int port
, RMIServerSocketFactory ssf
) throws RemoteException
{
78 manager
= UnicastConnectionManager
.getInstance(port
, ssf
);
81 public RemoteStub
exportObject(Remote obj
) throws RemoteException
{
84 // Save it to server manager, to let client calls in the same VM to issue
86 manager
.serverobj
= obj
;
88 // Find and install the stub
89 Class cls
= obj
.getClass();
92 // where ist the _Stub? (check superclasses also)
93 expCls
= findStubSkelClass(cls
);
94 } catch (Exception ex
) {
95 throw new RemoteException("can not find stubs for class: " + cls
, ex
);
98 stub
= (RemoteStub
)getHelperClass(expCls
, "_Stub");
100 throw new RemoteException("failed to export: " + cls
);
103 // Find and install the skeleton (if there is one)
104 skel
= (Skeleton
)getHelperClass(expCls
, "_Skel");
106 // Build hash of methods which may be called.
107 buildMethodHash(obj
.getClass(), true);
110 UnicastServer
.exportObject(this);
116 public RemoteStub
exportObject(Remote remote
, Object obj
)
117 throws RemoteException
120 return exportObject(remote
);
123 public RemoteStub
getStub(){
128 public boolean unexportObject(Remote obj
, boolean force
) {
129 // Remove all hashes of methods which may be called.
130 buildMethodHash(obj
.getClass(), false);
131 return UnicastServer
.unexportObject(this, force
);
136 * The Subs/Skels might not there for the actual class, but maybe
137 * for one of the superclasses.
140 private Class
findStubSkelClass(Class startCls
) throws Exception
{
141 Class cls
= startCls
;
145 String stubClassname
= cls
.getName() + "_Stub";
146 ClassLoader cl
= cls
.getClassLoader();
147 Class scls
= cl
== null ? Class
.forName(stubClassname
)
148 : cl
.loadClass(stubClassname
);
149 return cls
; // found it
150 } catch (ClassNotFoundException e
) {
151 Class superCls
= cls
.getSuperclass();
153 || superCls
== java
.rmi
.server
.UnicastRemoteObject
.class)
155 throw new Exception("Neither " + startCls
156 + " nor one of their superclasses (like" + cls
+ ")"
166 private Object
getHelperClass(Class cls
, String type
) {
168 String classname
= cls
.getName();
169 ClassLoader cl
= cls
.getClassLoader();
170 Class scls
= cl
== null ? Class
.forName(classname
+ type
)
171 : cl
.loadClass(classname
+ type
);
172 if (type
.equals("_Stub")) {
175 Constructor con
= scls
.getConstructor(stubprototype
);
176 return (con
.newInstance(new Object
[]{this}));
178 catch (NoSuchMethodException e
) {
180 catch (InstantiationException e
) {
182 catch (IllegalAccessException e
) {
184 catch (IllegalArgumentException e
) {
186 catch (InvocationTargetException e
) {
189 RemoteStub stub
= (RemoteStub
)scls
.newInstance();
190 UnicastRemoteStub
.setStubRef(stub
, this);
195 return (scls
.newInstance());
198 catch (ClassNotFoundException e
) {
200 catch (InstantiationException e
) {
202 catch (IllegalAccessException e
) {
209 public String
getClientHost() throws ServerNotActiveException
{
210 return RemoteServer
.getClientHost();
213 private void buildMethodHash(Class cls
, boolean build
) {
214 Method
[] meths
= cls
.getMethods();
215 for (int i
= 0; i
< meths
.length
; i
++) {
216 /* Don't need to include any java.xxx related stuff */
217 if (meths
[i
].getDeclaringClass().getName().startsWith("java.")) {
220 long hash
= RMIHashes
.getMethodHash(meths
[i
]);
222 methods
.put(new Long (hash
), meths
[i
]);
224 methods
.remove(new Long (hash
));
225 //System.out.println("meth = " + meths[i] + ", hash = " + hash);
229 Class
getMethodReturnType(int method
, long hash
) throws Exception
232 Method meth
= (Method
)methods
.get(new Long (hash
));
233 return meth
.getReturnType();
238 public Object
incomingMessageCall(UnicastConnection conn
, int method
, long hash
) throws Exception
{
239 //System.out.println("method = " + method + ", hash = " + hash);
240 // If method is -1 then this is JDK 1.2 RMI - so use the hash
241 // to locate the method
243 Method meth
= (Method
)methods
.get(new Long (hash
));
244 //System.out.println("class = " + myself.getClass() + ", meth = " + meth);
246 throw new NoSuchMethodException();
249 ObjectInputStream in
= conn
.getObjectInputStream();
250 int nrargs
= meth
.getParameterTypes().length
;
251 Object
[] args
= new Object
[nrargs
];
252 for (int i
= 0; i
< nrargs
; i
++) {
254 * For debugging purposes - we don't handle CodeBases
255 * quite right so we don't always find the stubs. This
259 // need to handle primitive types
260 args
[i
] = ((RMIObjectInputStream
)in
).readValue(meth
.getParameterTypes()[i
]);
263 catch (Exception t
) {
268 //We must reinterpret the exception thrown by meth.invoke()
269 //return (meth.invoke(myself, args));
272 ret
= meth
.invoke(myself
, args
);
273 }catch(InvocationTargetException e
){
274 Throwable cause
= e
.getTargetException();
275 if (cause
instanceof Exception
) {
276 throw (Exception
)cause
;
278 else if (cause
instanceof Error
) {
282 throw new Error("The remote method threw a java.lang.Throwable that is neither java.lang.Exception nor java.lang.Error.", e
);
287 // Otherwise this is JDK 1.1 style RMI - we find the skeleton
288 // and invoke it using the method number. We wrap up our
289 // connection system in a UnicastRemoteCall so it appears in a
290 // way the Skeleton can handle.
293 throw new NoSuchMethodException();
295 UnicastRemoteCall call
= new UnicastRemoteCall(conn
);
296 skel
.dispatch(myself
, call
, method
, hash
);
297 if (!call
.isReturnValue())
298 return RMIVoidValue
.INSTANCE
;
300 return (call
.returnValue());