Source for gnu.java.rmi.server.UnicastServer

   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: }