File Coverage

lib/XML/Compile/SOAP/WSA.pm
Criterion Covered Total %
statement 12 12 100.0
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 16 16 100.0


line stmt bran cond sub pod time code
1             # Copyrights 2010-2015 by [Mark Overmeer].
2             # For other contributors see ChangeLog.
3             # See the manual pages for details on the licensing terms.
4             # Pod stripped from pm file by OODoc 2.01.
5 1     1   1021 use warnings;
  1         2  
  1         37  
6 1     1   3 use strict;
  1         2  
  1         40  
7              
8             package XML::Compile::SOAP::WSA;
9 1     1   3 use vars '$VERSION';
  1         2  
  1         84  
10             $VERSION = '0.94';
11              
12 1     1   6 use base 'XML::Compile::SOAP::Extension';
  1         3  
  1         678  
13              
14             use Log::Report 'xml-compile-soap-wsa';
15              
16             use XML::Compile::WSA::Util qw/WSA10MODULE WSA09 WSA10 WSDL11WSAW/;
17             use XML::Compile::SOAP::Util qw/WSDL11/;
18             use XML::Compile::Util qw/pack_type/;
19              
20             use File::Spec ();
21             use File::Basename qw/dirname/;
22              
23             my @common_hdr_elems = qw/To From Action ReplyTo FaultTo MessageID
24             RelatesTo RetryAfter/;
25             my @wsa09_hdr_elems = (@common_hdr_elems, qw/ReplyAfter/);
26             my @wsa10_hdr_elems = (@common_hdr_elems, qw/ReferenceParameters/);
27              
28             my %versions =
29             ( '0.9' => { xsd => '20070619-wsa09.xsd', wsa => WSA09
30             , hdr => \@wsa09_hdr_elems }
31             , '1.0' => { xsd => '20080723-wsa10.xsd', wsa => WSA10
32             , hdr => \@wsa10_hdr_elems }
33             );
34              
35             my $xsddir = File::Spec->catdir((dirname dirname __FILE__), 'WSA', 'xsd');
36              
37              
38             sub init($)
39             { my ($self, $args) = @_;
40              
41             $self->SUPER::init($args);
42             my $version = $args->{version}
43             or error __x"explicit wsa_version required";
44             trace "initializing wsa $version";
45              
46             $version = '1.0' if $version eq WSA10MODULE;
47             $versions{$version}
48             or error __x"unknown wsa version {v}, pick from {vs}"
49             , v => $version, vs => [keys %versions];
50             $self->{version} = $version;
51             $self;
52             }
53              
54             #-----------
55              
56              
57             sub version() {shift->{version}}
58             sub wsaNS() {$versions{shift->{version}}{wsa}}
59              
60             # This is not uglier than the WSA specification does: if you do not
61             # specify these attributes cleanly in the WSDL specs, then everyone
62             # needs hacks.
63             # Documented in XML::Compile::SOAP::Operation
64              
65             sub XML::Compile::SOAP::Operation::wsaAction($)
66             { my ($self, $dir) = @_;
67             $dir eq 'INPUT' ? $self->{wsa}{action_input} : $self->{wsa}{action_output};
68             }
69              
70             #-----------
71              
72             sub _load_ns($$)
73             { my ($self, $schema, $fn) = @_;
74             $schema->importDefinitions(File::Spec->catfile($xsddir, $fn));
75             }
76              
77             sub wsdl11Init($$)
78             { my ($self, $wsdl, $args) = @_;
79             my $def = $versions{$self->{version}};
80              
81             my $ns = $self->wsaNS;
82             $wsdl->addPrefixes(wsa => $ns, wsaw => WSDL11WSAW);
83             $wsdl->addKeyRewrite('PREFIXED(wsa,wsaw)');
84              
85             $wsdl->addCompileOptions('READERS'
86             , anyElement => 'TAKE_ALL'
87             , anyAttribute => 'TAKE_ALL'
88             );
89              
90             trace "loading wsa $self->{version}";
91             $self->_load_ns($wsdl, $def->{xsd});
92             $self->_load_ns($wsdl, '20060512-wsaw.xsd');
93              
94             my $wsa_action_ns = $self->version eq '0.9' ? $ns : WSDL11WSAW;
95             $wsdl->addHook
96             ( action => 'READER'
97             , type => pack_type(WSDL11, 'tParam')
98             , after => sub
99             { my ($xml, $data, $path) = @_;
100             $data->{wsa_action} = $xml->getAttributeNS($wsa_action_ns,'Action');
101             $data;
102             }
103             );
104              
105             # [0.94] Many headers may contain attributes (which are usually not auto-
106             # detected anyway), which will cause the field to be a HASH. Older
107             # versions of this module would always simply return the content, not a
108             # HASH. Let's not break those.
109             $wsdl->addHook
110             ( action => 'READER'
111             , type => 'wsa:AttributedURIType'
112             , after => sub
113             { my ($xml, $data, $path) = @_;
114             $data = $data->{_}
115             if ref $data eq 'HASH' && keys %$data==1 && $data->{_};
116             $data;
117             }
118             );
119              
120             # For unknown reason, the FaultDetail header is described everywhere
121             # in the docs, but missing from the schema.
122             $wsdl->importDefinitions( <<_FAULTDETAIL );
123            
124             xmlns:tns="$ns" targetNamespace="$ns"
125             elementFormDefault="qualified"
126             attributeFormDefault="unqualified">
127            
128            
129            
130            
131            
132            
133            
134            
135             _FAULTDETAIL
136              
137             $self;
138             }
139              
140             sub soap11OperationInit($$)
141             { my ($self, $op, $args) = @_;
142             my $ns = $self->wsaNS;
143              
144             $op->{wsa}{action_input} = $args->{input_def}{body}{wsa_action};
145             $op->{wsa}{action_output} = $args->{output_def}{body}{wsa_action};
146              
147             trace "adding wsa header logic";
148             my $def = $versions{$self->{version}};
149             foreach my $hdr ( @{$def->{hdr}} )
150             { $op->addHeader(INPUT => "wsa_$hdr" => "{$ns}$hdr");
151             $op->addHeader(OUTPUT => "wsa_$hdr" => "{$ns}$hdr");
152             }
153              
154             # soap11 specific
155             $op->addHeader(OUTPUT => wsa_FaultDetail => "{$ns}FaultDetail");
156             }
157             *soap12OperationInit = \&soap11OperationInit;
158              
159             sub soap11ClientWrapper($$$)
160             { my ($self, $op, $call, $args) = @_;
161             my $to = ($op->endPoints)[0];
162             my $action = $op->wsaAction('INPUT') || $op->soapAction;
163             # my $outact = $op->wsaAction('OUTPUT');
164              
165             trace "added wsa in call $to".($action ? " for $action" : '');
166             sub
167             { my $data = @_==1 ? shift : {@_};
168             $data->{wsa_To} ||= $to;
169             $data->{wsa_Action} ||= $action;
170             $call->($data);
171             # should we check that the wsa_Action in the reply is correct?
172             };
173             }
174             *soap12ClientWrapper = \&soap11ClientWrapper;
175              
176             sub soap11HandlerWrapper($$$)
177             { my ($self, $op, $cb, $args) = @_;
178             my $outact = $op->wsaAction('OUTPUT');
179             defined $outact
180             or return $cb;
181              
182             sub
183             { my $data = $cb->(@_);
184             $data->{wsa_Action} = $outact;
185             $data;
186             };
187             }
188             *soap12HandlerWrapper = \&soap11HandlerWrapper;
189              
190              
191             1;