Home > Articles > Web Services > XML

  • Print
  • + Share This
This chapter is from the book

This chapter is from the book

What Are Web Services?

The term "web services" means different things to different people. From a technical point of view, web services describe a suite of protocols built upon XML and HyperText Transfer Protocol (HTTP). HTTP is widely available all across the Internet and it is very well supported. Why use XML and HTTP? Well, we all know the benefits of XML when it comes to exchanging data. When combined with HTTP, XML can be used to describe both simple and sophisticated transactions between clients and services across the Internet. But before we actually discuss web services, let's take a look back and see how and why they were developed.

Throughout the short history of web programming, developers have created unique ways of allowing applications to communicate with one another. Most of the time, the developers of both systems would get together, define their interface, and then modify their applications to adapt to the new protocol. In many cases, that worked fine, but the web is enormous and you can only imagine the complexity required if an application required a unique protocol to exchange information with a large number of other applications—you would need hundreds (if not thousands) of APIs to support this. The next section discusses the application of a simple web service.

Example of a Web Service

Imagine that you are responsible for a web portal for a vacation resort. The web page includes resort-specific information, such as contact information, travel directions, and so forth. Now, as a convenient feature for potential customers, you'd like to display the current temperature in your city. There are several approaches to providing this information.

  • You can get a thermometer and update the temperature frequently (not very practical).

  • You can check http://www.weather.com and possibly have a link to their web site.

  • The third, and most practical, approach would be to provide live temperature information from another organization such as http://www.weather.com that provides weather information as a web service.

Well, we're in luck because http://www.weather.com does provide temperature information as a web service. Now you can easily add an interface to your application that will access their web service and retrieve the current temperature for your resort. This way, whenever a customer looks at your web site, they'll see the current temperature. Because http://www.weather.com provides the temperature service without any restrictions (that is, anyone can use it), you need to provide the service with some type of geographic information (that is, where you live), so it can provide the proper temperature reading. Whenever you make a temperature query, all you need to do is provide a zip or postal code; this way, the service provider can look up the current weather in your area.

Exchanging Data on the Web

One of the first approaches to exchanging data on the web was Electronic Data Exchange (EDI). EDI defined messages and protocols, but it didn't define any network requirements. Unfortunately, the end result was a series of proprietary networks with limited memberships that were difficult to interconnect.

Another approach to distributing information across the web attempted to build a distributed object infrastructure and distribute objects containing data. There were actually three similar implementations that built upon the idea of distributing objects. The three approaches were Common Object Request Broker Architecture (CORBA), and Distributed Component Object Model (DCOM). The problem with these approaches is that each implementation selected a different protocol to transport objects. For example, the CORBA developers decided to use Internet Inter-ORB Protocol (IIOP), the DCOM developers decided to use Object Remote Procedure Call (ORPC), and the RMI developers decided to use Java Remote Method Protocol (JRMP). The major problem with these approaches was the lack of interoperability. Following this schema, CORBA could only communicate to CORBA, RMI could only communicate to RMI, and DCOM could only communicate to DCOM. Also, none of the approaches could easily communicate directly to the web— each required an extra protocol layer that provided a special socket interface.

As you can see, the early approaches to exchanging data on the web all had their own problems. To address most (if not all) of these problems, new XML-based protocols for web services were developed. The most important of these protocols is discussed in the next section.

Web Service Protocols

Web services use XML messaging as a means of communication. Because they use XML, web services and the language used to implement them are transparent to the platform on which they reside. This way, any application running on any platform and written in almost any programming language can communicate with an XML-based web service.

The three major protocols involved with web services are Simple Object Access Protocol (SOAP); Universal Description, Discovery, and Integration Protocol (UDDI); and Web Services Description Language (WSDL). In this section, I'll briefly discuss each of these protocols.

Simple Object Access Protocol

Microsoft, Develop-Mentor, and Dave Winer developed a new protocol named SOAP to address the shortcomings of the previous approaches to distributing services.Version 1.0 of the SOAP specification was released in 1998. The W3C took over development of the standard and released version 1.2 in July 2001.

SOAP is an XML-based messaging protocol that was designed to facilitate exchanging structure information using the web or a web-like environment (that is, decentralized). SOAP messages are XML documents that are transported back and forth between servers and clients. SOAP can use a variety of network protocols to connect to web services, including HTTP, POP3, FTP, and SMTP. SOAP can also be used in a variety of applications that require XML messaging. I'll only discuss the most popular usage of SOAP, which is its facility for remote method invocation over HTTP. SOAP is cross-platform, as long as the programming language you use has the SOAP facilities. Even if your favorite programming language doesn't have the SOAP API, you can contribute to the open source community by writing your version of the SOAP API. SOAP specifications are open source and available at http://www.w3.org for anyone to implement.

What is so great about SOAP? It combines the best of both worlds by using the capabilities of XML with the transport capability of HTTP. By taking advantage of both of these open standards, SOAP eliminates the data transport problems associated with EDI and the interoperability problems associated with CORBA, RMI, and DCOM. Just as XML separates data from the presentation of the data, SOAP separates the data from the underlying transport protocol. In the next section, we'll take a look at the format of a SOAP message.

Format of a SOAP Message

A SOAP message is an XML document that follows a particular format. The SOAP message format has the following sections:

  • Envelope (required)— The SOAP message envelope is actually the mandatory root element named <Envelope> of the SOAP message.

  • Header (optional)— The SOAP message <Header> element is an optional component of a SOAP message. The <Header> element is used to instruct SOAP servers to perform some specialized processing before sending the SOAP message out to the next destination. An example of a <Header> element instruction would be to instruct a SOAP server to add some security-related information for authentication.

  • Body (required)— The <Body> element of a SOAP message contains the transported XML document.

Universal Description, Discovery, and Integration Protocol

The Universal Description, Discovery, and Integration (UDDI) protocol is used to describe the components of web services. After a web service has been described using UDDI, it can be registered with an Internet directory that advertises the web service. The Internet directories enable businesses to advertise their web services and find other web services. The major benefit of UDDI is that it provides a global and platform-independent method of describing and discovering web services.

Web Services Description Language

The Web Services Description Language (WSDL) standard is an XML-based standard used to describe web services. WSDL defines XML grammar that describes both the interface and implementation details of web services. It is important to note that WSDL supports describing web services regardless of the message format or protocol that is used.

Relationship Between Web Services Protocols

Now that I've introduced you to the web services protocols, let's take a look at how they work together to support web services. Figure 10.1 shows the interaction between web services protocols.

Figure 1Figure 10.1. Web services protocols interaction.


As you can see in Figure 10.1, we have a web services provider, a web services directory, and a web services client. The first step shown in Figure 10.1 is labeled with the number "1" and shows the exchange using UDDI between a web services provider and a web services directory. A web services provider registers a web service using UDDI with a web services directory, so that web clients can locate the web service. After the service has been registered with the web services directory, a web services client can locate the web service by searching the web services directory. This is labeled as step "2" in Figure 10.1. The web services client receives a WSDL XML document that provides all the required connection information. After the web services client has the XML WSDL document, it can connect to the web services provider. Later in this chapter, I'll show examples of web services clients connecting to web service providers.

As you can see, the web services directory has a function similar to a Domain Name Server (DNS). Usually, if your PC or workstation tries to ping a host on the Internet (let's say www.newriders.com), your PC or workstation first queries a DNS server and asks for the equivalent IP address. That's because PCs, workstations, and routers use IP addresses rather than hostnames. In the case of web services, we're asking the web services directory which web services provider offers a particular service and what information do I need to connect to it.

I think that you can now see the potential and usefulness of web services. The rest of the chapter concentrates on several examples that demonstrate how to access web services as well as how to develop your own web service.

Web Service SOAP Client Examples

The SOAP::Lite Perl module provides a Perl API to SOAP and handles most of the low-level details for you. A SOAP server and a SOAP client are two applications that are usually (but aren't required to be) running on different machines. A SOAP client sends a request to a SOAP server, the server processes the request, and returns the result to the SOAP client. In the case of Remote Procedure Calls (RPCs), the request sent by the SOAP client is actually a request to execute a function on the SOAP server. When the SOAP server receives the requests, it executes the requested function, packages up the results in a SOAP message, and returns the results to the calling SOAP client.

Earlier, I discussed a web service provider that would return the current temperature for a particular postal zip code. In the next section, I'm going to show you how to build a Perl client that accesses a web service that provides temperature information.

SOAP Client

In this section, we'll build several SOAP clients using the SOAP::Lite Perl module. Don't be misled by the name—the SOAP::Lite Perl module is a full and advanced implementation of SOAP. The word Lite in the module title applies to the Perl module's ease of use rather than its functionality.

The first step in building a SOAP client is to determine the web service that we want to use. Where are publicly available SOAP servers, and what services do they offer? Due to the popularity of SOAP, a number of web service repositories have been created that contain information about available web services. These repositories contain information about available web services (for example, where they are located) and provide the API documentation necessary to use them. One such web service repository that was particularly useful during the development of the book is http://www.xmethods.net. This web site provides a variety of web services itself and also provides information about web services available on other servers. Looking through the site, we found a web service provided by XMethods named Weather-Temperature. As you may have already guessed from the name, the Weather-Temperature service provides the current temperature based on a zip code.

Associated with each web service is an RPC profile . An RPC contains all the information that is required to manually configure SOAP RPC calls. The RPC profile for the Weather-Temperature web service is shown in Table 10.1.

Table 10.1. RPC profile for the Weather-Temperature web service.

Method Name

GetTemp

Endpoint URL

http://services.xmethods.net:80/soap/servlet/rpcrouter

SOAPAction

 

Method Namespace URI

urn:xmethods-Temperature

Input Parameters

Zip code string

Output Parameters

Return float


Looking at the RPC profile in the preceding table, we can see that there is only one method available. The method is named getTemp. As you can see from Table 10.1, the method has one input parameter and one output parameter. The input parameter is the zip code from the area of interest, and the output method contains the current temperature. Note that the method is contained in the urn:xmethods-Temperature namespace and that the service URL is:

http://services.xmethods.net:80/soap/servlet/rpcrouter

Now that we have the information that we need (that is, the contents of the RPC profile), we can create a SOAP::Lite client and use it to call the Weather-Temperature service. The SOAP::Lite client application built using the contents of the RPC profile is shown in Listing 10.1.

Listing 10.1 SOAP::Lite-based client application to retrieve temperature based on a zip code. (Filename: ch10_soap_retrieve_temp_app.pl)

1.   use strict;
2.   use SOAP::Lite;
3.
4.   # Instantiate a new SOAP::Lite object
5.   my $service = new SOAP::Lite
6.             ->uri('urn:xmethods-Temperature')
7.             ->proxy('http://services.xmethods.net/soap/servlet/rpcrouter');
8.
9.   # Remotely call the getTemp method
10.  my $result = $service->getTemp(SOAP::Data->type(string => '08736'));
11.
12.  unless ($result->fault) {
13.    print $result->result();
14.  } else {
15.    print join ', ',
16.      $result->faultcode,
17.      $result->faultstring,
18.      $result->faultfactor,
19.      $result->faultdetail;
20.  }
 

1–7 In this section of the application, we start off by using the standard use strict pragma statement. Because we're using SOAP::Lite, we also need the use SOAP::Lite pragma statement to load the module. The first step after loading the module is to instantiate a SOAP::Lite module by using the new() method.

After we create a SOAP::Lite object, we call the uri() and proxy() methods. The uri() method is actually a shortcut to the serializer->uri() method. The uri() method enables us to specify the URI for SOAP methods. In our case, the URI is the method namespace specified in the namespace profile. Note that URIs may look similar to URLs, but aren't required to actually point anywhere. URIs will, however, be unique within the space of XML documents.

The proxy method is actually a shortcut to the transport->proxy() method. The proxy method enables us to specify an endpoint (or service address) for the web service. Note that the name of the module is prepended with the transport protocol that we'll be using.

The prefix SOAP::Transport is also prepended to the name, so the module will be loaded and an object (also with an appended "::Client") will be created. So, the class that creates objects will look for the name "SOAP:: Transport::HTTP::Client."

In this example, we're not using any transport-specific parameters, but the proxy() method can also accept any transport-specific parameters that may be required. For example, we can specify an HTTP timeout or any required cookie-specific parameters.

1.   use strict;
2.   use SOAP::Lite;
3.
4.   # Instantiate a new SOAP::Lite object
5.   my $service = new SOAP::Lite
6.             ->uri('urn:xmethods-Temperature')
7.             ->proxy('http://services.xmethods.net/soap/servlet/rpcrouter'); 

NOTE

The context of the calls may look a little strange (that is, no commas between the new(), uri(), and proxy() methods). That's because all the methods with parameters will return the current object. The SOAP::Lite Perl module author says that the module supports method "stacking."

9–10 After we have created our service object, we can proceed to call the getTemp method available through the web service and pass it the zip_code argument (in our case 08736). After the call is processed by the web service, it returns the current temperature (in degrees Fahrenheit) in a float data type. Because Perl does not have strong typing, the temperature is returned as a scalar. Note that the result is returned in a result object instead of just a value. This object can then be used to retrieve the returned value or print out an error message if an error was returned by the web service.

9.   # Remotely call the getTemp method
10.  my $result = $service->getTemp(SOAP::Data->type(string => '08736')); 

12–19 If the remote method didn't encounter any errors and no faults have been returned, we can print the result. The result is retrieved from the object by using an access method named result(). If an error occurred, it is returned as a SOAP Fault element. Each SOAP Fault element contains the following four child elements:

  • faultcode— This element is intended to be used by your software to provide a mechanism to identify the fault. The faultcode is required to appear in a SOAP Fault element, and it must be an XML-qualified name. The SOAP standard has defined a few SOAP faultcodes that cover basic faults.

  • faultstring— This element is supposed to provide a human-readable string that describes the fault. The faultstring element is required to appear in a SOAP Fault element.

  • faultfactor— This element is intended to provide additional information about who caused the fault to occur throughout the message path.

  • faultdetail— This element is intended to carry application-specific fault information.

12.  unless ($result->fault) {
13.    print $result->result();
14.  } else {
15.    print join ', ',
16.      $result->faultcode,
17.      $result->faultstring,
18.      $result->faultfactor,
19.      $result->faultdetail;
20.  } 

When you run the example shown in Listing 10.1, the temperature for your zip code is returned. Before we move on to the next example, take a look at Listing 10.2. Listing 10.2 contains the SOAP request that we sent out to the temperature web service.

Listing 10.2 Example SOAP weather request to retrieve the temperature for a particular zip code. (Filename: ch10_soap_request.xml)

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
                   xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
                   xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1:getTemp xmlns:ns1="urn:xmethods-Temperature"
             SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<zipcode xsi:type="xsd:string">08736</zipcode>
</ns1:getTemp>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
 

As you can see, the SOAP request contains the required SOAP <Envelope> and <Body> elements.You can see that we are calling the xmethods-Temperature service and executing the getTemp method with the zip_code argument.

After the server receives this call, it is responsible for parsing the request and providing the information requested as a SOAP response. The simple return message for this RPC is shown in Listing 10.3.

Listing 10.3 Example SOAP weather reply. (Filename: ch10_soap_response.xml)

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
                   xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
                   xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1:getTempResponse xmlns:ns1="urn:xmethods-Temperature"
                     SOAP-
ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<return xsi:type="xsd:float">79.0</return>
</ns1:getTempResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
 

WSDL

Another technology that is quickly emerging along with SOAP is the WSDL specification that is used to describe web services. WSDL describes all functions available for the web service, all the data types for response and request messages, web service location information, and the transport protocol binding information. WSDL facilitates web service invocation by providing both descriptive and connectivity information about a web service in a single XML document. Using WSDL tools, you can easily construct a SOAP client that can be quickly modified to support any potential web service changes.

The service described earlier, Weather-Temperature, has an associated WSDL file that describes the web service. The WSDL file is shown in Listing 10.4.

NOTE

The WSDL file can be viewed at http://www.xmethods.net/sd/2001/TemperatureService.wsdl.

Listing 10.4 Weather temperature WSDL file. (Filename: ch10_temp_service.wsdl)

<?xml version="1.0"?>
<definitions name="TemperatureService"
targetNamespace="http://www.xmethods.net/sd/TemperatureService.wsdl"
xmlns:tns="http://www.xmethods.net/sd/TemperatureService.wsdl"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
   <message name="getTempRequest">
      <part name="zipcode" type="xsd:string"/>
   </message>
   <message name="getTempResponse">
      <part name="return" type="xsd:float"/>
   </message>
   <portType name="TemperaturePortType">
      <operation name="getTemp">
         <input message="tns:getTempRequest"/>
         <output message="tns:getTempResponse"/>
      </operation>
   </portType>
   <binding name="TemperatureBinding" type="tns:TemperaturePortType">
      <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
      <operation name="getTemp">
         <soap:operation soapAction=""/>
         <input>
            <soap:body use="encoded" namespace="urn:xmethods-Temperature"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
         </input>
         <output>
            <soap:body use="encoded" namespace="urn:xmethods-Temperature"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
         </output>
      </operation>
   </binding>
   <service name="TemperatureService">
      <documentation>Returns current temperature in a given U.S. zipcode </documentation>
      <port name="TemperaturePort" binding="tns:TemperatureBinding">
         <soap:address location="http://services.xmethods.net:80/ soap/servlet/rpcrouter"/
>
      </port>
   </service>
</definitions>

Looking at the WSDL file, you'll notice some familiar contents that include the web service URL, namespace, and its method(s). Now we'll take a look at a SOAP::Lite-based example to invoke this web service with the WSDL file. The Perl application to do this is shown in Listing 10.5.

Listing 10.5 Program that uses the SOAP::Lite module and a WSDL file to retrieve the temperature based on a zip code. (Filename: ch10_getWeather_wsdl.pl)

1.   use SOAP::Lite;
2.
3.   my $result = SOAP::Lite
4.      ->service('http://www.xmethods.net/sd/2001/TemperatureService.wsdl')
5.      ->getTemp(08736);
6.
7.   print $result; 

Running this example, the result was 84 degrees (a warm early summer day). As you can see, this is a very short example, but I believe it is an important example. It demonstrates how to use a WSDL XML document to access a web service. Looking at the above example, we can see that the WSDL file is first loaded using the SOAP::Lite service method, and then the method is called. Notice that we didn't have to specify the service namespace or location because SOAP::Lite retrieves this information from the WSDL file. Also, note that we didn't need a copy of the WSDL XML document locally to access the web service; we just needed a path to the WSDL file. So far, the examples have only been SOAP clients. In the next example, I'll show you what is required to build your own web service provider application.

Web Service Client and Server Example

Now that I demonstrated how easily SOAP clients can be built and used with the existing SOAP servers, we'll build a full SOAP application (that is, both the server and the client). So, if you wanted to register this application as a web service with a web services directory, it would be accessible through the Internet.

Because SOAP was originally designed to be platform- and language-independent, the SOAP client and SOAP server can each reside on two different platforms and can be written in two different languages. For example, Weather-Temperature service, which we accessed in our earlier SOAP client examples, was actually written using the Apache SOAP toolkit for Java. We don't need to know which platform a web service resides on, nor do we need to know which toolkit/language was used to develop the service. As long as a web service conforms to the SOAP standards, we know our client will be able to communicate with the web service.

In this example, both the SOAP client and the SOAP server will reside on the same platform (that is, we will connect to a service located on localhost/127.0.0.1).

NOTE

To run this example, you'll need a web server (for example, Apache) installed, running, and configured to accept incoming connections on port 80. Precompiled Apache web server binaries for a number of platforms are available at http://www.apache.org.

Web Service Description

Let's pretend that you work for an online reseller, and you've been asked to develop a web service application that provides real-time access to the current book inventory. Currently, the book inventory is stored in an XML document that contains the following information for each book: name, publisher, author, pages, and price.

Our SOAP-based application is a web services client that retrieves information about any published book. The only input required is the International Standard Book Number (ISBN) number that has been assigned to the book. Listing 10.6 shows the DTD for the XML document that contains the inventory information.

NOTE

In case you're not familiar with it, the ISBN is almost like a social security number for books—each book is assigned a unique number. Keep this in mind in case you ever need to build a real-life application to track books; the ISBN number provides a perfect unique key.

Listing 10.6 DTD for the book inventory. (Filename: ch10_book_inventory.dtd)

<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT books (book+)>
<!ELEMENT book (name, publisher, author+,pages,price)>
<!ATTLIST book
      isbn CDATA #REQUIRED>
<!ELEMENT name (#PCDATA)>
<!ELEMENT publisher (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT pages (#PCDATA)>
<!ELEMENT price (#PCDATA)> 

Listing 10.7 contains the XML schema that defines the XML book inventory document.

Listing 10.7 XML schema for the book inventory. (Filename: ch10_book_inventory.xsd)

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
   <xs:element name="author" type="xs:string"/>
   <xs:element name="book">
      <xs:complexType>
         <xs:sequence>
            <xs:element ref="name"/>
            <xs:element ref="publisher"/>
            <xs:element ref="author" maxOccurs="unbounded"/>
            <xs:element ref="pages"/>
            <xs:element ref="price"/>
         </xs:sequence>
         <xs:attribute name="isbn" type="xs:string" use="required"/>
      </xs:complexType>
   </xs:element>
   <xs:element name="books">
      <xs:complexType>
         <xs:sequence>
            <xs:element ref="book" maxOccurs="unbounded"/>
         </xs:sequence>
      </xs:complexType>
   </xs:element>
   <xs:element name="name" type="xs:string"/>
   <xs:element name="pages" type="xs:string"/>
   <xs:element name="price" type="xs:string"/>
   <xs:element name="publisher" type="xs:string"/>
</xs:schema>
 

The XML document containing all the book information is shown in Listing 10.8. As you can see, this is a fairly simple XML document that contains the important information for several books.

Listing 10.8 Book inventory information stored in XML. (Filename: ch10_book_inventory.xml)

1.   <?xml version="1.0"?>
2.   <books>
3.     <book isbn="0596000952">
4.       <name>Programming Web Services with SOAP</name>
5.       <publisher>O'Reilly</publisher>
6.       <author>James Snell</author>
7.       <author>Doug Tidwell</author>
8.       <author>Pavel Kulchenko</author>
9.       <pages>244</pages>
10.      <price>34.95</price>
11.    </book>
12.    <book isbn="0201615711">
13.      <name>Network Programming with Perl</name>
14.      <publisher>Addison Wesley</publisher>
15.      <author>Lincoln D. Stein</author>
16.      <pages>754</pages>
17.      <price>39.99</price>
18.    </book>
19.    <book isbn="020170353X">
20.      <name>Accelerated C++</name>
21.      <publisher>Addison Wesley</publisher>
22.      <author>Andrew Koenig</author>
23.      <author>Barbara E. Moo</author>
24.      <pages>336</pages>
25.      <price>33.95</price>
26.    </book>
27.  </books>
 

Now that we've looked at the data that our web service needs to provide, let's take a look at how we build a SOAP server.

SOAP Server Implementation

In this section, we're going to design and build our SOAP server that provides access to the data in the XML inventory file. Our SOAP server will provide one method named getInfo. The SOAP server getInfo method will take the ISBN of the book that the web services client is interested in as an argument. It will then parse the XML document shown in Listing 10.8 (ch10_book_ inventory.xml) and search for the desired ISBN number. If the SOAP server's getInfo method finds the desired book, it will return the book information; otherwise, it will return the "ISBN: ##### Not Found" message. The source code for the Perl module is shown in Listing 10.9.

Listing 10.9 Perl module Books.pm containing the getInfo method. (Filename: Books.pm)

1.   package Books;
2.   use XML::SAX::ParserFactory;
3.
4.   # This is the method that will be available as a Web service.
5.   sub getInfo {
6.     shift;  # get the class name
7.     my $isbn = shift;
8.     my $return_message = "";
9.
10.    # Instantiate a new handler object.
11.    my $handler = Books::Handler->new(ISBN => $isbn,
12.                                      RETURN_MESSAGE => \$return_message);
13.    my $p = XML::SAX::ParserFactory->parser(Handler => $handler);
14.    $p->parse_uri("ch10_book_inventory.xml");
15.    return $return_message;
16.  }
17.
18.  # Handler package definition
19.  package Books::Handler;
20.
21.  my $flag = 0;
22.  my $elem = "";
23.  my $data = "";
24.
25.  sub new {
26.    my $class = shift;
27.    die "Usage: new(ISBN => '3429493', RETURN_MESSAGE => \$mess)" if @_ != 4;
28.    return bless {@_}, $class;  ## This will bless and
29.                                ## return a Book::Handler class
30.  }
31.
32.  # start_element event handler
33.  sub start_element {
34.    my ($self, $element) = @_;
35.
36.    if ($element->{Attributes}->{'{}isbn'}->{Value} eq $self->{ISBN}) {
37.      $flag = 1;
38.      $elem = $element->{Name};
39.    }
40.  }
41.
42.  # characters event handler
43.  sub characters {
44.    my ($self, $char) = @_;
45.    $data = $char->{Data};
46.  }
47.
48.  # end_element event handler
49.  sub end_element {
50.    my ($self, $element) = @_;
51.
52.    if ($flag and $element->{Name} eq $elem) {
53.      $flag = 0;
54.      $elem = "";
55.    }
56.
57.    if ($flag) {
58.      ${$self->{RETURN_MESSAGE}} .= "$element->{Name}: $data\n";
59.    }
60.  }
 

This Perl module is very similar to the SAX examples that we discussed in Chapter 3, "Event-Driven Parser Modules," so we won't go through it in great detail. As you can see, Books.pm uses a SAX2 parser to iterate through the ch10_book_inventory.xml file and retrieve the information based on the ISBN number that was provided. After the ISBN number is found, the module Books::Handler collects the data and appends it to the string that is later returned in the getInfo method. If you are having difficulties, refer to Chapter 3 for more information.

The next step is to create a SOAP server that accepts incoming RPCs from the SOAP client. After the RPCs are accepted, they must be routed to the appropriate module and methods. The SOAP server is shown in Listing 10.10.

Listing 10.10 SOAP server. (Filename: ch10_book_service.cgi)

1.  #!perl
2.
3.  use SOAP::Transport::HTTP;
4.  SOAP::Transport::HTTP::CGI
5.    ->dispatch_to('Books::(?:getInfo)')
6.    ->handle; 

Yes, that's all there is to it.You can see how easily and quickly you can create a SOAP server. The SOAP server can accept and forward incoming requests to the methods of any module. So, it is fair to say that Perl web service programming with the SOAP::Lite module can be accomplished using only six lines of code by anyone who can type the preceding program without any typing mistakes. Let's discuss a few subtle points about this example.

1 The construct on the first line (!#perl) is the shebang line, and it specifies that the Perl interpreter should run this program as a Common Gateway Interface (CGI) script. Although it is not mandatory to include the shebang to run non-CGI programs, the server's CGI execution environment requires this line to execute the script with the correct interpreter.

3 In this example, we're using SOAP and the HTTP protocol on the standard port 80. So, we need the use SOAP::Transport::HTTP pragma. The SOAP::Lite Perl module supports a number of other protocols. In addition to HTTP, the SOAP::Lite Perl module supports POP3, TCP, or SMTP. For additional information on support for these transport protocols, please see the perldoc SOAP::Lite documentation.

4–6 This section of the Perl application is where our SOAP web service server handles the incoming RPC calls. There are two steps to the incoming RPC calls. First, we use the dispatch_to method to specify the module (that is, namespace) we are using to make the calls, as well as the methods we want to allow to be invoked. Second, we call the handle() method that receives and parses the SOAP request message and processes the RPC. After the method returns, the SOAP response message is sent back to the client.

That's about it for the server side. Not too bad, right? So far, we have developed the following server-side components:

  • A Perl module to locate and return the book inventory information

  • The XML document that contains the book inventory information

  • The SOAP server to handle the RPCs and process all web service requests

These are all the components required on the server side. The last piece of our web service example that we need is a web service client. The SOAP client is discussed in the next section.

SOAP Client

This section discusses the SOAP client that communicates with our web services server that reads the book inventory. Our web services client application is very similar to the application we discussed earlier that accessed the Weather-Temperature web service. This is an important point because after you're familiar with the structure of a SOAP client, chances are that you will only need minor modifications to use any web service. The book inventory web service client is shown in Listing 10.11.

Listing 10.11 SOAP client to access the book inventory . (Filename: ch10_soap_book_client.pl)

1.   use strict;
2.   use SOAP::Lite;
3.
4.   # ISBN come in as a command line argument
5.   my $isbn = shift ||
6.     die "Must start the service with ISBN number\n";
7.
8.   print "Now searching for a book with ISBN # $isbn\n\n";
9.
10.  # Instantiate a SOAP::Lite object, passing in the ISBN
11.  # number as an argument.
12.  my $result = new SOAP::Lite
13.    ->uri('urn:Books')
14.    ->proxy('http://localhost/cgi-bin/book_service.cgi')
15.    ->getInfo($isbn);
16.
17.  # Print the result or error.
18.  unless ($result->fault) {
19.    print $result->result();
20.  } else {
21.    print join ', ',
22.      $result->faultcode,
23.      $result->faultstring,
24.      $result->faultfactor,
25.      $result->faultdetail;
26.  }
 

1–8 Our book client starts with the standard use strict pragma statement. Because we're using the SOAP::Lite module, we also need the use SOAP::Lite pragma statement. Our application requires an ISBN number as a command-line argument and proceeds to invoke the web service. We assign the command-line argument to $isbn, or terminate the application if a command-line argument isn't provided. A message is generated that provides some feedback to the user that indicates that the search is in progress.

  • + Share This
  • 🔖 Save To Your Account