=pod

=head1 NAME

SOAP::WSDL::Manual - Accessing WSDL based web services

=head1 Accessing a WSDL-based web service

=head2 Quick walk-through for the unpatient

=over

=item * Create WSDL bindings

 perl wsdl2perl.pl -b base_dir URL 

=item * Look what has been generated

Check the results of the generator. There should be one 
MyInterfaces/SERVICE_NAME/PORT_NAME.pm file per port (and one directory per 
service).

=item * Write script

 use MyInterface::SERVICE_NAME::PORT_NAME;
 my $service = MyInterface::SERVICE_NAME::PORT_NAME->new();
 
 my $result = $service->SERVICE_METHOD();
 die $result if not $result;
 
 print $result;

C<perldoc MyInterface::SERVICE_NAME> should give you some overview about the 
service's interface structure.

The results of all calls to your service object's methods (except new) are 
objects based on SOAP::WSDL's XML schema implementation.

To access the object's properties use get_NAME / set_NAME getter/setter 
methods whith NAME corresponding to the XML tag name / the hash structure as 
showed in the generated pod.

=item  * Run script

=back

=head2 Instrumenting web services with interface classes

SOAP::WSDL (starting from 2.00) instruments WSDL based web services with 
interface classes. This means that SOAP::WSDL features a code generator 
which creates one class for every web service you want to access.

Moreover, the data types from the WSDL definitions are also wrapped into 
classes and returned to the user as objects. 

To find out which class a particular XML node should be, SOAP::WSDL uses 
typemaps. For every Web service, there's also a typemap created.

=head2 Interface class creation

To create interface classes, follow the steps above from 
L<Quick walk-through for the unpatient|Quick walk-through for the unpatient>.

If this works fine for you, skip the next paragraphs. If not, read on.

The steps to instrument a web service with SOAP::WSDL perl bindings 
(in detail) are as follows:

=over

=item * Gather web service information

You'll need to know at least a URL pointing to the web service's WSDL 
definition.

If you already know more - like which methods the service provides, or how 
the XML messages look like, that's fine. All these things will help you 
later.

=item * Create WSDL bindings

 perl wsdl2perl.pl -b base_dir URL 

This will generate the perl bindings in the directory specified by base_dir.

For more options, see L<wsdl2perl.pl> - you may want to specify class 
prefixes for XML type and element classes, type maps and interface classes, 
and you may even want to add custom typemap elements.

=item * Check the result

There should be a bunch of classes for types (in the MyTypes:: namespace by 
default), elements (in MyElements::), and at least one typemap (in 
MyTypemaps::) and one ore more interface classes (in MyInterfaces::).

If you don't already know the details of the web service you're going to 
instrument, it's now time to read the perldoc of the generated interface 
classes. It will tell you what methods each service provides, and which 
parameters they take.

If the WSDL definition is informative about what these methods do, the 
included perldoc will be, too - if not, blame the web service author.

=item * Write a perl script (or module) accessing the web service.

 use MyInterface::SERVICE_NAME;
 my $service = MyInterface::SERVICE_NAME->new();
 
 my $result = $service->SERVICE_METHOD();
 die $result if not $result;
 print $result;

The above handling of errors ("die $result if not $result") may look a bit 
strange - it is due to the nature of 
L<SOAP::WSDL::SOAP::Typelib::Fault11|SOAP::WSDL::SOAP::Typelib::Fault11> 
objects SOAP::WSDL uses for signalling failure.

These objects are false in boolean context, but serialize to their XML 
structure on stringification.

You may, of course, access individual fault properties, too. To get a list of 
fault properties, see L<SOAP::WSDL::SOAP::Typelib::Fault11>

=back

=head2 Adding missing information

Sometimes, WSDL definitions are incomplete. In most of these cases, proper 
fault definitions are missing. This means that though the specification sais 
nothing about it, Fault messages include extra elements in the 
E<lt>detailE<gt> section, or errors are even indicated by non-fault messages.

There are two steps you need to perform for adding additional information.

=over

=item * Provide required type classes

For each extra data type used in the XML messages, a type class has to be 
created. 

It is strongly discouraged to use the same namespace for hand-written and 
generated classes - while generated classes may be many, you probably will 
only implement a few by hand. These (precious) few classes may get lost in 
the mass of (cheap) generated ones. Just imagine one of your co-workers (or 
even yourself) deleting the whole bunch and re-generating everything - oops 
- almost everything. You got the point.

For simplicity, you probably just want to use builtin types wherever possible 
- you are probably not interested in whether a fault detail's error code is 
presented to you as a simpleType ranging from 1 to 10 (which you have to 
write) or as a int (which is a builtin type ready to use). 

Using builtin types for simpleType definitions may greatly reduce the number 
of additional classes you need to implement.

If the extra type classes you need include E<lt>complexType E<gt> or 
E<lt>element /E<gt> definitions, see L<SOAP::WSDL::SOAP::Typelib::ComplexType> 
and L<SOAP::WSDL::SOAP::Typelib::Element> on how to create ComplexType and 
Element type classes.

=item * Provide a typemap snippet to wsdl2perl.pl

SOAP::WSDL uses typemaps for finding out into which class' object a XML node 
should be transformed.

Typemaps basically map the path of every XML element inside the Body tag to a 
perl class.

Typemap snippets have to look like this (which is actually the default Fault 
typemap included in every generated one):

 (
 'Fault' => 'SOAP::WSDL::SOAP::Typelib::Fault11',
 'Fault/faultcode' => 'SOAP::WSDL::XSD::Typelib::Builtin::anyURI',
 'Fault/faultactor' => 'SOAP::WSDL::XSD::Typelib::Builtin::anyURI',
 'Fault/faultstring' => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
 'Fault/detail' => 'SOAP::WSDL::XSD::Typelib::Builtin::anyType',
 );

The lines are hash key - value pairs. The keys are the XPath expressions 
without occurence numbers (like [1]) relative to the Body element. 
Namespaces are ignored. 

If you don't know about XPath: They are just the names of the XML tags, 
starting from the one inside E<lt>BodyE<gt> up to the current one joined by /.

One line for every XML node is required.

You may use all builtin, generated or custom type class names as values.

Use wsdl2perl.pl -mi=FILE to include custom typemap snippets.

Note that typemap include files for wsdl2perl.pl must evaluate to a valid 
perl hash - it will be imported via eval (OK, to be honest: via I<do $file>, 
but that's almost the same...).

Your extra statements are included last, so they override potential typemap 
statements with the same keys.

=back

=head1 Accessing a web service without a WSDL definition

Accessing a web service without a WSDL definition is more cumbersome. There 
are two ways to go:

=over

=item * Write a WSDL definition and generate interface

This is the way to go if you already are experienced in writing WSDL files. 
If you are not, be warned: Writing a correct WSDL is not an easy task, and 
writing correct WSDL files with only a text editor is almost impossible.

You should definitely use a WSDL editor. The WSDL editor should support 
conformance checks for the WS-I Basic Profile (1.0 is preferred by 
SOAP::WSDL) 

=item * Write a typemap and class library from scratch

If the web service is relatively simple, this is probably easier than first 
writing a WSDL definition. Besides, it can be done in perl, a language you 
are probably more familiar with than WSDL.

L<SOAP::WSDL::XSD::Typelib::ComplexType>, L<SOAP::WSDL::XSD::Typelib::SimpleType> and 
L<SOAP::WSDL::XSD::Typelib::Element> tell you how to create subclasses of XML schema 
types.

L<SOAP::WSDL::Parser> will tell you how to create a typemap class.

=back

=head1 Troubleshooting

=head2 Accessing HTTPS webservices

You need Crypt::SSLeay installed to access HTTPS webservices.

=head2 Accessing protected web services

Passing a userndame and password, or a client certificate and key, to the 
transport layer is highly dependent on the transport backend.

=head3 Accessing HTTP(S) webservices with basic/digest authentication

When using SOAP::WSDL::Transport::HTTP (SOAP::Lite not installed), add a 
method called "get_basic_credentials" to SOAP::WSDL::Transport::HTTP:

 *SOAP::WSDL::Transport::HTTP::get_basic_credentials = sub {
 	return ($user, $password);
 };

When using SOAP::Transport::HTTP (SOAP::Lite is installed), do the same to 
this backend:

 *SOAP::Transport::HTTP::get_basic_credentials = sub {
 	return ($user, $password);
 };

=head3 Accessing HTTP(S) webservices protected by NTLM authentication

Besides passing user credentials as when accessing a web service protected 
by basic or digest authentication, you also need to enforce connection 
keep_alive on the transport backens.

To do so, pass a I<proxy> argument to the new() method of the generated 
class. This unfortunately means that you have to set the endpoint URL, too:

 my $interface = MyInterfaces::SERVICE_NAME::PORT_NAME->new({
     proxy => [ $url, keep_alive => 1 ]
 });

You may, of course, decide to just hack the generated class. Be advised that 
subclassing might be a more appropriate solution - re-generating overwrites 
your changes.

=head3 Accessing HTTPS webservices protected by certificate authentication

You need Crypt::SSLeay installed to access HTTPS webservices.

See L<Crypt::SSLeay> on how to configure client certificate authentication.

=head1 SEE ALSO

L<SOAP::WSDL::Manual::Glossary> The meaning of all these words

L<SOAP::WSDL::Client> Basic client for SOAP::WSDL based interfaces

L<SOAP::WSDL> an interpreting WSDL based SOAP client

=head1 LICENSE

Copyright 2007 Martin Kutter.

This file is part of SOAP-WSDL. You may distribute/modify it under 
the same terms as perl itself

=head1 AUTHOR

Martin Kutter E<lt>martin.kutter fen-net.deE<gt>

=cut
