2 Copyright (c) 1996, 1997, 1998, 1999, 2002, 2005, 2006
3 Free Software Foundation, Inc.
5 This file is part of GNU Classpath.
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)
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.
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
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
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. */
40 package gnu
.java
.rmi
.server
;
42 import gnu
.java
.rmi
.dgc
.LeaseRenewingTask
;
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
;
65 public class UnicastRef
66 implements RemoteRef
, ProtocolConstants
70 * Use serial version UID for iteroperability
72 private static final long serialVersionUID
= 1;
76 UnicastConnectionManager manager
;
79 * Used by serialization, and let subclass capable of having default
82 // must be public otherwise java.rmi.RemoteObject cannot instantiate this
89 public UnicastRef(ObjID objid
, String host
, int port
,
90 RMIClientSocketFactory csf
)
93 manager
= UnicastConnectionManager
.getInstance(host
, port
, csf
);
96 public UnicastRef(ObjID objid
)
101 public Object
invoke(Remote obj
, Method method
, Object
[] params
, long opnum
)
104 // Check if client and server are in the same VM, then local call can be
106 // replace remote call, but it's somewhat violating remote semantic.
107 Object svrobj
= manager
.serverobj
;
109 // Make sure that the server object is compatible. It could be loaded from a
112 if (svrobj
!= null && method
.getDeclaringClass().isInstance(svrobj
))
118 ret
= method
.invoke(svrobj
, params
);
120 catch (InvocationTargetException e
)
122 throw (Exception
) e
.getTargetException();
124 // System.out.println("\n\n ***** local call: " + method + "\nreturn: "
128 // System.out.println("***************** remote call:" +
129 // manager.serverPort);
130 return (invokeCommon(obj
, method
, params
, - 1, opnum
));
134 * The ordinary number of the DGC messages.
136 static long dgcSequence
;
139 * The DGC object id, also serves as a synchronization target to increment the
140 * dgcSequence safely.
142 static final ObjID dgcId
= new ObjID(ObjID
.DGC_ID
);
147 * The number of the method "dirty" in the DGC.
149 static int DIRTY
= 1;
152 * The DGC interface hash code.
154 static final long dgcInterfaceHash
= - 669196253586618813L;
157 * Notify the DGC of the remote side that we still hold this object.
159 public Lease
notifyDGC(Lease lease
) throws Exception
168 this_id
= new ObjID
[] { objid
};
170 UnicastConnection conn
;
173 conn
= manager
.getConnection();
175 catch (IOException e1
)
177 throw new RemoteException("connection failed to host: "
178 + manager
.serverName
, e1
);
181 ObjectOutputStream out
;
182 DataOutputStream dout
;
185 dout
= conn
.getDataOutputStream();
186 dout
.writeByte(MESSAGE_CALL
);
188 out
= conn
.startObjectOutputStream(); // (re)start ObjectOutputStream
191 // The number of the operation is 1 ("dirty")
193 out
.writeLong(dgcInterfaceHash
);
195 RMIObjectOutputStream rout
= (RMIObjectOutputStream
) out
;
197 rout
.writeValue(this_id
, this_id
.getClass());
199 rout
.writeValue(lease
, lease
.getClass());
203 catch (IOException e2
)
205 throw new RemoteException("DGC call failed: ", e2
);
211 ObjectInputStream in
;
215 din
= conn
.getDataInputStream();
217 if ((returncode
= din
.readUnsignedByte()) != MESSAGE_CALL_ACK
)
220 throw new RemoteException("DGC Call not acked:" + returncode
);
223 in
= conn
.startObjectInputStream(); // (re)start ObjectInputStream
224 returncode
= in
.readUnsignedByte();
227 if (returncode
== RETURN_NACK
)
229 returnval
= in
.readObject(); // get Exception
234 returnval
= ((RMIObjectInputStream
) in
).readValue(Lease
.class);
237 catch (IOException e3
)
239 throw new RemoteException("DGC call return failed: ", e3
);
242 manager
.discardConnection(conn
);
244 if (returncode
!= RETURN_ACK
&& returnval
!= null)
246 if (returncode
== RETURN_NACK
)
247 throw (Exception
) returnval
;
249 throw new RemoteException("DGC unexpected returncode: " + returncode
);
252 return (Lease
) returnval
;
255 * Invoke the remote method on the given object. This part is overridden by
256 * the activatable objects.
258 protected Object
invokeCommon(Remote obj
, Method method
, Object
[] params
,
259 int opnum
, long hash
) throws Exception
261 UnicastConnection conn
;
264 conn
= manager
.getConnection();
265 return invokeCommon(conn
, obj
, method
, params
, opnum
, hash
);
267 catch (IOException e1
)
269 throw new RemoteException("connection failed to host: "
270 + manager
.serverName
, e1
);
275 * Invoke the remote method on the given object when connection is already
278 protected Object
invokeCommon(UnicastConnection conn
, Remote obj
,
279 Method method
, Object
[] params
, int opnum
,
280 long hash
) throws Exception
282 ObjectOutputStream out
;
283 DataOutputStream dout
;
286 dout
= conn
.getDataOutputStream();
287 dout
.writeByte(MESSAGE_CALL
);
289 out
= conn
.startObjectOutputStream(); // (re)start ObjectOutputStream
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
]);
302 catch (IOException e2
)
304 throw new RemoteException("call failed: ", e2
);
310 ObjectInputStream in
;
314 din
= conn
.getDataInputStream();
316 if ((returncode
= din
.readUnsignedByte()) != MESSAGE_CALL_ACK
)
319 throw new RemoteException("Call not acked:" + returncode
);
322 in
= conn
.startObjectInputStream(); // (re)start ObjectInputStream
323 returncode
= in
.readUnsignedByte();
326 Class cls
= method
.getReturnType();
328 if (returncode
== RETURN_NACK
)
330 returnval
= in
.readObject(); // get Exception
333 else if (cls
== Void
.TYPE
)
336 // in.readObject() // not required! returntype 'void' means no field
341 returnval
= ((RMIObjectInputStream
) in
).readValue(cls
); // get
345 catch (IOException e3
)
347 // for debug: e3.printStackTrace();
348 throw new RemoteException("call return failed: ", e3
);
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();
357 manager
.discardConnection(conn
);
359 if (returncode
!= RETURN_ACK
&& returnval
!= null)
361 if (returncode
== RETURN_NACK
)
362 throw (Exception
) returnval
;
364 throw new RemoteException("unexpected returncode: " + returncode
);
373 public RemoteCall
newCall(RemoteObject obj
, Operation
[] op
, int opnum
,
374 long hash
) throws RemoteException
376 UnicastConnection conn
;
380 conn
= manager
.getConnection();
382 catch (IOException e1
)
384 throw new ConnectException("connection failed to host: "
385 + manager
.serverName
, e1
);
390 return (new UnicastRemoteCall(conn
, objid
, opnum
, hash
));
396 public void invoke(RemoteCall call
) throws Exception
398 UnicastRemoteCall c
= (UnicastRemoteCall
) call
;
405 public void done(RemoteCall call
) throws RemoteException
407 UnicastRemoteCall c
= (UnicastRemoteCall
) call
;
412 catch (IOException e
)
415 UnicastConnection conn
= c
.getConnection();
416 manager
.discardConnection(conn
);
419 public void writeExternal(ObjectOutput out
) throws IOException
423 throw new IOException("no connection");
427 // This byte is somewhat confusing when interoperating with JDK
428 out
.writeByte(0); // RETURN_ACK);
431 public void readExternal(ObjectInput in
) throws IOException
,
432 ClassNotFoundException
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 */)
440 throw new IOException("no ack found");
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);
450 public boolean remoteEquals(RemoteRef ref
)
452 throw new Error("Not implemented");
455 public int remoteHashCode()
457 throw new Error("Not implemented");
460 public String
getRefClass(ObjectOutput out
)
462 return ("UnicastRef");
466 * Return the string representing the remote reference information.
468 public String
remoteToString()
471 return manager
.toString();
473 return "null manager";
476 public void dump(UnicastConnection conn
)
480 DataInputStream din
= conn
.getDataInputStream();
483 int b
= din
.readUnsignedByte();
484 System
.out
.print(Integer
.toHexString(b
));
485 if (b
>= 32 && b
< 128)
487 System
.out
.print(": " + (char) b
);
489 System
.out
.println();
492 catch (IOException _
)
498 * Check if this UnicastRef points to the object as the passed UnicastRef.
499 * Both the object Id and manager must be the same.
501 * @return true if the passed reference points to the same remote object as
502 * this reference, false otherwise.
504 public boolean equals(Object other
)
506 if (other
instanceof UnicastRef
)
508 UnicastRef r
= (UnicastRef
) other
;
509 return r
.manager
.equals(manager
) && r
.objid
.equals(objid
);
516 * Get the hash code of this UnicastRef, combining hash code of the manager
517 * with hash code of the object id.
519 public int hashCode()
521 return manager
.hashCode() ^ objid
.hashCode();