=head1 NAME

XML::Compile::SOAP - base-class for SOAP implementations

=head1 INHERITANCE

 XML::Compile::SOAP is extended by
   XML::Compile::SOAP11
   XML::Compile::SOAP12

=head1 SYNOPSIS

 ** WARNING: Implementation not finished (but making progress)
 ** see README.todo in distribution!!!

 use XML::Compile::SOAP11::Client;
 use XML::Compile::Util qw/pack_type/;

 # There are some (hidden) differences between SOAP1.1 and 1.2
 my $client = XML::Compile::SOAP11::Client->new;

 # load extra schemas always explicitly
 $client->schemas->importDefinitions(...);

 # !!! THE NEXT STEPS ARE ONLY REQUIRED WHEN YOU DO NOT HAVE A WSDL
 # !!! SEE XML::Compile::WSDL11 IF YOU HAVE A WSDL FILE
 
 my $h1el = pack_type $myns, $some_element;
 my $b1el = "{$myns}$other_element";  # same, less clean

 my $encode_query = $client->compileMessage
   ( 'SENDER'
   , header   => [ h1 => $h1el ]
   , body     => [ b1 => $b1el ]
   , destination    => [ h1 => 'NEXT' ]
   , mustUnderstand => 'h1'
   , encodings => { b1 => { use => 'literal' }}
   );

 my $decode_response = $client->compileMessage
   ( 'RECEIVER'
   , header    => [ h2 => $h2el ]
   , body      => [ b2 => $b2el ]
   , faults    => [ ... ]
   , encodings => { h2 => { use => 'literal' }}
   );

 my $http = XML::Compile::SOAP::HTTPClient->new
   ( action  => 'http://...'
   , address => $server
   );

 # In nice, small steps:

 my @query    = (h1 => ..., b1 => ...);
 my $request  = $encode_query->($query);
 my ($response, $trace) = $http->($request);
 my $answer   = $decode_response->($response);
 use Data::Dumper;
 warn Dumper $answer;     # see: a HASH with h2 and b2!
 if($answer->{Fault}) ... # error

 # Simplify your life

 my $call   = $client->compileClient
   ( kind      => 'request-response'
   , request   => $encode_query
   , response  => $decode_response
   , transport => $http
   );

 my $result = $call->(h1 => ..., b1 => ...);
 print $result->{h2}->{...};
 print $result->{b2}->{...};

 my ($result, $trace) = $call->(...);

=head1 DESCRIPTION

This module handles the SOAP protocol.  The first implementation is
SOAP1.1 (F<http://www.w3.org/TR/2000/NOTE-SOAP-20000508/>), which is still
most often used.  The SOAP1.2 definition (F<http://www.w3.org/TR/soap12/>)
is quite different; this module tries to define a sufficiently abstract
interface to hide the protocol differences.

On the moment, B<XML-RPC is not supported>.  There are many more limitations,
which can be found in the README.todo file which is part of the
distribution package.

=head1 METHODS

=head2 Constructors

$obj-E<gt>B<new>(OPTIONS)

=over 4

Create a new SOAP object.  You have to instantiate either the SOAP11 or
SOAP12 sub-class of this, because there are quite some differences (which
can be hidden for you)

 Option     --Default
 encoding_ns  <required>
 envelope_ns  <required>
 media_type   application/soap+xml
 schemas      created internally
 version      <required>

. encoding_ns => URI

. envelope_ns => URI

. media_type => MIMETYPE

. schemas => C<XML::Compile::Schema> object

=over 4

Use this when you have already processed some schema definitions.  Otherwise,
you can add schemas later with C<< $soap->schames->importDefinitions() >>

=back

. version => STRING

=over 4

The simple string representation of the protocol.

=back

=back

=head2 Accessors

$obj-E<gt>B<encodingNS>

=over 4

=back

$obj-E<gt>B<envelopeNS>

=over 4

=back

$obj-E<gt>B<prefixPreferences>(TABLE)

=over 4

=back

$obj-E<gt>B<schemas>

=over 4

Returns the L<XML::Compile::Schema|XML::Compile::Schema> object which contains the
knowledge about the types.

=back

$obj-E<gt>B<version>

=over 4

=back

=head2 Single messages

$obj-E<gt>B<compileMessage>(('SENDER'|'RECEIVER'), OPTIONS)

=over 4

The payload is defined explicitly, where all headers and bodies are
specified as ARRAY containing key-value pairs (ENTRIES).  When you
have a WSDL file, these ENTRIES are generated automatically.

To make your life easy, the ENTRIES use a label (a free to choose key,
the I<part name> in WSDL terminology), to ease relation of your data with
the type where it belongs to.  The element of an entry (the value) is
defined as an C<any> element in the schema, and therefore you will need
to explicitly specify the element to be processed.

 Option        --Default
 body            []
 destination     []
 encodings       {}
 faults          []
 header          undef
 mustUnderstand  []
 role            ULTIMATE
 roles           []

. body => ENTRIES

=over 4

ARRAY of PAIRS, defining a nice LABEL (free of choice but unique,
also w.r.t. the header and fault ENTRIES).  The LABEL will appear
in the Perl HASH only, to be able to refer to a body element in a
simple way.

=back

. destination => ARRAY

=over 4

Writers only.  Indicate who the target of the header entry is.
By default, the end-point is the destination of each header element.

The ARRAY contains a LIST of key-value pairs, specifing an entry label
followed by an I<actor> (soap1.1) or I<role> (soap1.2) URI.  You may use
the predefined actors/roles, like 'NEXT'.  See L<roleURI()|XML::Compile::SOAP/"Helpers"> and
L<roleAbbreviation()|XML::Compile::SOAP/"Helpers">.

=back

. encodings => HASH-of-HASHes

=over 4

Message components can be encoded, as defined in WSDL.   Typically, some
message part has a binding C<< use="encoded" >> and C<encodingStyle>
and C<namespace> parameters.  The encodings are organized per label.

=back

. faults => ENTRIES

=over 4

The SOAP1.1 and SOAP1.2 protocols define fault entries in the
answer.  Both have a location to add your own additional
information: the type(-processor) is to specified here, but the
returned information structure is larger and differs per SOAP
implementation.

=back

. header => ENTRIES

=over 4

ARRAY of PAIRS, defining a nice LABEL (free of choice but unique)
and an element reference.  The LABEL will appear in the Perl HASH, to
refer to the element in a simple way.

=back

. mustUnderstand => STRING|ARRAY-OF-STRING

=over 4

Writers only.  The specified header entry labels specify which elements
must be understood by the destination.  These elements will get the
C<mustUnderstand> attribute set to C<1> (soap1.1) or C<true> (soap1.2).

=back

. role => URI|ARRAY-OF-URI

=over 4

Readers only.
One or more URIs, specifying the role(s) you application has in the
process.  Only when your role contains C<ULTIMATE>, the body is
parsed.  Otherwise, the body is returned as uninterpreted XML tree.
You should not use the role C<NEXT>, because every intermediate
node is a C<NEXT>.

All understood headers are parsed when the C<actor> (soap1.1) or
C<role> (soap1.2) attribute address the specified URI.  When other
headers emerge which are not understood but carry the C<mustUnderstood>
attribute, an fault is returned automatically.  In that case, the
call to the compiled subroutine will return C<undef>.

=back

. roles => ARRAY-OF-URI

=over 4

Alternative for option C<role>

=back

=back

=head2 Sender (internals)

$obj-E<gt>B<sender>(ARGS)

=over 4

=back

$obj-E<gt>B<writerCreateBody>(BODY-DEFS, NAMESPACE-TABLE)

=over 4

=back

$obj-E<gt>B<writerCreateFault>(FAULT-DEFS, NAMESPACE-TABLE, FAULTTYPE)

=over 4

=back

$obj-E<gt>B<writerCreateHeader>(HEADER-DEFS, NS-TABLE, UNDERSTAND, DESTINATION)

=over 4

=back

$obj-E<gt>B<writerEncstyleHook>(NAMESPACE-TABLE)

=over 4

=back

$obj-E<gt>B<writerHook>(NAMESPACE, LOCAL, ACTIONS)

=over 4

=back

=head2 Receiver (internals)

$obj-E<gt>B<readerEncstyleHook>

=over 4

=back

$obj-E<gt>B<readerHook>(NAMESPACE, LOCAL, ACTIONS)

=over 4

=back

$obj-E<gt>B<readerParseBody>(BODYDEF)

=over 4

=back

$obj-E<gt>B<readerParseFaults>(FAULTSDEF)

=over 4

=back

$obj-E<gt>B<readerParseHeader>(HEADERDEF)

=over 4

=back

$obj-E<gt>B<receiver>(ARGS)

=over 4

=back

=head2 Helpers

$obj-E<gt>B<replyMustUnderstandFault>(TYPE)

=over 4

Produce an error structure to be returned to the sender.

=back

$obj-E<gt>B<roleAbbreviation>(URI)

=over 4

Translate a role URI into a simple string, if predefined.  See
L<roleURI()|XML::Compile::SOAP/"Helpers">.

=back

$obj-E<gt>B<roleURI>(URI|STRING)

=over 4

Translates actor/role/destination abbreviations into URIs. Various
SOAP protocol versions have different pre-defined STRINGs, which can
be abbreviated for readibility.  Returns the unmodified URI in
all other cases.

SOAP11 only defines C<NEXT>.  SOAP12 defines C<NEXT>, C<NONE>, and
C<ULTIMATE>.

=back

=head1 DETAILS

=head2 Using the produced calls

First, you compile the call either via a WSDL file (see
L<XML::Compile::WSDL11|XML::Compile::WSDL11>), or in small manual steps, as described in
the next section.  So, in one of both ways, you end-up with

    # compile once
    my $call = $soap->compileClient(...);

    # and call often
    my $anwer = $call->(%request);  # list of pairs
    my $anwer = $call->(\%request); # same, but HASH
    my $anwer = $call->(\%request, 'UTF-8');  # same

But what is the structure of C<%request> and C<$answer> ?  Well, there
are various syntaxes possible: from structurally perfect, to user-friendly.

First, find out which data structures can be present.  When you compiled
your messages explicitly, you have picked your own names.  When the
call was initiated from a WSDL file, then you have to find the names
of the message parts which can be used.  The component names are for
header blocks, body blocks, headerfaults, and (body) faults.

Let's say that the WSDL defines this (ignoring all name-space issues)

 <message name="GetLastTradePriceInput">
   <part name="count" type="int" />
   <part name="request" element="TradePriceRequest"/>
 </message>

 <message name="GetLastTradePriceOutput">
   <part name="answer" element="TradePrice"/>
 </message>

 <definitions ...>
  <binding ...>
   <operation ...>
    <input>
     <soap:header message="GetLastTradePriceInput" part="count"
     <soap:body message="GetLastTradePriceInput" parts="request"
    <output>
     <soap:body message="GetLastTradePriceOutput"

The input message needs explicitly named parts, in this case, where the
output message simply uses all defined in the body.  So, the input message
has one header block C<count>, and one body block C<request>.  The output
message only has one body block C<answer>.

Then, the definitions of the blocks:

 <element name="TradePriceRequest">
   <complexType>
     <all>
       <element name="tickerSymbol" type="string"/>

 <element name="TradePrice">
   <complexType>
     <all>
       <element name="price" type="float"/>

Now, calling the compiled function can be done like this:

  my $anwer = $call->(count => 5, request => {tickerSymbol => 'IBM'});
  my $anwer = $call->(
      {count => 5, request => {tickerSymbol => 'IBM'}}, 'UTF-8');

However, in this case you may simplify the call.  First, all pairs
which use known block names are collected.  Then, if there is exactly
one body block which is not used yet, it will get all of the left over
names.  So... in this case, you could also use

 my $got = $call->(count => 5, tickerSymbol => 'IBM');

This does not work if the block element is a simple type.  In most
existing SOAP schemas, this simplification probably is possible.

The C<$got> is a HASH, which will not be simplified.  The return
might be (Data::Dumper is your friend)

 $got = { answer => { price => 16.3 } }

To access the value use

 printf "%.2f US\$\n", $got->{answer}->{price};
 printf "%.2f US\$\n", $got->{answer}{price};

=head3 Faults

Faults and headerfaults are a slightly different story: the type which
is specified with them is not of the fault XML node itself, but of the
C<details> sub-element within the standard fault structure.

When producing the data for faults, you must be aware of the fact that
the structure is different for SOAP1.1 and SOAP1.2.  When interpreting
faults, the same problems are present, although the implementation
tries to help you.

Check whether SOAP1.1 or SOAP1.2 is used by looking for a C<faultcode>
(SOAP1.1) or a C<Code> (SOAP1.2) field in the data:

  if(my $fault = $got->{Fault})
  {  if($fault->{faultcode}) { ... SOAP1.1 ... }
     elsif($fault->{Code})   { ... SOAP1.2 ... }
     else { die }
  }

In either protocol case, the following will get you at a compatible
structure:

  if(my $fault = $got->{Fault})
  {   my $decoded = $got->{$fault->{_NAME}};
      print $decoded->{code};
      ...
  }

See the respective manuals L<XML::Compile::SOAP11|XML::Compile::SOAP11> and
L<XML::Compile::SOAP12|XML::Compile::SOAP12> for the (ugly) specifics.

=head2 Calling SOAP without WSDL

See the manual page of L<XML::Compile::WSDL11|XML::Compile::WSDL11> to see how simple
you can use this module when you have a WSDL file at hand.  The
creation of a correct WSDL file is NOT SIMPLE.

When using SOAP without WSDL file, it gets a little bit more complicate
to use: you need to describe the content of the messages yourself.
The following example is used as test-case C<t/10soap11.t>, directly
taken from the SOAP11 specs section 1.3 example 1.

 # for simplification
 my $TestNS   = 'http://test-types';
 my $SchemaNS = 'http://www.w3.org/2001/XMLSchema';

First, the schema (hopefully someone else created for you, because they
can be quite hard to create correctly) is in file C<myschema.xsd>

 <schema targetNamespace="$TestNS"
   xmlns="$SchemaNS">

 <element name="GetLastTradePrice">
   <complexType>
      <all>
        <element name="symbol" type="string"/>
      </all>
   </complexType>
 </element>

 <element name="GetLastTradePriceResponse">
   <complexType>
      <all>
         <element name="price" type="float"/>
      </all>
   </complexType>
 </element>

 <element name="Transaction" type="int"/>
 </schema>

Ok, now the program you create the request:

 use XML::Compile::SOAP11;
 use XML::Compile::Util  qw/pack_type/;

 my $soap   = XML::Compile::SOAP11->new;
 $soap->schemas->importDefinitions('myschema.xsd');

 my $get_price = $soap->compileMessage
   ( 'SENDER'
   , header =>
      [ transaction => pack_type($TestNS, 'Transaction') ]
   , body  =>
      [ request => pack_type($TestNS, 'GetLastTradePrice') ]
   , mustUnderstand => 'transaction'
   , destination    => [ transaction => 'NEXT http://actor' ]
   );

C<INPUT> is used in the WSDL terminology, indicating this message is
an input message for the server.  This C<$get_price> is a WRITER.  Above
is done only once in the initialization phase of your program.

At run-time, you have to call the CODE reference with a
data-structure which is compatible with the schema structure.
(See L<XML::Compile::Schema::template()|XML::Compile::Schema/"Compilers"> if you have no clue how it should
look)  So: let's send this:

 # insert your data
 my %data_in = (transaction => 5, request => {symbol => 'DIS'});
 my %data_in = (transaction => 5, symbol => 'DIS'); # alternative

 # create a XML::LibXML tree
 my $xml  = $get_price->(\%data_in, 'UTF-8');
 print $xml->toString;

And the output is:

 <SOAP-ENV:Envelope
    xmlns:x0="http://test-types"
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Header>
     <x0:Transaction
       mustUnderstand="1"
       actor="http://schemas.xmlsoap.org/soap/actor/next http://actor">
         5
     </x0:Transaction>
   </SOAP-ENV:Header>
   <SOAP-ENV:Body>
     <x0:GetLastTradePrice>
       <symbol>DIS</symbol>
     </x0:GetLastTradePrice>
   </SOAP-ENV:Body>
 </SOAP-ENV:Envelope>

Some transport protocol will sent this data from the client to the
server.  See L<XML::Compile::SOAP::HTTPClient|XML::Compile::SOAP::HTTPClient>, as one example.

On the SOAP server side, we will parse the message.  The string C<$soap>
contains the XML.  The program looks like this:

 my $server = $soap->compileMessage # create once
  ( 'RECEIVER'
  , header => [ transaction => pack_type($TestNS, 'Transaction') ]
  , body   => [ request => pack_type($TestNS, 'GetLastTradePrice') ]
  );

 my $data_out = $server->($soap);   # call often

Now, the C<$data_out> reference on the server, is stucturally exactly 
equivalent to the C<%data_in> from the client.

=head2 Encodings

=head1 SEE ALSO

This module is part of XML-Compile-SOAP distribution version 0.57,
built on October 18, 2007. Website: F<http://perl.overmeer.net/xml-compile/>

=head1 LICENSE

Copyrights 2007 by Mark Overmeer. For other contributors see ChangeLog.

This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
See F<http://www.perl.com/perl/misc/Artistic.html>

