KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > aspectwerkz > connectivity > RemoteProxy


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
3  */

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

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

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

40   private transient static Map JavaDoc s_instances = new WeakHashMap JavaDoc();
41
42   /**
43    * The server host address.
44    */

45   private final String JavaDoc m_address;
46
47   /**
48    * The server port.
49    */

50   private final int m_port;
51
52   /**
53    * The handle to the instance wrapped by this proxy.
54    */

55   private String JavaDoc m_handle = null;
56
57   /**
58    * The interface class for the wrapped instance.
59    */

60   private Class JavaDoc[] m_targetInterfaces = null;
61
62   /**
63    * The names of all the interfaces for the wrapped instance.
64    */

65   private String JavaDoc[] m_targetInterfaceNames = null;
66
67   /**
68    * The class name for the wrapped instance.
69    */

70   private String JavaDoc m_targetImplName = null;
71
72   /**
73    * The socket.
74    */

75   private transient Socket JavaDoc m_socket;
76
77   /**
78    * The input stream.
79    */

80   private transient ObjectInputStream JavaDoc m_in;
81
82   /**
83    * The output stream.
84    */

85   private transient ObjectOutputStream JavaDoc m_out;
86
87   /**
88    * The class loader to use.
89    */

90   private transient ClassLoader JavaDoc m_loader;
91
92   /**
93    * The client context.
94    */

95   private transient Object JavaDoc m_context = null;
96
97   /**
98    * The dynamic proxy instance to the wrapped instance.
99    */

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

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

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

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

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

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

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

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

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

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

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

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

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

373   public static String JavaDoc wrapInstance(final Object JavaDoc instance) {
374     final String JavaDoc handle = UuidGenerator.generate(instance);
375     s_instances.put(handle, instance);
376     return handle;
377   }
378 }
Popular Tags