Source for gnu.java.rmi.server.UnicastRef

   1: /* UnicastRef.java --
   2:    Copyright (c) 1996, 1997, 1998, 1999, 2002, 2005, 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 gnu.java.rmi.dgc.LeaseRenewingTask;
  43: 
  44: import java.io.DataInputStream;
  45: import java.io.DataOutputStream;
  46: import java.io.IOException;
  47: import java.io.ObjectInput;
  48: import java.io.ObjectInputStream;
  49: import java.io.ObjectOutput;
  50: import java.io.ObjectOutputStream;
  51: import java.lang.reflect.InvocationTargetException;
  52: import java.lang.reflect.Method;
  53: import java.rmi.ConnectException;
  54: import java.rmi.Remote;
  55: import java.rmi.RemoteException;
  56: import java.rmi.dgc.Lease;
  57: import java.rmi.server.ObjID;
  58: import java.rmi.server.Operation;
  59: import java.rmi.server.RMIClientSocketFactory;
  60: import java.rmi.server.RemoteCall;
  61: import java.rmi.server.RemoteObject;
  62: import java.rmi.server.RemoteRef;
  63: import java.rmi.server.UID;
  64: 
  65: public class UnicastRef
  66:     implements RemoteRef, ProtocolConstants
  67: {
  68: 
  69:   /**
  70:    * Use serial version UID for iteroperability
  71:    */
  72:   private static final long serialVersionUID = 1;
  73: 
  74:   public ObjID objid;
  75: 
  76:   UnicastConnectionManager manager;
  77: 
  78:   /**
  79:    * Used by serialization, and let subclass capable of having default
  80:    * constructor
  81:    */
  82:   // must be public otherwise java.rmi.RemoteObject cannot instantiate this
  83:   // class
  84:   // -- iP
  85:   public UnicastRef()
  86:   {
  87:   }
  88: 
  89:   public UnicastRef(ObjID objid, String host, int port,
  90:                     RMIClientSocketFactory csf)
  91:   {
  92:     this(objid);
  93:     manager = UnicastConnectionManager.getInstance(host, port, csf);
  94:   }
  95: 
  96:   public UnicastRef(ObjID objid)
  97:   {
  98:     this.objid = objid;
  99:   }
 100: 
 101:   public Object invoke(Remote obj, Method method, Object[] params, long opnum)
 102:       throws Exception
 103:   {
 104:     // Check if client and server are in the same VM, then local call can be
 105:     // used to
 106:     // replace remote call, but it's somewhat violating remote semantic.
 107:     Object svrobj = manager.serverobj;
 108: 
 109:     // Make sure that the server object is compatible. It could be loaded from a
 110:     // different
 111:     // classloader --iP
 112:     if (svrobj != null && method.getDeclaringClass().isInstance(svrobj))
 113:       {
 114:         // local call
 115:         Object ret = null;
 116:         try
 117:           {
 118:             ret = method.invoke(svrobj, params);
 119:           }
 120:         catch (InvocationTargetException e)
 121:           {
 122:             throw (Exception) e.getTargetException();
 123:           }
 124:         // System.out.println("\n\n ***** local call: " + method + "\nreturn: "
 125:         // + ret + "\n\n");
 126:         return ret;
 127:       }
 128:     // System.out.println("***************** remote call:" +
 129:     // manager.serverPort);
 130:     return (invokeCommon(obj, method, params, - 1, opnum));
 131:   }
 132: 
 133:   /**
 134:    * The ordinary number of the DGC messages.
 135:    */
 136:   static long dgcSequence;
 137: 
 138:   /**
 139:    * The DGC object id, also serves as a synchronization target to increment the
 140:    * dgcSequence safely.
 141:    */
 142:   static final ObjID dgcId = new ObjID(ObjID.DGC_ID);
 143: 
 144:   ObjID[] this_id;
 145: 
 146:   /**
 147:    * The number of the method "dirty" in the DGC.
 148:    */
 149:   static int DIRTY = 1;
 150: 
 151:   /**
 152:    * The DGC interface hash code.
 153:    */
 154:   static final long dgcInterfaceHash = - 669196253586618813L;
 155: 
 156:   /**
 157:    * Notify the DGC of the remote side that we still hold this object.
 158:    */
 159:   public Lease notifyDGC(Lease lease) throws Exception
 160:   {
 161:     long seq;
 162:     synchronized (dgcId)
 163:       {
 164:         seq = dgcSequence++;
 165:       }
 166: 
 167:     if (this_id == null)
 168:       this_id = new ObjID[] { objid };
 169: 
 170:     UnicastConnection conn;
 171:     try
 172:       {
 173:         conn = manager.getConnection();
 174:       }
 175:     catch (IOException e1)
 176:       {
 177:         throw new RemoteException("connection failed to host: "
 178:                                   + manager.serverName, e1);
 179:       }
 180: 
 181:     ObjectOutputStream out;
 182:     DataOutputStream dout;
 183:     try
 184:       {
 185:         dout = conn.getDataOutputStream();
 186:         dout.writeByte(MESSAGE_CALL);
 187: 
 188:         out = conn.startObjectOutputStream(); // (re)start ObjectOutputStream
 189: 
 190:         dgcId.write(out);
 191:         // The number of the operation is 1 ("dirty")
 192:         out.writeInt(DIRTY);
 193:         out.writeLong(dgcInterfaceHash);
 194: 
 195:         RMIObjectOutputStream rout = (RMIObjectOutputStream) out;
 196: 
 197:         rout.writeValue(this_id, this_id.getClass());
 198:         rout.writeLong(seq);
 199:         rout.writeValue(lease, lease.getClass());
 200: 
 201:         out.flush();
 202:       }
 203:     catch (IOException e2)
 204:       {
 205:         throw new RemoteException("DGC call failed: ", e2);
 206:       }
 207: 
 208:     int returncode;
 209:     Object returnval;
 210:     DataInputStream din;
 211:     ObjectInputStream in;
 212:     UID ack;
 213:     try
 214:       {
 215:         din = conn.getDataInputStream();
 216: 
 217:         if ((returncode = din.readUnsignedByte()) != MESSAGE_CALL_ACK)
 218:           {
 219:             conn.disconnect();
 220:             throw new RemoteException("DGC Call not acked:" + returncode);
 221:           }
 222: 
 223:         in = conn.startObjectInputStream(); // (re)start ObjectInputStream
 224:         returncode = in.readUnsignedByte();
 225:         ack = UID.read(in);
 226: 
 227:         if (returncode == RETURN_NACK)
 228:           {
 229:             returnval = in.readObject(); // get Exception
 230: 
 231:           }
 232:         else
 233:           {
 234:             returnval = ((RMIObjectInputStream) in).readValue(Lease.class);
 235:           }
 236:       }
 237:     catch (IOException e3)
 238:       {
 239:         throw new RemoteException("DGC call return failed: ", e3);
 240:       }
 241: 
 242:     manager.discardConnection(conn);
 243: 
 244:     if (returncode != RETURN_ACK && returnval != null)
 245:       {
 246:         if (returncode == RETURN_NACK)
 247:           throw (Exception) returnval;
 248:         else
 249:           throw new RemoteException("DGC unexpected returncode: " + returncode);
 250:       }
 251: 
 252:     return (Lease) returnval;
 253:   }
 254:   /**
 255:    * Invoke the remote method on the given object. This part is overridden by
 256:    * the activatable objects.
 257:    */
 258:   protected Object invokeCommon(Remote obj, Method method, Object[] params,
 259:                                 int opnum, long hash) throws Exception
 260:   {
 261:     UnicastConnection conn;
 262:     try
 263:       {
 264:         conn = manager.getConnection();
 265:         return invokeCommon(conn, obj, method, params, opnum, hash);
 266:       }
 267:     catch (IOException e1)
 268:       {
 269:         throw new RemoteException("connection failed to host: "
 270:                                   + manager.serverName, e1);
 271:       }
 272:   }
 273: 
 274:   /**
 275:    * Invoke the remote method on the given object when connection is already
 276:    * established.
 277:    */
 278:   protected Object invokeCommon(UnicastConnection conn, Remote obj,
 279:                                 Method method, Object[] params, int opnum,
 280:                                 long hash) throws Exception
 281:   {
 282:     ObjectOutputStream out;
 283:     DataOutputStream dout;
 284:     try
 285:       {
 286:         dout = conn.getDataOutputStream();
 287:         dout.writeByte(MESSAGE_CALL);
 288: 
 289:         out = conn.startObjectOutputStream(); // (re)start ObjectOutputStream
 290: 
 291:         objid.write(out);
 292:         out.writeInt(opnum);
 293:         out.writeLong(hash);
 294: 
 295:         // must handle primitive class and their wrapper classes
 296:         Class clss[] = method.getParameterTypes();
 297:         for (int i = 0; i < clss.length; i++)
 298:           ((RMIObjectOutputStream) out).writeValue(params[i], clss[i]);
 299: 
 300:         out.flush();
 301:       }
 302:     catch (IOException e2)
 303:       {
 304:         throw new RemoteException("call failed: ", e2);
 305:       }
 306: 
 307:     int returncode;
 308:     Object returnval;
 309:     DataInputStream din;
 310:     ObjectInputStream in;
 311:     UID ack;
 312:     try
 313:       {
 314:         din = conn.getDataInputStream();
 315: 
 316:         if ((returncode = din.readUnsignedByte()) != MESSAGE_CALL_ACK)
 317:           {
 318:             conn.disconnect();
 319:             throw new RemoteException("Call not acked:" + returncode);
 320:           }
 321: 
 322:         in = conn.startObjectInputStream(); // (re)start ObjectInputStream
 323:         returncode = in.readUnsignedByte();
 324:         ack = UID.read(in);
 325: 
 326:         Class cls = method.getReturnType();
 327: 
 328:         if (returncode == RETURN_NACK)
 329:           {
 330:             returnval = in.readObject(); // get Exception
 331: 
 332:           }
 333:         else if (cls == Void.TYPE)
 334:           {
 335:             returnval = null;
 336:             // in.readObject() // not required! returntype 'void' means no field
 337:             // is returned.
 338:           }
 339:         else
 340:           {
 341:             returnval = ((RMIObjectInputStream) in).readValue(cls); // get
 342:             // returnvalue
 343:           }
 344:       }
 345:     catch (IOException e3)
 346:       {
 347:         // for debug: e3.printStackTrace();
 348:         throw new RemoteException("call return failed: ", e3);
 349:       }
 350: 
 351:     /*
 352:      * if DGCAck is necessary?? //According to RMI wire protocol, send a DGCAck //
 353:      * to indicate receiving return value dout.writeByte(MESSAGE_DGCACK);
 354:      * ack.write(dout); out.flush();
 355:      */
 356: 
 357:     manager.discardConnection(conn);
 358: 
 359:     if (returncode != RETURN_ACK && returnval != null)
 360:       {
 361:         if (returncode == RETURN_NACK)
 362:           throw (Exception) returnval;
 363:         else
 364:           throw new RemoteException("unexpected returncode: " + returncode);
 365:       }
 366: 
 367:     return (returnval);
 368:   }
 369: 
 370:   /**
 371:    * @deprecated
 372:    */
 373:   public RemoteCall newCall(RemoteObject obj, Operation[] op, int opnum,
 374:                             long hash) throws RemoteException
 375:   {
 376:     UnicastConnection conn;
 377: 
 378:     try
 379:       {
 380:         conn = manager.getConnection();
 381:       }
 382:     catch (IOException e1)
 383:       {
 384:         throw new ConnectException("connection failed to host: "
 385:                                    + manager.serverName, e1);
 386:       }
 387: 
 388:     // obj: useless?
 389: 
 390:     return (new UnicastRemoteCall(conn, objid, opnum, hash));
 391:   }
 392: 
 393:   /**
 394:    * @deprecated
 395:    */
 396:   public void invoke(RemoteCall call) throws Exception
 397:   {
 398:     UnicastRemoteCall c = (UnicastRemoteCall) call;
 399:     call.executeCall();
 400:   }
 401: 
 402:   /**
 403:    * @deprecated
 404:    */
 405:   public void done(RemoteCall call) throws RemoteException
 406:   {
 407:     UnicastRemoteCall c = (UnicastRemoteCall) call;
 408:     try
 409:       {
 410:         c.done();
 411:       }
 412:     catch (IOException e)
 413:       {
 414:       }
 415:     UnicastConnection conn = c.getConnection();
 416:     manager.discardConnection(conn);
 417:   }
 418: 
 419:   public void writeExternal(ObjectOutput out) throws IOException
 420:   {
 421:     if (manager == null)
 422:       {
 423:         throw new IOException("no connection");
 424:       }
 425:     manager.write(out);
 426:     objid.write(out);
 427:     // This byte is somewhat confusing when interoperating with JDK
 428:     out.writeByte(0); // RETURN_ACK);
 429:   }
 430: 
 431:   public void readExternal(ObjectInput in) throws IOException,
 432:       ClassNotFoundException
 433:   {
 434:     manager = UnicastConnectionManager.read(in);
 435:     objid = ObjID.read(in);
 436:     byte ack = in.readByte();
 437:     // This byte is somewhat confusing when interoperating with JDK
 438:     if (ack != RETURN_ACK && ack != 0/* jdk ack value */)
 439:       {
 440:         throw new IOException("no ack found");
 441:       }
 442: 
 443:     // Notify the DGC of the remote side that we hold the reference to the
 444:     // received object. Do not notify if the client and server are on the
 445:     // same virtual machine.
 446:     if (manager.serverobj == null)
 447:       LeaseRenewingTask.scheduleLeases(this);
 448:   }
 449: 
 450:   public boolean remoteEquals(RemoteRef ref)
 451:   {
 452:     throw new Error("Not implemented");
 453:   }
 454: 
 455:   public int remoteHashCode()
 456:   {
 457:     throw new Error("Not implemented");
 458:   }
 459: 
 460:   public String getRefClass(ObjectOutput out)
 461:   {
 462:     return ("UnicastRef");
 463:   }
 464: 
 465:   /**
 466:    * Return the string representing the remote reference information.
 467:    */
 468:   public String remoteToString()
 469:   {
 470:     if (manager!=null)
 471:       return manager.toString();
 472:     else
 473:       return "null manager";
 474:   }
 475: 
 476:   public void dump(UnicastConnection conn)
 477:   {
 478:     try
 479:       {
 480:         DataInputStream din = conn.getDataInputStream();
 481:         for (;;)
 482:           {
 483:             int b = din.readUnsignedByte();
 484:             System.out.print(Integer.toHexString(b));
 485:             if (b >= 32 && b < 128)
 486:               {
 487:                 System.out.print(": " + (char) b);
 488:               }
 489:             System.out.println();
 490:           }
 491:       }
 492:     catch (IOException _)
 493:       {
 494:       }
 495:   }
 496: 
 497:   /**
 498:    * Check if this UnicastRef points to the object as the passed UnicastRef.
 499:    * Both the object Id and manager must be the same.
 500:    *
 501:    * @return true if the passed reference points to the same remote object as
 502:    *         this reference, false otherwise.
 503:    */
 504:   public boolean equals(Object other)
 505:   {
 506:     if (other instanceof UnicastRef)
 507:       {
 508:         UnicastRef r = (UnicastRef) other;
 509:         return r.manager.equals(manager) && r.objid.equals(objid);
 510:       }
 511:     else
 512:       return false;
 513:   }
 514: 
 515:   /**
 516:    * Get the hash code of this UnicastRef, combining hash code of the manager
 517:    * with hash code of the object id.
 518:    */
 519:   public int hashCode()
 520:   {
 521:     return manager.hashCode() ^ objid.hashCode();
 522:   }
 523: 
 524: }