KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xmlrpc > XmlRpcClient


1 /*
2  * Copyright 1999,2005 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17
18 package org.apache.xmlrpc;
19
20 import java.io.IOException JavaDoc;
21 import java.net.MalformedURLException JavaDoc;
22 import java.net.URL JavaDoc;
23 import java.util.EmptyStackException JavaDoc;
24 import java.util.Stack JavaDoc;
25 import java.util.Vector JavaDoc;
26
27 /**
28  * A multithreaded, reusable XML-RPC client object. Use this if you
29  * need a full-grown HTTP client (e.g. for Proxy and Basic Auth
30  * support). If you don't need that, <code>XmlRpcClientLite</code> may
31  * work better for you.
32  *
33  * @author <a HREF="mailto:hannes@apache.org">Hannes Wallnoefer</a>
34  * @author <a HREF="mailto:andrew@kungfoocoder.org">Andrew Evers</a>
35  * @author <a HREF="mailto:rhoegg@isisnetworks.net">Ryan Hoegg</a>
36  * @version $Id: XmlRpcClient.java,v 1.22 2005/04/22 10:25:57 hgomez Exp $
37  */

38 public class XmlRpcClient implements XmlRpcHandler
39 {
40     protected URL JavaDoc url;
41     
42     // stored user and password for deprecated setBasicAuthentication method
43
private String JavaDoc storedUser;
44     private String JavaDoc storedPassword;
45
46     // pool of worker instances
47
protected Stack JavaDoc pool = new Stack JavaDoc();
48     protected int workers = 0;
49     protected int asyncWorkers = 0;
50     protected XmlRpcTransportFactory transportFactory;
51
52     // a queue of calls to be handled asynchronously
53
private CallData first, last;
54
55     /**
56      * The maximum number of threads which can be used concurrently, by defaut use the one defined
57      * in XmlRpc
58      */

59     private int maxThreads = -1;
60
61     
62     /**
63      * Construct a XML-RPC client with this URL and a specified transport
64      * factory.
65      */

66     public XmlRpcClient(URL JavaDoc url, XmlRpcTransportFactory transportFactory)
67     {
68        this.url = url;
69        this.transportFactory = transportFactory;
70     }
71
72     /**
73      * Construct a XML-RPC client with this URL.
74      */

75     public XmlRpcClient(URL JavaDoc url)
76     {
77         this.url = url;
78         if (XmlRpc.debug)
79         {
80             System.out.println("Created client to url space " + url);
81         }
82     }
83
84     /**
85      * Construct a XML-RPC client for the URL represented by this String.
86      */

87     public XmlRpcClient(String JavaDoc url) throws MalformedURLException JavaDoc
88     {
89         this(new URL JavaDoc(url));
90     }
91
92     /**
93      * Construct a XML-RPC client for the specified hostname and port.
94      */

95     public XmlRpcClient(String JavaDoc hostname, int port) throws MalformedURLException JavaDoc
96     {
97         this(new URL JavaDoc("http://" + hostname + ':' + port + "/RPC2"));
98     }
99
100     /**
101      * Set the MaxThreads for this Client
102      */

103     public void setMaxThreads(int maxThreads)
104     {
105         this.maxThreads = maxThreads;
106     }
107     
108     /**
109      * Get the MaxThreads for this Client
110      */

111     public int getMaxThreads()
112     {
113         if (maxThreads == -1)
114             return (XmlRpc.getMaxThreads());
115         
116         return (maxThreads);
117     }
118     
119     /**
120      * Return the URL for this XML-RPC client.
121      */

122     public URL JavaDoc getURL()
123     {
124         return url;
125     }
126
127     /**
128      * Sets Authentication for this client. This will be sent as Basic
129      * Authentication header to the server as described in
130      * <a HREF="http://www.ietf.org/rfc/rfc2617.txt">
131      * http://www.ietf.org/rfc/rfc2617.txt</a>.
132      *
133      * This method has been deprecated. Furthermore, it has no
134      * effect on the overloads for execute and executeAsync that
135      * use an XmlRpcClientRequest or an XmlRpcTransport.
136      *
137      * @deprecated Authentication is now handled by each XmlRpcTransport
138      *
139      * @see DefaultXmlRpcTransport
140      * @see LiteXmlRpcTransport
141      * @see CommonsXmlRpcTransport
142      */

143     public void setBasicAuthentication(String JavaDoc user, String JavaDoc password)
144     {
145         /*
146          * Store for use in execute and executeAsync
147          *
148          * Will be unnecessary once this method is removed.
149          */

150         storedUser = user;
151         storedPassword = password;
152     }
153
154     /**
155      * Generate an XML-RPC request and send it to the server. Parse the result
156      * and return the corresponding Java object.
157      *
158      * @exception XmlRpcException: If the remote host returned a fault message.
159      * @exception IOException: If the call could not be made because of lower
160      * level problems.
161      */

162     public Object JavaDoc execute(String JavaDoc method, Vector JavaDoc params)
163             throws XmlRpcException, IOException JavaDoc
164     {
165         /* Setting user and password on transport if setBasicAuthentication was
166          * used and there is no XmlRpcTransportFactory. As setBasicAuthentication
167          * is deprecated, this should be removed in a future version.
168          */

169         if ((storedUser != null) && (storedPassword != null) && (transportFactory == null))
170         {
171             DefaultXmlRpcTransport transport = createDefaultTransport();
172             transport.setBasicAuthentication(storedUser, storedPassword);
173             return execute(new XmlRpcRequest(method, params), transport);
174         }
175         else
176         {
177             return execute(new XmlRpcRequest(method, params));
178         }
179     }
180
181     public Object JavaDoc execute(XmlRpcClientRequest request)
182             throws XmlRpcException, IOException JavaDoc
183     {
184         return execute(request, createTransport());
185     }
186
187     public Object JavaDoc execute(XmlRpcClientRequest request, XmlRpcTransport transport)
188             throws XmlRpcException, IOException JavaDoc
189     {
190         XmlRpcClientWorker worker = getWorker(false);
191         try
192         {
193             Object JavaDoc retval = worker.execute(request, transport);
194             return retval;
195         }
196         finally
197         {
198             releaseWorker(worker, false);
199         }
200     }
201     /**
202      * Generate an XML-RPC request and send it to the server in a new thread.
203      * This method returns immediately.
204      * If the callback parameter is not null, it will be called later to handle
205      * the result or error when the call is finished.
206      */

207     public void executeAsync(String JavaDoc method, Vector JavaDoc params,
208             AsyncCallback callback)
209     {
210         XmlRpcRequest request = new XmlRpcRequest(method, params);
211         if ((storedUser != null) && (storedPassword != null) && (transportFactory == null))
212         {
213             DefaultXmlRpcTransport transport = createDefaultTransport();
214             transport.setBasicAuthentication(storedUser, storedPassword);
215             executeAsync(request, callback, transport);
216         }
217         else
218         {
219             executeAsync(request, callback);
220         }
221     }
222
223     public void executeAsync(XmlRpcClientRequest request,
224             AsyncCallback callback)
225     {
226         executeAsync(request, callback, null);
227     }
228
229     public void executeAsync(XmlRpcClientRequest request,
230             AsyncCallback callback, XmlRpcTransport transport)
231     {
232         CallData call = new CallData(request, callback, transport);
233
234         // if at least 4 threads are running, don't create any new ones,
235
// just enqueue the request.
236
if (asyncWorkers >= 4)
237         {
238             enqueue(call);
239             return;
240         }
241         XmlRpcClientWorker worker = null;
242         try
243         {
244             new XmlRpcClientAsyncThread(getWorker(true), call).start();
245         }
246         catch(IOException JavaDoc iox)
247         {
248             // make a queued worker that doesn't run immediately
249
enqueue(call);
250         }
251     }
252
253     class XmlRpcClientAsyncThread extends Thread JavaDoc
254     {
255         protected XmlRpcClientWorker worker;
256         protected CallData call;
257
258         protected XmlRpcClientAsyncThread(XmlRpcClientWorker worker, CallData initialCall)
259         {
260            this.worker = worker;
261            this.call = initialCall;
262         }
263
264         public void run()
265         {
266             try
267             {
268                 while (call != null)
269                 {
270                     call = dequeue();
271                     executeAsync(call.request, call.callback, call.transport);
272                 }
273             }
274             finally
275             {
276                 releaseWorker(worker, true);
277             }
278         }
279
280         /**
281          * Execute an XML-RPC call and handle asyncronous callback.
282          */

283         void executeAsync(XmlRpcClientRequest request, AsyncCallback callback, XmlRpcTransport transport)
284         {
285             Object JavaDoc res = null;
286             try
287             {
288                 if (transport == null)
289                 {
290                     transport = createTransport();
291                 }
292                 res = worker.execute(request, transport);
293                 // notify callback object
294
if (callback != null)
295                 {
296                     callback.handleResult(res, url, request.getMethodName());
297                 }
298             }
299             catch(Exception JavaDoc x)
300             {
301                 if (callback != null)
302                 {
303                     try
304                     {
305                         callback.handleError(x, url, request.getMethodName());
306                     }
307                     catch(Exception JavaDoc ignore)
308                     {
309                     }
310                 }
311             }
312         }
313     }
314     /**
315      *
316      * @param async
317      * @return
318      * @throws IOException
319      */

320     synchronized XmlRpcClientWorker getWorker(boolean async) throws IOException JavaDoc
321     {
322         try
323         {
324             XmlRpcClientWorker w = (XmlRpcClientWorker) pool.pop();
325             if (async)
326             {
327                 asyncWorkers += 1;
328             }
329             else
330             {
331                 workers += 1;
332             }
333             return w;
334         }
335         catch(EmptyStackException JavaDoc x)
336         {
337             if (workers < getMaxThreads())
338             {
339                 if (async)
340                 {
341                     asyncWorkers += 1;
342                 }
343                 else
344                 {
345                     workers += 1;
346                 }
347                 return new XmlRpcClientWorker();
348             }
349             throw new IOException JavaDoc("XML-RPC System overload");
350         }
351     }
352
353     /**
354      * Release possibly big per-call object references to allow them to be
355      * garbage collected
356      */

357     synchronized void releaseWorker(XmlRpcClientWorker w, boolean async)
358     {
359         if (pool.size() < 20)
360         {
361             pool.push(w);
362         }
363         if (async)
364         {
365             asyncWorkers -= 1;
366         }
367         else
368         {
369             workers -= 1;
370         }
371     }
372
373     /**
374      *
375      * @param method
376      * @param params
377      * @param callback
378      */

379     synchronized void enqueue(CallData call)
380     {
381         if (last == null)
382         {
383             first = last = call;
384         }
385         else
386         {
387             last.next = call;
388             last = call;
389         }
390     }
391
392     /**
393      *
394      * @return
395      */

396     synchronized CallData dequeue()
397     {
398         if (first == null)
399         {
400             return null;
401         }
402         CallData call = first;
403         if (first == last)
404         {
405             first = last = null;
406         }
407         else
408         {
409             first = first.next;
410         }
411         return call;
412     }
413
414     class CallData
415     {
416         XmlRpcClientRequest request;
417         XmlRpcTransport transport;
418         AsyncCallback callback;
419         CallData next;
420
421         /**
422          * Make a call to be queued and then executed by the next free async
423          * thread
424          */

425         public CallData(XmlRpcClientRequest request, AsyncCallback callback, XmlRpcTransport transport)
426         {
427             this.request = request;
428             this.callback = callback;
429             this.transport = transport;
430             this.next = null;
431         }
432     }
433
434     protected XmlRpcTransport createTransport() throws XmlRpcClientException
435     {
436         if (transportFactory == null)
437         {
438           return createDefaultTransport();
439         }
440         return transportFactory.createTransport();
441     }
442     
443     private DefaultXmlRpcTransport createDefaultTransport() {
444         return new DefaultXmlRpcTransport(url);
445     }
446
447     /**
448      * Just for testing.
449      */

450     public static void main(String JavaDoc args[]) throws Exception JavaDoc
451     {
452         // XmlRpc.setDebug(true);
453
// XmlRpc.setKeepAlive(true);
454
try
455         {
456             String JavaDoc url = args[0];
457             String JavaDoc method = args[1];
458             Vector JavaDoc v = new Vector JavaDoc();
459             for (int i = 2; i < args.length; i++)
460             {
461                 try
462                 {
463                     v.addElement(new Integer JavaDoc(Integer.parseInt(args[i])));
464                 }
465                 catch(NumberFormatException JavaDoc nfx)
466                 {
467                     v.addElement(args[i]);
468                 }
469             }
470             XmlRpcClient client = new XmlRpcClient(url);
471             try
472             {
473                 System.out.println(client.execute(method, v));
474             }
475             catch(Exception JavaDoc ex)
476             {
477                 System.err.println("Error: " + ex.getMessage());
478             }
479         }
480         catch(Exception JavaDoc x)
481         {
482             System.err.println(x);
483             System.err.println("Usage: java org.apache.xmlrpc.XmlRpcClient "
484                     + "<url> <method> <arg> ....");
485             System.err.println("Arguments are sent as integers or strings.");
486         }
487     }
488 }
489
Popular Tags