| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
# Copyrights 2014-2021 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.02. |
|
5
|
|
|
|
|
|
|
# This code is part of distribution XML-Compile-WSDL11. Meta-POD processed |
|
6
|
|
|
|
|
|
|
# with OODoc into POD and HTML manual-pages. See README.md |
|
7
|
|
|
|
|
|
|
# Copyright Mark Overmeer. Licensed under the same terms as Perl itself. |
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
package XML::Compile::WSDL11; |
|
10
|
5
|
|
|
5
|
|
1461889
|
use vars '$VERSION'; |
|
|
5
|
|
|
|
|
94
|
|
|
|
5
|
|
|
|
|
313
|
|
|
11
|
|
|
|
|
|
|
$VERSION = '3.08'; |
|
12
|
|
|
|
|
|
|
|
|
13
|
5
|
|
|
5
|
|
34
|
use base 'XML::Compile::Cache'; |
|
|
5
|
|
|
|
|
6
|
|
|
|
5
|
|
|
|
|
3034
|
|
|
14
|
|
|
|
|
|
|
|
|
15
|
5
|
|
|
5
|
|
721840
|
use warnings; |
|
|
5
|
|
|
|
|
14
|
|
|
|
5
|
|
|
|
|
150
|
|
|
16
|
5
|
|
|
5
|
|
28
|
use strict; |
|
|
5
|
|
|
|
|
9
|
|
|
|
5
|
|
|
|
|
119
|
|
|
17
|
|
|
|
|
|
|
|
|
18
|
5
|
|
|
5
|
|
26
|
use Log::Report 'xml-compile-soap'; |
|
|
5
|
|
|
|
|
12
|
|
|
|
5
|
|
|
|
|
41
|
|
|
19
|
|
|
|
|
|
|
|
|
20
|
5
|
|
|
5
|
|
1517
|
use XML::Compile (); |
|
|
5
|
|
|
|
|
9
|
|
|
|
5
|
|
|
|
|
109
|
|
|
21
|
5
|
|
|
5
|
|
30
|
use XML::Compile::Util qw/pack_type unpack_type/; |
|
|
5
|
|
|
|
|
11
|
|
|
|
5
|
|
|
|
|
275
|
|
|
22
|
5
|
|
|
5
|
|
3077
|
use XML::Compile::SOAP (); |
|
|
5
|
|
|
|
|
49117
|
|
|
|
5
|
|
|
|
|
177
|
|
|
23
|
5
|
|
|
5
|
|
46
|
use XML::Compile::SOAP::Util qw/:wsdl11/; |
|
|
5
|
|
|
|
|
17
|
|
|
|
5
|
|
|
|
|
658
|
|
|
24
|
5
|
|
|
5
|
|
2800
|
use XML::Compile::SOAP::Extension; |
|
|
5
|
|
|
|
|
4688
|
|
|
|
5
|
|
|
|
|
176
|
|
|
25
|
|
|
|
|
|
|
|
|
26
|
5
|
|
|
5
|
|
2598
|
use XML::Compile::SOAP::Operation (); |
|
|
5
|
|
|
|
|
10983
|
|
|
|
5
|
|
|
|
|
128
|
|
|
27
|
5
|
|
|
5
|
|
2553
|
use XML::Compile::Transport (); |
|
|
5
|
|
|
|
|
7566
|
|
|
|
5
|
|
|
|
|
120
|
|
|
28
|
|
|
|
|
|
|
|
|
29
|
5
|
|
|
5
|
|
34
|
use File::Spec (); |
|
|
5
|
|
|
|
|
10
|
|
|
|
5
|
|
|
|
|
108
|
|
|
30
|
5
|
|
|
5
|
|
31
|
use List::Util qw/first/; |
|
|
5
|
|
|
|
|
9
|
|
|
|
5
|
|
|
|
|
310
|
|
|
31
|
5
|
|
|
5
|
|
32
|
use Scalar::Util qw/blessed/; |
|
|
5
|
|
|
|
|
7
|
|
|
|
5
|
|
|
|
|
297
|
|
|
32
|
5
|
|
|
5
|
|
30
|
use File::Basename qw/dirname/; |
|
|
5
|
|
|
|
|
9
|
|
|
|
5
|
|
|
|
|
21464
|
|
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
sub init($) |
|
36
|
5
|
|
|
5
|
0
|
8971
|
{ my ($self, $args) = @_; |
|
37
|
5
|
50
|
|
|
|
26
|
$args->{schemas} and panic "new(schemas) option removed in 0.78"; |
|
38
|
5
|
|
|
|
|
15
|
my $wsdl = delete $args->{top}; |
|
39
|
|
|
|
|
|
|
|
|
40
|
5
|
|
|
|
|
17
|
local $args->{any_element} = 'ATTEMPT'; |
|
41
|
5
|
|
|
|
|
14
|
local $args->{any_attribute} = 'ATTEMPT'; # not implemented |
|
42
|
5
|
|
|
|
|
15
|
local $args->{allow_undeclared} = 1; |
|
43
|
|
|
|
|
|
|
|
|
44
|
5
|
|
|
|
|
40
|
$self->SUPER::init($args); |
|
45
|
|
|
|
|
|
|
|
|
46
|
5
|
|
|
|
|
1871
|
$self->{index} = {}; |
|
47
|
|
|
|
|
|
|
|
|
48
|
5
|
|
|
|
|
28
|
$self->addPrefixes(wsdl => WSDL11, soap => WSDL11SOAP, http => WSDL11HTTP); |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
# next modules should change into an extension as well... |
|
51
|
|
|
|
|
|
|
$_->can('_initWSDL11') && $_->_initWSDL11($self) |
|
52
|
5
|
|
50
|
|
|
654
|
for XML::Compile::SOAP->registered; |
|
53
|
|
|
|
|
|
|
|
|
54
|
5
|
|
|
|
|
77
|
XML::Compile::SOAP::Extension->wsdl11Init($self, $args); |
|
55
|
|
|
|
|
|
|
|
|
56
|
5
|
|
|
|
|
61
|
$self->declare |
|
57
|
|
|
|
|
|
|
( READER => 'wsdl:definitions' |
|
58
|
|
|
|
|
|
|
, key_rewrite => 'PREFIXED(wsdl,soap,http)' |
|
59
|
|
|
|
|
|
|
, hook => {type => 'wsdl:tOperation', after => 'ELEMENT_ORDER'} |
|
60
|
|
|
|
|
|
|
); |
|
61
|
|
|
|
|
|
|
|
|
62
|
5
|
|
|
|
|
22
|
$self->{XCW_dcopts} = {}; |
|
63
|
5
|
|
|
|
|
16
|
$self->{XCW_server} = $args->{server_type}; |
|
64
|
|
|
|
|
|
|
|
|
65
|
5
|
|
|
|
|
670
|
my @xsds = map File::Spec->catdir(dirname(__FILE__), 'WSDL11', 'xsd', $_) |
|
66
|
|
|
|
|
|
|
, qw(wsdl.xsd wsdl-mime.xsd wsdl-http.xsd); |
|
67
|
|
|
|
|
|
|
|
|
68
|
5
|
|
|
|
|
42
|
$self->importDefinitions(\@xsds, element_form_default => 'qualified'); |
|
69
|
|
|
|
|
|
|
|
|
70
|
5
|
50
|
|
|
|
25086
|
$self->addWSDL($_) for ref $wsdl eq 'ARRAY' ? @$wsdl : $wsdl; |
|
71
|
5
|
|
|
|
|
160
|
$self; |
|
72
|
|
|
|
|
|
|
} |
|
73
|
|
|
|
|
|
|
|
|
74
|
0
|
|
|
0
|
0
|
0
|
sub schemas(@) { panic "schemas() removed in v2.00, not needed anymore" } |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
#-------------------------- |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
sub compileAll(;$$) |
|
80
|
0
|
|
|
0
|
1
|
0
|
{ my ($self, $need, $usens) = @_; |
|
81
|
0
|
0
|
0
|
|
|
0
|
$self->SUPER::compileAll($need, $usens) |
|
82
|
|
|
|
|
|
|
if !$need || $need ne 'CALLS'; |
|
83
|
|
|
|
|
|
|
|
|
84
|
0
|
0
|
0
|
|
|
0
|
$self->compileCalls |
|
85
|
|
|
|
|
|
|
if !$need || $need eq 'CALLS'; |
|
86
|
0
|
|
|
|
|
0
|
$self; |
|
87
|
|
|
|
|
|
|
} |
|
88
|
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
sub compileCalls(@) |
|
91
|
0
|
|
|
0
|
1
|
0
|
{ my ($self, %args) = @_; |
|
92
|
0
|
|
|
|
|
0
|
my $long = $args{long_names}; |
|
93
|
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
my @ops = $self->operations |
|
95
|
|
|
|
|
|
|
( service => delete $args{service} |
|
96
|
|
|
|
|
|
|
, port => delete $args{port} |
|
97
|
|
|
|
|
|
|
, binding => delete $args{binding} |
|
98
|
0
|
|
|
|
|
0
|
); |
|
99
|
|
|
|
|
|
|
|
|
100
|
0
|
|
|
|
|
0
|
foreach my $op (@ops) |
|
101
|
0
|
0
|
|
|
|
0
|
{ my $alias = $long ? $op->longName : undef; |
|
102
|
0
|
|
|
|
|
0
|
$self->compileCall($op, alias => $alias, %args); |
|
103
|
|
|
|
|
|
|
} |
|
104
|
|
|
|
|
|
|
|
|
105
|
0
|
|
|
|
|
0
|
$self; |
|
106
|
|
|
|
|
|
|
} |
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub compileCall($@) |
|
110
|
0
|
|
|
0
|
1
|
0
|
{ my ($self, $oper, %opts) = @_; |
|
111
|
0
|
|
|
|
|
0
|
my $alias = delete $opts{alias}; |
|
112
|
0
|
0
|
|
|
|
0
|
my $op = blessed $oper ? $oper : $self->operation($oper, %opts); |
|
113
|
|
|
|
|
|
|
|
|
114
|
0
|
|
0
|
|
|
0
|
my $name = $alias || $op->name; |
|
115
|
|
|
|
|
|
|
error __x"a compiled call for {name} already exists", name => $name |
|
116
|
0
|
0
|
|
|
|
0
|
if $self->{XCW_ccode}{$name}; |
|
117
|
|
|
|
|
|
|
|
|
118
|
0
|
|
0
|
|
|
0
|
my $dopts = $self->{XCW_dcopts} || {}; |
|
119
|
0
|
|
|
|
|
0
|
my @opts = %opts; |
|
120
|
0
|
0
|
|
|
|
0
|
push @opts, ref $dopts eq 'ARRAY' ? @$dopts : %$dopts; |
|
121
|
0
|
|
|
|
|
0
|
trace "compiling call `$name'"; |
|
122
|
0
|
|
|
|
|
0
|
$self->{XCW_ccode}{$name} = $op->compileClient(@opts); |
|
123
|
|
|
|
|
|
|
} |
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
sub call($@) |
|
127
|
0
|
|
|
0
|
1
|
0
|
{ my ($self, $name) = (shift, shift); |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
my $codes = $self->{XCW_ccode} |
|
130
|
0
|
0
|
|
|
|
0
|
or error __x"you can only use call() after compileCalls()"; |
|
131
|
|
|
|
|
|
|
|
|
132
|
0
|
0
|
|
|
|
0
|
my $call = $codes->{$name} |
|
133
|
|
|
|
|
|
|
or error __x"operation `{name}' is not known", name => $name; |
|
134
|
|
|
|
|
|
|
|
|
135
|
0
|
|
|
|
|
0
|
$call->(@_); |
|
136
|
|
|
|
|
|
|
} |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
#-------------------------- |
|
139
|
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
sub addWSDL($%) |
|
142
|
6
|
|
|
6
|
1
|
24
|
{ my ($self, $data, %args) = @_; |
|
143
|
6
|
50
|
|
|
|
25
|
defined $data or return (); |
|
144
|
|
|
|
|
|
|
|
|
145
|
6
|
50
|
|
|
|
24
|
if(ref $data eq 'ARRAY') |
|
146
|
0
|
|
|
|
|
0
|
{ $self->addWSDL($_) for @$data; |
|
147
|
0
|
|
|
|
|
0
|
return $self; |
|
148
|
|
|
|
|
|
|
} |
|
149
|
|
|
|
|
|
|
|
|
150
|
6
|
|
|
|
|
28
|
my ($node, %details) = $self->dataToXML($data); |
|
151
|
6
|
50
|
|
|
|
1947
|
defined $node or return $self; |
|
152
|
|
|
|
|
|
|
|
|
153
|
6
|
50
|
33
|
|
|
83
|
$node->localName eq 'definitions' && $node->namespaceURI eq WSDL11 |
|
154
|
|
|
|
|
|
|
or error __x"root element for WSDL is not 'wsdl:definitions'"; |
|
155
|
|
|
|
|
|
|
|
|
156
|
6
|
|
|
|
|
35
|
$self->importDefinitions($node, details => \%details); |
|
157
|
6
|
|
|
|
|
9105
|
$self->learnPrefixes($node); |
|
158
|
|
|
|
|
|
|
|
|
159
|
6
|
|
|
|
|
260
|
my $spec = $self->reader('wsdl:definitions')->($node); |
|
160
|
|
|
|
|
|
|
my $tns = $spec->{targetNamespace} |
|
161
|
6
|
50
|
|
|
|
663312
|
or error __x"WSDL sets no targetNamespace"; |
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
# WSDL 1.1 par 2.1.1 says: WSDL def types each in own name-space |
|
164
|
6
|
|
|
|
|
23
|
my $index = $self->{index}; |
|
165
|
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
# silly WSDL structure |
|
167
|
6
|
|
50
|
|
|
29
|
my $toplevels = $spec->{gr_wsdl_anyTopLevelOptionalElement} || []; |
|
168
|
|
|
|
|
|
|
|
|
169
|
6
|
|
|
|
|
22
|
foreach my $toplevel (@$toplevels) |
|
170
|
33
|
|
|
|
|
97
|
{ my ($which, $def) = %$toplevel; # always only one |
|
171
|
33
|
100
|
|
|
|
187
|
$which =~ s/^wsdl_(service|message|binding|portType)$/$1/ |
|
172
|
|
|
|
|
|
|
or next; |
|
173
|
|
|
|
|
|
|
|
|
174
|
27
|
|
|
|
|
109
|
$index->{$which}{pack_type $tns, $def->{name}} = $def; |
|
175
|
|
|
|
|
|
|
|
|
176
|
27
|
100
|
|
|
|
210
|
if($which eq 'service') |
|
177
|
5
|
50
|
|
|
|
14
|
{ foreach my $port ( @{$def->{wsdl_port} || []} ) |
|
|
5
|
|
|
|
|
27
|
|
|
178
|
9
|
|
|
9
|
|
85
|
{ my $addr_label = first { /address$/ } keys %$port |
|
179
|
|
|
|
|
|
|
or error __x"no address in port {port}" |
|
180
|
5
|
50
|
|
|
|
53
|
, port => $port->{name}; |
|
181
|
5
|
|
|
|
|
28
|
my $first_addr = $port->{$addr_label}; |
|
182
|
5
|
50
|
|
|
|
29
|
$first_addr = $first_addr->[0] if ref $first_addr eq 'ARRAY'; |
|
183
|
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
# Is XML::Compile::SOAP loaded? |
|
185
|
5
|
50
|
|
|
|
22
|
ref $first_addr eq 'HASH' |
|
186
|
|
|
|
|
|
|
or error __x"wsdl namespace {ns} not loaded" |
|
187
|
|
|
|
|
|
|
, ns => $first_addr->namespaceURI; |
|
188
|
|
|
|
|
|
|
|
|
189
|
5
|
|
|
|
|
28
|
$index->{port}{pack_type $tns, $port->{name}} = $port; |
|
190
|
|
|
|
|
|
|
} |
|
191
|
|
|
|
|
|
|
} |
|
192
|
|
|
|
|
|
|
} |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
# no service block when only one port |
|
195
|
6
|
50
|
|
|
|
69
|
unless($index->{service}) |
|
196
|
|
|
|
|
|
|
{ # only from this WSDL, cannot use collective $index |
|
197
|
0
|
|
0
|
|
|
0
|
my @portTypes = map $_->{wsdl_portType}||(), @$toplevels; |
|
198
|
0
|
0
|
|
|
|
0
|
@portTypes==1 |
|
199
|
|
|
|
|
|
|
or error __x"no service definition so needs 1 portType, found {nr}" |
|
200
|
|
|
|
|
|
|
, nr => scalar @portTypes; |
|
201
|
|
|
|
|
|
|
|
|
202
|
0
|
|
0
|
|
|
0
|
my @bindings = map $_->{wsdl_binding}||(), @$toplevels; |
|
203
|
0
|
0
|
|
|
|
0
|
@bindings==1 |
|
204
|
|
|
|
|
|
|
or error __x"no service definition so needs 1 binding, found {nr}" |
|
205
|
|
|
|
|
|
|
, nr => scalar @bindings; |
|
206
|
|
|
|
|
|
|
|
|
207
|
0
|
|
|
|
|
0
|
my $binding = pack_type $tns, $bindings[0]->{name}; |
|
208
|
0
|
|
|
|
|
0
|
my $portname = $portTypes[0]->{name}; |
|
209
|
0
|
|
|
|
|
0
|
my $servname = $portname; |
|
210
|
0
|
0
|
|
|
|
0
|
$servname =~ s/Service$|(?:Service)?Port(?:Type)?$/Service/i |
|
211
|
|
|
|
|
|
|
or $servname .= 'Service'; |
|
212
|
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
my $addr |
|
214
|
|
|
|
|
|
|
= $bindings[0]->{soap_binding} ? 'soap_address' |
|
215
|
0
|
0
|
|
|
|
0
|
: $bindings[0]->{soap12_binding} ? 'soap12_address' |
|
|
|
0
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
: error __x"unrecognized binding type for wsdl without service block"; |
|
217
|
|
|
|
|
|
|
|
|
218
|
0
|
|
|
|
|
0
|
my %port = (name => $portname, binding => $binding |
|
219
|
|
|
|
|
|
|
, $addr => {location => 'http://localhost'} ); |
|
220
|
|
|
|
|
|
|
|
|
221
|
0
|
|
|
|
|
0
|
$index->{service}{pack_type $tns, $servname} |
|
222
|
|
|
|
|
|
|
= { name => $servname, wsdl_port => [ \%port ] }; |
|
223
|
0
|
|
|
|
|
0
|
$index->{port}{pack_type $tns, $portname} = \%port; |
|
224
|
|
|
|
|
|
|
} |
|
225
|
|
|
|
|
|
|
#warn "INDEX: ",Dumper $index; |
|
226
|
6
|
|
|
|
|
50
|
$self; |
|
227
|
|
|
|
|
|
|
} |
|
228
|
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
sub namesFor($) |
|
231
|
0
|
|
|
0
|
1
|
0
|
{ my ($self, $class) = @_; |
|
232
|
0
|
0
|
|
|
|
0
|
keys %{shift->index($class) || {}}; |
|
|
0
|
|
|
|
|
0
|
|
|
233
|
|
|
|
|
|
|
} |
|
234
|
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
# new options, then also add them to the list in compileClient() |
|
237
|
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
sub operation(@) |
|
239
|
9
|
|
|
9
|
1
|
88968
|
{ my $self = shift; |
|
240
|
9
|
100
|
|
|
|
50
|
my $name = @_ % 2 ? shift : undef; |
|
241
|
9
|
|
|
|
|
38
|
my %args = (name => $name, @_); |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
# |
|
244
|
|
|
|
|
|
|
## Service structure |
|
245
|
|
|
|
|
|
|
# |
|
246
|
|
|
|
|
|
|
|
|
247
|
9
|
|
|
|
|
43
|
my $service = $self->findDef(service => delete $args{service}); |
|
248
|
|
|
|
|
|
|
|
|
249
|
9
|
|
|
|
|
24
|
my $port; |
|
250
|
9
|
50
|
|
|
|
15
|
my @ports = @{$service->{wsdl_port} || []}; |
|
|
9
|
|
|
|
|
41
|
|
|
251
|
9
|
50
|
|
9
|
|
63
|
if(my $not = first {blessed $_} @ports) |
|
|
9
|
|
|
|
|
48
|
|
|
252
|
0
|
|
|
|
|
0
|
{ error __x"not all name-spaces loaded, {ns} not parsed in port" |
|
253
|
|
|
|
|
|
|
, ns => $not->namespaceURI; |
|
254
|
|
|
|
|
|
|
} |
|
255
|
|
|
|
|
|
|
|
|
256
|
9
|
|
|
|
|
63
|
my @portnames = map $_->{name}, @ports; |
|
257
|
9
|
100
|
|
|
|
59
|
if(my $portname = delete $args{port}) |
|
|
|
50
|
|
|
|
|
|
|
258
|
2
|
|
|
2
|
|
9
|
{ $port = first {$_->{name} eq $portname} @ports; |
|
|
2
|
|
|
|
|
6
|
|
|
259
|
2
|
50
|
|
|
|
8
|
error __x"cannot find port `{portname}', pick from {ports}" |
|
260
|
|
|
|
|
|
|
, portname => $portname, ports => join("\n ", '', @portnames) |
|
261
|
|
|
|
|
|
|
unless $port; |
|
262
|
|
|
|
|
|
|
} |
|
263
|
|
|
|
|
|
|
elsif(@ports==1) |
|
264
|
7
|
|
|
|
|
19
|
{ $port = shift @ports; |
|
265
|
|
|
|
|
|
|
} |
|
266
|
|
|
|
|
|
|
else |
|
267
|
0
|
|
|
|
|
0
|
{ error __x"specify port explicitly, pick from {portnames}" |
|
268
|
|
|
|
|
|
|
, portnames => join("\n ", '', @portnames); |
|
269
|
|
|
|
|
|
|
} |
|
270
|
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
# get plugin for operation |
|
272
|
14
|
100
|
|
14
|
|
150
|
my $address = first { /address$/ && $port->{$_}{location}} keys %$port |
|
273
|
|
|
|
|
|
|
or error __x"no address provided in service {service} port {port}" |
|
274
|
9
|
50
|
|
|
|
60
|
, service => $service->{name}, port => $port->{name}; |
|
275
|
|
|
|
|
|
|
|
|
276
|
9
|
50
|
|
|
|
54
|
if($address =~ m/^{/) # } |
|
277
|
0
|
|
|
|
|
0
|
{ my ($ns) = unpack_type $address; |
|
278
|
|
|
|
|
|
|
|
|
279
|
0
|
0
|
|
|
|
0
|
warning __"Since v2.00 you have to require XML::Compile::SOAP11 explicitly" |
|
280
|
|
|
|
|
|
|
if $ns eq WSDL11SOAP; |
|
281
|
|
|
|
|
|
|
|
|
282
|
0
|
|
|
|
|
0
|
error __x"ports of type {ns} not supported (not loaded?)", ns => $ns; |
|
283
|
|
|
|
|
|
|
} |
|
284
|
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
#use Data::Dumper; |
|
286
|
|
|
|
|
|
|
#warn Dumper $port, $self->prefixes; |
|
287
|
9
|
|
|
|
|
68
|
my ($prefix) = $address =~ m/(\w+)_address$/; |
|
288
|
9
|
50
|
|
|
|
31
|
$prefix |
|
289
|
|
|
|
|
|
|
or error __x"port address not prefixed; probably need to add a plugin XML::Compile::SOAP12"; |
|
290
|
|
|
|
|
|
|
|
|
291
|
9
|
|
|
|
|
90
|
my $opns = $self->findName("$prefix:"); |
|
292
|
9
|
|
|
|
|
299
|
my $protocol = XML::Compile::SOAP->plugin($opns); |
|
293
|
9
|
50
|
|
|
|
70
|
unless($protocol) |
|
294
|
0
|
0
|
|
|
|
0
|
{ my $pkg = $opns eq WSDL11SOAP ? 'SOAP11' |
|
|
|
0
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
: $opns eq WSDL11SOAP12 ? 'SOAP12' |
|
296
|
|
|
|
|
|
|
: undef; |
|
297
|
|
|
|
|
|
|
|
|
298
|
0
|
0
|
|
|
|
0
|
if($pkg) |
|
299
|
0
|
|
|
|
|
0
|
{ error __x"add 'use XML::Compile::{pkg}' to your script", pkg=>$pkg; |
|
300
|
|
|
|
|
|
|
} |
|
301
|
|
|
|
|
|
|
else |
|
302
|
0
|
|
|
|
|
0
|
{ notice __x"ignoring unsupported namespace {ns}", ns => $opns; |
|
303
|
0
|
|
|
|
|
0
|
return; |
|
304
|
|
|
|
|
|
|
} |
|
305
|
|
|
|
|
|
|
} |
|
306
|
|
|
|
|
|
|
|
|
307
|
9
|
|
|
|
|
28
|
my $opclass = $protocol.'::Operation'; |
|
308
|
9
|
50
|
|
|
|
194
|
$opclass->can('_fromWSDL11') |
|
309
|
|
|
|
|
|
|
or error __x"WSDL11 not supported by {class}", class => $opclass; |
|
310
|
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
# |
|
312
|
|
|
|
|
|
|
## Binding |
|
313
|
|
|
|
|
|
|
# |
|
314
|
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
my $bindtype = $port->{binding} |
|
316
|
|
|
|
|
|
|
or error __x"no binding defined in port '{name}'" |
|
317
|
9
|
50
|
|
|
|
41
|
, name => $port->{name}; |
|
318
|
|
|
|
|
|
|
|
|
319
|
9
|
|
|
|
|
28
|
my $binding = $self->findDef(binding => $bindtype); |
|
320
|
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
my $type = $binding->{type} # get portTypeType |
|
322
|
9
|
50
|
|
|
|
35
|
or error __x"no type defined with binding `{name}'" |
|
323
|
|
|
|
|
|
|
, name => $bindtype; |
|
324
|
|
|
|
|
|
|
|
|
325
|
9
|
|
|
|
|
25
|
my $portType = $self->findDef(portType => $type); |
|
326
|
|
|
|
|
|
|
my $types = $portType->{wsdl_operation} |
|
327
|
9
|
50
|
|
|
|
34
|
or error __x"no operations defined for portType `{name}'" |
|
328
|
|
|
|
|
|
|
, name => $type; |
|
329
|
|
|
|
|
|
|
|
|
330
|
9
|
|
|
|
|
97
|
my @port_ops = map $_->{name}, @$types; |
|
331
|
|
|
|
|
|
|
|
|
332
|
9
|
|
66
|
|
|
34
|
$name ||= delete $args{operation}; |
|
333
|
9
|
|
|
|
|
16
|
my $port_op; |
|
334
|
9
|
50
|
|
|
|
40
|
if(defined $name) |
|
|
|
0
|
|
|
|
|
|
|
335
|
9
|
|
|
10
|
|
70
|
{ $port_op = first {$_->{name} eq $name} @$types; |
|
|
10
|
|
|
|
|
31
|
|
|
336
|
9
|
100
|
|
|
|
55
|
error __x"no operation `{op}' for portType {pt}, pick from{ops}" |
|
337
|
|
|
|
|
|
|
, op => $name, pt => $type, ops => join("\n ", '', @port_ops) |
|
338
|
|
|
|
|
|
|
unless $port_op; |
|
339
|
|
|
|
|
|
|
} |
|
340
|
|
|
|
|
|
|
elsif(@port_ops==1) |
|
341
|
0
|
|
|
|
|
0
|
{ $port_op = shift @$types; |
|
342
|
0
|
|
|
|
|
0
|
$name = $port_op->{name}; |
|
343
|
|
|
|
|
|
|
} |
|
344
|
|
|
|
|
|
|
else |
|
345
|
0
|
|
|
|
|
0
|
{ error __x"multiple operations in portType `{pt}', pick from {ops}" |
|
346
|
|
|
|
|
|
|
, pt => $type, ops => join("\n ", '', @port_ops) |
|
347
|
|
|
|
|
|
|
} |
|
348
|
|
|
|
|
|
|
|
|
349
|
8
|
50
|
|
|
|
20
|
my @bindops = @{$binding->{wsdl_operation} || []}; |
|
|
8
|
|
|
|
|
44
|
|
|
350
|
8
|
|
|
9
|
|
42
|
my $bind_op = first {$_->{name} eq $name} @bindops; |
|
|
9
|
|
|
|
|
22
|
|
|
351
|
8
|
50
|
|
|
|
59
|
$bind_op |
|
352
|
|
|
|
|
|
|
or error __x"cannot find bind operation for {name}", name => $name; |
|
353
|
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
# This should be detected while parsing the WSDL because the order of |
|
355
|
|
|
|
|
|
|
# input and output is significant (and lost), but WSDL 1.1 simplifies |
|
356
|
|
|
|
|
|
|
# our life by saying that only 2 out-of 4 predefined types can actually |
|
357
|
|
|
|
|
|
|
# be used at present. |
|
358
|
|
|
|
|
|
|
|
|
359
|
8
|
|
|
|
|
16
|
my @order = map +(unpack_type $_)[1], @{$port_op->{_ELEMENT_ORDER}}; |
|
|
8
|
|
|
|
|
50
|
|
|
360
|
|
|
|
|
|
|
|
|
361
|
8
|
|
|
|
|
160
|
my ($first_in, $first_out); |
|
362
|
8
|
|
|
|
|
53
|
for(my $i = 0; $i<@order; $i++) |
|
363
|
16
|
100
|
66
|
|
|
75
|
{ $first_in = $i if !defined $first_in && $order[$i] eq 'input'; |
|
364
|
16
|
100
|
100
|
|
|
94
|
$first_out = $i if !defined $first_out && $order[$i] eq 'output'; |
|
365
|
|
|
|
|
|
|
} |
|
366
|
|
|
|
|
|
|
|
|
367
|
8
|
50
|
|
|
|
52
|
my $kind |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
= !defined $first_in ? 'notification-operation' |
|
369
|
|
|
|
|
|
|
: !defined $first_out ? 'one-way' |
|
370
|
|
|
|
|
|
|
: $first_in < $first_out ? 'request-response' |
|
371
|
|
|
|
|
|
|
: 'solicit-response'; |
|
372
|
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
# |
|
374
|
|
|
|
|
|
|
### message components |
|
375
|
|
|
|
|
|
|
# |
|
376
|
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
my $operation = $opclass->_fromWSDL11 |
|
378
|
|
|
|
|
|
|
( name => $name, |
|
379
|
|
|
|
|
|
|
, kind => $kind |
|
380
|
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
, service => $service |
|
382
|
|
|
|
|
|
|
, serv_port => $port |
|
383
|
|
|
|
|
|
|
, binding => $binding |
|
384
|
|
|
|
|
|
|
, bind_op => $bind_op |
|
385
|
|
|
|
|
|
|
, portType => $portType |
|
386
|
|
|
|
|
|
|
, port_op => $port_op |
|
387
|
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
, wsdl => $self |
|
389
|
|
|
|
|
|
|
, action => $args{action} |
|
390
|
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
, server_type => $args{server_type} || $self->{XCW_server} |
|
392
|
8
|
|
33
|
|
|
115
|
); |
|
393
|
|
|
|
|
|
|
|
|
394
|
8
|
|
|
|
|
1538
|
$operation; |
|
395
|
|
|
|
|
|
|
} |
|
396
|
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
sub compileClient(@) |
|
399
|
0
|
|
|
0
|
1
|
0
|
{ my $self = shift; |
|
400
|
0
|
0
|
|
|
|
0
|
unshift @_, 'operation' if @_ % 2; |
|
401
|
0
|
0
|
|
|
|
0
|
my $op = $self->operation(@_) or return (); |
|
402
|
|
|
|
|
|
|
|
|
403
|
0
|
|
0
|
|
|
0
|
my $dopts = $self->{XCW_dcopts} || {}; |
|
404
|
0
|
0
|
|
|
|
0
|
$op->compileClient(@_, (ref $dopts eq 'ARRAY' ? @$dopts : %$dopts)); |
|
405
|
|
|
|
|
|
|
} |
|
406
|
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
#--------------------- |
|
408
|
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
sub declare($$@) |
|
411
|
10
|
|
|
10
|
1
|
12242
|
{ my ($self, $need, $names, @opts) = @_; |
|
412
|
10
|
50
|
|
|
|
37
|
my $opts = @opts==1 ? shift @opts : \@opts; |
|
413
|
10
|
50
|
|
|
|
36
|
$opts = [ %$opts ] if ref $opts eq 'HASH'; |
|
414
|
|
|
|
|
|
|
|
|
415
|
10
|
50
|
|
|
|
73
|
$need eq 'OPERATION' |
|
416
|
|
|
|
|
|
|
or $self->SUPER::declare($need, $names, @opts); |
|
417
|
|
|
|
|
|
|
|
|
418
|
10
|
100
|
|
|
|
1870
|
foreach my $name (ref $names eq 'ARRAY' ? @$names : $names) |
|
419
|
|
|
|
|
|
|
{ # checking existence of opname is expensive here |
|
420
|
|
|
|
|
|
|
# and may be problematic with multiple bindings. |
|
421
|
35
|
|
|
|
|
77
|
$self->{XCW_dcopts}{$name} = $opts; |
|
422
|
|
|
|
|
|
|
} |
|
423
|
|
|
|
|
|
|
|
|
424
|
10
|
|
|
|
|
20
|
$self; |
|
425
|
|
|
|
|
|
|
} |
|
426
|
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
#-------------------------- |
|
428
|
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
sub index(;$$) |
|
431
|
53
|
|
|
53
|
1
|
77
|
{ my $index = shift->{index}; |
|
432
|
53
|
50
|
|
|
|
121
|
@_ or return $index; |
|
433
|
|
|
|
|
|
|
|
|
434
|
53
|
50
|
|
|
|
131
|
my $class = $index->{ (shift) } |
|
435
|
|
|
|
|
|
|
or return (); |
|
436
|
|
|
|
|
|
|
|
|
437
|
53
|
50
|
|
|
|
159
|
@_ ? $class->{ (shift) } : $class; |
|
438
|
|
|
|
|
|
|
} |
|
439
|
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
sub findDef($;$) |
|
442
|
53
|
|
|
53
|
1
|
9268
|
{ my ($self, $class, $name) = @_; |
|
443
|
53
|
50
|
|
|
|
109
|
my $group = $self->index($class) |
|
444
|
|
|
|
|
|
|
or error __x"no definitions for `{class}' found", class => $class; |
|
445
|
|
|
|
|
|
|
|
|
446
|
53
|
100
|
|
|
|
111
|
if(defined $name) |
|
447
|
41
|
100
|
|
|
|
190
|
{ return $group->{$name} if exists $group->{$name}; # QNAME |
|
448
|
|
|
|
|
|
|
|
|
449
|
3
|
50
|
|
|
|
17
|
if($name =~ m/\:/) # PREFIXED |
|
450
|
0
|
|
|
|
|
0
|
{ my $qname = $self->findName($name); |
|
451
|
0
|
0
|
|
|
|
0
|
return $group->{$qname} if exists $group->{$qname}; |
|
452
|
|
|
|
|
|
|
} |
|
453
|
|
|
|
|
|
|
|
|
454
|
3
|
100
|
|
3
|
|
21
|
if(my $q = first { (unpack_type $_)[1] eq $name } keys %$group) |
|
|
3
|
|
|
|
|
14
|
|
|
455
|
2
|
|
|
|
|
35
|
{ return $group->{$q}; |
|
456
|
|
|
|
|
|
|
} |
|
457
|
|
|
|
|
|
|
|
|
458
|
1
|
|
|
|
|
25
|
error __x"no definition for `{name}' as {class}, pick from:{groups}" |
|
459
|
|
|
|
|
|
|
, name => $name, class => $class |
|
460
|
|
|
|
|
|
|
, groups => join("\n ", '', sort keys %$group); |
|
461
|
|
|
|
|
|
|
} |
|
462
|
|
|
|
|
|
|
|
|
463
|
12
|
100
|
|
|
|
49
|
return values %$group |
|
464
|
|
|
|
|
|
|
if wantarray; |
|
465
|
|
|
|
|
|
|
|
|
466
|
9
|
50
|
|
|
|
58
|
return (values %$group)[0] |
|
467
|
|
|
|
|
|
|
if keys %$group==1; |
|
468
|
0
|
|
|
|
|
0
|
my @alts = map $self->prefixed($_), sort keys %$group; |
|
469
|
0
|
|
|
|
|
0
|
error __x"explicit selection required: pick one {class} from {alts}" |
|
470
|
|
|
|
|
|
|
, class => $class, alts => join("\n ", '', @alts); |
|
471
|
|
|
|
|
|
|
} |
|
472
|
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
sub operations(@) |
|
475
|
2
|
|
|
2
|
1
|
5336
|
{ my ($self, %args) = @_; |
|
476
|
2
|
50
|
|
|
|
9
|
$args{produce} and die "produce option removed in 0.81"; |
|
477
|
|
|
|
|
|
|
|
|
478
|
2
|
|
|
|
|
2
|
my @ops; |
|
479
|
2
|
|
|
|
|
5
|
my @services = $self->findDef('service'); |
|
480
|
2
|
|
|
|
|
5
|
foreach my $service (@services) |
|
481
|
2
|
|
|
|
|
5
|
{ my $sname = $service->{name}; |
|
482
|
2
|
50
|
33
|
|
|
7
|
next if $args{service} && $args{service} ne $sname; |
|
483
|
|
|
|
|
|
|
|
|
484
|
2
|
50
|
|
|
|
3
|
my @ports = @{$service->{wsdl_port} || []}; |
|
|
2
|
|
|
|
|
8
|
|
|
485
|
2
|
|
|
|
|
4
|
foreach my $port (@ports) |
|
486
|
|
|
|
|
|
|
{ |
|
487
|
2
|
50
|
33
|
|
|
5
|
next if $args{port} && $args{port} ne $port->{name}; |
|
488
|
|
|
|
|
|
|
my $bindtype = $port->{binding} |
|
489
|
|
|
|
|
|
|
or error __x"no binding defined in port '{name}'" |
|
490
|
2
|
50
|
|
|
|
10
|
, name => $port->{name}; |
|
491
|
2
|
|
|
|
|
5
|
my $binding = $self->findDef(binding => $bindtype); |
|
492
|
|
|
|
|
|
|
|
|
493
|
2
|
50
|
33
|
|
|
6
|
next if $args{binding} && $args{binding} ne $binding->{name}; |
|
494
|
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
my $type = $binding->{type} |
|
496
|
2
|
50
|
|
|
|
7
|
or error __x"no type defined with binding `{name}'" |
|
497
|
|
|
|
|
|
|
, name => $bindtype; |
|
498
|
|
|
|
|
|
|
|
|
499
|
2
|
|
|
|
|
2
|
my %all_ops; |
|
500
|
2
|
50
|
|
|
|
3
|
foreach my $operation ( @{$binding->{wsdl_operation}||[]} ) |
|
|
2
|
|
|
|
|
7
|
|
|
501
|
2
|
|
|
|
|
3
|
{ my $opname = $operation->{name}; |
|
502
|
|
|
|
|
|
|
|
|
503
|
2
|
50
|
|
|
|
7
|
if(my $has = $all_ops{$opname}) |
|
504
|
|
|
|
|
|
|
{ error __x"operation {name} found again; choose service {has} or {also}" |
|
505
|
|
|
|
|
|
|
, name => $opname, has => $has->serviceName |
|
506
|
|
|
|
|
|
|
, also => $sname |
|
507
|
0
|
0
|
0
|
|
|
0
|
if @services > 1 && !$args{service}; |
|
508
|
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
error __x"need one set of operations, pick port from {ports}" |
|
510
|
0
|
|
|
|
|
0
|
, ports => [ map $_->{name}, @ports ], _join => ', '; |
|
511
|
|
|
|
|
|
|
} |
|
512
|
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
my $op = $all_ops{$opname} = $self->operation |
|
514
|
|
|
|
|
|
|
( service => $sname |
|
515
|
|
|
|
|
|
|
, port => $port->{name} |
|
516
|
|
|
|
|
|
|
, binding => $bindtype |
|
517
|
|
|
|
|
|
|
, operation => $opname |
|
518
|
|
|
|
|
|
|
, portType => $type |
|
519
|
|
|
|
|
|
|
, server_type => $args{server_type} |
|
520
|
2
|
|
|
|
|
11
|
); |
|
521
|
|
|
|
|
|
|
|
|
522
|
2
|
|
|
|
|
8
|
push @ops, $op; |
|
523
|
|
|
|
|
|
|
} |
|
524
|
|
|
|
|
|
|
} |
|
525
|
|
|
|
|
|
|
} |
|
526
|
|
|
|
|
|
|
|
|
527
|
2
|
|
|
|
|
7
|
@ops; |
|
528
|
|
|
|
|
|
|
} |
|
529
|
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
sub endPoint(@) |
|
532
|
2
|
|
|
2
|
1
|
1561
|
{ my ($self, %args) = @_; |
|
533
|
2
|
|
|
|
|
6
|
my $service = $self->findDef(service => delete $args{service}); |
|
534
|
|
|
|
|
|
|
|
|
535
|
2
|
|
|
|
|
3
|
my $port; |
|
536
|
2
|
50
|
|
|
|
3
|
my @ports = @{$service->{wsdl_port} || []}; |
|
|
2
|
|
|
|
|
9
|
|
|
537
|
2
|
|
|
|
|
9
|
my @portnames = map $_->{name}, @ports; |
|
538
|
2
|
50
|
|
|
|
10
|
if(my $portname = delete $args{port}) |
|
|
|
50
|
|
|
|
|
|
|
539
|
0
|
|
|
0
|
|
0
|
{ $port = first {$_->{name} eq $portname} @ports; |
|
|
0
|
|
|
|
|
0
|
|
|
540
|
0
|
0
|
|
|
|
0
|
error __x"cannot find port `{portname}', pick from {ports}" |
|
541
|
|
|
|
|
|
|
, portname => $portname, ports => join("\n ", '', @portnames) |
|
542
|
|
|
|
|
|
|
unless $port; |
|
543
|
|
|
|
|
|
|
} |
|
544
|
|
|
|
|
|
|
elsif(@ports==1) |
|
545
|
2
|
|
|
|
|
3
|
{ $port = shift @ports; |
|
546
|
|
|
|
|
|
|
} |
|
547
|
|
|
|
|
|
|
else |
|
548
|
0
|
|
|
|
|
0
|
{ error __x"specify port explicitly, pick from {portnames}" |
|
549
|
|
|
|
|
|
|
, portnames => join("\n ", '', @portnames); |
|
550
|
|
|
|
|
|
|
} |
|
551
|
|
|
|
|
|
|
|
|
552
|
2
|
|
|
|
|
8
|
foreach my $k (keys %$port) |
|
553
|
2
|
50
|
|
|
|
29
|
{ return $port->{$k}{location} if $k =~ m/address$/; |
|
554
|
|
|
|
|
|
|
} |
|
555
|
|
|
|
|
|
|
|
|
556
|
0
|
|
|
|
|
0
|
(); |
|
557
|
|
|
|
|
|
|
} |
|
558
|
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
sub printIndex(@) |
|
561
|
1
|
|
|
1
|
1
|
6829
|
{ my $self = shift; |
|
562
|
1
|
50
|
|
|
|
5
|
my $fh = @_ % 2 ? shift : select; |
|
563
|
1
|
|
|
|
|
4
|
my @args = @_; |
|
564
|
|
|
|
|
|
|
|
|
565
|
1
|
|
|
|
|
2
|
my %tree; |
|
566
|
1
|
|
|
|
|
4
|
foreach my $op ($self->operations(@args)) |
|
567
|
1
|
|
|
|
|
7
|
{ my $port = $op->version.' port '.$op->portName; |
|
568
|
1
|
|
|
|
|
7
|
my $bind = '(binding '.$op->bindingName.')'; |
|
569
|
1
|
|
|
|
|
8
|
$tree{'service '.$op->serviceName}{"$port $bind"}{$op->name} = $_; |
|
570
|
|
|
|
|
|
|
} |
|
571
|
|
|
|
|
|
|
|
|
572
|
1
|
|
|
|
|
20
|
foreach my $service (sort keys %tree) |
|
573
|
1
|
|
|
|
|
13
|
{ $fh->print("$service\n"); |
|
574
|
1
|
|
|
|
|
11
|
foreach my $port (sort keys %{$tree{$service}}) |
|
|
1
|
|
|
|
|
4
|
|
|
575
|
1
|
|
|
|
|
5
|
{ $fh->print(" $port\n"); |
|
576
|
1
|
|
|
|
|
7
|
foreach my $op (sort keys %{$tree{$service}{$port}}) |
|
|
1
|
|
|
|
|
4
|
|
|
577
|
1
|
|
|
|
|
4
|
{ $fh->print(" $op\n"); |
|
578
|
|
|
|
|
|
|
} |
|
579
|
|
|
|
|
|
|
} |
|
580
|
|
|
|
|
|
|
} |
|
581
|
|
|
|
|
|
|
} |
|
582
|
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
sub explain($$$@) |
|
585
|
0
|
|
|
0
|
1
|
|
{ my ($self, $opname, $format, $direction, @opts) = @_; |
|
586
|
0
|
0
|
|
|
|
|
my $op = $self->operation($opname, @opts) |
|
587
|
|
|
|
|
|
|
or error __x"explain operation {name} not found", name => $opname; |
|
588
|
0
|
|
|
|
|
|
$op->explain($self, $format, $direction, @opts); |
|
589
|
|
|
|
|
|
|
} |
|
590
|
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
#-------------------------------- |
|
592
|
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
1; |