KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > codehaus > aspectwerkz > connectivity > RemoteProxy


1 /**************************************************************************************
2  * Copyright (c) Jonas Bonér, Alexandre Vasseur. All rights reserved. *
3  * http://aspectwerkz.codehaus.org *
4  * ---------------------------------------------------------------------------------- *
5  * The software in this package is published under the terms of the LGPL license *
6  * a copy of which has been included with this distribution in the license.txt file. *
7  **************************************************************************************/

8 package org.codehaus.aspectwerkz.connectivity;
9
10 import org.codehaus.aspectwerkz.exception.WrappedRuntimeException;
11 import org.codehaus.aspectwerkz.util.UuidGenerator;
12
13 import java.io.IOException JavaDoc;
14 import java.io.ObjectInputStream JavaDoc;
15 import java.io.ObjectOutputStream JavaDoc;
16 import java.io.Serializable JavaDoc;
17 import java.lang.reflect.InvocationHandler JavaDoc;
18 import java.lang.reflect.Method JavaDoc;
19 import java.lang.reflect.Proxy JavaDoc;
20 import java.net.InetAddress JavaDoc;
21 import java.net.Socket JavaDoc;
22 import java.util.Map JavaDoc;
23 import java.util.WeakHashMap JavaDoc;
24
25 /**
26  * This class provides a general remote proxy. It uses the Dynamic Proxy mechanism that was introduced with JDK 1.3.
27  * <p/>The client proxy sends all requests to a server via a socket connection. The server returns results in the same
28  * way. Every object that is transferred (i.e. result of method invocation) has to support the Serializable interface.
29  *
30  * @author <a HREF="mailto:jboner@codehaus.org">Jonas Bonér </a>
31  */

32 public class RemoteProxy implements InvocationHandler JavaDoc, Serializable JavaDoc {
33     /**
34      * The serial version uid for the class.
35      *
36      * @TODO: recalculate
37      */

38     private static final long serialVersionUID = 1L;
39
40     /**
41      * All the instances that have been wrapped by a proxy. Maps each instance to its handle.
42      */

43     private transient static Map JavaDoc s_instances = new WeakHashMap JavaDoc();
44
45     /**
46      * The server host address.
47      */

48     private final String JavaDoc m_address;
49
50     /**
51      * The server port.
52      */

53     private final int m_port;
54
55     /**
56      * The handle to the instance wrapped by this proxy.
57      */

58     private String JavaDoc m_handle = null;
59
60     /**
61      * The interface class for the wrapped instance.
62      */

63     private Class JavaDoc[] m_targetInterfaces = null;
64
65     /**
66      * The names of all the interfaces for the wrapped instance.
67      */

68     private String JavaDoc[] m_targetInterfaceNames = null;
69
70     /**
71      * The class name for the wrapped instance.
72      */

73     private String JavaDoc m_targetImplName = null;
74
75     /**
76      * The socket.
77      */

78     private transient Socket JavaDoc m_socket;
79
80     /**
81      * The input stream.
82      */

83     private transient ObjectInputStream JavaDoc m_in;
84
85     /**
86      * The output stream.
87      */

88     private transient ObjectOutputStream JavaDoc m_out;
89
90     /**
91      * The class loader to use.
92      */

93     private transient ClassLoader JavaDoc m_loader;
94
95     /**
96      * The client context.
97      */

98     private transient Object JavaDoc m_context = null;
99
100     /**
101      * The dynamic proxy instance to the wrapped instance.
102      */

103     private transient Object JavaDoc m_proxy = null;
104
105     /**
106      * Creates a new proxy based on the interface and class names passes to it. For client-side use. This method is
107      * never called directly.
108      *
109      * @param interfaces the class name of the interface for the object to create the proxy for
110      * @param impl the class name of the the object to create the proxy for
111      * @param address the address to connect to.
112      * @param port the port to connect to.
113      * @param context the context carrying the users principal and credentials
114      * @param loader the class loader to use
115      */

116     private RemoteProxy(final String JavaDoc[] interfaces,
117                         final String JavaDoc impl,
118                         final String JavaDoc address,
119                         final int port,
120                         final Object JavaDoc context,
121                         final ClassLoader JavaDoc loader) {
122         if ((interfaces == null) || (interfaces.length == 0)) {
123             throw new IllegalArgumentException JavaDoc("at least one interface must be specified");
124         }
125         if (impl == null) {
126             throw new IllegalArgumentException JavaDoc("implementation class name can not be null");
127         }
128         if (address == null) {
129             throw new IllegalArgumentException JavaDoc("address can not be null");
130         }
131         if (port < 0) {
132             throw new IllegalArgumentException JavaDoc("port not valid");
133         }
134         m_targetInterfaceNames = interfaces;
135         m_targetImplName = impl;
136         m_address = address;
137         m_port = port;
138         m_context = context;
139         m_loader = loader;
140     }
141
142     /**
143      * Creates a new proxy based on the instance passed to it. For server-side use. This method is never called
144      * directly.
145      *
146      * @param targetInstance target instance to create the proxy for
147      * @param address the address to connect to.
148      * @param port the port to connect to.
149      */

150     private RemoteProxy(final Object JavaDoc targetInstance, final String JavaDoc address, final int port) {
151         if (targetInstance == null) {
152             throw new IllegalArgumentException JavaDoc("target instance can not be null");
153         }
154         if (address == null) {
155             throw new IllegalArgumentException JavaDoc("address can not be null");
156         }
157         if (port < 0) {
158             throw new IllegalArgumentException JavaDoc("port not valid");
159         }
160         m_targetInterfaces = targetInstance.getClass().getInterfaces();
161         m_address = address;
162         m_port = port;
163         m_handle = wrapInstance(targetInstance);
164     }
165
166     /**
167      * Creates a new proxy to a class. To be used on the client side to create a new proxy to an object.
168      *
169      * @param interfaces the class name of the interface for the object to create the proxy for
170      * @param impl the class name of the the object to create the proxy for
171      * @param address the address to connect to.
172      * @param port the port to connect to.
173      * @return the new remote proxy instance
174      */

175     public static RemoteProxy createClientProxy(final String JavaDoc[] interfaces,
176                                                 final String JavaDoc impl,
177                                                 final String JavaDoc address,
178                                                 final int port) {
179         return RemoteProxy.createClientProxy(
180                 interfaces, impl, address, port, Thread.currentThread()
181                                                  .getContextClassLoader()
182         );
183     }
184
185     /**
186      * Creates a new proxy to a class. To be used on the client side to create a new proxy to an object.
187      *
188      * @param interfaces the class name of the interface for the object to create the proxy for
189      * @param impl the class name of the the object to create the proxy for
190      * @param address the address to connect to.
191      * @param port the port to connect to.
192      * @param context the context carrying the users principal and credentials
193      * @return the new remote proxy instance
194      */

195     public static RemoteProxy createClientProxy(final String JavaDoc[] interfaces,
196                                                 final String JavaDoc impl,
197                                                 final String JavaDoc address,
198                                                 final int port,
199                                                 final Object JavaDoc context) {
200         return RemoteProxy.createClientProxy(
201                 interfaces, impl, address, port, context, Thread.currentThread()
202                                                           .getContextClassLoader()
203         );
204     }
205
206     /**
207      * Creates a new proxy to a class. To be used on the client side to create a new proxy to an object.
208      *
209      * @param interfaces the class name of the interface for the object to create the proxy for
210      * @param impl the class name of the the object to create the proxy for
211      * @param address the address to connect to.
212      * @param port the port to connect to.
213      * @param loader the class loader to use
214      * @return the new remote proxy instance
215      */

216     public static RemoteProxy createClientProxy(final String JavaDoc[] interfaces,
217                                                 final String JavaDoc impl,
218                                                 final String JavaDoc address,
219                                                 final int port,
220                                                 final ClassLoader JavaDoc loader) {
221         return RemoteProxy.createClientProxy(interfaces, impl, address, port, null, loader);
222     }
223
224     /**
225      * Creates a new proxy to a class. To be used on the client side to create a new proxy to an object.
226      *
227      * @param interfaces the class name of the interface for the object to create the proxy for
228      * @param impl the class name of the the object to create the proxy for
229      * @param address the address to connect to.
230      * @param port the port to connect to.
231      * @param ctx the context carrying the users principal and credentials
232      * @param loader the class loader to use
233      * @return the new remote proxy instance
234      */

235     public static RemoteProxy createClientProxy(final String JavaDoc[] interfaces,
236                                                 final String JavaDoc impl,
237                                                 final String JavaDoc address,
238                                                 final int port,
239                                                 final Object JavaDoc context,
240                                                 final ClassLoader JavaDoc loader) {
241         return new RemoteProxy(interfaces, impl, address, port, context, loader);
242     }
243
244     /**
245      * Creates a proxy to a specific <b>instance </b> in the on the server side. This proxy could then be passed to the
246      * client which can invoke method on this specific <b>instance </b>.
247      *
248      * @param the target instance to create the proxy for
249      * @param address the address to connect to.
250      * @param port the port to connect to.
251      * @return the new remote proxy instance
252      */

253     public static RemoteProxy createServerProxy(final Object JavaDoc targetlInstance, final String JavaDoc address, final int port) {
254         return new RemoteProxy(targetlInstance, address, port);
255     }
256
257     /**
258      * Look up and retrives a proxy to an object from the server.
259      *
260      * @param loader the classloader to use
261      * @return the proxy instance
262      */

263     public Object JavaDoc getInstance(final ClassLoader JavaDoc loader) {
264         m_loader = loader;
265         return getInstance();
266     }
267
268     /**
269      * Look up and retrives a proxy to an object from the server.
270      *
271      * @return the proxy instance
272      */

273     public Object JavaDoc getInstance() {
274         if (m_proxy != null) {
275             return m_proxy;
276         }
277         if (m_loader == null) {
278             m_loader = Thread.currentThread().getContextClassLoader();
279         }
280         try {
281             m_socket = new Socket JavaDoc(InetAddress.getByName(m_address), m_port);
282             m_socket.setTcpNoDelay(true);
283             m_out = new ObjectOutputStream JavaDoc(m_socket.getOutputStream());
284             m_in = new ObjectInputStream JavaDoc(m_socket.getInputStream());
285         } catch (Exception JavaDoc e) {
286             throw new WrappedRuntimeException(e);
287         }
288         if (m_handle == null) {
289             // is a client side proxy
290
if (m_targetInterfaceNames == null) {
291                 throw new IllegalStateException JavaDoc("interface class name can not be null");
292             }
293             if (m_targetImplName == null) {
294                 throw new IllegalStateException JavaDoc("implementation class name can not be null");
295             }
296             try {
297                 // create a new instance on the server and get the handle to it in return
298
m_out.write(Command.CREATE);
299                 m_out.writeObject(m_targetImplName);
300                 m_out.flush();
301                 m_handle = (String JavaDoc) m_in.readObject();
302                 m_targetInterfaces = new Class JavaDoc[m_targetInterfaceNames.length];
303                 for (int i = 0; i < m_targetInterfaceNames.length; i++) {
304                     try {
305                         m_targetInterfaces[i] = Class.forName(m_targetInterfaceNames[i], false, m_loader);
306                     } catch (ClassNotFoundException JavaDoc e) {
307                         throw new WrappedRuntimeException(e);
308                     }
309                 }
310             } catch (Exception JavaDoc e) {
311                 throw new WrappedRuntimeException(e);
312             }
313         }
314         m_proxy = Proxy.newProxyInstance(m_loader, m_targetInterfaces, this);
315         return m_proxy;
316     }
317
318     /**
319      * This method is invoked automatically by the proxy. Should not be called directly.
320      *
321      * @param proxy the proxy instance that the method was invoked on
322      * @param method the Method instance corresponding to the interface method invoked on the proxy instance.
323      * @param args an array of objects containing the values of the arguments passed in the method invocation on the
324      * proxy instance.
325      * @return the value to return from the method invocation on the proxy instance.
326      */

327     public Object JavaDoc invoke(final Object JavaDoc proxy, final Method JavaDoc method, final Object JavaDoc[] args) {
328         try {
329             m_out.write(Command.INVOKE);
330             m_out.writeObject(m_context);
331             m_out.writeObject(m_handle);
332             m_out.writeObject(method.getName());
333             m_out.writeObject(method.getParameterTypes());
334             m_out.writeObject(args);
335             m_out.flush();
336             final Object JavaDoc response = m_in.readObject();
337             if (response instanceof Exception JavaDoc) {
338                 throw (Exception JavaDoc) response;
339             }
340             return response;
341         } catch (Exception JavaDoc e) {
342             throw new WrappedRuntimeException(e);
343         }
344     }
345
346     /**
347      * Closes the proxy and the connection to the server.
348      */

349     public void close() {
350         try {
351             m_out.write(Command.CLOSE);
352             m_out.flush();
353             m_out.close();
354             m_in.close();
355             m_socket.close();
356         } catch (IOException JavaDoc e) {
357             throw new WrappedRuntimeException(e);
358         }
359     }
360
361     /**
362      * Returns a proxy wrapped instance by its handle.
363      *
364      * @param handle the handle
365      * @return the instance
366      */

367     public static Object JavaDoc getWrappedInstance(final String JavaDoc handle) {
368         return s_instances.get(handle);
369     }
370
371     /**
372      * Wraps a new instance and maps it to a handle.
373      *
374      * @param instance the instance to wrap
375      * @return the handle for the instance
376      */

377     public static String JavaDoc wrapInstance(final Object JavaDoc instance) {
378         final String JavaDoc handle = UuidGenerator.generate(instance);
379         s_instances.put(handle, instance);
380         return handle;
381     }
382 }
Popular Tags