Merge from mainline.
[official-gcc.git] / libjava / classpath / gnu / java / rmi / server / UnicastServerRef.java
blobcd891a1aaea22aa86d62ceac9792552d46eccd5a
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)
10 any later version.
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
20 02110-1301 USA.
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
25 combination.
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;
61 /**
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
66 extends UnicastRef
69 /**
70 * Use GNU Classpath v 0.20 SVUID for interoperability
72 private static final long serialVersionUID = - 5585608108300801246L;
74 /**
75 * The class array, defining parameters of the jdk 1.2 RMI stub constructor.
77 private static final Class[] stubprototype = new Class[] { RemoteRef.class };
79 /**
80 * The exported remote object itself.
82 Remote myself; // save the remote object itself
84 /**
85 * The skeleton (if any), associated with the exported remote object.
87 protected Skeleton skel;
89 /**
90 * The stub, associated with the exported remote object (may be proxy class).
92 protected Remote stub;
94 /**
95 * The method table (RMI hash code to method) of the methods of the
96 * exported object.
98 protected Hashtable methods = new Hashtable();
101 * Used by serialization.
103 UnicastServerRef()
107 public UnicastServerRef(ObjID id, int port, RMIServerSocketFactory ssf)
108 throws RemoteException
110 super(id);
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
117 * proxy stub class.
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
128 if (myself == null)
130 myself = obj;
131 // Save it to server manager, to let client calls in the same VM to
132 // issue local call
133 manager.serverobj = obj;
135 String ignoreStubs;
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.
141 if (loader==null)
142 ignoreStubs = "false";
143 else
144 ignoreStubs = System.getProperty("java.rmi.server.ignoreStubClasses",
145 "false");
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);
155 if (expCls != null)
157 stub = (RemoteStub) getHelperClass(expCls, "_Stub");
158 // Find and install the skeleton (if there is one)
159 skel = (Skeleton) getHelperClass(expCls, "_Skel");
163 if (stub == null)
164 stub = createProxyStub(obj.getClass(), this);
166 // Build hash of methods which may be called.
167 buildMethodHash(obj.getClass(), true);
169 // Export it.
170 UnicastServer.exportObject(this);
173 return stub;
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()
183 return stub;
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
204 * the superclasses.
206 * @return the class having stub defined, null if none.
208 protected Class findStubSkelClass(Class startCls)
210 Class cls = startCls;
212 while (true)
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();
225 if (superCls == null
226 || superCls == java.rmi.server.UnicastRemoteObject.class)
228 return null;
230 cls = superCls;
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"))
260 // JDK 1.2 stubs
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)
279 // JDK 1.1 stubs
280 RemoteStub stub = (RemoteStub) scls.newInstance();
281 UnicastRemoteStub.setStubRef(stub, this);
282 return (stub);
284 else
286 // JDK 1.1 skel
287 return (scls.newInstance());
290 catch (ClassNotFoundException e)
293 catch (InstantiationException e)
296 catch (IllegalAccessException e)
299 return (null);
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
310 * the table.
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."))
324 continue;
326 long hash = RMIHashes.getMethodHash(meths[i]);
327 if (build)
328 methods.put(new Long(hash), meths[i]);
329 else
330 methods.remove(new Long(hash));
331 // System.out.println("meth = " + meths[i] + ", hash = " + hash);
335 Class getMethodReturnType(int method, long hash) throws Exception
337 if (method == - 1)
339 Method meth = (Method) methods.get(new Long(hash));
340 return meth.getReturnType();
342 else
343 return null;
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
356 if (method == - 1)
358 Method meth = (Method) methods.get(new Long(hash));
359 // System.out.println("class = " + myself.getClass() + ", meth = " +
360 // meth);
361 if (meth == null)
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]);
383 catch (Exception t)
385 t.printStackTrace();
386 throw t;
389 //We must reinterpret the exception thrown by meth.invoke()
390 //return (meth.invoke(myself, args));
391 Object ret = null;
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)
405 throw (Error) cause;
407 else
409 throw new Error(
410 "The remote method threw a java.lang.Throwable that"+
411 " is neither java.lang.Exception nor java.lang.Error.",
415 return ret;
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.
421 else
423 if (skel == null)
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;
430 else
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();
451 Class c = stubFor;
452 Class[] intfs;
454 while (c != null)
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);
474 Object proxy =
475 Proxy.newProxyInstance(stubFor.getClassLoader(), intfs, handler);
477 return (Remote) proxy;