If you have read and understood the previous document about the Apache XML-RPC client, then the server isn't too much news.
First of all, there is an object, called the XmlRpcServer. This objects purpose is to receive and execute XML-RPC calls by the clients. The XmlRpcServer can be embedded into a servlet container, or another HTTP server (for example, the minimal web server, that comes with XML-RPC), but it doesn't need to. Take the local transport as an example: In that case the XML-RPC server is simply embedded into the client application.
Like the XmlRpcClient, the XmlRpcServer needs a configuration, which is given by the XmlRpcServerConfigImpl object.
The easiest of creating an XML-RPC Server is the XmlRpcServlet. This servlet allows you to create a server within 10 minutes or so:
package org.apache.xmlrpc.demo; public class Calculator { public int add(int i1, int i2) { return i1 + i2; } public int subtract(int i1, int i2) { return i1 - i2; } }
This class has two public, non-static methods, which should be available to the clients. The only important thing to consider is: The class must be stateless. In other words, it must not contain any non-final fields. (The same restriction applies, for example, to servlet classes.)
Calculator=org.apache.xmlrpc.demo.Calculator
The property file must be called XmlRpcServlet.properties, and it must be located in the package org.apache.xmlrpc.webserver. In other words, you would typically put it into the directory org/apache/xmlrpc/webserver and add it to your jar file.
<servlet> <servlet-name>XmlRpcServlet</servlet-name> <servlet-class>org.apache.xmlrpc.webserver.XmlRpcServlet</servlet-class> <init-param> <param-name>enabledForExtensions</param-name> <param-value>true</param-value> <description> Sets, whether the servlet supports vendor extensions for XML-RPC. </description> </init-param> </servlet> <servlet-mapping> <servlet-name>XmlRpcServlet</servlet-name> <url-pattern>/xmlrpc</url-pattern> </servlet-mapping>
That's it! You have just created your first XML-RPC server. :-)
Unlike in the case of the clients configuration, there isn't much to configure on the server. The reason is, that most things depend on the client and the HTTP headers, which are received by the client. There is one very important property to configure, though:
Property Name | Description |
enabledForExtensions | Whether the vendor extensions of Apache XML-RPC should be enabled. By default, Apache XML-RPC is strictly compliant to the XML-RPC specification. Enabling this property doesn't indicate, that the server is unable to serve requests by standard clients: In contrary, the servers behaviour depends on the client. Setting this property to true will only advice the server, that it may accept requests, which ask for vendor extensions. For example, if a client sends a content-length header, then the server assumes, that the client wants a content-length header in the request and disables the streaming mode. |
Basic authentication is frequently used to authenticate and authorize users. Within Apache XML-RPC, basic authentication is done by the XmlRpcHandler. The handler receives an instance of XmlRpcRequest. This object has a method getConfig(), which returns an instance of XmlRpcRequestConfig.
If you are running within a HTTP server, then the request configuration may be casted to an instance of XmlRpcHttpRequestConfig. This object has methods getBasicUserName(), and getBasicPassword(), which provide the necessary details.
In other words: Your task is to provide your own instance of XmlRpcHandlerMapping, which creates your own handlers. And your own handlers are responsible to validate the basic authentication details.
Here's an example servlet, which overrides the default PropertyHandlerMapping.
public class MyServlet extends PropertyHandlerMapping { private boolean isAuthenticated(String pUserName, String pPassword) { return "foo".equals(pUserName) && "bar".equals(pPassword); } protected XmlRpcHandlerMapping newXmlRpcHandlerMapping() throws XmlRpcException { PropertyHandlerMapping mapping = (PropertyHandlerMapping) super.newXmlRpcHandlerMapping(); PropertyHandlerMapping.AuthenticationHandler handler = new PropertyHandlerMapping.AuthenticationHandler(){ public boolean isAuthorized(XmlRpcRequest pRequest){ XmlRpcHttpRequestConfig config = (XmlRpcHttpRequestConfig) pRequest.getConfig(); return isAuthenticated(config.getBasicUserName(), config.getBasicPassword()); }; }; mapping.setAuthenticationHandler(handler); return mapping; } }