2.3 From HTTP to RPC

Remote procedure calls, or RPC, have been around for a long time. The concept is simple: let's say you have a function along the lines of the following:

int adjustBankAccount(long account, float adjustment);

Expressed in a more object-oriented syntax, you might have something more along the lines of this:

BankAccount.adjust(Money amount);

Now, these methods are pretty easy to understand and work with as part of a program compiled and running on a single machine. An RPC is, in theory, the same thing; however, instead you're making the method call code on another machine. So, consider this code:

// Local code

Money adjustment = new Money(1.50);

// Remote code

myBankAccount.adjust(adjustment);

The reference to myBankAccount.adjust( ) is converted by the underlying RPC framework into a request made to the bank server, with all the underlying argument data type, networking, and error-handling code taken care of for you. In theory, you're working with code running on another system just as easily as you work with local code!

2.3.1 Leaky RPC Plumbing

The reality, unfortunately, tends to be a bit more complicated. It's what you call a leaky abstraction: the idea that a method call on a local system is the same as a method call on a remote system hides a lot of important details. The most basic are the issues of latency, reliability, and bandwidth (as discussed earlier in this chapter). Other issues include security and availability. Perhaps most significantly, different programming languages and operating systems have wildly different ideas about such matters as method calls, type information, error handling, and more. This becomes an extremely political issue because pretty much everyone seems to recognize that if a particular standard for remote procedure calls becomes dominant, all other environments risk withering (much as network standards competitive with TCP/IP continue to fade).

Early attempts at these distributed systems included CORBA, DCOM, Java RMI, and a host of others. These attempts encountered tremendous difficulty establishing themselves as standards because they weren't compatible with nonproprietary environments (Java RMI and DCOM) or they were overwhelmingly complex (DSOM[2] and CORBA). Interestingly, all these attempts encoded their data in a binary format, offering potentially high performance but at a significant cost: they were uniformly difficult to understand, debug, and implement.

[2] http://www.webopedia.com/TERM/D/DSOM.html

2.3.2 RPC Meets the Internet

As the Internet came to the fore and XML became popular, many people noticed that it was easy to use an HTTP GET or POST to retrieve an XML document. Pretty much everyone, regardless of programming language or environment, had some sort of wrapper library to easily access the data returned by an HTTP GET, and there was a profusion of XML parsers. Instead of using a cumbersome build process to generate a host of files to access proprietary binary data, people realized that they could build an RPC system using simple, existing technologies and standards.

Arguably the first true Internet web service framework (and still one of the most simple and easy to use) is XML-RPC (http://www.xmlrpc.com/). It's a pretty terse specification, but if you just need to get a small amount of information over the wire, it's hard to think of a much easier mechanism. Notably, a variety of libraries exist in a variety of programming languages, allowing different systems to easily share data using XML-RPC.

2.3.3 Evolving to SOAP

Unfortunately, XML-RPC suffered from a number of problems due to the lack of sufficiently detailed specification. Certain limitations (e.g., the inability to specify a language encoding for strings other than English ASCII) meant that the specification was bound to fracture as it tried to gain wide adoption.

Despite these limitations, XML-RPC served as a powerful precursor to its eventual replacement, SOAP. It showed that it was possible to define a very simple specification for performing RPC via the Internet, using XML as the packaging.

2.3.4 SOAP

The Simple Object Access Protocol is perhaps one of the worst names ever chosen for a technology. While it is (in theory) simple, you often get the impression that vendors are doing everything they can to make it as complex as possible. The term "object" in SOAP would seem to imply some connection to object-oriented development, but instead SOAP is almost totally procedural in nature. Finally, "protocol" might convey some sense that it's a replacement or upgrade to HTTP or SMTP, but instead SOAP relies on these protocols to actually handle data transfer. SOAP is effectively XML-RPC's bigger, more sophisticated younger brother. The specification, now at Version 1.2, is maintained by the W3C XML Protocol Working Group at http://www.w3.org/2000/xp/Group/.

Simply put, SOAP provides rules for handling remote procedure calls using XML as the wrapping protocol (called an envelope). This reliance on XML makes it easier to implement SOAP infrastructure. Most programming languages now offer SOAP support, making working with SOAP a relatively familiar, XML-parsing-free experience.

To see how to work with SOAP as an RPC system, let's look at the snippet of code shown in Example 2-5 (from the Apache Axis project).

Example 2-5. Accessing SOAP from Java
package samples.userguide.example1;



import org.apache.axis.client.Call;

import org.apache.axis.client.Service;



import javax.xml.namespace.QName;



public class TestClient

{

   public static void main(String [] args) {

       try {

           Service service = new Service( );

           Call call = (Call) service.createCall( );



           call.setTargetEndpointAddress(new java.net.URL(

            "http://nagoya.apache.org:5049/axis/services/echo"));

           call.setOperationName(

            new QName("http://soapinterop.org/", "echoString"));



           String ret = (String)call.invoke(new Object[]{"Hello!"});



           System.out.println("Sent 'Hello!', got '" + ret + "'");

       } catch (Exception e) {

           System.err.println(e.toString( ));

       }

   }

}

There is no reference in Example 2-5 to XML. Interestingly, a popular use of SOAP is to transmit XML data. This means that you are, in effect, wrapping an XML document inside another XML document, then using HTTP or SMTP to move data around. Fortunately, you don't actually have to worry about this; the SOAP libraries take care of the details of these rather confusing tasks for you.

Giving SOAP a REST?

Instead of SOAP, you can use a methodology called Representational State Transfer (REST). In many ways, REST is a return to the simpler XML-RPC concept, because it lets you interchange XML documents using standard HTTP concepts. That said, REST is an architectural style without a concrete specification; as a result, using REST is a lot closer to opening up a stream of bytes.

For more information on REST, consult http://conveyor.com/RESTwiki/moin.cgi.


As you can imagine, it is quite convenient when working with SOAP to use various developer tools to more seamlessly integrate remote services. This led to the emergence of another technology, WSDL.

2.3.5 Web Services Definition Language

The Web Services Definition Language, or WSDL, is a specification for describing the methods and data types provided by a SOAP interface. This sort of metadata is very useful when trying to build tools that support SOAP, much the same way that the JavaBeans specification provides support for an IDE to graphically wire together a visual application.

To understand the distinction between the metadata and the actual object, consider the programmatic interfaces you use when building your application. For example, C developers use header files to share the functions exposed by their library. The headers are analogous to WSDL, whereas the linked methods are analogous to a SOAP message or payload.

It's true that you don't need WSDL to access a SOAP service, but it can be slow-going work without it. Instead, it's often easier to feed a vendor-provided WSDL to your tools and have them build language-specific bindings. For example, a developer using C# tools can easily work with a Java-based server if given an appropriate WSDL file. We won't be spending a lot of time worrying about how to generate WSDL files, because most environments provide mechanisms for automatically generating WSDL from the services you expose. We will, however, be using WSDL presented by other vendors to reduce the drudgery of building our applications.

As we walk through the progression from basic networking, HTTP, and then on to SOAP and WSDL as RPC mechanisms, it would seem only logical that most of the modern web services offered today are built using SOAP and WSDL. Instead, as you'll see, many web services are available as raw XML delivered via HTTP (such as eBay or FedEx) or even just a stream of specially formatted text (such as CDDB1, described in Chapter 9).

The next chapter looks at setting up our development environment and then get started actually building web service-based applications.