KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > hudson > remoting > RemoteInvocationHandler


1 package hudson.remoting;
2
3 import java.io.IOException JavaDoc;
4 import java.io.ObjectInputStream JavaDoc;
5 import java.io.Serializable JavaDoc;
6 import java.lang.reflect.InvocationHandler JavaDoc;
7 import java.lang.reflect.InvocationTargetException JavaDoc;
8 import java.lang.reflect.Method JavaDoc;
9 import java.lang.reflect.Proxy JavaDoc;
10
11 /**
12  * Sits behind a proxy object and implements the proxy logic.
13  *
14  * @author Kohsuke Kawaguchi
15  */

16 final class RemoteInvocationHandler implements InvocationHandler JavaDoc, Serializable JavaDoc {
17     /**
18      * This proxy acts as a proxy to the object of
19      * Object ID on the remote {@link Channel}.
20      */

21     private final int oid;
22
23     /**
24      * Represents the connection to the remote {@link Channel}.
25      *
26      * <p>
27      * This field is null when a {@link RemoteInvocationHandler} is just
28      * created and not working as a remote proxy. Once tranferred to the
29      * remote system, this field is set to non-null.
30      */

31     private transient Channel channel;
32
33     /**
34      * True if we are proxying the user object.
35      */

36     private final boolean userProxy;
37
38     RemoteInvocationHandler(int id, boolean userProxy) {
39         this.oid = id;
40         this.userProxy = userProxy;
41     }
42
43     /**
44      * Creates a proxy that wraps an existing OID on the remote.
45      */

46     RemoteInvocationHandler(Channel channel, int id, boolean userProxy) {
47         this.channel = channel;
48         this.oid = id;
49         this.userProxy = userProxy;
50     }
51
52     /**
53      * Wraps an OID to the typed wrapper.
54      */

55     public static <T> T wrap(Channel channel, int id, Class JavaDoc<T> type, boolean userProxy) {
56         return type.cast(Proxy.newProxyInstance( type.getClassLoader(), new Class JavaDoc[]{type},
57             new RemoteInvocationHandler(channel,id,userProxy)));
58     }
59
60     public Object JavaDoc invoke(Object JavaDoc proxy, Method JavaDoc method, Object JavaDoc[] args) throws Throwable JavaDoc {
61         if(channel==null)
62             throw new IllegalStateException JavaDoc("proxy is not connected to a channel");
63
64         if(args==null) args = EMPTY_ARRAY;
65
66         Class JavaDoc<?> dc = method.getDeclaringClass();
67         if(dc ==Object JavaDoc.class) {
68             // handle equals and hashCode by ourselves
69
try {
70                 return method.invoke(this,args);
71             } catch (InvocationTargetException JavaDoc e) {
72                 throw e.getTargetException();
73             }
74         }
75         
76         // delegate the rest of the methods to the remote object
77
if(userProxy)
78             return channel.call(new RPCRequest(oid,method,args,dc.getClassLoader()));
79         else
80             return new RPCRequest(oid,method,args).call(channel);
81     }
82
83     private void readObject(ObjectInputStream JavaDoc ois) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
84         channel = Channel.current();
85         ois.defaultReadObject();
86     }
87
88     /**
89      * Two proxies are the same iff they represent the same remote object.
90      */

91     public boolean equals(Object JavaDoc o) {
92         if(Proxy.isProxyClass(o.getClass()))
93             o = Proxy.getInvocationHandler(o);
94
95         if (this == o) return true;
96         if (o == null || getClass() != o.getClass()) return false;
97
98         RemoteInvocationHandler that = (RemoteInvocationHandler) o;
99
100         return this.oid==that.oid && this.channel==that.channel;
101
102     }
103
104     public int hashCode() {
105         return oid;
106     }
107
108
109     protected void finalize() throws Throwable JavaDoc {
110         // unexport the remote object
111
if(channel!=null)
112             channel.send(new UnexportCommand(oid));
113         super.finalize();
114     }
115
116     private static final long serialVersionUID = 1L;
117
118     /**
119      * Executes the method call remotely.
120      *
121      * If used as {@link Request}, this can be used to provide a lower-layer
122      * for the use inside remoting, to implement the classloader delegation, and etc.
123      * The downside of this is that the classes used as a parameter/return value
124      * must be available to both JVMs.
125      *
126      * If used as {@link Callable} in conjunction with {@link UserRequest},
127      * this can be used to send a method call to user-level objects, and
128      * classes for the parameters and the return value are sent remotely if needed.
129      */

130     private static final class RPCRequest extends Request<Serializable JavaDoc,Throwable JavaDoc> implements DelegatingCallable<Serializable JavaDoc,Throwable JavaDoc> {
131         /**
132          * Target object id to invoke.
133          */

134         private final int oid;
135
136         private final String JavaDoc methodName;
137         /**
138          * Type name of the arguments to invoke. They are names because
139          * neither {@link Method} nor {@link Class} is serializable.
140          */

141         private final String JavaDoc[] types;
142         /**
143          * Arguments to invoke the method with.
144          */

145         private final Object JavaDoc[] arguments;
146
147         /**
148          * If this is used as {@link Callable}, we need to remember what classloader
149          * to be used to serialize the request and the response.
150          */

151         private transient ClassLoader JavaDoc classLoader;
152
153         public RPCRequest(int oid, Method JavaDoc m, Object JavaDoc[] arguments) {
154             this(oid,m,arguments,null);
155         }
156
157         public RPCRequest(int oid, Method JavaDoc m, Object JavaDoc[] arguments, ClassLoader JavaDoc cl) {
158             this.oid = oid;
159             this.arguments = arguments;
160             this.methodName = m.getName();
161             this.classLoader = cl;
162
163             this.types = new String JavaDoc[arguments.length];
164             Class JavaDoc<?>[] params = m.getParameterTypes();
165             for( int i=0; i<arguments.length; i++ )
166                 types[i] = params[i].getName();
167         }
168
169         public Serializable JavaDoc call() throws Throwable JavaDoc {
170             return perform(Channel.current());
171         }
172
173         public ClassLoader JavaDoc getClassLoader() {
174             if(classLoader!=null)
175                 return classLoader;
176             else
177                 return getClass().getClassLoader();
178         }
179
180         protected Serializable JavaDoc perform(Channel channel) throws Throwable JavaDoc {
181             Object JavaDoc o = channel.getExportedObject(oid);
182             if(o==null)
183                 throw new IllegalStateException JavaDoc("Unable to call "+methodName+". Invalid object ID "+oid);
184             try {
185                 Method JavaDoc m = choose(o);
186                 m.setAccessible(true); // in case the class is not public
187
return (Serializable JavaDoc) m.invoke(o,arguments);
188             } catch (InvocationTargetException JavaDoc e) {
189                 throw e.getTargetException();
190             }
191         }
192
193         /**
194          * Chooses the method to invoke.
195          */

196         private Method JavaDoc choose(Object JavaDoc o) {
197             OUTER:
198             for(Method JavaDoc m : o.getClass().getMethods()) {
199                 if(!m.getName().equals(methodName))
200                     continue;
201                 Class JavaDoc<?>[] paramTypes = m.getParameterTypes();
202                 if(types.length!=arguments.length)
203                     continue;
204                 for( int i=0; i<types.length; i++ ) {
205                     if(!types[i].equals(paramTypes[i].getName()))
206                         continue OUTER;
207                 }
208                 return m;
209             }
210             return null;
211         }
212
213         public String JavaDoc toString() {
214             return "RPCRequest("+oid+","+methodName+")";
215         }
216
217         private static final long serialVersionUID = 1L;
218     }
219
220     private static final Object JavaDoc[] EMPTY_ARRAY = new Object JavaDoc[0];
221 }
222
Popular Tags