Frames | No Frames |
1: /* UnicastServerRef.java -- 2: Copyright (c) 1996, 1997, 1998, 1999, 2002, 2003, 2004, 2006 3: Free Software Foundation, Inc. 4: 5: This file is part of GNU Classpath. 6: 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. 11: 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. 16: 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. 21: 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. 26: 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. */ 38: 39: 40: package gnu.java.rmi.server; 41: 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; 60: 61: /** 62: * This class connects the local, remotely available (exported) object to 63: * the local RMI server that accepts the remote calls. 64: */ 65: public class UnicastServerRef 66: extends UnicastRef 67: { 68: 69: /** 70: * Use GNU Classpath v 0.20 SVUID for interoperability 71: */ 72: private static final long serialVersionUID = - 5585608108300801246L; 73: 74: /** 75: * The class array, defining parameters of the jdk 1.2 RMI stub constructor. 76: */ 77: private static final Class[] stubprototype = new Class[] { RemoteRef.class }; 78: 79: /** 80: * The exported remote object itself. 81: */ 82: Remote myself; // save the remote object itself 83: 84: /** 85: * The skeleton (if any), associated with the exported remote object. 86: */ 87: protected Skeleton skel; 88: 89: /** 90: * The stub, associated with the exported remote object (may be proxy class). 91: */ 92: protected Remote stub; 93: 94: /** 95: * The method table (RMI hash code to method) of the methods of the 96: * exported object. 97: */ 98: protected Hashtable methods = new Hashtable(); 99: 100: /** 101: * Used by serialization. 102: */ 103: UnicastServerRef() 104: { 105: } 106: 107: public UnicastServerRef(ObjID id, int port, RMIServerSocketFactory ssf) 108: throws RemoteException 109: { 110: super(id); 111: manager = UnicastConnectionManager.getInstance(port, ssf); 112: } 113: 114: /** 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. 118: * 119: * Stubs and skeletons are always ignored (even if present) if the 120: * java.rmi.server.ignoreStubClasses property is set to true. 121: * 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 125: */ 126: public Remote exportObject(Remote obj) throws RemoteException 127: { 128: if (myself == null) 129: { 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; 134: 135: String ignoreStubs; 136: 137: ClassLoader loader =obj.getClass().getClassLoader(); 138: 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"); 146: 147: if (! ignoreStubs.equals("true")) 148: { 149: // Find and install the stub 150: Class cls = obj.getClass(); 151: 152: // where ist the _Stub? (check superclasses also) 153: Class expCls = findStubSkelClass(cls); 154: 155: if (expCls != null) 156: { 157: stub = (RemoteStub) getHelperClass(expCls, "_Stub"); 158: // Find and install the skeleton (if there is one) 159: skel = (Skeleton) getHelperClass(expCls, "_Skel"); 160: } 161: } 162: 163: if (stub == null) 164: stub = createProxyStub(obj.getClass(), this); 165: 166: // Build hash of methods which may be called. 167: buildMethodHash(obj.getClass(), true); 168: 169: // Export it. 170: UnicastServer.exportObject(this); 171: } 172: 173: return stub; 174: } 175: 176: /** 177: * Get the stub (actual class or proxy) of the exported remote object. 178: * 179: * @return the remote stub (null if exportObject has not been called). 180: */ 181: public Remote getStub() 182: { 183: return stub; 184: } 185: 186: /** 187: * Unexport the object (remove methods from the method hashcode table 188: * and call UnicastServer.unexportObject. 189: * 190: * @param obj the object being unexported 191: * @param force passed to the UnicastServer.unexportObject. 192: * @return value, returned by the UnicastServer.unexportObject. 193: */ 194: public boolean unexportObject(Remote obj, boolean force) 195: { 196: // Remove all hashes of methods which may be called. 197: buildMethodHash(obj.getClass(), false); 198: return UnicastServer.unexportObject(this, force); 199: } 200: 201: /** 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. 205: * 206: * @return the class having stub defined, null if none. 207: */ 208: protected Class findStubSkelClass(Class startCls) 209: { 210: Class cls = startCls; 211: 212: while (true) 213: { 214: try 215: { 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 221: } 222: catch (ClassNotFoundException e) 223: { 224: Class superCls = cls.getSuperclass(); 225: if (superCls == null 226: || superCls == java.rmi.server.UnicastRemoteObject.class) 227: { 228: return null; 229: } 230: cls = superCls; 231: } 232: } 233: } 234: 235: /** 236: * Get the helper (assisting) class with the given type. 237: * 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. 240: * 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). 244: * 245: * @return the instantiated instance of the helper class or null if the 246: * helper class cannot be found or instantiated. 247: */ 248: protected Object getHelperClass(Class cls, String type) 249: { 250: try 251: { 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")) 257: { 258: try 259: { 260: // JDK 1.2 stubs 261: Constructor con = scls.getConstructor(stubprototype); 262: return (con.newInstance(new Object[] { this })); 263: } 264: catch (NoSuchMethodException e) 265: { 266: } 267: catch (InstantiationException e) 268: { 269: } 270: catch (IllegalAccessException e) 271: { 272: } 273: catch (IllegalArgumentException e) 274: { 275: } 276: catch (InvocationTargetException e) 277: { 278: } 279: // JDK 1.1 stubs 280: RemoteStub stub = (RemoteStub) scls.newInstance(); 281: UnicastRemoteStub.setStubRef(stub, this); 282: return (stub); 283: } 284: else 285: { 286: // JDK 1.1 skel 287: return (scls.newInstance()); 288: } 289: } 290: catch (ClassNotFoundException e) 291: { 292: } 293: catch (InstantiationException e) 294: { 295: } 296: catch (IllegalAccessException e) 297: { 298: } 299: return (null); 300: } 301: 302: public String getClientHost() throws ServerNotActiveException 303: { 304: return RemoteServer.getClientHost(); 305: } 306: 307: /** 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. 311: * 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. 315: */ 316: protected void buildMethodHash(Class cls, boolean build) 317: { 318: Method[] meths = cls.getMethods(); 319: for (int i = 0; i < meths.length; i++) 320: { 321: /* Don't need to include any java.xxx related stuff */ 322: if (meths[i].getDeclaringClass().getName().startsWith("java.")) 323: { 324: continue; 325: } 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); 332: } 333: } 334: 335: Class getMethodReturnType(int method, long hash) throws Exception 336: { 337: if (method == - 1) 338: { 339: Method meth = (Method) methods.get(new Long(hash)); 340: return meth.getReturnType(); 341: } 342: else 343: return null; 344: } 345: 346: /** 347: * This method is called from the {@link UnicastServer#incomingMessageCall} 348: * to deliver the remote call to this object. 349: */ 350: public Object incomingMessageCall(UnicastConnection conn, int method, 351: long hash) throws Exception 352: { 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) 357: { 358: Method meth = (Method) methods.get(new Long(hash)); 359: // System.out.println("class = " + myself.getClass() + ", meth = " + 360: // meth); 361: if (meth == null) 362: { 363: throw new NoSuchMethodException( 364: myself.getClass().getName()+" hash "+hash); 365: } 366: 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++) 371: { 372: /** 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. 375: */ 376: try 377: { 378: // need to handle primitive types 379: args[i] = ((RMIObjectInputStream) in) 380: .readValue(meth.getParameterTypes()[i]); 381: 382: } 383: catch (Exception t) 384: { 385: t.printStackTrace(); 386: throw t; 387: } 388: } 389: //We must reinterpret the exception thrown by meth.invoke() 390: //return (meth.invoke(myself, args)); 391: Object ret = null; 392: try 393: { 394: ret = meth.invoke(myself, args); 395: } 396: catch (InvocationTargetException e) 397: { 398: Throwable cause = e.getTargetException(); 399: if (cause instanceof Exception) 400: { 401: throw (Exception) cause; 402: } 403: else if (cause instanceof Error) 404: { 405: throw (Error) cause; 406: } 407: else 408: { 409: throw new Error( 410: "The remote method threw a java.lang.Throwable that"+ 411: " is neither java.lang.Exception nor java.lang.Error.", 412: e); 413: } 414: } 415: return ret; 416: } 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 422: { 423: if (skel == null) 424: throw new NoSuchMethodException("JDK 1.1 call - Skeleton required"); 425: 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()); 432: } 433: } 434: 435: /** 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. 438: * 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 441: * 442: * @return the applicable proxy stub. 443: * 444: * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) 445: */ 446: Remote createProxyStub(Class stubFor, RemoteRef reference) 447: { 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; 453: 454: while (c != null) 455: { 456: intfs = c.getInterfaces(); 457: for (int i = 0; i < intfs.length; i++) 458: { 459: if (Remote.class.isAssignableFrom(intfs[i])) 460: interfaces.add(intfs[i]); 461: } 462: c = c.getSuperclass(); 463: } 464: 465: intfs = new Class[interfaces.size()]; 466: Iterator it = interfaces.iterator(); 467: 468: for (int i = 0; i < intfs.length; i++) 469: intfs[i] = (Class) it.next(); 470: 471: RemoteObjectInvocationHandler handler = 472: new RemoteObjectInvocationHandler(reference); 473: 474: Object proxy = 475: Proxy.newProxyInstance(stubFor.getClassLoader(), intfs, handler); 476: 477: return (Remote) proxy; 478: } 479: 480: 481: }