CSE 134A
Section Notes 11/30/2001
TA: Greg Hamerly

Remote procedure calls (RPC)

SOAP is a new way to do an old thing. That old thing is called a Remote Procedure Call, or RPC. RPC is defined as:
RPC (definition from Whatis )
Remote Procedure Call (RPC) is a protocol that one program can use to request a service from a program located in another computer in a network without having to understand network details. (A procedure call is also sometimes known as a function call or a subroutine call .) RPC uses the client/server model. The requesting program is a client and the service-providing program is the server.
There are many different ways of doing RPC. Basically, the idea is to make it easy for a programmer to access (or provide) functionality across a network. So if you have a database server, or in our case an address server, you might use RPC from another machine to query the server. RPCs have existed for a long time in one form or another. Java calls it RMI (remote method invocation). Our project is using SOAP, which is a new emerging standard to do RPC.

SOAP as RPC

SOAP simply provides a standard way for you to do two things (same as RPC):
  1. Publish a method on the internet (such as "query_database($querystring)"). This is done on the server.
  2. Call remote methods from your programs. This is done from the client.
There are several things that make SOAP unique, though there is nothing really new here:
  1. SOAP servers run on top of HTTP (in other words, you access it through the web server).
  2. SOAP uses its own subset of XML to describe data.
Some implementations of RPC servers require a special process (you may have heard of a "portmapper") that runs all the time and listens for RPC requests. When they receive a request, they then call the function that the client wants, and return the result over the network. Because SOAP works on top of the web server, it does not need a special process or daemon running all the time. The web server (which does run all the time) invokes a SOAP script whenever it receives a request for that script. Just like your PHP scripts for generating HTML, a SOAP server only lives when it is invoked by the web server.

SOAP uses XML to describe data. Just like in any programming language, the way to describe data is extremely important. Imagine a SOAP client that is a Perl script, which makes a call to a SOAP server that is a large C++ program. You can be sure that (internally), Perl and C++ do not represent data in the same way. But because they both use SOAP to describe their data, they can talk to one another.

Bleeding edge technology

Though SOAP is nice in theory, it is still a young technology, and it's hard to find perfect implementations. Still, it's important not to reinvent the wheel so we use libraries to take care of all the details for us. Those details are: To do this, we use SOAPx4 ( http://dietrich.ganx4.com/soapx4/ ). This library provides code for implementing your own SOAP clients and servers. Documentation is non-existant; therefore we will go through a small example here. Please also refer to http://ieng9.ucsd.edu/php-cs134f/pdimitri/soap.html (Paul Dimitriu's web page on the matter).

Problems with the library

To our knowledge, this library should work on ieng9 with one small change. In the file "class.soap_server.php", there are two calls to a function "call_user_func_array()". However, the PHP version on ieng9 doesn't have this function call. If you remove the "_array" from each of those two occurrences (around lines 182 and 199), things should work. You can get a version that has these changes from Paul's page, here: http://ieng9.ucsd.edu/php-cs134f/pdimitri/class.soap_server.zip.

Library files needed

The SOAPx4 library comes with a number of php files. You can ignore all the files besides "class.soap_client.php" and "class.soap_server.php". The other files are not needed for this project.

A simple example: "Multiply" client/server

The library comes with some example code -- see "test_methods.php". However, this file is overly complicated. Here we'll run through a smaller example.  You can see this code in action at http://ai.ucsd.edu/~ghamerly/134A/soap/multiply_client.php. Let's jump right in and look at the server:

Multiply server


1 : <?php
2 : /* Example SOAP server, providing a function called "multiply".
3 :  * Written by Greg Hamerly (11/29/2001)
4 :  * This code depends on the SOAPx4 PHP library.
5 : 6 :  * Note that the only thing this file *actually does* is:
7 :  * 1. create a server
8 :  * 2. tell the server about our function (multiply)
9 :  * 3. tell the server to service the client's request
10:  */
11: 
12: /* Include the client and server classes from the library (both are needed). */
13: include("class.soap_client.php");
14: include("class.soap_server.php");
15: 
16: /* 1. Create a new SOAP server */
17: $server = new soap_server;
18: 
19: /* 2. Tell the server about the function we will provide The "multiply"
20:  * function takes two arguments (string, int) and returns an array object. 
21:  */
22: $server->add_to_map("multiply", array("string", "int"), array("array"));
23: 
24: /* Here is the actual multiply function. It takes one argument, $x, which is an
25:  * array of data that the client sent us. The data is dereferenced using the
26:  * field names of the data. 
27:  */
28: function multiply($x) {
29:     $str = $x["value"]; /* retrieve the values from the input array */
30:     $times = $x["times"];
31:     for ($i = 0; $i < $times; $i++) {
32:         $result[] = $str; /* create an array of strings */
33:     }
34:     return $result;
35: }
36: 
37: /* 3. Tells the server to parse the data and invoke any functions that have
38:  * been called
39:  */
40: $server->service($HTTP_RAW_POST_DATA);
41: 
42: ?>

First let's look at the "multiply()" function of this file, on lines 28-35. The multiply() function is defined to take as a parameter an array. The first element in this array, indexed by "value", is the string that we are interested in multiplying. The second element, indexed by "times", is the integer number of times to multiply the string. The function then creates an array that contains "times" copies of the given string, and returns that array.

Note that the input to the multiply() function was a single array that contained all the parameters; the multiply function itself has only one parameter. Also note that there is nothing particularly unique about this function, other than an odd way of passing in parameters. But in most ways, this is a normal PHP function, and could be used outside of the context of SOAP.

Now let's look at the SOAP-specific parts of the server. On lines 13 and 14, we include the libraries that are needed. Then on line 17, we create a new soap_server object, which will handle everything for us.

On line 22, we tell the server about our function "multiply()", by giving it the name ("multiply"), the input parameters ("string", "int"), and the output parameter ("array"). These values are used for type-checking the function calls made by clients. Additionally, there are data types "float", "soapstruct", and others; but for this project you should be able to get by with what we use here.

Finally, on line 40, we tell the server to process any requests that have come in. Note that in all this, we never called the function multiply() . So how does the function get called? When the server processes the client requests, it will receive a request for the "multiply()" function. Then it will look up in its table for functions that it knows about (which we provided in line 22). Then the server object will call our function, passing it the data from the client, and it will handle returning the data from our server function back to the client.

Now that we have a taste for what this SOAP service will do, let's look at the client code (which is a little messier).

Multiply client


1 : <html><head><title>SOAP example</title><body>
2 : <h1>SOAP test</h1>
3 : <?
4 : /* Example SOAP client, calling a function called "multiply".
5 :  * Written by Greg Hamerly (11/29/2001)
6 :  * This code depends on the SOAPx4 PHP library.
7 :  */
8 : 
9 : /* include this for access to SOAPx4 library */
10: include("class.soap_client.php");
11: 
12: /* declare the server, the method to call, and the data to send */
13: $server = "http://ai.ucsd.edu/~ghamerly/134A/soap/multiply_server.php";
14: $method = "multiply";
15: $data = array("value" => "foo", "times" => 5);
16: 
17: print("<b>Data to send:</b><br>\n");
18: print_r($data);
19: print("<p>\n");
20: 
21: /* create the client that will send the data */
22: $soap_client = new soap_client($server);
23: 
24: /* create a SOAP message to send */
25: $soap_message = new soapmsg($method, $data);
26: 
27: $return = $soap_client->send($soap_message, "foo" /*"urn:soapinterop"*/);
28: if ($return) {
29:     /* Assume that we got here without an error... more error checking is
30:      * really required here. 
31:      */
32:     print("<b>Data received:</b><br>\n");
33:     /* Get the data we're interested in, and print it out. The next few lines
34:      * will differ depending on which type of data you get back (e.g. scalar,
35:      * array, object).
36:      */
37:     $outdata = $return->decode();
38:     $outdata = $outdata["multiply"];
39:     foreach ($outdata as $key => $value) {
40:         print("$key => $value<br>\n");
41:     }
42: } else {
43:     print("An error has occurred\n");
44: }
45: print "<hr><strong>Request:</strong><br>\n";
46: print "<xmp>$soap_client->outgoing_payload</xmp><br>";
47: print "<strong>Response:</strong><br>\n";
48: print "<xmp>$soap_client->incoming_payload</xmp>";
49: 
50: ?>
51: </body></html>
 

This SOAP client program does several things:

In the data declaration, the important thing to note is that all the data is sent in one array, just like it comes to the "multiply()" function on the server. This array holds two elements (which are key/value pairs): one is the string to multiply, and the other is the integer operand.

The soap client and message creation (lines 22, 25) are fairly self-explanatory. The message send() operation on line 27 requires the message to send, and returns the data that the server sends into the variable $return.

The error checking we do here (line 28) is really not enough. We have taken much of it out to simplify it. To do better error checking, we should do the following within the if statement on line 28:

if (get_class($return) == "soapval"){
    print "Correctly decoded server's response";
    if (eregi("fault",$return->name)){
        $status = "failed";
    } else {
        $status = "passed";
    }
} else {
    print "Client could not decode server's response";
}
Once we have done the call/return and checked for any errors, we need to retrieve our data. This is done on lines 37-41, where we first call $return->decode() to get an array of return values. This array is indexed by the method we called ("multiply"), which contains another array, which is the data we're actually interested in. Then we print out that data.

Of course, to create your own SOAP client/server application for project 4, you will have to do more than I have done here. However, you may use this example as a stepping stone to get you to where you need to be.


Greg Hamerly -- 11/30/2001