KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > hessian > client > HessianProxyFactory


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in
15  * the documentation and/or other materials provided with the
16  * distribution.
17  *
18  * 3. The end-user documentation included with the redistribution, if
19  * any, must include the following acknowlegement:
20  * "This product includes software developed by the
21  * Caucho Technology (http://www.caucho.com/)."
22  * Alternately, this acknowlegement may appear in the software itself,
23  * if and wherever such third-party acknowlegements normally appear.
24  *
25  * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
26  * endorse or promote products derived from this software without prior
27  * written permission. For written permission, please contact
28  * info@caucho.com.
29  *
30  * 5. Products derived from this software may not be called "Resin"
31  * nor may "Resin" appear in their names without prior written
32  * permission of Caucho Technology.
33  *
34  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
35  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
36  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
37  * DISCLAIMED. IN NO EVENT SHALL CAUCHO TECHNOLOGY OR ITS CONTRIBUTORS
38  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
39  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
40  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
41  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
42  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
43  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
44  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45  *
46  * @author Scott Ferguson
47  */

48
49 package com.caucho.hessian.client;
50
51 import com.caucho.hessian.io.*;
52 import com.caucho.services.client.ServiceProxyFactory;
53
54 import javax.naming.Context JavaDoc;
55 import javax.naming.Name JavaDoc;
56 import javax.naming.NamingException JavaDoc;
57 import javax.naming.RefAddr JavaDoc;
58 import javax.naming.Reference JavaDoc;
59 import javax.naming.spi.ObjectFactory JavaDoc;
60 import java.io.IOException JavaDoc;
61 import java.io.InputStream JavaDoc;
62 import java.io.OutputStream JavaDoc;
63 import java.io.PrintWriter JavaDoc;
64 import java.lang.reflect.InvocationHandler JavaDoc;
65 import java.lang.reflect.Proxy JavaDoc;
66 import java.net.MalformedURLException JavaDoc;
67 import java.net.URL JavaDoc;
68 import java.net.URLConnection JavaDoc;
69 import java.util.Hashtable JavaDoc;
70 import java.util.logging.Logger JavaDoc;
71
72 /**
73  * Factory for creating Hessian client stubs. The returned stub will
74  * call the remote object for all methods.
75  *
76  * <pre>
77  * String url = "http://localhost:8080/ejb/hello";
78  * HelloHome hello = (HelloHome) factory.create(HelloHome.class, url);
79  * </pre>
80  *
81  * After creation, the stub can be like a regular Java class. Because
82  * it makes remote calls, it can throw more exceptions than a Java class.
83  * In particular, it may throw protocol exceptions.
84  *
85  * The factory can also be configured as a JNDI resource. The factory
86  * expects to parameters: "type" and "url", corresponding to the two
87  * arguments to <code>create</code>
88  *
89  * In Resin 3.0, the above example would be configured as:
90  * <pre>
91  * &lt;reference>
92  * &lt;jndi-name>hessian/hello&lt;/jndi-name>
93  * &lt;factory>com.caucho.hessian.client.HessianProxyFactory&lt;/factory>
94  * &lt;init-param url="http://localhost:8080/ejb/hello"/>
95  * &lt;init-param type="test.HelloHome"/>
96  * &lt;/reference>
97  * </pre>
98  *
99  * To get the above resource, use JNDI as follows:
100  * <pre>
101  * Context ic = new InitialContext();
102  * HelloHome hello = (HelloHome) ic.lookup("java:comp/env/hessian/hello");
103  *
104  * System.out.println("Hello: " + hello.helloWorld());
105  * </pre>
106  *
107  * <h3>Authentication</h3>
108  *
109  * <p>The proxy can use HTTP basic authentication if the user and the
110  * password are set.
111  */

112 public class HessianProxyFactory implements ServiceProxyFactory, ObjectFactory JavaDoc {
113   protected static Logger JavaDoc log
114     = Logger.getLogger(HessianProxyFactory.class.getName());
115
116   private SerializerFactory _serializerFactory;
117   private HessianRemoteResolver _resolver;
118   
119   private String JavaDoc _user;
120   private String JavaDoc _password;
121   private String JavaDoc _basicAuth;
122
123   private boolean _isOverloadEnabled = false;
124
125   private boolean _isHessian2Reply = false;
126   private boolean _isHessian2Request = false;
127
128   private boolean _isChunkedPost = false;
129   private boolean _isDebug = false;
130
131   private long _readTimeout = -1;
132
133   private String JavaDoc _connectionFactoryName = "jms/ConnectionFactory";
134
135   /**
136    * Creates the new proxy factory.
137    */

138   public HessianProxyFactory()
139   {
140     _resolver = new HessianProxyResolver(this);
141   }
142
143   /**
144    * Sets the user.
145    */

146   public void setUser(String JavaDoc user)
147   {
148     _user = user;
149     _basicAuth = null;
150   }
151
152   /**
153    * Sets the password.
154    */

155   public void setPassword(String JavaDoc password)
156   {
157     _password = password;
158     _basicAuth = null;
159   }
160
161   /**
162    * Sets the name of the connection factory to use when connecting
163    * to JMS Hessian services.
164    */

165   public void setConnectionFactoryName(String JavaDoc connectionFactoryName)
166   {
167     _connectionFactoryName = connectionFactoryName;
168   }
169
170   /**
171    * Sets the debug
172    */

173   public void setDebug(boolean isDebug)
174   {
175     _isDebug = isDebug;
176   }
177
178   /**
179    * Gets the debug
180    */

181   public boolean isDebug()
182   {
183     return _isDebug;
184   }
185
186   /**
187    * Returns true if overloaded methods are allowed (using mangling)
188    */

189   public boolean isOverloadEnabled()
190   {
191     return _isOverloadEnabled;
192   }
193
194   /**
195    * set true if overloaded methods are allowed (using mangling)
196    */

197   public void setOverloadEnabled(boolean isOverloadEnabled)
198   {
199     _isOverloadEnabled = isOverloadEnabled;
200   }
201
202   /**
203    * Set true if should use chunked encoding on the request.
204    */

205   public void setChunkedPost(boolean isChunked)
206   {
207     _isChunkedPost = isChunked;
208   }
209
210   /**
211    * Set true if should use chunked encoding on the request.
212    */

213   public boolean isChunkedPost()
214   {
215     return _isChunkedPost;
216   }
217
218   /**
219    * The socket timeout on requests in milliseconds.
220    */

221   public long getReadTimeout()
222   {
223     return _readTimeout;
224   }
225
226   /**
227    * The socket timeout on requests in milliseconds.
228    */

229   public void setReadTimeout(long timeout)
230   {
231     _readTimeout = timeout;
232   }
233
234   /**
235    * True if the proxy can read Hessian 2 responses.
236    */

237   public void setHessian2Reply(boolean isHessian2)
238   {
239     _isHessian2Reply = isHessian2;
240   }
241
242   /**
243    * True if the proxy should send Hessian 2 requests.
244    */

245   public void setHessian2Request(boolean isHessian2)
246   {
247     _isHessian2Request = isHessian2;
248
249     if (isHessian2)
250       _isHessian2Reply = true;
251   }
252
253   /**
254    * Returns the remote resolver.
255    */

256   public HessianRemoteResolver getRemoteResolver()
257   {
258     return _resolver;
259   }
260
261   /**
262    * Sets the serializer factory.
263    */

264   public void setSerializerFactory(SerializerFactory factory)
265   {
266     _serializerFactory = factory;
267   }
268
269   /**
270    * Gets the serializer factory.
271    */

272   public SerializerFactory getSerializerFactory()
273   {
274     if (_serializerFactory == null)
275       _serializerFactory = new SerializerFactory();
276     
277     return _serializerFactory;
278   }
279
280   /**
281    * Creates the URL connection.
282    */

283   protected URLConnection JavaDoc openConnection(URL JavaDoc url)
284     throws IOException JavaDoc
285   {
286     URLConnection JavaDoc conn = url.openConnection();
287
288     conn.setDoOutput(true);
289
290     if (_readTimeout > 0) {
291       try {
292     conn.setReadTimeout((int) _readTimeout);
293       } catch (Throwable JavaDoc e) {
294       }
295     }
296
297     conn.setRequestProperty("Content-Type", "x-application/hessian");
298
299     if (_basicAuth != null)
300       conn.setRequestProperty("Authorization", _basicAuth);
301     else if (_user != null && _password != null) {
302       _basicAuth = "Basic " + base64(_user + ":" + _password);
303       conn.setRequestProperty("Authorization", _basicAuth);
304     }
305
306     return conn;
307   }
308
309   /**
310    * Creates a new proxy with the specified URL. The API class uses
311    * the java.api.class value from _hessian_
312    *
313    * @param url the URL where the client object is located.
314    *
315    * @return a proxy to the object with the specified interface.
316    */

317   public Object JavaDoc create(String JavaDoc url)
318     throws MalformedURLException JavaDoc, ClassNotFoundException JavaDoc
319   {
320     HessianMetaInfoAPI metaInfo;
321
322     metaInfo = (HessianMetaInfoAPI) create(HessianMetaInfoAPI.class, url);
323
324     String JavaDoc apiClassName =
325       (String JavaDoc) metaInfo._hessian_getAttribute("java.api.class");
326
327     if (apiClassName == null)
328       throw new HessianRuntimeException(url + " has an unknown api.");
329
330     ClassLoader JavaDoc loader = Thread.currentThread().getContextClassLoader();
331
332     Class JavaDoc apiClass = Class.forName(apiClassName, false, loader);
333
334     return create(apiClass, url);
335   }
336
337   /**
338    * Creates a new proxy with the specified URL. The returned object
339    * is a proxy with the interface specified by api.
340    *
341    * <pre>
342    * String url = "http://localhost:8080/ejb/hello");
343    * HelloHome hello = (HelloHome) factory.create(HelloHome.class, url);
344    * </pre>
345    *
346    * @param api the interface the proxy class needs to implement
347    * @param url the URL where the client object is located.
348    *
349    * @return a proxy to the object with the specified interface.
350    */

351   public Object JavaDoc create(Class JavaDoc api, String JavaDoc urlName)
352     throws MalformedURLException JavaDoc
353   {
354     return create(api, urlName,
355           Thread.currentThread().getContextClassLoader());
356   }
357
358   /**
359    * Creates a new proxy with the specified URL. The returned object
360    * is a proxy with the interface specified by api.
361    *
362    * <pre>
363    * String url = "http://localhost:8080/ejb/hello");
364    * HelloHome hello = (HelloHome) factory.create(HelloHome.class, url);
365    * </pre>
366    *
367    * @param api the interface the proxy class needs to implement
368    * @param url the URL where the client object is located.
369    *
370    * @return a proxy to the object with the specified interface.
371    */

372   public Object JavaDoc create(Class JavaDoc api, String JavaDoc urlName, ClassLoader JavaDoc loader)
373     throws MalformedURLException JavaDoc
374   {
375     InvocationHandler JavaDoc handler = null;
376
377     if (urlName.startsWith("jms:")) {
378       String JavaDoc jndiName = urlName.substring("jms:".length());
379
380       try {
381         handler = new HessianJMSProxy(this, jndiName, _connectionFactoryName);
382       } catch (Exception JavaDoc e) {
383         log.info("Unable to create JMS proxy: " + e);
384         return null;
385       }
386     }
387     else {
388       URL JavaDoc url = new URL JavaDoc(urlName);
389       handler = new HessianProxy(this, url);
390     }
391
392     return Proxy.newProxyInstance(api.getClassLoader(),
393                                   new Class JavaDoc[] { api,
394                                                 HessianRemoteObject.class },
395                                   handler);
396   }
397
398   public AbstractHessianInput getHessianInput(InputStream JavaDoc is)
399   {
400     AbstractHessianInput in;
401
402     if (_isDebug)
403       is = new HessianDebugInputStream(is, new PrintWriter JavaDoc(System.out));
404
405     if (_isHessian2Reply)
406       in = new Hessian2Input(is);
407     else
408       in = new HessianInput(is);
409     
410     in.setRemoteResolver(getRemoteResolver());
411
412     in.setSerializerFactory(getSerializerFactory());
413
414     return in;
415   }
416
417   public AbstractHessianOutput getHessianOutput(OutputStream JavaDoc os)
418   {
419     AbstractHessianOutput out;
420
421     if (_isHessian2Request)
422       out = new Hessian2Output(os);
423     else {
424       HessianOutput out1 = new HessianOutput(os);
425       out = out1;
426
427       if (_isHessian2Reply)
428         out1.setVersion(2);
429     }
430       
431     out.setSerializerFactory(getSerializerFactory());
432
433     return out;
434   }
435
436   /**
437    * JNDI object factory so the proxy can be used as a resource.
438    */

439   public Object JavaDoc getObjectInstance(Object JavaDoc obj, Name JavaDoc name,
440                                   Context JavaDoc nameCtx, Hashtable JavaDoc<?,?> environment)
441     throws Exception JavaDoc
442   {
443     Reference JavaDoc ref = (Reference JavaDoc) obj;
444
445     String JavaDoc api = null;
446     String JavaDoc url = null;
447     String JavaDoc user = null;
448     String JavaDoc password = null;
449
450     for (int i = 0; i < ref.size(); i++) {
451       RefAddr JavaDoc addr = ref.get(i);
452
453       String JavaDoc type = addr.getType();
454       String JavaDoc value = (String JavaDoc) addr.getContent();
455
456       if (type.equals("type"))
457     api = value;
458       else if (type.equals("url"))
459     url = value;
460       else if (type.equals("user"))
461     setUser(value);
462       else if (type.equals("password"))
463     setPassword(value);
464     }
465
466     if (url == null)
467       throw new NamingException JavaDoc("`url' must be configured for HessianProxyFactory.");
468     // XXX: could use meta protocol to grab this
469
if (api == null)
470       throw new NamingException JavaDoc("`type' must be configured for HessianProxyFactory.");
471
472     ClassLoader JavaDoc loader = Thread.currentThread().getContextClassLoader();
473     Class JavaDoc apiClass = Class.forName(api, false, loader);
474
475     return create(apiClass, url);
476   }
477
478   /**
479    * Creates the Base64 value.
480    */

481   private String JavaDoc base64(String JavaDoc value)
482   {
483     StringBuffer JavaDoc cb = new StringBuffer JavaDoc();
484
485     int i = 0;
486     for (i = 0; i + 2 < value.length(); i += 3) {
487       long chunk = (int) value.charAt(i);
488       chunk = (chunk << 8) + (int) value.charAt(i + 1);
489       chunk = (chunk << 8) + (int) value.charAt(i + 2);
490         
491       cb.append(encode(chunk >> 18));
492       cb.append(encode(chunk >> 12));
493       cb.append(encode(chunk >> 6));
494       cb.append(encode(chunk));
495     }
496     
497     if (i + 1 < value.length()) {
498       long chunk = (int) value.charAt(i);
499       chunk = (chunk << 8) + (int) value.charAt(i + 1);
500       chunk <<= 8;
501
502       cb.append(encode(chunk >> 18));
503       cb.append(encode(chunk >> 12));
504       cb.append(encode(chunk >> 6));
505       cb.append('=');
506     }
507     else if (i < value.length()) {
508       long chunk = (int) value.charAt(i);
509       chunk <<= 16;
510
511       cb.append(encode(chunk >> 18));
512       cb.append(encode(chunk >> 12));
513       cb.append('=');
514       cb.append('=');
515     }
516
517     return cb.toString();
518   }
519
520   public static char encode(long d)
521   {
522     d &= 0x3f;
523     if (d < 26)
524       return (char) (d + 'A');
525     else if (d < 52)
526       return (char) (d + 'a' - 26);
527     else if (d < 62)
528       return (char) (d + '0' - 52);
529     else if (d == 62)
530       return '+';
531     else
532       return '/';
533   }
534 }
535
536
Popular Tags