Source for gnu.java.rmi.server.UnicastServerRef

   1: /* UnicastServerRef.java --
   2:    Copyright (c) 1996, 1997, 1998, 1999, 2002, 2003, 2004
   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.rmi.Remote;
  47: import java.rmi.RemoteException;
  48: import java.rmi.server.ObjID;
  49: import java.rmi.server.RMIServerSocketFactory;
  50: import java.rmi.server.RemoteRef;
  51: import java.rmi.server.RemoteServer;
  52: import java.rmi.server.RemoteStub;
  53: import java.rmi.server.ServerNotActiveException;
  54: import java.rmi.server.ServerRef;
  55: import java.rmi.server.Skeleton;
  56: import java.util.Hashtable;
  57: 
  58: public class UnicastServerRef
  59:     extends UnicastRef 
  60:     implements ServerRef{ //SHOULD implement ServerRef
  61: 
  62: final static private Class[] stubprototype = new Class[] { RemoteRef.class };
  63: 
  64: Remote myself; //save the remote object itself
  65: private Skeleton skel;
  66: private RemoteStub stub;
  67: private Hashtable methods = new Hashtable();
  68: 
  69: /**
  70:  * Used by serialization.
  71:  */
  72: UnicastServerRef()
  73: {
  74: }
  75: 
  76: public UnicastServerRef(ObjID id, int port, RMIServerSocketFactory ssf) throws RemoteException {
  77:     super(id);
  78:     manager = UnicastConnectionManager.getInstance(port, ssf);
  79: }
  80: 
  81: public RemoteStub exportObject(Remote obj) throws RemoteException {
  82:     if (myself == null) {
  83:         myself = obj;
  84:         // Save it to server manager, to let client calls in the same VM to issue
  85:         //  local call
  86:         manager.serverobj = obj;
  87: 
  88:         // Find and install the stub
  89:         Class cls = obj.getClass();
  90:         Class expCls;
  91:         try {
  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);
  96:         }
  97: 
  98:         stub = (RemoteStub)getHelperClass(expCls, "_Stub");
  99:         if (stub == null) {
 100:             throw new RemoteException("failed to export: " + cls);
 101:         }
 102: 
 103:         // Find and install the skeleton (if there is one)
 104:         skel = (Skeleton)getHelperClass(expCls, "_Skel");
 105: 
 106:         // Build hash of methods which may be called.
 107:         buildMethodHash(obj.getClass(), true);
 108: 
 109:         // Export it.
 110:         UnicastServer.exportObject(this);
 111:     }
 112: 
 113:     return (stub);
 114: }
 115: 
 116: public RemoteStub exportObject(Remote remote, Object obj)
 117:         throws RemoteException
 118: {
 119:     //FIX ME
 120:     return exportObject(remote);
 121: }
 122: 
 123: public RemoteStub getStub(){
 124:     return stub;
 125: }
 126: 
 127: 
 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);
 132: }
 133: 
 134: /**
 135: *
 136: *  The Subs/Skels might not there for the actual class, but maybe 
 137: *  for one of the superclasses.
 138: *
 139: */
 140: private Class findStubSkelClass(Class startCls) throws Exception {
 141:     Class cls = startCls;
 142: 
 143:     while (true) {
 144:         try {
 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();
 152:             if (superCls == null 
 153:                 || superCls == java.rmi.server.UnicastRemoteObject.class) 
 154:             {
 155:                 throw new Exception("Neither " + startCls 
 156:                     + " nor one of their superclasses (like" + cls + ")" 
 157:                     + " has a _Stub");
 158:             }
 159:             cls = superCls;
 160:         }
 161:     }
 162: }
 163: 
 164: 
 165: 
 166: private Object getHelperClass(Class cls, String type) {
 167:     try {   
 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")) {
 173:             try {
 174:                 // JDK 1.2 stubs
 175:                 Constructor con = scls.getConstructor(stubprototype);
 176:                 return (con.newInstance(new Object[]{this}));
 177:             }
 178:             catch (NoSuchMethodException e) {
 179:             }
 180:             catch (InstantiationException e) {
 181:             }
 182:             catch (IllegalAccessException e) {
 183:             }
 184:             catch (IllegalArgumentException e) {
 185:             }
 186:             catch (InvocationTargetException e) {
 187:             }
 188:             // JDK 1.1 stubs
 189:             RemoteStub stub = (RemoteStub)scls.newInstance();
 190:             UnicastRemoteStub.setStubRef(stub, this);
 191:             return (stub);
 192:         }
 193:         else {
 194:             // JDK 1.1 skel
 195:             return (scls.newInstance());
 196:         }
 197:     }
 198:     catch (ClassNotFoundException e) {
 199:     }
 200:     catch (InstantiationException e) {
 201:     }
 202:     catch (IllegalAccessException e) {
 203:     }
 204:     return (null);
 205: }
 206: 
 207: 
 208: 
 209: public String getClientHost() throws ServerNotActiveException {
 210:     return RemoteServer.getClientHost();
 211: }
 212: 
 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.")) {
 218:             continue;
 219:         }
 220:         long hash = RMIHashes.getMethodHash(meths[i]);
 221:         if(build)
 222:             methods.put(new Long (hash), meths[i]);
 223:         else
 224:             methods.remove(new Long (hash));
 225: //System.out.println("meth = " + meths[i] + ", hash = " + hash);
 226:     }
 227: }
 228: 
 229: Class getMethodReturnType(int method, long hash) throws Exception
 230: {
 231:     if (method == -1) {
 232:         Method meth = (Method)methods.get(new Long (hash));
 233:         return meth.getReturnType();
 234:     }else
 235:         return null;
 236: }
 237: 
 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
 242:     if (method == -1) {
 243:         Method meth = (Method)methods.get(new Long (hash));
 244: //System.out.println("class = " + myself.getClass() + ", meth = " + meth);
 245:         if (meth == null) {
 246:             throw new NoSuchMethodException();
 247:         }
 248: 
 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++) {
 253:             /** 
 254:              * For debugging purposes - we don't handle CodeBases
 255:              * quite right so we don't always find the stubs.  This
 256:              * lets us know that.
 257:              */
 258:             try {
 259:                 // need to handle primitive types
 260:                 args[i] = ((RMIObjectInputStream)in).readValue(meth.getParameterTypes()[i]);
 261:                 
 262:             }
 263:             catch (Exception t) {
 264:                 t.printStackTrace();
 265:                 throw t;
 266:             }
 267:         }
 268:         //We must reinterpret the exception thrown by meth.invoke()
 269:         //return (meth.invoke(myself, args));
 270:         Object ret = null;
 271:         try{
 272:             ret = meth.invoke(myself, args);
 273:         }catch(InvocationTargetException e){
 274:                     Throwable cause = e.getTargetException();
 275:                     if (cause instanceof Exception) {
 276:                         throw (Exception)cause;
 277:                     }
 278:                     else if (cause instanceof Error) {
 279:                         throw (Error)cause;
 280:                     }
 281:                     else {
 282:                         throw new Error("The remote method threw a java.lang.Throwable that is neither java.lang.Exception nor java.lang.Error.", e);
 283:                     }
 284:         }
 285:         return ret;
 286:     }
 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.
 291:     else {
 292:         if (skel == null) {
 293:             throw new NoSuchMethodException();
 294:         }
 295:         UnicastRemoteCall call = new UnicastRemoteCall(conn);
 296:         skel.dispatch(myself, call, method, hash);          
 297:         if (!call.isReturnValue())
 298:           return RMIVoidValue.INSTANCE;
 299:         else
 300:           return (call.returnValue());
 301:     }
 302: }
 303: 
 304: }
 305: