KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > turbine > services > xmlrpc > TurbineXmlRpcService


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

18
19 import java.io.InputStream JavaDoc;
20 import java.net.InetAddress JavaDoc;
21 import java.net.Socket JavaDoc;
22 import java.net.URL JavaDoc;
23 import java.net.UnknownHostException JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.List JavaDoc;
26 import java.util.Vector JavaDoc;
27
28 import javax.servlet.ServletConfig JavaDoc;
29
30 import org.apache.commons.configuration.Configuration;
31 import org.apache.commons.lang.StringUtils;
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34
35 import org.apache.xerces.parsers.SAXParser;
36 import org.apache.xmlrpc.WebServer;
37 import org.apache.xmlrpc.XmlRpc;
38 import org.apache.xmlrpc.XmlRpcClient;
39 import org.apache.xmlrpc.XmlRpcServer;
40 import org.apache.xmlrpc.secure.SecureWebServer;
41
42 import org.apache.turbine.services.InitializationException;
43 import org.apache.turbine.services.TurbineBaseService;
44 import org.apache.turbine.services.xmlrpc.util.FileTransfer;
45 import org.apache.turbine.util.TurbineException;
46
47 /**
48  * This is a service which will make an xml-rpc call to a remote
49  * server.
50  *
51  * Here's an example of how it would be done:
52  * <blockquote><code><pre>
53  * XmlRpcService xs =
54  * (XmlRpcService)TurbineServices.getInstance()
55  * .getService(XmlRpcService.XMLRPC_SERVICE_NAME);
56  * Vector vec = new Vector();
57  * vec.addElement(new Integer(5));
58  * URL url = new URL("http://betty.userland.com/RPC2");
59  * String name = (String)xs.executeRpc(url, "examples.getStateName", vec);
60  * </pre></code></blockquote>
61  *
62  * <p>TODO: Handle XmlRpc.setDebug(boolean)</p>
63  *
64  * @author <a HREF="mailto:josh@stonecottage.com">Josh Lucas</a>
65  * @author <a HREF="mailto:magnus@handtolvur.is">Magnús Þór Torfason</a>
66  * @author <a HREF="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
67  * @author <a HREF="mailto:jvanzyl@periapt.com">Jason van Zyl</a>
68  * @author <a HREF="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
69  * @author <a HREF="mailto:mpoeschl@marmot.at">Martin Poeschl</a>
70  * @author <a HREF="mailto:quintonm@bellsouth.net">Quinton McCombs</a>
71  * @version $Id: TurbineXmlRpcService.java,v 1.20.2.3 2004/08/16 22:57:49 henning Exp $
72  */

73 public class TurbineXmlRpcService
74         extends TurbineBaseService
75         implements XmlRpcService
76 {
77     /** Logging */
78     private static Log log = LogFactory.getLog(TurbineXmlRpcService.class);
79
80     /**
81      * Whether a version of Apache's XML-RPC library greater than 1.1
82      * is available.
83      */

84     protected boolean isModernVersion = false;
85
86     /** The standalone xmlrpc server. */
87     protected WebServer webserver = null;
88
89     /** The encapsulated xmlrpc server. */
90     protected XmlRpcServer server = null;
91
92     /**
93      * The address to listen on. The default of <code>null</code>
94      * indicates all network interfaces on a multi-homed host.
95      */

96     private InetAddress JavaDoc address = null;
97
98     /** The port to listen on. */
99     protected int port = 0;
100
101     /**
102      * This function initializes the XmlRpcService.This is
103      * a zero parameter variant which queries the Turbine Servlet
104      * for its config.
105      *
106      * @throws InitializationException Something went wrong in the init
107      * stage
108      */

109     public void init()
110             throws InitializationException
111     {
112         Configuration conf = getConfiguration();
113
114         try
115         {
116             server = new XmlRpcServer();
117
118             // setup JSSE System properties from secure.server.options
119
Configuration secureServerOptions =
120                     conf.subset("secure.server.option");
121
122             if (secureServerOptions != null)
123             {
124                 setSystemPropertiesFromConfiguration(secureServerOptions);
125             }
126
127             // Host and port information for the WebServer
128
String JavaDoc addr = conf.getString("address", "0.0.0.0");
129             port = conf.getInt("port", 0);
130
131             if (port != 0)
132             {
133                 if (addr != null && addr.length() > 0)
134                 {
135                     try
136                     {
137                         address = InetAddress.getByName(addr);
138                     }
139                     catch (UnknownHostException JavaDoc useDefault)
140                     {
141                         address = null;
142                     }
143                 }
144
145                 log.debug("Port: " + port + ", Address: " + address);
146
147                 if (conf.getBoolean("secure.server", false))
148                 {
149                     webserver = new SecureWebServer(port, address);
150                 }
151                 else
152                 {
153                     webserver = new WebServer(port, address);
154                 }
155             }
156
157             // Set the XML driver to the correct SAX parser class
158
String JavaDoc saxParserClass =
159                     conf.getString("parser", SAXParser.class.getName());
160
161             XmlRpc.setDriver(saxParserClass);
162
163             // Check if there are any handlers to register at startup
164
for (Iterator JavaDoc keys = conf.getKeys("handler"); keys.hasNext();)
165             {
166                 String JavaDoc handler = (String JavaDoc) keys.next();
167                 String JavaDoc handlerName = handler.substring(handler.indexOf('.')+1);
168                 String JavaDoc handlerClass = conf.getString(handler);
169
170                 log.debug("Found Handler " + handler + " as " + handlerName + " / " + handlerClass);
171
172                 registerHandler(handlerName, handlerClass);
173             }
174
175             // Turn on paranoia for the webserver if requested.
176
boolean stateOfParanoia =
177                     conf.getBoolean("paranoid", false);
178
179             if (stateOfParanoia)
180             {
181                 webserver.setParanoid(stateOfParanoia);
182                 log.info(XmlRpcService.SERVICE_NAME +
183                         ": Operating in a state of paranoia");
184
185                 // Only set the accept/deny client lists if we
186
// are in a state of paranoia as they will just
187
// be ignored so there's no point in setting them.
188

189                 // Set the list of clients that can connect
190
// to the xmlrpc server. The accepted client list
191
// will only be consulted if we are paranoid.
192
List JavaDoc acceptedClients =
193                         conf.getList("acceptClient");
194
195                 for (int i = 0; i < acceptedClients.size(); i++)
196                 {
197                     String JavaDoc acceptClient = (String JavaDoc) acceptedClients.get(i);
198
199                     if (StringUtils.isNotEmpty(acceptClient))
200                     {
201                         webserver.acceptClient(acceptClient);
202                         log.info(XmlRpcService.SERVICE_NAME +
203                                 ": Accepting client -> " + acceptClient);
204                     }
205                 }
206
207                 // Set the list of clients that can connect
208
// to the xmlrpc server. The denied client list
209
// will only be consulted if we are paranoid.
210
List JavaDoc deniedClients = conf.getList("denyClient");
211
212                 for (int i = 0; i < deniedClients.size(); i++)
213                 {
214                     String JavaDoc denyClient = (String JavaDoc) deniedClients.get(i);
215
216                     if (StringUtils.isNotEmpty(denyClient))
217                     {
218                         webserver.denyClient(denyClient);
219                         log.info(XmlRpcService.SERVICE_NAME +
220                                 ": Denying client -> " + denyClient);
221                     }
222                 }
223             }
224             // If we have a XML-RPC JAR whose version is greater than the
225
// 1.1 series, the WebServer must be explicitly start()'d.
226
try
227             {
228                 Class.forName("org.apache.xmlrpc.XmlRpcRequest");
229                 isModernVersion = true;
230                 webserver.start();
231             }
232             catch (ClassNotFoundException JavaDoc ignored)
233             {
234                 // XmlRpcRequest does not exist in versions 1.1 and lower.
235
// Assume that our WebServer was already started.
236
}
237             log.debug(XmlRpcService.SERVICE_NAME + ": Using " +
238                     "Apache XML-RPC version " +
239                     (isModernVersion ?
240                     "greater than 1.1" : "1.1 or lower"));
241         }
242         catch (Exception JavaDoc e)
243         {
244             String JavaDoc errorMessage = "XMLRPCService failed to initialize";
245             log.error(errorMessage, e);
246             throw new InitializationException(errorMessage, e);
247         }
248
249         setInit(true);
250     }
251
252     /**
253      * This function initializes the XmlRpcService.
254      *
255      * @deprecated Use init() instead.
256      */

257     public void init(ServletConfig JavaDoc config) throws InitializationException
258     {
259         init();
260     }
261
262     /**
263      * Create System properties using the key-value pairs in a given
264      * Configuration. This is used to set system properties and the
265      * URL https connection handler needed by JSSE to enable SSL
266      * between XML-RPC client and server.
267      *
268      * @param configuration the Configuration defining the System
269      * properties to be set
270      */

271     private void setSystemPropertiesFromConfiguration(Configuration configuration)
272     {
273         for (Iterator JavaDoc i = configuration.getKeys(); i.hasNext();)
274         {
275             String JavaDoc key = (String JavaDoc) i.next();
276             String JavaDoc value = configuration.getString(key);
277
278             log.debug("JSSE option: " + key + " => " + value);
279
280             System.setProperty(key, value);
281         }
282     }
283
284     /**
285      * Register an Object as a default handler for the service.
286      *
287      * @param handler The handler to use.
288      */

289     public void registerHandler(Object JavaDoc handler)
290     {
291         registerHandler("$default", handler);
292     }
293
294     /**
295      * Register an Object as a handler for the service.
296      *
297      * @param handlerName The name the handler is registered under.
298      * @param handler The handler to use.
299      */

300     public void registerHandler(String JavaDoc handlerName,
301                                 Object JavaDoc handler)
302     {
303         if (webserver != null)
304         {
305             webserver.addHandler(handlerName, handler);
306         }
307
308         server.addHandler(handlerName, handler);
309         
310         log.debug("Registered Handler " + handlerName + " as "
311                 + handler.getClass().getName()
312                 + ", Server: " + server
313                 + ", Webserver: " + webserver);
314     }
315
316     /**
317      * A helper method that tries to initialize a handler and register it.
318      * The purpose is to check for all the exceptions that may occur in
319      * dynamic class loading and throw an InitializationException on
320      * error.
321      *
322      * @param handlerName The name the handler is registered under.
323      * @param handlerClass The name of the class to use as a handler.
324      * @exception TurbineException Couldn't instantiate handler.
325      */

326     public void registerHandler(String JavaDoc handlerName, String JavaDoc handlerClass)
327             throws TurbineException
328     {
329         try
330         {
331             Object JavaDoc handler = Class.forName(handlerClass).newInstance();
332
333             if (webserver != null)
334             {
335                 webserver.addHandler(handlerName, handler);
336             }
337
338             server.addHandler(handlerName, handler);
339         }
340                 // those two errors must be passed to the VM
341
catch (ThreadDeath JavaDoc t)
342         {
343             throw t;
344         }
345         catch (OutOfMemoryError JavaDoc t)
346         {
347             throw t;
348         }
349
350         catch (Throwable JavaDoc t)
351         {
352             throw new TurbineException
353                     ("Failed to instantiate " + handlerClass, t);
354         }
355     }
356
357     /**
358      * Unregister a handler.
359      *
360      * @param handlerName The name of the handler to unregister.
361      */

362     public void unregisterHandler(String JavaDoc handlerName)
363     {
364         if (webserver != null)
365         {
366             webserver.removeHandler(handlerName);
367         }
368
369         server.removeHandler(handlerName);
370     }
371
372     /**
373      * Handle an XML-RPC request using the encapsulated server.
374      *
375      * You can use this method to handle a request from within
376      * a Turbine screen.
377      *
378      * @param is the stream to read request data from.
379      * @return the response body that needs to be sent to the client.
380      */

381     public byte[] handleRequest(InputStream JavaDoc is)
382     {
383         return server.execute(is);
384     }
385
386     /**
387      * Handle an XML-RPC request using the encapsulated server with user
388      * authentication.
389      *
390      * You can use this method to handle a request from within
391      * a Turbine screen.
392      *
393      * <p> Note that the handlers need to implement AuthenticatedXmlRpcHandler
394      * interface to access the authentication infomration.
395      *
396      * @param is the stream to read request data from.
397      * @param user the user that is making the request.
398      * @param password the password given by user.
399      * @return the response body that needs to be sent to the client.
400      */

401     public byte[] handleRequest(InputStream JavaDoc is, String JavaDoc user, String JavaDoc password)
402     {
403         return server.execute(is, user, password);
404     }
405
406     /**
407      * Client's interface to XML-RPC.
408      *
409      * The return type is Object which you'll need to cast to
410      * whatever you are expecting.
411      *
412      * @param url A URL.
413      * @param methodName A String with the method name.
414      * @param params A Vector with the parameters.
415      * @return An Object.
416      * @exception TurbineException
417      */

418     public Object JavaDoc executeRpc(URL JavaDoc url,
419                              String JavaDoc methodName,
420                              Vector JavaDoc params)
421             throws TurbineException
422     {
423         try
424         {
425             XmlRpcClient client = new XmlRpcClient(url);
426             return client.execute(methodName, params);
427         }
428         catch (Exception JavaDoc e)
429         {
430             throw new TurbineException("XML-RPC call failed", e);
431         }
432     }
433
434     /**
435      * Client's Authenticated interface to XML-RPC.
436      *
437      * The return type is Object which you'll need to cast to
438      * whatever you are expecting.
439      *
440      * @param url A URL.
441      * @param username The username to try and authenticate with
442      * @param password The password to try and authenticate with
443      * @param methodName A String with the method name.
444      * @param params A Vector with the parameters.
445      * @return An Object.
446      * @throws TurbineException
447      */

448     public Object JavaDoc executeAuthenticatedRpc(URL JavaDoc url,
449                                           String JavaDoc username,
450                                           String JavaDoc password,
451                                           String JavaDoc methodName,
452                                           Vector JavaDoc params)
453             throws TurbineException
454     {
455         try
456         {
457             XmlRpcClient client = new XmlRpcClient(url);
458             client.setBasicAuthentication(username, password);
459             return client.execute(methodName, params);
460         }
461         catch (Exception JavaDoc e)
462         {
463             throw new TurbineException("XML-RPC call failed", e);
464         }
465     }
466
467     /**
468      * Method to allow a client to send a file to a server.
469      *
470      * @param serverURL
471      * @param sourceLocationProperty
472      * @param sourceFileName
473      * @param destinationLocationProperty
474      * @param destinationFileName
475      * @deprecated This is not scope of the Service itself but of an
476      * application which uses the service.
477      */

478     public void send(String JavaDoc serverURL,
479                      String JavaDoc sourceLocationProperty,
480                      String JavaDoc sourceFileName,
481                      String JavaDoc destinationLocationProperty,
482                      String JavaDoc destinationFileName)
483             throws TurbineException
484     {
485         FileTransfer.send(serverURL,
486                 sourceLocationProperty,
487                 sourceFileName,
488                 destinationLocationProperty,
489                 destinationFileName);
490     }
491
492     /**
493      * Method to allow a client to send a file to a server that
494      * requires authentication
495      *
496      * @param serverURL
497      * @param username
498      * @param password
499      * @param sourceLocationProperty
500      * @param sourceFileName
501      * @param destinationLocationProperty
502      * @param destinationFileName
503      * @deprecated This is not scope of the Service itself but of an
504      * application which uses the service.
505      */

506     public void send(String JavaDoc serverURL,
507                      String JavaDoc username,
508                      String JavaDoc password,
509                      String JavaDoc sourceLocationProperty,
510                      String JavaDoc sourceFileName,
511                      String JavaDoc destinationLocationProperty,
512                      String JavaDoc destinationFileName)
513             throws TurbineException
514     {
515         FileTransfer.send(serverURL,
516                 username,
517                 password,
518                 sourceLocationProperty,
519                 sourceFileName,
520                 destinationLocationProperty,
521                 destinationFileName);
522     }
523
524     /**
525      * Method to allow a client to get a file from a server.
526      *
527      * @param serverURL
528      * @param sourceLocationProperty
529      * @param sourceFileName
530      * @param destinationLocationProperty
531      * @param destinationFileName
532      * @deprecated This is not scope of the Service itself but of an
533      * application which uses the service.
534      */

535     public void get(String JavaDoc serverURL,
536                     String JavaDoc sourceLocationProperty,
537                     String JavaDoc sourceFileName,
538                     String JavaDoc destinationLocationProperty,
539                     String JavaDoc destinationFileName)
540             throws TurbineException
541     {
542         FileTransfer.get(serverURL,
543                 sourceLocationProperty,
544                 sourceFileName,
545                 destinationLocationProperty,
546                 destinationFileName);
547     }
548
549     /**
550      * Method to allow a client to get a file from a server that
551      * requires authentication.
552      *
553      * @param serverURL
554      * @param username
555      * @param password
556      * @param sourceLocationProperty
557      * @param sourceFileName
558      * @param destinationLocationProperty
559      * @param destinationFileName
560      * @deprecated This is not scope of the Service itself but of an
561      * application which uses the service.
562      */

563     public void get(String JavaDoc serverURL,
564                     String JavaDoc username,
565                     String JavaDoc password,
566                     String JavaDoc sourceLocationProperty,
567                     String JavaDoc sourceFileName,
568                     String JavaDoc destinationLocationProperty,
569                     String JavaDoc destinationFileName)
570             throws TurbineException
571     {
572         FileTransfer.get(serverURL,
573                 username,
574                 password,
575                 sourceLocationProperty,
576                 sourceFileName,
577                 destinationLocationProperty,
578                 destinationFileName);
579     }
580
581     /**
582      * Method to allow a client to remove a file from
583      * the server
584      *
585      * @param serverURL
586      * @param sourceLocationProperty
587      * @param sourceFileName
588      * @deprecated This is not scope of the Service itself but of an
589      * application which uses the service.
590      */

591     public void remove(String JavaDoc serverURL,
592                        String JavaDoc sourceLocationProperty,
593                        String JavaDoc sourceFileName)
594             throws TurbineException
595     {
596         FileTransfer.remove(serverURL,
597                 sourceLocationProperty,
598                 sourceFileName);
599     }
600
601     /**
602      * Method to allow a client to remove a file from
603      * a server that requires authentication.
604      *
605      * @param serverURL
606      * @param username
607      * @param password
608      * @param sourceLocationProperty
609      * @param sourceFileName
610      * @deprecated This is not scope of the Service itself but of an
611      * application which uses the service.
612      */

613     public void remove(String JavaDoc serverURL,
614                        String JavaDoc username,
615                        String JavaDoc password,
616                        String JavaDoc sourceLocationProperty,
617                        String JavaDoc sourceFileName)
618             throws TurbineException
619     {
620         FileTransfer.remove(serverURL,
621                 username,
622                 password,
623                 sourceLocationProperty,
624                 sourceFileName);
625     }
626
627     /**
628      * Switch client filtering on/off.
629      *
630      * @param state Whether to filter clients.
631      *
632      * @see #acceptClient(java.lang.String)
633      * @see #denyClient(java.lang.String)
634      */

635     public void setParanoid(boolean state)
636     {
637         webserver.setParanoid(state);
638     }
639
640     /**
641      * Add an IP address to the list of accepted clients. The parameter can
642      * contain '*' as wildcard character, e.g. "192.168.*.*". You must
643      * call setParanoid(true) in order for this to have
644      * any effect.
645      *
646      * @param address The address to add to the list.
647      *
648      * @see #denyClient(java.lang.String)
649      * @see #setParanoid(boolean)
650      */

651     public void acceptClient(String JavaDoc address)
652     {
653         webserver.acceptClient(address);
654     }
655
656     /**
657      * Add an IP address to the list of denied clients. The parameter can
658      * contain '*' as wildcard character, e.g. "192.168.*.*". You must call
659      * setParanoid(true) in order for this to have any effect.
660      *
661      * @param address The address to add to the list.
662      *
663      * @see #acceptClient(java.lang.String)
664      * @see #setParanoid(boolean)
665      */

666     public void denyClient(String JavaDoc address)
667     {
668         webserver.denyClient(address);
669     }
670
671     /**
672      * Shuts down this service, stopping running threads.
673      */

674     public void shutdown()
675     {
676         // Stop the XML RPC server.
677
webserver.shutdown();
678
679         if (!isModernVersion)
680         {
681             // org.apache.xmlrpc.WebServer used to block in a call to
682
// ServerSocket.accept() until a socket connection was made.
683
try
684             {
685                 Socket JavaDoc interrupt = new Socket JavaDoc(address, port);
686                 interrupt.close();
687             }
688             catch (Exception JavaDoc notShutdown)
689             {
690                 // It's remotely possible we're leaving an open listener
691
// socket around.
692
log.warn(XmlRpcService.SERVICE_NAME +
693                         "It's possible the xmlrpc server was not " +
694                         "shutdown: " + notShutdown.getMessage());
695             }
696         }
697
698         setInit(false);
699     }
700 }
701
Popular Tags