Cover | Table of Contents | Colophon
mass=getMass(objectID)
getMass( )is implemented on a
remote system. In this case, calling the procedure requires your
program to know a lot more about a more complex process. Your program
needs to know which remote system to contact, how to package and send
the parameters, how to receive an answer, and how to unpackage and
present that answer to the routine that called it originally.
http://meerkat.oreillynet.com) to provide an
interface that can be accessed from several different environments.
Meerkat, which aggregates news and announcement information from
hundreds of sites, can be searched through a traditional web
interface or through an XML-RPC interface (documented at
http://www.oreillynet.com/pub/a/rss/2000/11/14/meerkat_xmlrpc.html).
Developers who want to use Meerkat information in their own
applications can call functions on the Meerkat server, and
Meerkat's maintainers don't need to know anything about
the details.
http://www.xmlrpc.com/spec), which is
the first point of reference for the technology. In addition, the
chapter draws upon current practice to recommend guidelines for
implementation and use, and to highlight areas for future
specialization or extension of the technology.
POST request containing the request information to
the target server.
POST request and passes the XML content to an
XML-RPC listener.
POST request.
<value>
...
</value> element.
<value><i4>n</i4></value>
<value><int>n</int></value>
4 in i4 is
derived from the length of the integer: four octets, 32 bits.)
<int> and
</int> there may only occur the characters
<methodCall>
</methodCall>
tags.
The method name is then given in the <methodName> ...
</methodName>
element. This is followed by a list of parameters, enclosed within
<params> ...
</params>. Each parameter is an XML-RPC
value, as defined in the data types section earlier in this chapter,
and must also be enclosed in <param>
...
</param> tags.
print("Hello,
World!"):
<?xml version="1.0"?>
<methodCall>
<methodName>print</methodName>
<params>
<param>
<value><string>Hello, World!</string></value>
</param>
</params>
</methodCall>
<params> element may
contain zero or more <param> elements. Even
if the method requires no parameters, the
<params> element must still be present.
updateDetails(name="Fred", age=43). This has no
equivalent in XML-RPC, which means you cannot create methods that
take a variable number of parameters.
<?xml version="1.0"?>
<methodCall>
<methodName>updateDetails</methodName>
<params>
<param>
<value><struct>
<member><name>name</name>
<value><string>Fred</string></value>
</member>
<member><name>age</name>
<value><int>43</int></value>
</member>
</struct></value>
</param>
</params>
</methodCall><methodResponse>
...
</methodResponse>
tags and contains a <params> list (with only
one <param>) in much the same format as the
method request payload. Here's a response to a hypothetical
method that asks for the capital city of England:
<?xml version="1.0"?>
<methodResponse>
<params>
<param>
<value><string>London</string></value>
</param>
</params>
</methodResponse>
void function in C. However,
XML-RPC mandates that exactly one parameter must be returned from a
method invocation. This conflict means that if you want to use
valueless methods with XML-RPC, you must use some kind of workaround.
Here are some possible finesses:
true!
nil value as a return value (see
Section 2.5 later in this chapter).
http://www.ontosys.com/xml-rpc/extensions.html.
<value><nil/></value>
<nil/> as the equivalent of the host
language's empty value.
<!ELEMENT i4 (#PCDATA)>
<!ELEMENT int (#PCDATA)>
<!ELEMENT boolean (#PCDATA)>
<!ELEMENT string (#PCDATA)>
<!ELEMENT double (#PCDATA)>
<!ELEMENT dateTime.iso8601 (#PCDATA)>
<!ELEMENT base64 (#PCDATA)>
<!ELEMENT data (value*)>
<!ELEMENT array (data)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT member (name, value)>
<!ELEMENT struct (member*)>
<!ELEMENT value ( i4 | int | boolean | string | dateTime.iso8601
| double | base64 | struct | array )>
<!ELEMENT param (value)>
<!ELEMENT params (param*)>
<!ELEMENT methodName (#PCDATA)>
<!ELEMENT methodCall (methodName, params)>
<!-- note that the content model for fault is underspecified here -->
<!ELEMENT fault (value)>
<!ELEMENT methodResponse (params|fault)>
nil element type, can be found online at
http://www.ontosys.com/xml-rpc/xml-rpc.dtd.
http://classic.helma.at/hannes/xmlrpc/,
and additional resources (including a
mailing list with archives) are also
available there. The examples in the current chapter use the
helma.xmlrpc library, which is available at that
site.
helma.xmlrpc package includes:
helma.xmlrpc
library is available for free
download as a zip archive at
http://classic.helma.at/hannes/xmlrpc/.
You'll need an unzipping utility to open the archive, which
contains documentation, examples, source code, and three Java archive
(helma.xmlrpc package is a relatively simple
operation, involving the creation of an
XmlRpcClient object, assigning parameters, and
making a call to the XmlRpcClient's execute
method. There are a number of exceptions that can be thrown, and
there may be delays in getting a response, but for the most part,
calling XML-RPC routines requires only a small amount of extra
coding, much of which actually deals with exception handling.
execute(
)
methods are the core of the XmlRpcClient class.
The easiest way to handle them is in a
try/catch structure, though you
can encapsulate them in methods that throw the exceptions to a
higher-level handler. The constructor may throw a
MalformedURLException, a subclass of
IOException; the execute( )
method may throw either IOException (when
connections are refused, impossible, etc.) or
XmlRpcException, which is issued when the XML-RPC
server reports an error. The constructor accepts a
String object representing a URL, a URL object, or
the combination of a String for the hostname and
an int for the port.
XmlRpcClient objects are reusable, though they
only connect to the server originally specified when they were
constructed. Applications that establish repeated connections to the
same server may want to reuse the objects, but many applications just
create the client, call a method, and disappear. In these cases, the
constructor and execute( ) method may appear
inside a single try/catch
statement. When the constructor and execute( )
method appear together, the MalformedURLException
may be treated as just another IOException, making
it one fewer exception to catch.
double (retrieved from user input through the
args[] array) to a method identified as
area.circleArea, expecting to get back the area of
a circle whose radius is the double sent as the parameter. This code
doesn't do anything with the result; it just sends the request
and handles any exceptions that might be thrown.
WebServer class
to create a minimal server handling only XML-RPC requests.
WebServer class and uses the
XmlRpcServer
class's built-in ability to
recognize Java classes and methods during the registration process.
If you just need to publish methods whose parameters conform to the
XML-RPC data types described earlier in this chapter, this is usually
straightforward.
helma.xmlrpc package includes a simple
WebServer class that makes it easy to set up
XML-RPC on systems that don't have a web server installed
previously or to add an extra server listening on a nonstandard port.
The WebServer class provides only the core of HTTP
functionality used by XML-RPC, not the full set of functionality used
to distribute web pages. This limitation should reduce the fears of
network administrators who don't want to install internal web
sites, while giving Java developers a small-footprint approach to
adding XML-RPC to computers that aren't intended to be web
servers.
WebServer class requires calling its constructor
with a port number. For example, to create a web server that listens
for XML-RPC requests on port 9876, you can call its constructor as
follows:
WebServer server = new WebServer(9876);
WebServer can't start on the
specified port, it throws a java.io.IOException.
Depending on how you structure the program, you may want to enclose
the constructor (and subsequent registrations) in a
try/catch statement, or you may
want the method managing the XML-RPC interface to pass the exception
on to another handler.
WebServer and
XmlRpcServer employ the same set of methods for
registering and unregistering classes whose methods can be used
through XML-RPC. Java classes whose methods accept the standard data
types (described earlier in this chapter) can use the
WebServer and XmlRpcServer
classes' built-in logic for mapping XML-RPC calls to Java
methods; other classes can be extended with a single
execute( )
method for mapping XML-RPC requests to Java methods. In both cases,
the addHandler( )
and removeHandler(
)
methods are used the same way to add and remove classes that can
handle XML-RPC methods.
public class testHandler {
public String nameTester(String first, String last) {
return "Reversed: " + last + ", " + first;
}
}
nameTester(
)
method available as an XML-RPC procedure requires two steps. First,
set up a web server to handle the HTTP transactions. Second, register
this method with that server to make it available via XML-RPC. Once
the server object has been created, the
testHandler can be registered with the server
using the addHandler(
)
method. The server then accepts and processes requests for the
method:
WebServer server = new WebServer(9876);
server.addHandler("test", new testHandler( ));
testHandler
class and extracts its method signatures
for mapping to XML-RPC requests. XML-RPC clients may now send
requests for the test.nameTester method, sending
two strings as parameters. They'll receive a single string
back, which begins with the text "Reversed:" and then
concatenates the strings in reverse order.
AreaHandler
class has two methods and no properties.
The first method takes two arguments, length and
width, and returns the area of a rectangle; the
second method takes a single argument, radius, and
returns the area of a circle.
public class AreaHandler {
public Double rectArea(double length, double width) {
return new Double(length*width);
}
public Double circleArea(double radius) {
double value=(radius*radius*Math.PI);
return new Double (value);
}
}
helma.xmlrpc library's built-in
WebServerhelma.xmlrpc package can provide you with a
foundation for communication with non-Java systems with which you can
define the roles of client and server as you find
appropriate.
Frontier::RPC, embodies this.
Frontier::RPC, makes remote procedure calls,
consider the following code snippet:
use Frontier::Client;
my $client = Frontier::Client->new
( url => "http://example.com:1080");
print "helloWorld('Bob') returned: ",
$client->call('helloWorld', 'Bob'), "\n";
helloWorld( ). Given these
assumptions, these three lines of Perl code are all that's
needed to make an XML-RPC call. Although this chapter explores the
details of using this library more thoroughly, many XML-RPC Perl
clients aren't any more complicated than this example.
Frontier::RPC. Then it covers how to create
XML-RPC clients and servers using Perl, including instructions for
running an XML-RPC server from a web server.
http://www.cpan.org). It's named
Frontier::RPC and consists of several
Frontier modules, a number of examples, and
Apache::XMLRPC
,
which embeds an XML-RPC server in the Apache web server using
mod_perl.
Frontier::RPC together, the XML-RPC
specification didn't exist. The protocol was merely "RPC
over HTTP via XML," the one used at Dave Winer's UserLand
site, implemented in the Frontier language. Ken's work was, in
fact, the first third-party implementation of the protocol to be
released. Note that this chapter is based on Version 0.07 of
http://www.cpan.org). It's named
Frontier::RPC and consists of several
Frontier modules, a number of examples, and
Apache::XMLRPC
,
which embeds an XML-RPC server in the Apache web server using
mod_perl.
Frontier::RPC together, the XML-RPC
specification didn't exist. The protocol was merely "RPC
over HTTP via XML," the one used at Dave Winer's UserLand
site, implemented in the Frontier language. Ken's work was, in
fact, the first third-party implementation of the protocol to be
released. Note that this chapter is based on Version 0.07 of
Frontier::RPC. There are significant changes from
the previous version, including the introduction of a new module,
Responder, so be sure to upgrade if you have an
earlier version.
Frontier::RPC uses other modules for much of its
work: Data::Dumper,
MIME::Base64, MD5,
HTML::Parser, URI, various
Net:: modules from the libnet distribution,
various modules from the libwww-perl (LWP) suite, and
XML::Parser. These are all available from CPAN.
XML::Parser
module (a front end to the expat XML parser,
written in C) does not include the expat C source. You must download
this source from
http://sourceforge.net/projects/expat.
Fortunately, expat compiles cleanly on most
versions of Unix, and Windows users of ActiveState Perl will find
that XML::Parser is already installed.
Frontier::Client module. An XML-RPC client script
creates a Frontier::Client object and makes remote
procedure calls through methods of that object.
Frontier::Daemon module. ("daemon" is
the traditional Unix term for a long-running server process.) The
script creates a long-lived 2.718 is encoded as a
parameter:
<param><value><double>2.718</double></value></param>
|
XML-RPC data type(XML element)
|
Perl built-in data type
|
Frontier::RPC2 module
|
|---|---|---|
<int> (or <i4>) |
scalar
|
Frontier::RPC2::Integer |
<double> |
scalar
|
Frontier::RPC2::Double |
<string> |
scalar
|
Frontier::RPC2::String |
<boolean> |
scalar
|
Frontier::RPC2::Boolean |
<dateTime.iso8601> |
scalar
|
Frontier::RPC2::DateTime::ISO8601 |
<base64> |
scalar
|
Frontier::RPC2::Base64 |
Frontier::Client
object. This object represents a
connection to that server. The script can then invoke the
Client object's call( )
method as many times as desired to make XML-RPC calls. The
call( ) method:
<methodCall>
message and sends it to the server
<methodResponse> message
returned by the XML-RPC server into Perl data
Frontier::Client object.Frontier::Client package:
use Frontier::Client;
Frontier::Client package
in the regular way, using the package's new(
)
method.
You must specify a url argument, which sets the
web address (URL) of the XML-RPC server host. For example: