File Coverage

lib/WSDL/Generator.pm
Criterion Covered Total %
statement 65 76 85.5
branch 1 8 12.5
condition 2 5 40.0
subroutine 13 16 81.2
pod 6 6 100.0
total 87 111 78.3


line stmt bran cond sub pod time code
1             =pod
2              
3             =head1 NAME
4              
5             WSDL::Generator - Generate wsdl file automagically
6              
7             =head1 SYNOPSIS
8              
9             use WSDL::Generator;
10             my $wsdl = WSDL::Generator->new($init);
11             Foo->a_method($param);
12             print $wsdl->get('Foo');
13              
14             =head1 DESCRIPTION
15              
16             You know folks out there who use another language than Perl (huh?) and you want to release a SOAP server for them
17              
18             1/ that's very kind of you
19             2/ you need to generate a wsdl file
20             3/ this module can help
21             Because Perl is dynamically typed, it is a fantastic language to write SOAP clients,
22             but that makes perl not-so-easy to use as SOAP server queried by statically typed languages
23             such as Delphi, Java, C++, VB...
24             These languages need a WSDL file to communicate with your server.
25             The WSDL file contains all the data structure definition necessary to interact with the server.
26             It contains also the namespace and URL as well.
27              
28             =cut
29             package WSDL::Generator;
30              
31 1     1   2077 use strict;
  1         2  
  1         30  
32 1     1   5 use warnings::register;
  1         2  
  1         168  
33 1     1   5 use Carp;
  1         5  
  1         85  
34 1     1   806 use Class::Hook;
  1         3975  
  1         26  
35 1     1   488 use WSDL::Generator::Schema;
  1         12  
  1         26  
36 1     1   459 use WSDL::Generator::Binding;
  1         3  
  1         29  
37 1     1   6 use base qw(WSDL::Generator::Base);
  1         2  
  1         73  
38 1     1   14 use 5.6.0;
  1         3  
  1         903  
39              
40             our $VERSION = '0.04';
41              
42             =pod
43              
44             =head1 CONSTRUCTOR
45              
46             =head2 new($init)
47              
48             $init = { 'schema_namesp' => 'http://www.acmetravel.com/AcmeTravelServices.xsd',
49             'services' => 'AcmeTravel',
50             'service_name' => 'BookFlight',
51             'target_namesp' => 'http://www.acmetravel.com/SOAP/',
52             'documentation' => 'Service to book tickets online',
53             'location' => 'http://www.acmetravel.com/SOAP/BookFlight' };
54             Install a spy which captures all the methods and subs calls to other classes
55              
56             =cut
57             sub new {
58 1     1 1 31 my $class = shift;
59 1   50     5 my $param = shift || {};
60 1         11 my $self = { calls => {},
61             %$param };
62 1         4 bless $self => $class;
63 1         29 Class::Hook->before(\&_before, $self);
64 1         14 Class::Hook->after(\&_after, $self);
65 1         13 Class::Hook->activate();
66 1         9074 return $self;
67             }
68              
69             =pod
70              
71             =head1 METHODS
72              
73             =head2 get($class)
74              
75             Returns the WSDL code for a specific class
76              
77             =cut
78             sub get : method {
79 1     1 1 21 my $self = shift;
80 1         3 my $class = shift;
81 1 50 33     15 unless (exists $self->{calls}{$class} and $self->{calls}{$class}) {
82 0         0 carp "Class $class not called";
83 0         0 return undef;
84             }
85 1         10 my $schema = WSDL::Generator::Schema->new( $self->{schema_namesp} );
86 1         13 my $binding = WSDL::Generator::Binding->new( { service_name => $self->{service_name},
87             services => $self->{services} } );
88 1         3 foreach my $method ( keys %{$self->{calls}{$class}} ) {
  1         5  
89 3         10 my $before = $self->{calls}{$class}->{$method}->{before};
90 3         7 my $after = $self->{calls}{$class}->{$method}->{after};
91 3         11 $schema->add($before, $method.'Request');
92 3         18 $schema->add($after, $method.'Response');
93 3         21 $binding->add_request($method);
94 3         8 $binding->add_response($method);
95             }
96 1         5 $self->{schema} = $schema->get;
97 1         5 $self->{message} = $binding->get_message;
98 1         4 $self->{porttype} = $binding->get_porttype;
99 1         5 $self->{binding} = $binding->get_binding;
100 1         15 $self->{service} = $self->get_wsdl_element( { wsdl_type => 'SERVICE',
101             %$self,
102             } );
103 1         12 $self->{definitions} = $self->get_wsdl_element( { wsdl_type => 'DEFINITIONS',
104             %$self,
105             } );
106 1         14 my $wsdl = $self->get_wsdl_element( { wsdl_type => 'WSDL',
107             %$self,
108             } );
109 1         14 Class::Hook->deactivate();
110 1         12 return $wsdl->to_string;
111             }
112              
113              
114             =pod
115              
116             =head2 get_all()
117              
118             Returns all classes available for a WSDL generation
119              
120             =cut
121             sub get_all : method {
122 1     1 1 988 my $self = shift;
123 1         3 return sort keys %{$self->{calls}};
  1         7  
124             }
125              
126              
127             =pod
128              
129             =head2 schema_namesp($value)
130              
131             Get or Set schema name space value
132              
133             =cut
134             sub schema_namesp {
135 0     0 1 0 my $self = shift;
136 0 0       0 my $value = shift or return $self->{schema_namesp};
137 0         0 $self->{schema_namesp} = $value;
138             }
139              
140             =pod
141              
142             =head2 service($value)
143              
144             Get or Set service name value
145              
146             =cut
147             sub service {
148 0     0 1 0 my $self = shift;
149 0 0       0 my $value = shift or return $self->{service};
150 0         0 $self->{service} = $value;
151             }
152              
153             =pod
154              
155             =head2 services($value)
156              
157             Get or Set services name value
158              
159             =cut
160             sub services {
161 0     0 1 0 my $self = shift;
162 0 0       0 my $value = shift or return $self->{services};
163 0         0 $self->{services} = $value;
164             }
165              
166              
167             sub _before {
168 3     3   252 my ($self, $param) = @_;
169 3         6 my $class = $param->{class};
170 3         7 my $method = $param->{method};
171 3         98 $self->{calls}{$class}{$method}{before} = $param->{param}->[0];
172             }
173              
174             sub _after {
175 3     3   146 my ($self, $param) = @_;
176 3         8 my $class = $param->{class};
177 3         6 my $method = $param->{method};
178 3         78 $self->{calls}{$class}{$method}{after} = $param->{'return'};
179             }
180              
181              
182              
183             1;
184              
185             =pod
186              
187             =head1 CAVEATS
188              
189             WSDL doesn't works only on perl 5.6 and not 5.8. UNIVERSAL::AUTOLOAD is broken in perl 5.8 and it is used by Class::Hook upon wich WSDL::Generator depends.
190              
191             WSDL is very flexible since it can describe any kind of data structure in a language non dependant description.
192             But that flexibility makes certain things difficult, such as array of inconsistant data types.
193             So, here is the current limitation of WSDL::Generator :
194              
195             Rule - "An array must contain elements of the same perl type".
196             Understand perl type as "scalar", "arrayref" or "hashref".
197             So, if you send this:
198              
199             [
200             {
201             key1 => 'Hello',
202             key2 => 'world',
203             },
204             {
205             key1 => 'Hi',
206             key3 => 'there',
207             },
208             {
209             key1 => 'Hi',
210             },
211             ]
212             That will do, but if you send:
213              
214             [
215             {
216             key1 => 'Hello',
217             key2 => 'world',
218             },
219             {
220             key1 => 'Hi',
221             key3 => 'there',
222             },
223             'a string instead of a hash ref',
224             ]
225             That won't work, since your structure is not "consistent", your array cannot contain both hashref and string.
226              
227             Another situation, if you send this:
228              
229             [
230             {
231             key1 => 'Hello',
232             key2 => 'world',
233             },
234             {
235             key1 => 'Hi',
236             key3 => 'there',
237             },
238             {
239             key1 => 'Hi',
240             },
241             ]
242             That will do, but if you send:
243              
244             [
245             {
246             key1 => 'Hello',
247             key2 => 'world',
248             },
249             {
250             key1 => [1,2,3],
251             key3 => 'there',
252             },
253             ]
254             That won't work either, since your key1 can have two complete different types of value (a string or an arrayref)
255             Finally, if you call several times a method, only the last call will be scanned to produce the WSDL file.
256             I hope these limitations will be lifted in the future.
257              
258             =head1 BUGS
259              
260             This is till n alpha release, so don't expect miracles and don't use it without caution - you've been warned!
261             Feel free to send me your bug reports, contribution and comments about this project.
262              
263             =head1 SEE ALSO
264              
265             SOAP::Lite, Class::Hook
266             http://www.w3.org/TR/SOAP/
267             http://www.w3.org/TR/wsdl
268              
269             =head1 ACKNOWLEDGEMENT
270              
271             A lot of thanks to:
272              
273             Paul Kulchenko for his fantastic SOAP::Lite module and his help
274             Patrick Morris, a Delphi wizard, for testing the wsdl generated and investing weird things
275             Joe Breeden for his excellent documentation
276             Yuval Mazor for his patch to make it compatible with .net wsdl compiler
277             Leon Brocard for his code review
278             James Duncan for his support
279              
280             =head1 AUTHOR
281              
282             Pierre Denis, C<< >>.
283              
284             =head1 COPYRIGHT
285              
286             Copyright 2009, Pierre Denis, All Rights Reserved.
287              
288             You may use, modify, and distribute this package under the
289             same terms as Perl itself.
290              
291             =cut