What is the Web of Services?
There're a lot of comments in the market about "The web of services" from the simple ways of
content syndication used today to the futuristic approach of UDDI. In its creation, the web
was a collection of documents, browseable information. As the web evolved it was good to add
some services to the web. In the future, the web will be the place where organizations provide
services useful to the consumer and/or other organizations. This synergy between b2b and
b2c models can be thought as a web of services.
What Services?
One big question is what kind of services can be provided on the web? Well, a lot of them, some
are already in use and some will be appearing in a short future. Just to be illustrative, this is a short
list of services:
- Vertical search engines specialized in topics.
- Knowledge databases where users can look for information.
- Expert systems that users can consult.
- Banking services.
- News and information publishing services.
- Digital cash related services.
- Image processing services.
- Health services.
How to Provide Services?
The big question is which is the proper way for organizations to provide services over the web? Today,
some services are offered with an HTML interface. They are using documents to provide services, but what
lies behind the service's interfaces? Web browsers are not alone in the race to conquer the web, cell phones,
palmtops, handhelds, devices such as microwave ovens, sewing machines and applications from other companies
want to access the web, query databases, convert data, pull information, etc. There should be a layer below
the presentation level enabling the real web of services.
Enter XML.
XML is perhaps the strongest standard of the decade. XML vocabularies are the building stones that organizations will
use to construct a universe of services. XML_RPC is a standard that will have to be studied to construct the
web of services because it is useful to put services available on the web and because it is a solid standard
that might easily get adopted. The importance of a standard to provide services is enormous for b2b
services, companies sharing a common standard can grow very fast by using services provided by other companies
and so on. I can't imagine a true web of services based on different propietary formats. They must find
a standard to adopt.
XML_RPC a Standard for Distributed Processing.
XML_RPC is a standard for distributed processing over the internet. RPC: remote procedure call is a
mechanism to launch procedures that may exist in different machines and be programmed in different
languages. This is the key paradigm of distributed processing. In a distributed processing environment
we can, for example, find a calculator software that runs the adding and substracting operations in
different machines, the adding operation might be programmed in APL in a RS6000 machine and the
substraction in "C" in a Unix Host. Other developers building distributed calculators can also use
this "distributed" procedures or choose better ones. In RPC the key components are "procedures", servers
provide procedures that the clients can call. Procedures might receive paremeters and return values.
XML_RPC implements the RPC mechanism by using an XML vocabulary for passing and receiving data and the
HTTP as the protocol carrier. XML_RPC servers accept XML_RPC requests and return XML_RPC responses.
XML_RPC clients send XML_RPC requests and accept XML_RPC responses. They must decode the response and
provide the answer in the way they want.
The XML_RPC Protocol.
The complete XML_RPC specification can be found in
http://www.xmlrpc.com/spec.
This is a summary:
The XML_RPC request.
It should be a HTTP POST request, the body of the request will be in XML, the format of the XML
part of the request is:
<?xml version="1.0" ?>
<methodCall>
<methodName>examples.getStateName</methodName>
<params>
<param>
<value><i4>41</i4></value>
</param>
</params>
</methodCall>
The URI where data should be posted is not specified, it may be "/" for example if the whole server
is dedicated to RPC processing. The payload is in XML, a single "methodCall" structure. The "methodCall"
must contain a "methodName" sub-element, a string containing the method to be called. It is entirely
up to the server to decide how to interpret the characters in "methodName". For example it could be
the name of a file to excute, the name of a row in a database, or anything else. If the procedure
receives parameters the "methodCall" may contain a "params" element with 1 to N "param" sub-elements,
each "param" element may have a value with a type indicator that can be:
| <i4> or <int> | four-byte signed integer -12 |
| <boolean> | 0 (false) or 1 (true) 1 |
| <string> | ASCII string hello world |
| <double> | double-precision signed floating point number -12.214 |
| <dateTime.iso8601> | date/time 19980717T14:08:55 |
| <base64> | base64-encoded binary eW91IGNhbid0IHJlYWQgdGhpcyE |
Structs:
A value may also be a struct:
A <struct> contains <member>s and each <member> contains a <name> and a <value>.
Here's an example of a two-element <struct>:
<struct>
<member>
<name>name</name>
<value><string>John</string></value>
</member>
<member>
<name>age</name>
<value><i4>19</i4></value>
</member>
</struct>
<struct>s can be recursive, any <value> may contain a <struct> or any other type, including an <array>, described below.
<array>s
A value can also be of type <array>.
An <array> contains a single <data> element, which can contain any number of <value>s.
Here's an example of a three-element array:
<array>
<data>
<value><boolean>0</boolean></value>
<value><i4>9</i4></value>
<value><string>Hello</string></value>
</data>
</array>
<array> elements do not have names.
You can mix types as the example above illustrates.
<arrays>s can be recursive, any value may contain an <array> or any other type, including a <struct>, described above.
The XML_RPC responses.
The XML response is a HTTP response content-type: text/xml with the body following the format:
<?xml version="1.0"?>
<methodResponse>
<params>
<param>
<value><string>South Dakota</string></value>
</param>
</params>
</methodResponse>
<methodResponse> may have a <params> structure or a <fault> structure as sub-elements depending on the sucess or not of the procedure call. The params structure is the same as in the XML request, a <fault> element follows this syntax:
<fault>
<value>
<struct>
<member>
<name>faultCode</name>
<value><int>4</int></value>
</member>
<member>
<name>faultString</name>
<value><string>Too many parameters.</string></value>
</member>
</struct>
</value>
</fault>
The Web of Services Using RPC.
As you can see the web of services may easily be constructed using XML_RPC, organizations must deploy XML_RPC
servers for different services provided by the company, client users, client software or client organizations
can use this services to build higher-level services or applications for the end-user. The competition to
provide more efficient, cheaper and better services will improve in a big way the quality of applications
the user receives.
There're some issues not solved, for example how to catalog/index/search for services in the web? UDDI tries
to solve this problem but is not a simple standard and the reaction of the industry to it is still unknown.
The use of XML_RPC inside your organization can improve code-reusability and generate a new philosphy of
distributed programming that can be a key knowledge in the following years. The evolution of XML_RPC from
a very good way to solve distributed processing to be the basic layer of the web of services will have to
be followed closely by people interested in this standard, meanwhile let's see XML_RPC in action!
Using XML_RPC from PHP.
PHP is a wonderful language to provide web services, we write the PHP code and then just place it where
it has to be and we have a URL "callable" service. The implementation of XML_RPC from PHP may or may not
be complex but there will be many to choose from. I have an XML_RCP extension in my next_PHP wishlist.
In this article I'll be using "Useful Information Company's" implementation of XML_RPC by Edd Dumbill,
you can download the code and documentation from
http://xmlrpc.usefulinc.com.
There're two files containing base classes:
xmlrpc.inc classes needed for XML_RPC php clients.
xmlrpcs.inc classes needed for XML_RPC php servers.
Writing Clients.
Writing a XML_RPC client implies:
- Cretaing a XML_RPC request message
- Setting XML_RPC parameters
- Creating a XML_RPC message
- Sending the message
- Getting the response
- Interpreting the response
Take a look at this example:
<?php
$f=new xmlrpcmsg('examples.getStateName',
array(new xmlrpcval(14, "int")));
$c=new xmlrpc_client("/RPC2", "betty.userland.com", 80);
$r=$c->send($f);
$v=$r->value();
if (!$r->faultCode()) {
print "State number ". $HTTP_POST_VARS["stateno"] . " is " .
$v->scalarval() . "<BR>";
print "<HR>I got this value back<BR><PRE>" .
htmlentities($r->serialize()). "</PRE><HR>\n";
} else {
print "Fault: ";
print "Code: " . $r->faultCode() .
" Reason '" .$r->faultString()."'<BR>";
}
?>
In the example we create a XML_RPC message to call the "examples.getStateName" method and we pass
an integer parameter of type "int" with the number 14. Then we create the RPC client indicating the
URL to call (path,domain and port). Then we send the message, receive a response object and check
for errors. If no errors are found we display the result.
Functions to program RPC clients:
A client is created with:
$client=new xmlrpc_client($server_path, $server_hostname, $server_port);
And the method to send a message is:
$response=$client->send($xmlrpc_message);
It returns and instance of xmlrpcresp. The message that we pass is an instance of xmlrpcmsg which
is created in the following way:
$msg=new xmlrpcmsg($methodName, $parameterArray);
Method name is the name of the method (procedure) to call, parameter array is a simple php array of xmlrpcval
objects. For example:
$msg=new xmlrpcmsg("examples.getStateName",
array(new xmlrpcval(23, "int")));
An xmlrpcval object may be created using this forms:
<?php
$myVal=new xmlrpcval($stringVal);
$myVal=new xmlrpcval($scalarVal, "int" | "boolean" | "string" | "double" | "dateTime.iso8601" | "base64");
$myVal=new xmlrpcval($arrayVal, "array" | "struct");
?>
The first creates a xmlrpc string value, the second creates a scalar value indicating value and type, the
third one may be used to create complex objects by grouping other xmlrpc vals in structures such as arrays
or structures as following:
<?php
$myArray=new xmlrpcval(array(
new xmlrpcval("Tom"), new xmlrpcval("Dick"),
new xmlrpcval("Harry")), "array");
$myStruct=new xmlrpcval(array(
"name" => new xmlrpcval("Tom"),
"age" => new xmlrpcval(34, "int"),
"geek" => new xmlrpcval(1, "boolean")), "struct");
?>
The response object is of type xmlrpcresp and is obtained calling the method "send" from a client object,
in a server you can create an xmlrpc resp using:
$resp=new xmlrpcresp($xmlrpcval);
In the client you use the method:
$xmlrpcVal=$resp->value();
To get the xmlrpcval from the response. Then you can use this method to get a PHP variable representing the response:
$scalarVal=$val->scalarval();
There're two useful functions to deal with complex types:
These functions reside in xmlrpc.inc.
$arr=xmlrpc_decode($xmlrpc_val);
Returns a PHP array stuffed with the values found in the xmlrpcval $xmlrpc_val, translated into native PHP types.
$xmlrpc_val=xmlrpc_encode($phpval);
Returns an xmlrpcval populated with the PHP values in $phpval. Works recursively on arrays and structs. Note that there's no support for non-base types like base-64 values or date-times.
Writing clients is a easy task in PHP, you can build web-based clients for XML_RPC services using PHP.
Writing Servers.
Building a sever is really easy with the classes provided by useful inc, you have to create a server by
instantiating a constructor this way:
<?php
$s=new xmlrpc_server( array("examples.myFunc" =>
array("function" => "foo")));
?>
What you pass to the constructor is an asociative array of asociative arrays. The array have as keys the name
of the methods to implement, each method has as key an array indicating with key "function" the name of a
function to call for the method. In the example the procedure "examples.myFunc" calls function "foo", foo
will be called a method handler for this reason.
Writing method handlers.
A method handler is easy this is a skeleton:
<?php
function foo ($params)
{
global $xmlrpcerruser; // import user errcode value
// $params is an Array of xmlrpcval objects
if ($err)
{
// this is an error condition
return new xmlrpcresp(0, $xmlrpcerruser+1, // user error 1
"There's a problem, Captain");
}
else {
// this is a successful value being returned
return new xmlrpcresp(new xmlrpcval("All's fine!", "string"));
}
}
?>
As you can see you just check for errors and return an error (starting from $xmlrpcerruser+1) or a xmlrpcresp
if everything went ok, all the rest of the wor is done by the class.
A sample XML_RPC Client and Server.
In this silly (really) example we build a server that given a number "n" returns "n*2", and a client that
uses the method to determine "5*2" WOW!
The server:
<?php
include("xmlrpc.inc");
include("xmlrpcs.inc");
function foo ($params)
{
global $xmlrpcerruser; // import user errcode value
// $params is an Array of xmlrpcval objects
$vala=$params->params[0];
$sval=$vala->scalarval();
$ret=$sval*2;
return new xmlrpcresp(new xmlrpcval($ret, "int"));
}
$s=new xmlrpc_server( array("product" => array("function" => "foo")));
?>
The client:
<?php
include("xmlrpc.inc");
if ($HTTP_POST_VARS["number"]!="")
{
$f=new xmlrpcmsg('product',
array(new xmlrpcval($HTTP_POST_VARS["number"], "int")));
$c=new xmlrpc_client("/xmlrpc/servfoo.php", "luigi.melpomenia.com.ar", 80);
$c->setDebug(0);
$r=$c->send($f);
$v=$r->value();
if (!$r->faultCode())
{
print "Number ". $HTTP_POST_VARS["number"] . " is " .
$v->scalarval() . "<BR>";
print "<HR>I got this value back<BR><PRE>" .
htmlentities($r->serialize()). "</PRE><HR>\n";
}
else
{
print "Fault: ";
print "Code: " . $r->faultCode() .
" Reason '" .$r->faultString()."'<BR>";
}
}
print "<FORM METHOD=\"POST\">
<INPUT NAME=\"number\" VALUE=\"${number}\"><input type=\"submit\" value=\"go\" name=\"submit\"></FORM><P>
enter a number";
?>
Conclusions.
There's lot of infraestructure work to make the web of services XML_RPC enabled, there must be a catalog
or indexing mechanism for distributed procedures and better interfaces to handle XML_RPC from programming
languages, perhaps a XML_RPC PHP extension will do the work.
There will be lot of news about XML_RPC and the web of services in the future, we'd better watch.
--Luis