File Coverage

blib/lib/SOAP/WSDL/Server.pm
Criterion Covered Total %
statement 44 45 97.7
branch 15 16 93.7
condition 5 9 55.5
subroutine 7 7 100.0
pod 1 1 100.0
total 72 78 92.3


line stmt bran cond sub pod time code
1             package SOAP::WSDL::Server;
2 2     2   1324 use strict;
  2         4  
  2         64  
3 2     2   8 use warnings;
  2         2  
  2         52  
4 2     2   1232 use Class::Std::Fast::Storable;
  2         15188  
  2         15  
5 2     2   193 use Scalar::Util qw(blessed);
  2         2  
  2         118  
6 2     2   627 use SOAP::WSDL::Factory::Deserializer;
  2         3  
  2         39  
7 2     2   606 use SOAP::WSDL::Factory::Serializer;
  2         3  
  2         794  
8              
9             our $VERSION = 3.003;
10              
11             my %dispatch_to_of :ATTR(:name :default<()>);
12             my %action_map_ref_of :ATTR(:name :default<{}>);
13             my %class_resolver_of :ATTR(:name :default<()>);
14             my %deserializer_of :ATTR(:name :default<()>);
15             my %serializer_of :ATTR(:name :default<()>);
16              
17             sub handle {
18 7     7 1 3060 my $self = shift;
19 7         15 my $ident = ident $self;
20             # this involves copying the request...
21 7         28 my $request = shift; # once
22              
23             # we only support 1.1 now...
24 7   66     21 $deserializer_of{ $ident } ||= SOAP::WSDL::Factory::Deserializer->get_deserializer({
25             soap_version => '1.1'
26             });
27 6   66     16 $serializer_of{ $ident } ||= SOAP::WSDL::Factory::Serializer->get_serializer({
28             soap_version => '1.1'
29             });
30              
31             # TODO: factor out dispatcher logic into dispatcher factory + dispatcher
32             # classes
33             # $dispatcher_of{ $ident } ||= SOAP::WSDL::Factory::Dispatcher->get_dispatcher({});
34              
35             # set class resolver if deserializer supports it
36 6 100       73 $deserializer_of{ $ident }->set_class_resolver( $class_resolver_of{ $ident } )
37             if ( $deserializer_of{ $ident }->can('set_class_resolver') );
38              
39             # Try deserializing response
40 6         199 my ($body, $header) = eval {
41 6         23 $deserializer_of{ $ident }->deserialize( $request->content() );
42             };
43 6 100       78 if ($@) {
44 1         8 die $deserializer_of{ $ident }->generate_fault({
45             code => 'SOAP-ENV:Server',
46             role => 'urn:localhost',
47             message => "Error deserializing message: $@. \n"
48             });
49             };
50 5 50 33     13 if (blessed($body) && $body->isa('SOAP::WSDL::SOAP::Typelib::Fault11')) {
51 0         0 die $body;
52             }
53              
54             # lookup method name by SOAPAction
55 5         16 my $soap_action = $request->header('SOAPAction');
56 5 100       190 $soap_action = '' if not defined $soap_action;
57 5         8 $soap_action =~s{ \A(?:"|')(.+)(?:"|') \z }{$1}xms;
58 5         6 my $method_name = $action_map_ref_of{ $ident }->{ $soap_action };
59              
60             # $dispatcher_of{ $ident }->dispatch({
61             # soap_action => $soap_action,
62             # request_body => $body,
63             # request_header => $header,
64             # });
65              
66 5 100       9 if (!$dispatch_to_of{ $ident }) {
67 1         4 die $deserializer_of{ $ident }->generate_fault({
68             code => 'SOAP-ENV:Server',
69             role => 'urn:localhost',
70             message => "No handler registered",
71             });
72             };
73              
74 4 100       7 if (! defined $request->header('SOAPAction') ) {
75 1         40 die $deserializer_of{ $ident }->generate_fault({
76             code => 'SOAP-ENV:Server',
77             role => 'urn:localhost',
78             message => "Not found: No SOAPAction given",
79             });
80             };
81              
82 3 100       66 if (! defined $method_name) {
83 1         5 die $deserializer_of{ $ident }->generate_fault({
84             code => 'SOAP-ENV:Server',
85             role => 'urn:localhost',
86             message => "Not found: No method found for the SOAPAction '$soap_action'",
87             });
88             };
89              
90             # find method in handling class/object
91 2         10 my $method_ref = $dispatch_to_of{ $ident }->can($method_name);
92              
93 2 100       62 if (!$method_ref) {
94 1         5 die $deserializer_of{ $ident }->generate_fault({
95             code => 'SOAP-ENV:Server',
96             role => 'urn:localhost',
97             message => "Not implemented: The handler does not implement the method $method_name",
98             });
99             };
100              
101 1         3 my ($response_body, $response_header) = $method_ref->($dispatch_to_of{ $ident }, $body, $header );
102              
103 1         6 return $serializer_of{ $ident }->serialize({
104             body => $response_body,
105             header => $response_header,
106             });
107             }
108              
109             1;
110              
111             =pod
112              
113             =head1 NAME
114              
115             SOAP::WSDL::Server - WSDL based SOAP server base class
116              
117             =head1 SYNOPSIS
118              
119             Don't use directly, use the SOAP::WSDL::Server::* subclasses
120             instead.
121              
122             =head1 DESCRIPTION
123              
124             SOAP::WSDL::Server basically follows the architecture sketched below
125             (though dispatcher classes are not implemented yet)
126              
127             SOAP Request SOAP Response
128             | ^
129             V |
130             ------------------------------------------
131             | SOAP::WSDL::Server |
132             | -------------------------------------- |
133             | | Transport Class | |
134             | |--------------------------------------| |
135             | | Deserializer | Serializer | |
136             | |--------------------------------------| |
137             | | Dispatcher | |
138             | -------------------------------------- |
139             ------------------------------------------
140             | calls ^
141             v | returns
142             -------------------------------------
143             | Handler |
144             -------------------------------------
145              
146             All of the components (Transport class, deserializer, dispatcher and
147             serializer) are implemented as plugins.
148              
149             The architecture is not implemented as planned yet, but the dispatcher is
150             currently part of SOAP::WSDL::Server, which aggregates serializer and
151             deserializer, and is subclassed by transport classes (of which
152             SOAP::WSDL::Server::CGI is the only implemented one yet).
153              
154             The dispatcher is currently based on the SOAPAction header. This does not
155             comply to the WS-I basic profile, which declares the SOAPAction as optional.
156              
157             The final dispatcher will be based on wire signatures (i.e. the classes
158             of the deserialized messages).
159              
160             A hash-based dispatcher could be implemented by examining the top level
161             hash keys.
162              
163             =head1 EXCEPTION HANDLING
164              
165             =head2 Builtin exceptions
166              
167             SOAP::WSDL::Server handles the following errors itself:
168              
169             In case of errors, a SOAP Fault containing an appropriate error message
170             is returned.
171              
172             =over
173              
174             =item * XML parsing errors
175              
176             =item * Configuration errors
177              
178             =back
179              
180             =head2 Throwing exceptions
181              
182             The proper way to throw a exception is just to die -
183             SOAP::WSDL::Server::CGI catches the exception and sends a SOAP Fault
184             back to the client.
185              
186             If you want more control over the SOAP Fault sent to the client, you can
187             die with a SOAP::WSDL::SOAP::Fault11 object - or just let the
188             SOAP::Server's deserializer create one for you:
189              
190             my $soap = MyServer::SomeService->new();
191              
192             die $soap->get_deserializer()->generate_fault({
193             code => 'SOAP-ENV:Server',
194             role => 'urn:localhost',
195             message => "The error message to pas back",
196             detail => "Some details on the error",
197             });
198              
199             You may use any other object as exception, provided it has a
200             serialize() method which returns the object's XML representation.
201              
202             =head2 Subclassing
203              
204             To write a transport-specific SOAP Server, you should subclass
205             SOAP::WSDL::Server.
206              
207             See the C modules for examples.
208              
209             A SOAP Server must call the following method to actually handle the request:
210              
211             =head3 handle
212              
213             Handles the SOAP request.
214              
215             Returns the response message as XML.
216              
217             Expects a C object as only parameter.
218              
219             You may use any other object as parameter, as long as it implements the
220             following methods:
221              
222             =over
223              
224             =item * header
225              
226             Called as header('SOAPAction'). Must return the corresponding HTTP header.
227              
228             =item * content
229              
230             Returns the request message
231              
232             =back
233              
234             =head1 LICENSE AND COPYRIGHT
235              
236             Copyright 2004-2008 Martin Kutter.
237              
238             This file is part of SOAP-WSDL. You may distribute/modify it under the same
239             terms as perl itself
240              
241             =head1 AUTHOR
242              
243             Martin Kutter Emartin.kutter fen-net.deE
244              
245             =head1 REPOSITORY INFORMATION
246              
247             $Rev: 391 $
248             $LastChangedBy: kutterma $
249             $Id: Client.pm 391 2007-11-17 21:56:13Z kutterma $
250             $HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL/Client.pm $
251              
252             =cut