Frames | No Frames |
1: /* UnicastServer.java -- 2: Copyright (c) 1996, 1997, 1998, 1999, 2002, 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 gnu.java.rmi.dgc.DGCImpl; 43: import gnu.java.util.WeakIdentityHashMap; 44: 45: import java.io.DataOutputStream; 46: import java.io.IOException; 47: import java.io.ObjectInputStream; 48: import java.io.ObjectOutputStream; 49: import java.rmi.NoSuchObjectException; 50: import java.rmi.Remote; 51: import java.rmi.RemoteException; 52: import java.rmi.ServerError; 53: import java.rmi.activation.ActivationException; 54: import java.rmi.activation.ActivationID; 55: import java.rmi.server.ObjID; 56: import java.rmi.server.UID; 57: import java.util.ArrayList; 58: import java.util.Collection; 59: import java.util.Collections; 60: import java.util.Hashtable; 61: import java.util.Iterator; 62: import java.util.Map; 63: import java.util.WeakHashMap; 64: 65: public class UnicastServer 66: implements ProtocolConstants 67: { 68: 69: /** 70: * Mapping OBJID to server ref by .equals(). 71: */ 72: static private Map objects = Collections.synchronizedMap(new WeakHashMap()); 73: 74: /** 75: * Mapping obj itself to server ref by identity. 76: */ 77: static private Map refcache = Collections.synchronizedMap(new WeakIdentityHashMap()); 78: 79: /** 80: * Mapping the registered activatable objects into they server references. 81: */ 82: public static Map actIds = new Hashtable(); 83: 84: /** 85: * The reference to the local distributed garbage collector. 86: */ 87: static private DGCImpl dgc; 88: 89: /** 90: * Connect this server reference to the server, allowing the local 91: * implementation, associated with this object, to receive remote calls. 92: * 93: * @param obj the server reference, encloses the (usually local) remote 94: * object. 95: */ 96: public static void exportObject(UnicastServerRef obj) 97: { 98: startDGC(); 99: objects.put(obj.objid, obj); 100: refcache.put(obj.myself, obj); 101: obj.manager.startServer(); 102: } 103: 104: /** 105: * Register the activatable object into the table of the activatable 106: * objects. 107: */ 108: public static void registerActivatable(ActivatableServerRef ref) 109: { 110: actIds.put(ref.actId, ref); 111: } 112: 113: /** 114: * Export tha activatable object. The object id is placed into the map, 115: * but the object itself not. This is enough to deliver call to 116: * the ref.incomingMessageCall where the object will be instantiated, 117: * if not present. 118: */ 119: public static void exportActivatableObject(ActivatableServerRef ref) 120: { 121: startDGC(); 122: objects.put(ref.objid, ref); 123: ref.manager.startServer(); 124: actIds.put(ref.actId, ref); 125: } 126: 127: 128: /** 129: * Get the activatable server reference that is handling activation of the 130: * given activation id. 131: */ 132: public static ActivatableServerRef getActivatableRef(ActivationID id) 133: throws ActivationException 134: { 135: ActivatableServerRef ref = (ActivatableServerRef) actIds.get(id); 136: if (ref == null) 137: throw new ActivationException(id + " was not registered with this server"); 138: return ref; 139: } 140: 141: /** 142: * Unregister the previously registered activatable server reference. 143: */ 144: public static void unregisterActivatable(ActivationID id) 145: { 146: actIds.remove(id); 147: } 148: 149: // FIX ME: I haven't handle force parameter 150: /** 151: * Remove the given server reference. The remote object, associated with 152: * this reference, will no longer receive remote calls via this server. 153: */ 154: public static boolean unexportObject(UnicastServerRef obj, boolean force) 155: { 156: objects.remove(obj.objid); 157: refcache.remove(obj.myself); 158: obj.manager.stopServer(); 159: 160: if (obj instanceof ActivatableServerRef) 161: { 162: ActivationID id = ((ActivatableServerRef) obj).actId; 163: unregisterActivatable(id); 164: } 165: return true; 166: } 167: 168: /** 169: * Get the exported reference of the given Remote. The identity map is used, 170: * the non-null value will only be returned if exactly the passed remote 171: * is part of the registered UnicastServerRef. 172: * 173: * @param remote the Remote that is connected to this server via 174: * {@link UnicastServerRef}. 175: * 176: * @return the UnicastServerRef that is used to connect the passed 177: * remote with this server or null, if this Remote is not connected 178: * to this server. 179: */ 180: public static UnicastServerRef getExportedRef(Remote remote) 181: { 182: return (UnicastServerRef) refcache.get(remote); 183: } 184: 185: /** 186: * Get the server references to the object, previously exported via this 187: * server. As the identity map is scanned, more than one reference may match 188: * this Id. 189: * 190: * @param id the id of the exported object 191: * @return the server reference to this object, null if none. 192: */ 193: public static Collection getExported(Object id) 194: { 195: synchronized (objects) 196: { 197: ArrayList list = new ArrayList(); 198: Iterator iter = objects.entrySet().iterator(); 199: Map.Entry e; 200: Object key; 201: while (iter.hasNext()) 202: { 203: e = (Map.Entry) iter.next(); 204: key = e.getKey(); 205: if (key != null && key.equals(id)) 206: list.add(e.getValue()); 207: } 208: return list; 209: } 210: } 211: 212: private static synchronized void startDGC() 213: { 214: if (dgc == null) 215: { 216: try 217: { 218: dgc = new DGCImpl(); 219: // Changed DGCImpl to inherit UnicastServerRef directly 220: // ((UnicastServerRef)dgc.getRef()).exportObject(dgc); 221: dgc.exportObject(dgc); 222: } 223: catch (RemoteException e) 224: { 225: e.printStackTrace(); 226: } 227: } 228: } 229: 230: public static void dispatch(UnicastConnection conn) throws Exception 231: { 232: switch (conn.getDataInputStream().readUnsignedByte()) 233: { 234: case MESSAGE_CALL: 235: incomingMessageCall(conn); 236: break; 237: case MESSAGE_PING: 238: // jdk sends a ping before each method call -> answer it! 239: DataOutputStream out = conn.getDataOutputStream(); 240: out.writeByte(MESSAGE_PING_ACK); 241: out.flush(); 242: break; 243: default: 244: throw new Exception("bad method type"); 245: } 246: } 247: 248: /** 249: * This method is invoked when the remote call is received. The method 250: * dispatches the call to the responsible object, connected to this 251: * server via UnicastServerReference. 252: */ 253: private static void incomingMessageCall(UnicastConnection conn) 254: throws IOException 255: { 256: ObjectInputStream in = conn.startObjectInputStream(); // (re)start 257: // ObjectInputStream 258: 259: ObjID objid = ObjID.read(in); 260: int method = in.readInt(); 261: long hash = in.readLong(); 262: 263: // System.out.println("ObjID: " + objid + ", method: " + method + ", hash: " 264: // + hash); 265: 266: // Use the objid to locate the relevant UnicastServerRef 267: UnicastServerRef uref = (UnicastServerRef) objects.get(objid); 268: Object returnval; 269: int returncode = RETURN_ACK; 270: // returnval is from Method.invoke(), so we must check the return class to 271: // see 272: // if it's primitive type 273: Class returncls = null; 274: if (uref != null) 275: { 276: try 277: { 278: // Dispatch the call to it. 279: returnval = uref.incomingMessageCall(conn, method, hash); 280: returncls = uref.getMethodReturnType(method, hash); 281: } 282: catch (Exception e) 283: { 284: returnval = e; 285: returncode = RETURN_NACK; 286: } 287: catch (Error e) 288: { 289: returnval = new ServerError( 290: "Server error, ObjID: " + objid + 291: ", method: " + method + ", hash: "+ hash, e); 292: returncode = RETURN_NACK; 293: } 294: } 295: else 296: { 297: returnval = new NoSuchObjectException("ObjID: " + objid); 298: returncode = RETURN_NACK; 299: } 300: 301: conn.getDataOutputStream().writeByte(MESSAGE_CALL_ACK); 302: 303: ObjectOutputStream out = conn.startObjectOutputStream(); // (re)start 304: // ObjectOutputStream 305: 306: out.writeByte(returncode); 307: (new UID()).write(out); 308: 309: // System.out.println("returnval=" + returnval + " returncls=" + returncls); 310: 311: if (returnval != null && returncls != null) 312: ((RMIObjectOutputStream) out).writeValue(returnval, returncls); 313: 314: // 1.1/1.2 void return type detection: 315: else if (! (returnval instanceof RMIVoidValue || returncls == Void.TYPE)) 316: out.writeObject(returnval); 317: 318: out.flush(); 319: } 320: 321: }