SOAP - WRITING A SOAP SERVER
WRITING A SOAP SERVER ^
See SOAP::Server, or SOAP::Transport.
FEATURES ^
ATTACHMENTS
SOAP::Lite features support for the SOAP with Attachments specification. Currently, SOAP::Lite only supports MIME based attachments. DIME based attachments are yet to be fully functional.
EXAMPLES
Client sending an attachment
SOAP::Lite clients can specify attachments to be sent along with a request by using the SOAP::Lite::parts() method, which takes as an argument an ARRAY of MIME::Entity's.
use SOAP::Lite;
use MIME::Entity;
my $ent = build MIME::Entity
Type => "image/gif",
Encoding => "base64",
Path => "somefile.gif",
Filename => "saveme.gif",
Disposition => "attachment";
my $som = SOAP::Lite
->uri($SOME_NAMESPACE)
->parts([ $ent ])
->proxy($SOME_HOST)
->some_method(SOAP::Data->name("foo" => "bar"));
Client retrieving an attachment
A client accessing attachments that were returned in a response by using the SOAP::SOM::parts() accessor.
use SOAP::Lite;
use MIME::Entity;
my $soap = SOAP::Lite
->uri($NS)
->proxy($HOST);
my $som = $soap->foo();
foreach my $part (${$som->parts}) {
print $part->stringify;
}
Server receiving an attachment
Servers, like clients, use the SOAP::SOM module to access attachments transmitted to it.
package Attachment;
use SOAP::Lite;
use MIME::Entity;
use strict;
use vars qw(@ISA);
@ISA = qw(SOAP::Server::Parameters);
sub someMethod {
my $self = shift;
my $envelope = pop;
foreach my $part (@{$envelope->parts}) {
print "AttachmentService: attachment found! (".ref($part).")\n";
}
# do something
}
Server responding with an attachment
Servers wishing to return an attachment to the calling client need only return MIME::Entity objects along with SOAP::Data elements, or any other data intended for the response.
package Attachment;
use SOAP::Lite;
use MIME::Entity;
use strict;
use vars qw(@ISA);
@ISA = qw(SOAP::Server::Parameters);
sub someMethod {
my $self = shift;
my $envelope = pop;
my $ent = build MIME::Entity
'Id' => "<1234>",
'Type' => "text/xml",
'Path' => "some.xml",
'Filename' => "some.xml",
'Disposition' => "attachment";
return SOAP::Data->name("foo" => "blah blah blah"),$ent;
}
DEFAULT SETTINGS
Though this feature looks similar to autodispatch they have (almost) nothing in common. This capability allows you specify default settings so that all objects created after that will be initialized with the proper default settings.
If you wish to provide common proxy() or uri() settings for all SOAP::Lite objects in your application you may do:
use SOAP::Lite
proxy => 'http://localhost/cgi-bin/soap.cgi',
uri => 'http://my.own.com/My/Examples';
my $soap1 = new SOAP::Lite; # will get the same proxy()/uri() as above
print $soap1->getStateName(1)->result;
my $soap2 = SOAP::Lite->new; # same thing as above
print $soap2->getStateName(2)->result;
# or you may override any settings you want
my $soap3 = SOAP::Lite->proxy('http://localhost/');
print $soap3->getStateName(1)->result;
Any SOAP::Lite properties can be propagated this way. Changes in object copies will not affect global settings and you may still change global settings with SOAP::Lite->self call which returns reference to global object. Provided parameter will update this object and you can even set it to undef:
SOAP::Lite->self(undef);
The use SOAP::Lite syntax also lets you specify default event handlers for your code. If you have different SOAP objects and want to share the same on_action() (or on_fault() for that matter) handler. You can specify on_action() during initialization for every object, but you may also do:
use SOAP::Lite
on_action => sub {sprintf '%s#%s', @_};
and this handler will be the default handler for all your SOAP objects. You can override it if you specify a handler for a particular object. See t/*.t for example of on_fault() handler.
Be warned, that since use ... is executed at compile time all use statements will be executed before script execution that can make unexpected results. Consider code:
use SOAP::Lite proxy => 'http://localhost/';
print SOAP::Lite->getStateName(1)->result;
use SOAP::Lite proxy => 'http://localhost/cgi-bin/soap.cgi';
print SOAP::Lite->getStateName(1)->result;
Both SOAP calls will go to 'http://localhost/cgi-bin/soap.cgi'. If you want to execute use at run-time, put it in eval:
eval "use SOAP::Lite proxy => 'http://localhost/cgi-bin/soap.cgi'; 1" or die;
Or alternatively,
SOAP::Lite->self->proxy('http://localhost/cgi-bin/soap.cgi');
SETTING MAXIMUM MESSAGE SIZE
One feature of SOAP::Lite is the ability to control the maximum size of a message a SOAP::Lite server will be allowed to process. To control this feature simply define $SOAP::Constants::MAX_CONTENT_SIZE in your code like so:
use SOAP::Transport::HTTP;
use MIME::Entity;
$SOAP::Constants::MAX_CONTENT_SIZE = 10000;
SOAP::Transport::HTTP::CGI
->dispatch_to('TemperatureService')
->handle;
IN/OUT, OUT PARAMETERS AND AUTOBINDING
SOAP::Lite gives you access to all parameters (both in/out and out) and also does some additional work for you. Lets consider following example:
<mehodResponse>
<res1>name1</res1>
<res2>name2</res2>
<res3>name3</res3>
</mehodResponse>
In that case:
$result = $r->result; # gives you 'name1'
$paramout1 = $r->paramsout; # gives you 'name2', because of scalar context
$paramout1 = ($r->paramsout)[0]; # gives you 'name2' also
$paramout2 = ($r->paramsout)[1]; # gives you 'name3'
or
@paramsout = $r->paramsout; # gives you ARRAY of out parameters
$paramout1 = $paramsout[0]; # gives you 'res2', same as ($r->paramsout)[0]
$paramout2 = $paramsout[1]; # gives you 'res3', same as ($r->paramsout)[1]
Generally, if server returns return (1,2,3) you will get 1 as the result and 2 and 3 as out parameters.
If the server returns return [1,2,3] you will get an ARRAY reference from result() and undef from paramsout().
Results can be arbitrary complex: they can be an array references, they can be objects, they can be anything and still be returned by result() . If only one parameter is returned, paramsout() will return undef.
Furthermore, if you have in your output parameters a parameter with the same signature (name+type) as in the input parameters this parameter will be mapped into your input automatically. For example:
Server Code:
sub mymethod {
shift; # object/class reference
my $param1 = shift;
my $param2 = SOAP::Data->name('myparam' => shift() * 2);
return $param1, $param2;
}
Client Code:
$a = 10;
$b = SOAP::Data->name('myparam' => 12);
$result = $soap->mymethod($a, $b);
After that, $result == 10 and $b->value == 24! Magic? Sort of.
Autobinding gives it to you. That will work with objects also with one difference: you do not need to worry about the name and the type of object parameter. Consider the PingPong example (examples/My/PingPong.pm and examples/pingpong.pl):
Server Code:
package My::PingPong;
sub new {
my $self = shift;
my $class = ref($self) || $self;
bless {_num=>shift} => $class;
}
sub next {
my $self = shift;
$self->{_num}++;
}
Client Code:
use SOAP::Lite +autodispatch =>
uri => 'urn:',
proxy => 'http://localhost/';
my $p = My::PingPong->new(10); # $p->{_num} is 10 now, real object returned
print $p->next, "\n"; # $p->{_num} is 11 now!, object autobinded
STATIC AND DYNAMIC SERVICE DEPLOYMENT
Let us scrutinize the deployment process. When designing your SOAP server you can consider two kind of deployment: static and dynamic. For both, static and dynamic, you should specify MODULE, MODULE::method, method or PATH/ when creating useing the SOAP::Lite module. The difference between static and dynamic deployment is that in case of 'dynamic', any module which is not present will be loaded on demand. See the "SECURITY" section for detailed description.
When statically deploying a SOAP Server, you need to know all modules handling SOAP requests before.
Dynamic deployment allows extending your SOAP Server's interface by just installing another module into the dispatch_to path (see below).
STATIC DEPLOYMENT EXAMPLE
use SOAP::Transport::HTTP;
use My::Examples; # module is preloaded
SOAP::Transport::HTTP::CGI
# deployed module should be present here or client will get
# 'access denied'
-> dispatch_to('My::Examples')
-> handle;
For static deployment you should specify the MODULE name directly.
You should also use static binding when you have several different classes in one file and want to make them available for SOAP calls.
DYNAMIC DEPLOYMENT EXAMPLE
use SOAP::Transport::HTTP;
# name is unknown, module will be loaded on demand
SOAP::Transport::HTTP::CGI
# deployed module should be present here or client will get 'access denied'
-> dispatch_to('/Your/Path/To/Deployed/Modules', 'My::Examples')
-> handle;
For dynamic deployment you can specify the name either directly (in that case it will be required without any restriction) or indirectly, with a PATH. In that case, the ONLY path that will be available will be the PATH given to the dispatch_to() method). For information how to handle this situation see "SECURITY" section.
SUMMARY
dispatch_to(
# dynamic dispatch that allows access to ALL modules in specified directory
PATH/TO/MODULES
# 1. specifies directory
# -- AND --
# 2. gives access to ALL modules in this directory without limits
# static dispatch that allows access to ALL methods in particular MODULE
MODULE
# 1. gives access to particular module (all available methods)
# PREREQUISITES:
# module should be loaded manually (for example with 'use ...')
# -- OR --
# you can still specify it in PATH/TO/MODULES
# static dispatch that allows access to particular method ONLY
MODULE::method
# same as MODULE, but gives access to ONLY particular method,
# so there is not much sense to use both MODULE and MODULE::method
# for the same MODULE
);
In addition to this SOAP::Lite also supports an experimental syntax that allows you to bind a specific URL or SOAPAction to a CLASS/MODULE or object.
For example:
dispatch_with({
URI => MODULE, # 'http://www.soaplite.com/' => 'My::Class',
SOAPAction => MODULE, # 'http://www.soaplite.com/method' => 'Another::Class',
URI => object, # 'http://www.soaplite.com/obj' => My::Class->new,
})
URI is checked before SOAPAction. You may use both the dispatch_to() and dispatch_with() methods in the same server, but note that dispatch_with() has a higher order of precedence. dispatch_to() will be checked only after URI and SOAPAction has been checked.
See also: EXAMPLE APACHE::REGISTRY USAGE, "SECURITY"
COMPRESSION
SOAP::Lite provides you option to enable transparent compression over the wire. Compression can be enabled by specifying a threshold value (in the form of kilobytes) for compression on both the client and server sides:
Note: Compression currently only works for HTTP based servers and clients.
Client Code
print SOAP::Lite
->uri('http://localhost/My/Parameters')
->proxy('http://localhost/', options => {compress_threshold => 10000})
->echo(1 x 10000)
->result;
Server Code
my $server = SOAP::Transport::HTTP::CGI
->dispatch_to('My::Parameters')
->options({compress_threshold => 10000})
->handle;
source:http://search.cpan.org/~phred/SOAP-Lite-1.20/lib/SOAP/Lite.pm#WRITING_A_SOAP_SERVER