WSO2 Web Services Framework/Perl (WSO2 WSF/Perl) is the Perl extension to the WSO2 Web Services Framework/C (WSF/C). Using this Perl extension, you can write applications that consume Web services. WSF/Perl supports SOAP 1.1, SOAP 1.2, SOAP MTOM, WS-Addressing, WS-Security UsernameToken, WS-ReliableMessaging as well as REST style invocation. WSF/Perl distinguishes itself being the first and the only Web Services Framework for Perl to support this stack of WS specifications.
Please see the Installation Guide for more information.
This section is aimed to help you get a Web Service up quickly using WSO2 WSF/Perl consumer API.
First follow the installation guide and get WSO2 WSF/Perl working
on your machine [Installation
Guide].
To start simple, let's see how to write a simple client to consume the Flickr photo search service.
Step 1:
my $req_payload_string = '
<x:FlickrRequest xmlns:x="urn:flickr">
<method>flickr.photos.search</method>
<api_key>#{key}</api_key>
<text>Sri Lanka</text>
</x:FlickrRequest>
';
In the above payload, you have to enter your flickr key in the "key" element. The "text" element contains the words that we want to search for.
NOTE: You can create a flickr key here
Step 2:Next we need to create a WSClient, with the options to be used by the client. For the Flickr photo service, we have to use only one option, i.e the endpoint reference of the Flickr service.
my $client = new WSO2::WSF::WSClient( { 'wsfc_home' => '/opt/wso2/wsf_c',
'to' => 'http://api.flickr.com/services/soap/' } );
Here is the complete source code for the Flickr photo search [flickr.pl]. Please remember to replace "key" string with a valid Flickr key.
use WSO2::WSF;
$payload =<<E;
<x:FlickrRequest xmlns:x="urn:flickr">
<method>flickr.test.echo</method>
<api_key>your_api_key</api_key>
<name>vacation</name>
</x:FlickrRequest>
E
my $client = new WSO2::WSF::WSClient( { 'wsfc_home' => '/opt/wso2/wsf_c',
'to' => 'http://api.flickr.com/services/soap/' } );
my $response = $client->request( { 'payload' => $payload } );
print $response->{str};
To run the script just execute the following command in a terminal.
perl flickr.pl
Now that you know how to write a client with WSO2 WSF/Perl, let's see the steps in detail.
The steps to be followed when implementing a client with WSO2 WSF/Perl include:
my $message = new WSO2::WSF::WSMessage(
{ 'payload' => $payload,
'wsfc_home' => '/opt/wso2/wsf_c/',
'to' => 'http://localhost:8585/axis2/services/echo'
} );
In the above code fragment, a WSMessage instance is created with a payload to be sent in the request and the service endpoint. The "to" element of the options hash is mapped to the address of the location of the service. In other words, the "to" address indicates where the request should be sent to.
my $client = new WSO2::WSF::WSClient();
my $response = $client->request( $message );
For sending a request with the output message created earlier, we need a WSClient instance. We pass the message to be sent to the service to the request() method. This will send the payload contained in the given message and receive the response and return a message instance with the response payload.
print $response->{str};
In our client sample, we access the response payload as a string from the returned message instance and display it.
Here is the complete source code for the client : hello_client.pl
To run the client, execute the following command on a terminal.
perl hello_client.pl
For consuming Web services with WSO2 WSF/Perl, using the XML in/out model,
you need to first find out the request payload format and the response
payload format. You also need to know the service endpoint URI.
Once this information is available, you can construct a WSMessage instance
with the payload and service endpoint URI information. These are the minimum
requirements for consuming a Web Service. These basics were explained in the
quick start guide.
The advantage of using the WSO2 WSF extension is that it supports more than just SOAP. You can use WS-Addressing, XOP/MTOM and WS-Security UsernameToken when providing and consuming Web services. You can also invoke services using REST style calls.
The following sections explain how you can achieve more with the options available for WSMessage and WSClient.
You can use the "use_soap" option at client level to specify the SOAP
version to be used. If this option is not set, the default SOAP version used
is SOAP 1.2.
There are multiple ways of setting the SOAP version, you can use any one of them.
# use SOAP 1.2
my $client = new WSO2::WSF::WSClient( {} );
my $client = new WSO2::WSF::WSClient( { 'useSOAP' => '1.2' } );
my $client = new WSO2::WSF::WSClient( { 'useSOAP' => 'true' } );
# use SOAP 1.1
my $client = new WSO2::WSF::WSClient( { 'useSOAP' => '1.1' } );
my $client = new WSO2::WSF::WSClient( { 'useSOAP' => 'false' } );
There is another option named "http_method", that you can use to specify the HTTP method to be used. When SOAP is in use, the default HTTP method used will be "POST" all the time. If you specify "GET" when SOAP is in use, then no request will be sent, because WSO2 WSF/Perl does not support SOAP with HTTP GET.
If you want to consume Web services using REST style calls, that can be
done by setting the "use_soap" option to "false". In case of REST style of
invocation, you can use either the HTTP POST method or the HTTP GET method.
The following example shows how to enable a REST style invocation using different HTTP methods.
# REST with HTTP POST
my $client = new WSO2::WSF::WSClient( { 'useSOAP' => 'false' } );
my $client = new WSO2::WSF::WSClient( { 'useSOAP' => 'false', 'HTTPMethod' => 'POST' } );
my $client = new WSO2::WSF::WSClient( { 'useSOAP' => 'false', 'HTTPMethod' => 'post' } );
# REST with HTTP GET
my $client = new WSO2::WSF::WSClient( { 'useSOAP' => 'false', 'HTTPMethod' => 'GET' } );
my $client = new WSO2::WSF::WSClient( { 'useSOAP' => 'false', 'HTTPMethod' => 'get' } );
When invoking Web Services, the WSO2 WSF/Perl extension allows you to provide the message payload as an XML string or as a WSMessage object.
Using a string as the request payload:
my $request_payload = '
<ns1:echoString xmlns:ns1="http://perl.wsf.wso2.net/samples">
<text>Hello World!</text>
</ns1:echoString>
';
my $client = new WSO2::WSF::WSClient( { 'wsfc_home' => '/opt/wso2/wsf_c',
'to' => 'http://localhost:9090/axis2/services/echo' } );
my $response = $client->request( { 'payload' => $request_payload } );
print $response->{str};
Using a WSMessage instance as the request payload:
my $request_payload = '
<ns1:echoString xmlns:ns1="http://perl.wsf.wso2.net/samples">
<text>Hello World!</text>
</ns1:echoString>
';
my $message = new WSO2::WSF::WSMessage( { 'wsfc_home' => '/opt/wso2/wsf_c',
'to' => 'http://localhost:9090/axis2/services/echo',
'payload' => $request_payload } );
my $client = new WSO2::WSF::WSClient();
my $response = $client->request( $message );
print $response->{str};
WSO2 WSF/Perl allows you to send and receive binary data with SOAP messages using MTOM/XOP conventions. When sending attachments, you have to use a WSMessage instance to represent the payload, and give the binary data as an array. When receiving attachments, you can get the attachments received from the attachments array of the WSMessage instance returned.
For sending an attachment, you need to specify the element where the attachment reference should be included in the payload.
my $request_payload = '
<ns1:upload xmlns:ns1="http://php.axis2.org/samples/mtom">
<ns1:fileName>test.jpg</ns1:fileName>
<ns1:image xmlmime:contentType="image/jpeg" xmlns:xmlmime="http://www.w3.org/2004/06/xmlmime">
<xop:Include href="cid:myid1" xmlns:xop="http://www.w3.org/2004/08/xop/include" />
</ns1:image>
</ns1:upload>
';
In the above sample payload shown, by placing the "Include" element within the "image" element, we specify that the attachment reference should be included in the "image" element. The "href" attribute of the "Include" element gives the ID of the attachment element in the attachments array of the outgoing WSMessage instance. Once the payload is prepared, you have to create the message with the attachment data array containing the binary data to be attached.
open FILE, "< axis2.jpg";
undef $/;
my $contents = <FILE>;
my $msg = new WSO2::WSF::WSMessage( { 'payload' => $payload,
'attachments' => {"myid1" => $contents} } );
In the above sample code fragment, we load the image contents to the "content" variable and pass the variable to the attachments option when creating the message. In the attachments associative array, you have to give the same ID as was given in the "Include" element's "href" attribute in the payload. In this sample, we use "myid1" as the ID.
When sending attachments, you can configure the client either to send the
attachment in the optimized format or in non-optimized format. If the
attachment is sent in binary optimized format, the file content will be sent
as it is, out of the SOAP body, using MIME headers and the payload would have
an XOP:Include element, referring to the MIME part that contains the binary
attachment.
In case of binary non-optimized format, the attachment content will be sent
in the payload itself, as a base64 encoded string.
# send attachments binary optimized
my $client = new WSO2::WSF::WSClient( { 'useMTOM' => 'true' } );
# send attachments binary non-optimized
my $client = new WSO2::WSF::WSClient( { 'useMTOM' => 'false' } );
WS-Addressing provides mechanisms to address Web Services and messages. With WSO2 WSF/Perl, you can use both WS-Addressing version 1.0 as well as the submission version.
There are two basic requirements that you have to specify when using WS-Addressing on the client side with WSO2 WSF/Perl. One is that you have to provide a WS-Addressing action at message level. The other is that you have to enable the use of WS-Addressing at client level.
my $message = new WSO2::WSF::WSMessage(
{ 'payload' => $payload,
'wsfc_home' => '/opt/wso2/wsf_c/',
'to' => 'http://localhost/samples/echo_service_addr.php',
'action' => 'http://php.axis2.org/samples/echoString'
} );
my $client = new WSO2::WSF::WSClient( { 'useWSA' => 'TRUE' } );
In the above sample code fragment, the WS-Addressing action is set using the "action" array element of the options array passed to the WSMessage constructor. WS-Addressing is enabled with the "use_wsa" option passed to the WSClient constructor.
You can choose to use different addressing versions. For that you have to use one of the possible options shown below.
# Setting WS-Addressing 1.0
my $client = new WSO2::WSF::WSClient( { 'useWSA' => 'TRUE' } );
my $client = new WSO2::WSF::WSClient( { 'useWSA' => '1.0' } );
# Setting WS-Addressing submission
my $client = new WSO2::WSF::WSClient( { 'useWSA' => 'submission' } );
In addition to the action, there are other WS-Addressing related SOAP headers that can be sent in a message. WSO2 WSF/Perl has support to set those headers as properties at the message level or as options at the client level. An example is shown below.
my $message = new WSO2::WSF::WSMessage( { 'payload' => $request_payload,
'to' => 'http://www.company_foo.com/order_processing/process',
'action' => 'http://perl.wsf.wso2.net/samples/order',
'from' => 'http://www.company_bar.com/order_placing/place',
'replyTo' => 'http://www.company_bar.com/billing/bill',
'faultTo' => 'http://www.company_bar.com/re_odering/order'
} );
In the above example, company "bar" sends a purchase order to company "foo" from the place order client. If the service invocation is successful, company foo would send the bill to the billing service of company bar; if the order failed, re-ordering service of company bar would be sent the fault details which would decide how to place the order again. WS-Addressing helps us to manage the order process, with replies and faults being directed to different endpoints.
With WSPolicy and WSSecurityToken, you can use WS-Security usernameTokens, encryption, signing, along with timestamp, time-to-live and digest support. The simplest form of using usernameToken is to provide a username and a password.
my $security_options = { 'useUsernameToken' => 'TRUE' };
my $policy = new WSO2::WSF::WSPolicy( { 'security' => $security_options } );
my $security_token = new WSO2::WSF::WSSecurityToken( { 'user' => 'frodo',
'password' => 'icannothasring'
} );
my $security_options = { 'useUsernameToken' => 'TRUE',
'includeTimeStamp' => 'TRUE' };
my $policy = new WSO2::WSF::WSPolicy( { 'security' => $security_options } );
my $security_token = new WSO2::WSF::WSSecurityToken( { 'user' => 'frodo',
'password' => 'icannothasring',
'ttl' => 300 } );
The request() method of WSClient that you have seen in the samples so far
adheres to the out-in message exchange patterns. That means, when the client
sends a request, it expects a response back.
Out-only message exchange pattern is another popular pattern when consuming
services. In the out-only model, the client sends a request but does not
expect a response back. The send_message() method of WSClient supports this message
exchange pattern.
my $client = new WSO2::WSF::WSClient( { 'to' => 'http://localhost/notify_service/notify' } );
$client->send_message( { 'payload' => $request_payload } );
print "Request sent\n";
In the above sample, the notify service accepts the payload sent by the client and consumes it, and will not send any response. The return type of send_message() is void. In case of errors, it would throw a fault.