6.2 DevelopMentor s SOAP Module


6.2 DevelopMentor's SOAP Module

The first of the modules that will be examined is the modestly named SOAP module from the engineers at DevelopMentor (http://www.develop.com). This module was originally engineering and written by Keith Brown, who worked in close concert with a Java engineer Don Box on a similar toolkit for Java. Their goal was to develop their tools in a side-by-side fashion, which allowed them to focus on both the feature set for the modules and on an interface that was consistent in both languages.

The primary drawback to this module is that it doesn't appear to be in active maintenance or development. The full SOAP specification isn't yet implemented in the toolkit, and likewise there is no level of support for the emerging SOAP 1.2 standard. It isn't clear what future plans there are for the module.

6.2.1 Example: Client to Convert a Number to Words

This script, shown in Example 6-1, connects to a public server that converts integer numbers to their text equivalents. It uses the SOAP toolkit to manage all the abstract elements such as XML encoding, the HTTP transport, and decoding the resulting XML. You can find a list of public SOAP services, including this one, at http://www.xmethods.com. [1]

[1] While not a strictly Perl site, the range of services listed here are excellent for developing tests. They represent SOAP implementations ranging from Delphi to .Net.

The service uses a RPC model for its interface. The service itself is simple: it takes an integer number and returns to the client a string of English text that expresses the value in words. Our client script takes the integer as a command-line argument and prints the string it gets back from the server.

Example 6-1. num2text.pl, converting an integer to text
 #!/usr/bin/perl     use strict;     use SOAP::EnvelopeMaker; use SOAP::Parser; use SOAP::Struct; use SOAP::Transport::HTTP::Client;     my $num = shift; $num =~ /^\d+$/ or die "USAGE: 
 #!/usr/bin/perl     use strict;     use SOAP::EnvelopeMaker; use SOAP::Parser; use SOAP::Struct; use SOAP::Transport::HTTP::Client;     my $num = shift; $num =~ /^\d+$/ or die "USAGE: $0 num\n";     my ($server, $endpoint, $soapaction, $method, $method_urn,     $message, $envelope, $response, $parser); $server     = 'www.tankebolaget.se'; $endpoint   = '/scripts/NumToWords.dll/soap/INumToWords'; $soapaction =     'urn:NumToWordsIntf-INumToWords#NumToWords_English'; $method     = 'NumToWords_English'; $method_urn = 'urn:NumToWordsIntf-INumToWords';     $envelope = SOAP::EnvelopeMaker->new(\$message); $envelope->set_body($method_urn, $method, 0,                     SOAP::Struct->new(aNumber => $num)); $response = SOAP::Transport::HTTP::Client->new( )                 ->send_receive($server, 80, $endpoint,                                $method_urn, $method,                                $message); $parser = SOAP::Parser->new; $parser->parsestring($response); $response = $parser->get_body; if (exists $response->{return}) {     print "$num may be expressed as $response->{return}\n"; } else {     print "A fault ($response->{faultcode}) occurred: " .         "$response->{faultstring}\n"; }     exit; 
num\n"; my ($server, $endpoint, $soapaction, $method, $method_urn, $message, $envelope, $response, $parser); $server = 'www.tankebolaget.se'; $endpoint = '/scripts/NumToWords.dll/soap/INumToWords'; $soapaction = 'urn:NumToWordsIntf-INumToWords#NumToWords_English'; $method = 'NumToWords_English'; $method_urn = 'urn:NumToWordsIntf-INumToWords'; $envelope = SOAP::EnvelopeMaker->new($message); $envelope->set_body($method_urn, $method, 0, SOAP::Struct->new(aNumber => $num)); $response = SOAP::Transport::HTTP::Client->new( ) ->send_receive($server, 80, $endpoint, $method_urn, $method, $message); $parser = SOAP::Parser->new; $parser->parsestring($response); $response = $parser->get_body; if (exists $response->{return}) { print "$num may be expressed as $response->{return}\n"; } else { print "A fault ($response->{faultcode}) occurred: " . "$response->{faultstring}\n"; } exit;

This may appear somewhat complex, but the elements themselves are simple to understand, despite how much seems to be present in such a "simple" example.

The first few lines are common to almost all Perl SOAP clients . The block of four use statements pull in the elements of the SOAP module used within the program. For this example, we need code for the envelope, parser, construction of data structures, and the HTTP client transport layer. The next line after those simply takes the one integer argument from the command line and checks that it is, in fact, a valid integer.

The first SOAP-specific action is this line:

 $envelope = SOAP::EnvelopeMaker->new($message); 

The $envelope object can construct and manipulate a message. In this case, the constructor is given a reference to a scalar variable, $message . When the envelope is ready to be transmitted, it's stored in this variable as one long string.

The constructor can also take a subroutine reference:

 $envelope = SOAP::EnvelopeMaker->new(sub { ... }); 

When the subroutine reference gets called, it is called with the envelope string and might, for example, spool the output directly to a raw TCP/IP socket.

The next line in the client script shows not only a class method for SOAP::EnvelopeMaker but also inline use of SOAP::Struct :

 $envelope->set_body($method_urn, $method, 0,                     SOAP::Struct->new(aNumber => $num)); 

The set_body method can take content in three ways. You can pass in an object (as we do here with a SOAP::Struct ), you can pass in a simple string to be used verbatim, or you can pass in a hash reference (which would have been serialized like a SOAP::Struct object).

The $method_urn and $method values tell the body constructor what the outer method (or containing tag) will be called, and what namespace it should be associated with. The third argument is used when the body is meant for a special-purpose use. Its value is in other examples as well, for now.

The parameter is the integer value the user passed on the command line, accessed by the name aNumber . After the set_body call, the scalar variable $message now holds the XML-encoded SOAP message.

6.2.1.1 Autogenerated XML

Example 6-2 shows the XML message generated by the code in Example 6-1, with line breaks added for readability. For the sake of this example, the number given to the program was "1001."

Example 6-2. XML message for "num2text.pl 1001"
 <s:Envelope     xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"     xmlns:xsd="http://www.w3.org/1999/XMLSchema"     xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"     xmlns:n1="urn:NumToWordsIntf-INumToWords"     s:encodingStyle=         "http://schemas.xmlsoap.org/soap/encoding/">   <s:Body>     <n1:NumToWords_English id="ref-1" s:root="1">       <aNumber>1001</aNumber>     </n1:NumToWords_English>   </s:Body> </s:Envelope> 

We won't show XML in future examples, as the toolkits successfully hide the details from you.

The XML in the example is entirely autogenerated by the classes within the SOAP module. Some things to note:

  • The message is encoded as a SOAP 1.1 request (check the URN of the s namespace).

  • It references earlier versions of the XML Schema.

  • The URN for the method name is declared in the Envelope tag, though it could just as easily have been deferred to either the Body tag or the NumToWords_English tag itself.

  • The opening tag generated for the NumToWords_English call goes to the trouble of defining an id attribute value and explicitly specifying that the entry is the root.

It's not unusual for autogenerated output to have abbreviated names ( s as opposed to SOAP-ENV , or even soap ) and unnecessary information like the attributes given in the method call's opening tag. Because the modules assume that the message isn't targeted to human reading, completeness is favored over clarity.

Though this example doesn't use it, there's also an add_header method for building the message header one entry at a time. It's documented in the manpage for the SOAP::EnvelopeMaker class, along with greater detail on the new and set_body methods .

Returning to the code, the transport code is in this block:

 $response = SOAP::Transport::HTTP::Client->new( )                 ->send_receive($server, 80, $endpoint,                                $method_urn, $method,                                $message); 

The SOAP::Transport::HTTP::Client wraps a number of lower-level components such as LWP::UserAgent and the related request and response classes. In the example, there was no need to hold on to the client object, so it was used in place and discarded after the send_receive method was called. As with the other classes, the finer details of the methods and their function can be found in the documentation that comes with the package itself.

The last of the SOAP elements used in Example 6-1 are:

 $parser = SOAP::Parser->new; $parser->parsestring($response); $response = $parser->get_body; 

Upon return from the server, the value in $response should be the response message returned from the server. That message comes back in the form of an XML document, so these lines use the SOAP::Parser class to work it into a Perl-readable data structure, in this case a hash-reference.

When the SOAP elements of the application have run their course, all that is left is the if-else block, in which the body extracted from the response is checked for an element called return . This is the element a SOAP RPC implementation is supposed to use to pass back the value from a successful call. If the element isn't present, the program assumes that a fault occurred and reports a failure using the faultstring and faultcode elements of the response.

When called as in this example, with the integer value 1001, the program returns the following simple output:

 1001 may be expressed as one thousand and one 

Because the SOAP module doesn't appear to be currently maintained , the focus now shifts to the other Perl toolkit for SOAP.



Programming Web Services with Perl
Programming Web Services with Perl
ISBN: 0596002068
EAN: 2147483647
Year: 2000
Pages: 123

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net