diff --git a/Build.PL b/Build.PL index a3a4469..e763e2e 100644 --- a/Build.PL +++ b/Build.PL @@ -1,43 +1,40 @@ use Module::Build; + Module::Build->new( - create_makefile_pl => 'passthrough', - dist_abstract => 'SOAP with WSDL support', - dist_name => 'SOAP-WSDL', - dist_version => '2.00_10', - module_name => 'SOAP::WSDL', - license => 'artistic', - requires => { - 'Class::Std' => q/v0.0.8/, - 'Class::Std::Storable' => 0, - 'Date::Parse' => 0, - 'Date::Format' => 0, - 'LWP::UserAgent' => 0, - 'List::Util' => 0, - 'File::Basename' => 0, - 'File::Path' => 0, - 'XML::LibXML' => 0, - 'XML::SAX::Base' => 0, - 'XML::SAX::ParserFactory' => 0, - 'XML::Parser::Expat' => 0, + create_makefile_pl => 'passthrough', + dist_abstract => 'SOAP with WSDL support', + dist_name => 'SOAP-WSDL', + dist_version => '2.00_11', + module_name => 'SOAP::WSDL', + license => 'artistic', + requires => { + 'Class::Std' => q/v0.0.8/, + 'Class::Std::Storable' => 0, + 'Date::Parse' => 0, + 'Date::Format' => 0, + 'LWP::UserAgent' => 0, + 'List::Util' => 0, + 'File::Basename' => 0, + 'File::Path' => 0, + 'XML::Parser::Expat' => 0, + 'Template' => 0, + 'Getopt::Long' => 0, }, - buildrequires => { - 'Date::Parse' => 0, - 'Date::Format' => 0, - 'Benchmark' => 0, - 'Cwd' => 0, - 'Test::More' => 0, - 'Class::Std' => 0.0.8, - 'Class::Std::Storable' => 0, - 'List::Util' => 0, - 'LWP::UserAgent' => 0, - 'File::Basename' => 0, - 'File::Path' => 0, - 'XML::Simple' => 0, - 'XML::LibXML' => 0, - 'XML::Parser::Expat' => 0, - 'XML::SAX::Base' => 0, - 'XML::SAX::ParserFactory' => 0, - 'Pod::Simple::Text' => 0, + buildrequires => { + 'Date::Parse' => 0, + 'Date::Format' => 0, + 'Test::More' => 0, + 'Class::Std' => q/v0.0.8/, + 'Class::Std::Storable' => 0, + 'List::Util' => 0, + 'LWP::UserAgent' => 0, + 'File::Basename' => 0, + 'File::Path' => 0, + 'XML::Parser::Expat' => 0, + 'Template' => 0, + 'Getopt::Long' => 0, + 'Cwd' => 0, + 'File::Find' => 0, }, recursive_test_files => 1, )->create_build_script; diff --git a/CHANGES b/CHANGES index a642566..16e6dcd 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,143 @@ ------------------------------------------------------------------------ +r176 | kutterma | 2007-08-31 17:28:29 +0200 (Fr, 31 Aug 2007) | 2 lines + +- set SVN keywords +- updated docs +------------------------------------------------------------------------ +r175 | kutterma | 2007-08-31 17:05:42 +0200 (Fr, 31 Aug 2007) | 6 lines + +- modified SOAP::WSDL::Client to allow passing the SOAPAction header to call() +- modified SOAP::WSDL::Definitions's generator to emit interfaces which include + soap_action and style information for every operation +- re-generated GetWeather example interface +- fixed wsdl2perl.pl (typo) + +------------------------------------------------------------------------ +r174 | kutterma | 2007-08-31 15:49:04 +0200 (Fr, 31 Aug 2007) | 2 lines + +- SOAPAction header is now always quoted. +- updated docs +------------------------------------------------------------------------ +r173 | kutterma | 2007-08-31 15:48:10 +0200 (Fr, 31 Aug 2007) | 1 line + +- added WS-I basic profile compliance docs. Looks like we're far from being compliant... +------------------------------------------------------------------------ +r172 | kutterma | 2007-08-30 22:58:41 +0200 (Do, 30 Aug 2007) | 1 line + +- updated TODO list +------------------------------------------------------------------------ +r170 | kutterma | 2007-08-30 22:32:56 +0200 (Do, 30 Aug 2007) | 1 line + +- added RELEASE_NOTES +------------------------------------------------------------------------ +r169 | kutterma | 2007-08-30 21:33:50 +0200 (Do, 30 Aug 2007) | 1 line + +- fixed SOAP11 serializer package name +------------------------------------------------------------------------ +r168 | kutterma | 2007-08-30 21:32:39 +0200 (Do, 30 Aug 2007) | 4 lines + +- added Serializer factory +- modified client to use serializer +- moved old SOAP::WSDL::Envelope into Serializer namespace +- moved Tranport factory into Factory namespace +------------------------------------------------------------------------ +r167 | kutterma | 2007-08-30 21:30:17 +0200 (Do, 30 Aug 2007) | 1 line + +- fixed Envelope to comply to new serializer scheme +------------------------------------------------------------------------ +r166 | kutterma | 2007-08-30 18:44:48 +0200 (Do, 30 Aug 2007) | 1 line + +- re-fixed Transport factory +------------------------------------------------------------------------ +r165 | kutterma | 2007-08-30 18:43:36 +0200 (Do, 30 Aug 2007) | 1 line + +- added HTTP Transport class (really) +------------------------------------------------------------------------ +r164 | kutterma | 2007-08-30 14:38:47 +0200 (Do, 30 Aug 2007) | 1 line + +- first try at serializer factory. +------------------------------------------------------------------------ +r163 | kutterma | 2007-08-30 10:34:00 +0200 (Do, 30 Aug 2007) | 1 line + +- updated docs (reference to homepage and forum) +------------------------------------------------------------------------ +r162 | kutterma | 2007-08-30 10:29:49 +0200 (Do, 30 Aug 2007) | 1 line + +- updated docs +------------------------------------------------------------------------ +r161 | kutterma | 2007-08-30 10:17:28 +0200 (Do, 30 Aug 2007) | 2 lines + +- modified client to use SOAP::WSDL::Transport factory +- fixed SOAP::WSDL::Transport factory +------------------------------------------------------------------------ +r160 | kutterma | 2007-08-30 00:20:09 +0200 (Do, 30 Aug 2007) | 1 line + +- added weird SOAP::Lite nameing scheme to registered && SOAP::Lite Transport instantiations +------------------------------------------------------------------------ +r159 | kutterma | 2007-08-30 00:00:15 +0200 (Do, 30 Aug 2007) | 1 line + +- first try at Transport factory and Transport::HTTP implementation class. +------------------------------------------------------------------------ +r158 | kutterma | 2007-08-29 22:36:34 +0200 (Mi, 29 Aug 2007) | 1 line + +- updated TODO list +------------------------------------------------------------------------ +r153 | kutterma | 2007-08-29 11:24:40 +0200 (Mi, 29 Aug 2007) | 4 lines + +- removed XML::LibXML dependencies (is now required, not used in test scripts) +- fixed WSDLParser to switch on expat namespace support when parsing files +- added expat based tests ported from XML::LibXML based WSDL parser tests +- updated docs +------------------------------------------------------------------------ +r152 | kutterma | 2007-08-28 23:28:06 +0200 (Di, 28 Aug 2007) | 3 lines + +- updated Build.PL +- updated CHANGES +- updated MANIFEST +------------------------------------------------------------------------ +r151 | kutterma | 2007-08-28 23:07:14 +0200 (Di, 28 Aug 2007) | 1 line + +- fixed namespace test +------------------------------------------------------------------------ +r150 | kutterma | 2007-08-28 23:06:00 +0200 (Di, 28 Aug 2007) | 1 line + +- renamed tests to better meet their content +------------------------------------------------------------------------ +r149 | kutterma | 2007-08-28 23:03:30 +0200 (Di, 28 Aug 2007) | 1 line + +- cleanup +------------------------------------------------------------------------ +r148 | kutterma | 2007-08-28 23:02:01 +0200 (Di, 28 Aug 2007) | 2 lines + +- added namespace test +- removed SAX handler from usage test +------------------------------------------------------------------------ +r147 | kutterma | 2007-08-28 22:57:48 +0200 (Di, 28 Aug 2007) | 1 line + +- added namespace support +------------------------------------------------------------------------ +r146 | kutterma | 2007-08-28 21:56:35 +0200 (Di, 28 Aug 2007) | 1 line + +- removed POD directive from template, so the CPAN indexer won't show it... +------------------------------------------------------------------------ +r145 | kutterma | 2007-08-28 16:35:18 +0200 (Di, 28 Aug 2007) | 5 lines + +- XML::SAX::Base and XML::SAX::ParserFactory and Pod::Simple::Text dependencies to ease testing +- removed unneccessary performance test +- Added Expat-based WSDL parser and test to get rid of XML::LibXML dependency some day... + - needs further work: namespaces are not processed correctly, yet + +------------------------------------------------------------------------ +r144 | kutterma | 2007-08-14 11:05:40 +0200 (Di, 14 Aug 2007) | 1 line + +- added missing prerequisite 'Template' to Build.PL +------------------------------------------------------------------------ +r143 | kutterma | 2007-08-13 20:43:20 +0200 (Mo, 13 Aug 2007) | 3 lines + +- fixed POD (#1772710) +- fixed Makefile.PL - now try the passthrough variant first. If too many CPAN testers still fail, we may switch to traditional, some day... +- prepared 2.00_10 pre-release +------------------------------------------------------------------------ r142 | kutterma | 2007-08-13 15:55:45 +0200 (Mo, 13 Aug 2007) | 1 line typo diff --git a/MANIFEST b/MANIFEST index df474b9..42bf646 100644 --- a/MANIFEST +++ b/MANIFEST @@ -22,6 +22,7 @@ example/lib/MyTypemaps/FullerData_x0020_Fortune_x0020_Cookie.pm example/lib/MyTypemaps/GlobalWeather.pm example/weather.pl example/weather_wsdl.pl +example/weather_xml_compile.pl example/wsdl/FortuneCookie.xml example/wsdl/genericbarcode.xml example/wsdl/globalweather.xml @@ -32,11 +33,16 @@ lib/SOAP/WSDL/Binding.pm lib/SOAP/WSDL/Client.pm lib/SOAP/WSDL/Client/Base.pm lib/SOAP/WSDL/Definitions.pm -lib/SOAP/WSDL/Envelope.pm lib/SOAP/WSDL/Expat/MessageParser.pm lib/SOAP/WSDL/Expat/MessageStreamParser.pm +lib/SOAP/WSDL/Expat/MessageSubParser.pm +lib/SOAP/WSDL/Expat/SubParser.pm +lib/SOAP/WSDL/Expat/WSDLParser.pm +lib/SOAP/WSDL/Factory/Serializer.pm +lib/SOAP/WSDL/Factory/Transport.pm lib/SOAP/WSDL/Manual.pod lib/SOAP/WSDL/Manual/Glossary.pod +lib/SOAP/WSDL/Manual/WS_I_BasicProfile_Compliance.pod lib/SOAP/WSDL/Message.pm lib/SOAP/WSDL/Operation.pm lib/SOAP/WSDL/OpMessage.pm @@ -44,11 +50,14 @@ lib/SOAP/WSDL/Parser.pod lib/SOAP/WSDL/Part.pm lib/SOAP/WSDL/Port.pm lib/SOAP/WSDL/PortType.pm +lib/SOAP/WSDL/RELEASE_NOTES lib/SOAP/WSDL/SAX/MessageHandler.pm lib/SOAP/WSDL/SAX/WSDLHandler.pm +lib/SOAP/WSDL/Serializer/SOAP11.pm lib/SOAP/WSDL/Service.pm lib/SOAP/WSDL/SOAP/Typelib/Fault11.pm lib/SOAP/WSDL/SoapOperation.pm +lib/SOAP/WSDL/Transport/HTTP.pm lib/SOAP/WSDL/TypeLookup.pm lib/SOAP/WSDL/Types.pm lib/SOAP/WSDL/XSD/Builtin.pm @@ -108,13 +117,18 @@ lib/SOAP/WSDL/XSD/Typelib/ComplexType.pm lib/SOAP/WSDL/XSD/Typelib/Element.pm lib/SOAP/WSDL/XSD/Typelib/SimpleType.pm LICENSE +Makefile.PL MANIFEST This list of files META.yml README t/001_use.t +t/002_parse_wsdl.t t/002_sax.t t/003_sax_serializer.t +t/003_wsdl_based_serializer.t +t/004_parse_wsdl.t t/004_sax_wsdl.t +t/005_parse_contributed.t t/005_sax_contributed_wsdl.t t/006_client.t t/007_envelope.t @@ -126,9 +140,13 @@ t/013_complexType.t t/014_sax_typelib.t t/015_to_typemap.t t/016_client_object.t -t/017_generator.t -t/018_generator.t +t/017_generator_expat.t +t/017_generator_libxml.t +t/018_generator_expat.t +t/018_generator_libxml.t t/020_storable.t +t/021_generator_element_ref_expat.t +t/021_generator_element_ref_libxml.t t/098_pod.t t/acceptance/results/03_complexType-all.xml t/acceptance/results/03_complexType-sequence.xml @@ -142,6 +160,7 @@ t/acceptance/wsdl/006_sax_client.wsdl t/acceptance/wsdl/008_complexType.wsdl t/acceptance/wsdl/02_port.wsdl t/acceptance/wsdl/03_complexType-all.wsdl +t/acceptance/wsdl/03_complexType-element-ref.wsdl t/acceptance/wsdl/03_complexType-sequence.wsdl t/acceptance/wsdl/04_element-simpleType.wsdl t/acceptance/wsdl/04_element.wsdl @@ -156,6 +175,8 @@ t/acceptance/wsdl/contributed/OITest.wsdl t/acceptance/wsdl/contributed/tools.wsdl t/acceptance/wsdl/email_account.wsdl t/Expat/01_expat.t +t/Expat/02_sub_parser.t +t/Expat/03_wsdl.t t/lib/MyComplexType.pm t/lib/MyElement.pm t/lib/MySimpleType.pm @@ -168,6 +189,7 @@ t/SOAP/WSDL/02_port.t t/SOAP/WSDL/03_complexType-all.t t/SOAP/WSDL/03_complexType-choice.t t/SOAP/WSDL/03_complexType-complexContent.t +t/SOAP/WSDL/03_complexType-element-ref.t t/SOAP/WSDL/03_complexType-group.t t/SOAP/WSDL/03_complexType-sequence.t t/SOAP/WSDL/03_complexType-simpleContent.t @@ -177,7 +199,6 @@ t/SOAP/WSDL/04_element.t t/SOAP/WSDL/05_simpleType-list.t t/SOAP/WSDL/05_simpleType-restriction.t t/SOAP/WSDL/05_simpleType-union.t -t/SOAP/WSDL/10_performance.t t/SOAP/WSDL/11_helloworld.NET.t t/SOAP/WSDL/12_binding.pl t/SOAP/WSDL/XSD/Typelib/Builtin/001_string.t @@ -185,4 +206,3 @@ t/SOAP/WSDL/XSD/Typelib/Builtin/002_dateTime.t t/SOAP/WSDL/XSD/Typelib/Builtin/002_time.t t/SOAP/WSDL/XSD/Typelib/Builtin/003_date.t TODO -Makefile.PL diff --git a/META.yml b/META.yml index c3dd05a..3017e61 100644 --- a/META.yml +++ b/META.yml @@ -1,6 +1,6 @@ --- name: SOAP-WSDL -version: 2.00_10 +version: 2.00_11 author: abstract: SOAP with WSDL support license: artistic @@ -11,12 +11,11 @@ requires: Date::Parse: 0 File::Basename: 0 File::Path: 0 + Getopt::Long: 0 LWP::UserAgent: 0 List::Util: 0 - XML::LibXML: 0 + Template: 0 XML::Parser::Expat: 0 - XML::SAX::Base: 0 - XML::SAX::ParserFactory: 0 generated_by: Module::Build version 0.2808 meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.2.html @@ -35,12 +34,16 @@ provides: file: lib/SOAP/WSDL/Client/Base.pm SOAP::WSDL::Definitions: file: lib/SOAP/WSDL/Definitions.pm - SOAP::WSDL::Envelope: - file: lib/SOAP/WSDL/Envelope.pm SOAP::WSDL::Expat::MessageParser: file: lib/SOAP/WSDL/Expat/MessageParser.pm SOAP::WSDL::Expat::MessageStreamParser: file: lib/SOAP/WSDL/Expat/MessageStreamParser.pm + SOAP::WSDL::Expat::MessageSubParser: + file: lib/SOAP/WSDL/Expat/MessageSubParser.pm + SOAP::WSDL::Factory::Serializer: + file: lib/SOAP/WSDL/Factory/Serializer.pm + SOAP::WSDL::Factory::Transport: + file: lib/SOAP/WSDL/Factory/Transport.pm SOAP::WSDL::Message: file: lib/SOAP/WSDL/Message.pm SOAP::WSDL::OpMessage: @@ -57,10 +60,14 @@ provides: file: lib/SOAP/WSDL/SAX/MessageHandler.pm SOAP::WSDL::SOAP::Typelib::Fault11: file: lib/SOAP/WSDL/SOAP/Typelib/Fault11.pm + SOAP::WSDL::Serializer::SOAP11: + file: lib/SOAP/WSDL/Serializer/SOAP11.pm SOAP::WSDL::Service: file: lib/SOAP/WSDL/Service.pm SOAP::WSDL::SoapOperation: file: lib/SOAP/WSDL/SoapOperation.pm + SOAP::WSDL::Transport::HTTP: + file: lib/SOAP/WSDL/Transport/HTTP.pm SOAP::WSDL::TypeLookup: file: lib/SOAP/WSDL/TypeLookup.pm SOAP::WSDL::Types: diff --git a/TODO b/TODO index bca635f..793436a 100644 --- a/TODO +++ b/TODO @@ -1,36 +1,35 @@ -- support embedded atomic types by including a second (and third and fourth) -package type_prefix::complex_type::element_name element package. -Allow unlimited depth (though this is rather wicked). -- fixup generated pod so it looks nice in SOAP::WSDL::Definitions. -- remove benchmarks from tests. Create benchmark/ directory and store benchmarks in. -- add tests for SOAP::WSDL::Definitions::create - - test for correct creation - - test against web service (fullerdata.com?) -- Improve docs - - Partially DONE -- Remove SOAP::Lite dependency - for now, just support HTTP(s) via LWP::UserAgent. - - Partially DONE. SOAP::WSDL still uses SOAP::Schema -- write inheritance Test for all XSD::Typelib::Builtin::* classes -- Check & probably fix simpleType support. -The WS at http://www.webservicex.net/genericbarcode.asmx?wsdl should make up a good example for simpleType -definitions. -- add default Fault11 typemap to generated typemaps - - DONE -- SOAP::WSDL::Definitions::create creates bad interface docs. Fix it. - - DONE -- update all Builtin Types to new constructor BEGIN block (Class::Std unfortunately is way slow) - - DONE. -- Remove useless (but on CPAN annoying) doc from Builtin::* classes - - DONE -- add example WS scripts - - DONE. -- SOAP::WSDL::XSD::Typelib::Builtin::string does not unescape XML builtin entities on get_value() - - WONTFIX. - Entities are unescaped by XML parser. - If you want the plain value, you have to use get_value, as XML conversion is overloaded on stringification. -- Make callin WS easier: implent WS-I-based SOAP::WSDL::Client::WSI - - WONTFIX - SOAP::WSDL::Base should behave equal -- add capability to create request objects based on input part definitions to SOAP::WSDL::Client::Base - - DONE. +TODO list for SOAP::WSDL + +2.00 Pre-releases +-------- +* SOAP Header support (#1764845) + +* Implement a interface similar to SOAP::Schema (#1783639) + +* (#1785195) Support deserializer plugins + * Support XML::Compiled as one serializer/deserializer + +* Check & probably fix simpleType support. +The WS at http://www.webservicex.net/genericbarcode.asmx?wsdl should +make up a good example for simpleType definitions. + +* Remove benchmarks from test. Create benchmark/ directory to store benchmarks. + +* write inheritance Test for all XSD::Typelib::Builtin::* classes + +* support embedded atomic types (#1761532) +Implement by including a second (and third and fourth) + +package type_prefix::complex_type::element_name; + +element package. +Maybe even allow unlimited depth? What does the specs say? + +2.1 release +-------- +Past 2.1 release +-------- +* XML schema support ("minimal conformant") (#1764845) +* Support SOAP attachments \ No newline at end of file diff --git a/bin/wsdl2perl.pl b/bin/wsdl2perl.pl index aee7f8f..5b57121 100644 --- a/bin/wsdl2perl.pl +++ b/bin/wsdl2perl.pl @@ -1,13 +1,10 @@ #!/usr/bin/perl -w use strict; use warnings; -use Fcntl; -use IO::File; use Pod::Usage; use Getopt::Long; use LWP::UserAgent; -use SOAP::WSDL::SAX::WSDLHandler; -use XML::LibXML; +use SOAP::WSDL::Expat::WSDLParser; my %opt = ( url => '', @@ -39,8 +36,7 @@ my $url = $ARGV[0]; pod2usage( -exit => 1 , verbose => 2 ) if ($opt{help}); pod2usage( -exit => 1 , verbose => 1 ) if not ($url); -my $handler = SOAP::WSDL::SAX::WSDLHandler->new(); -my $parser = XML::LibXML->new(); +my $parser = SOAP::WSDL::Expat::WSDLParser->new(); local $ENV{HTTP_PROXY} = $opt{proxy} if $opt{proxy}; my $lwp = LWP::UserAgent->new(); @@ -49,16 +45,13 @@ die $response->message(), "\n" if $response->code != 200; my $xml = $response->content(); -$parser->set_handler( $handler ); -$parser->parse_string( $xml ); - -my $wsdl = $handler->get_data(); +my $wsdl = $parser->parse_string( $xml ); if ($opt{typemap_include}) { - my $fh = IO::File->new($opt{typemap_include} , O_RDONLY) + open my $fh , $opt{typemap_include} or die "cannot open typemap_include file $opt{typemap_include}\n"; - $opt{custom_types} = join q{}, $fh->getlines(); - $fh->close(); + $opt{custom_types} .= join q{}, <$fh>; + close $fh; delete $opt{typemap_include}; } diff --git a/example/lib/MyElements/GetCitiesByCountry.pm b/example/lib/MyElements/GetCitiesByCountry.pm index 2591842..0775531 100644 --- a/example/lib/MyElements/GetCitiesByCountry.pm +++ b/example/lib/MyElements/GetCitiesByCountry.pm @@ -3,6 +3,7 @@ use strict; use Class::Std::Storable; use SOAP::WSDL::XSD::Typelib::Element; + # atomic complexType # definition use SOAP::WSDL::XSD::Typelib::ComplexType; @@ -16,7 +17,7 @@ my %CountryName_of :ATTR(:get); __PACKAGE__->_factory( - [ qw( + [ qw( CountryName ) ], { @@ -25,8 +26,8 @@ __PACKAGE__->_factory( }, { - CountryName => 'SOAP::WSDL::XSD::Typelib::Builtin::string', - + CountryName => 'SOAP::WSDL::XSD::Typelib::Builtin::string', + } ); @@ -46,9 +47,16 @@ __PACKAGE__->__set_ref(''); __END__ + + + + + =pod -=head1 NAME MyElements::GetCitiesByCountry +=head1 NAME + +MyElements::GetCitiesByCountry =head1 SYNOPSIS diff --git a/example/lib/MyElements/GetCitiesByCountryResponse.pm b/example/lib/MyElements/GetCitiesByCountryResponse.pm index 64f87b8..835bf39 100644 --- a/example/lib/MyElements/GetCitiesByCountryResponse.pm +++ b/example/lib/MyElements/GetCitiesByCountryResponse.pm @@ -3,6 +3,7 @@ use strict; use Class::Std::Storable; use SOAP::WSDL::XSD::Typelib::Element; + # atomic complexType # definition use SOAP::WSDL::XSD::Typelib::ComplexType; @@ -16,7 +17,7 @@ my %GetCitiesByCountryResult_of :ATTR(:get); __PACKAGE__->_factory( - [ qw( + [ qw( GetCitiesByCountryResult ) ], { @@ -25,8 +26,8 @@ __PACKAGE__->_factory( }, { - GetCitiesByCountryResult => 'SOAP::WSDL::XSD::Typelib::Builtin::string', - + GetCitiesByCountryResult => 'SOAP::WSDL::XSD::Typelib::Builtin::string', + } ); @@ -46,9 +47,16 @@ __PACKAGE__->__set_ref(''); __END__ + + + + + =pod -=head1 NAME MyElements::GetCitiesByCountryResponse +=head1 NAME + +MyElements::GetCitiesByCountryResponse =head1 SYNOPSIS diff --git a/example/lib/MyElements/GetWeather.pm b/example/lib/MyElements/GetWeather.pm index e132fb9..283ce3f 100644 --- a/example/lib/MyElements/GetWeather.pm +++ b/example/lib/MyElements/GetWeather.pm @@ -3,6 +3,7 @@ use strict; use Class::Std::Storable; use SOAP::WSDL::XSD::Typelib::Element; + # atomic complexType # definition use SOAP::WSDL::XSD::Typelib::ComplexType; @@ -18,9 +19,9 @@ my %CountryName_of :ATTR(:get); __PACKAGE__->_factory( - [ qw( + [ qw( CityName - + CountryName ) ], { @@ -30,11 +31,11 @@ __PACKAGE__->_factory( }, { - CityName => 'SOAP::WSDL::XSD::Typelib::Builtin::string', - + CityName => 'SOAP::WSDL::XSD::Typelib::Builtin::string', + - CountryName => 'SOAP::WSDL::XSD::Typelib::Builtin::string', - + CountryName => 'SOAP::WSDL::XSD::Typelib::Builtin::string', + } ); @@ -54,9 +55,16 @@ __PACKAGE__->__set_ref(''); __END__ + + + + + =pod -=head1 NAME MyElements::GetWeather +=head1 NAME + +MyElements::GetWeather =head1 SYNOPSIS diff --git a/example/lib/MyElements/GetWeatherResponse.pm b/example/lib/MyElements/GetWeatherResponse.pm index 0fb4ab3..416c300 100644 --- a/example/lib/MyElements/GetWeatherResponse.pm +++ b/example/lib/MyElements/GetWeatherResponse.pm @@ -3,6 +3,7 @@ use strict; use Class::Std::Storable; use SOAP::WSDL::XSD::Typelib::Element; + # atomic complexType # definition use SOAP::WSDL::XSD::Typelib::ComplexType; @@ -16,7 +17,7 @@ my %GetWeatherResult_of :ATTR(:get); __PACKAGE__->_factory( - [ qw( + [ qw( GetWeatherResult ) ], { @@ -25,7 +26,8 @@ __PACKAGE__->_factory( }, { - GetWeatherResult => 'SOAP::WSDL::XSD::Typelib::Builtin::string', + GetWeatherResult => 'SOAP::WSDL::XSD::Typelib::Builtin::string', + } ); @@ -45,9 +47,16 @@ __PACKAGE__->__set_ref(''); __END__ + + + + + =pod -=head1 NAME MyElements::GetWeatherResponse +=head1 NAME + +MyElements::GetWeatherResponse =head1 SYNOPSIS diff --git a/example/lib/MyElements/string.pm b/example/lib/MyElements/string.pm index 816ce1d..8208b0f 100644 --- a/example/lib/MyElements/string.pm +++ b/example/lib/MyElements/string.pm @@ -3,6 +3,7 @@ use strict; use Class::Std::Storable; use SOAP::WSDL::XSD::Typelib::Element; + # # definition # @@ -26,9 +27,16 @@ __PACKAGE__->__set_ref(''); __END__ + + + + + =pod -=head1 NAME MyElements::string +=head1 NAME + +MyElements::string =head1 SYNOPSIS diff --git a/example/lib/MyInterfaces/GlobalWeather.pm b/example/lib/MyInterfaces/GlobalWeather.pm index 573a060..634fd72 100644 --- a/example/lib/MyInterfaces/GlobalWeather.pm +++ b/example/lib/MyInterfaces/GlobalWeather.pm @@ -1,4 +1,5 @@ package MyInterfaces::GlobalWeather; + use strict; use warnings; use MyTypemaps::GlobalWeather; @@ -16,15 +17,29 @@ sub new { } __PACKAGE__->__create_methods( - GetWeather => [ 'MyElements::GetWeather', ], - GetCitiesByCountry => [ 'MyElements::GetCitiesByCountry', ], - + GetWeather => { + parts => [ 'MyElements::GetWeather', ], + soap_action => 'http://www.webserviceX.NET/GetWeather', + style => 'document', + # use => '', # use not implemented yet + }, + GetCitiesByCountry => { + parts => [ 'MyElements::GetCitiesByCountry', ], + soap_action => 'http://www.webserviceX.NET/GetCitiesByCountry', + style => 'document', + # use => '', # use not implemented yet + }, + ); 1; __END__ + + + + =pod =head1 NAME @@ -64,5 +79,5 @@ SYNOPSIS: -=cut +=pod diff --git a/example/weather.pl b/example/weather.pl index 295c200..7307c8b 100644 --- a/example/weather.pl +++ b/example/weather.pl @@ -14,6 +14,7 @@ use MyInterfaces::GlobalWeather; my $weather = MyInterfaces::GlobalWeather->new(); my $result = $weather->GetWeather({ CountryName => 'Germany', CityName => 'Munich' }); -die $result->get_faultstring()->get_value() if not ($result); # boolean comparison overloaded +# boolean comparison overloaded +die $result->get_faultstring()->get_value() if not ($result); print $result->get_GetWeatherResult()->get_value() , "\n"; diff --git a/example/weather_wsdl.pl b/example/weather_wsdl.pl index 4bece48..05acc8e 100644 --- a/example/weather_wsdl.pl +++ b/example/weather_wsdl.pl @@ -22,4 +22,18 @@ my $som = $soap->wsdl("file:///$path/wsdl/globalweather.xml") die $som->message() if $som->fault(); -print $som->result(); \ No newline at end of file +print $som->result(); + + +# SOAP::Lite variant: + +use SOAP::Lite; +my $soap = SOAP::Lite->new()->on_action( sub { join'/', @_ } ) + ->proxy("http://www.webservicex.net/globalweather.asmx"); +my $som = $soap->call( + SOAP::Data->name('GetWeather')->attr({ xmlns => 'http://www.webserviceX.NET' }), + SOAP::Data->name('CountryName')->value('Germany'), + SOAP::Data->name('CityName')->value('Munich') +); + +print $som->result(); diff --git a/example/weather_xml_compile.pl b/example/weather_xml_compile.pl new file mode 100644 index 0000000..f534a8c --- /dev/null +++ b/example/weather_xml_compile.pl @@ -0,0 +1,43 @@ +# Accessing the globalweather service at +# www.webservicex.net/GlobalWeather/GlobalWeather.asmx +# +# Note that the GlobalWeather web service returns a (quoted) XML structure - +# don't be surprised by the response's format. +# +# I have no connection to www.webservicex.net +# Use this script at your own risk. +# +# This script demonstrates the use of SOAP::WSDL in SOAP::Lite style. +=for later +use lib 'lib/'; +use lib '../lib'; +use SOAP::WSDL; +use File::Basename qw(dirname); +use File::Spec; +my $path = File::Spec->rel2abs( dirname __FILE__); + +my $soap = SOAP::WSDL->new(); +my $som = $soap->wsdl("file:///$path/wsdl/globalweather.xml")->no_dispatch(1) + ->call('GetWeather', GetWeather => { CountryName => 'Germany', CityName => 'Munich' }); + +print $som; + +=for later use + +die $som->message() if $som->fault(); + +print $som->result(); + +=cut + +use Carp; +use diagnostics; + +use XML::Compile::WSDL; +my $schema = XML::Compile::WSDL->new('wsdl/globalweather.xml', + schema_dirs => 'D:/Test/XMLC/' +); + +my $operation = $schema->prepare('GetWeather', role => 'CLIENT', port => 'GlobalWeatherSoap'); +use Data::Dumper; +print Dumper $operation; diff --git a/lib/SOAP/WSDL.pm b/lib/SOAP/WSDL.pm index 75951b7..f4b2800 100644 --- a/lib/SOAP/WSDL.pm +++ b/lib/SOAP/WSDL.pm @@ -598,27 +598,14 @@ The following facets have no influence yet: =head1 SEE ALSO -There are lots of SOAP Clients on CPAN, lately. - -You may wish to look at the following: - +=head2 Related projects + =over =item * L Full featured SOAP-library, little WSDL support. Supports rpc-encoded style only. Many protocols supported. -=item * L - -A very basic SOAP library without transport facilities. - -Handy if you got your XML message ready and just need an envelope around it. - -=item * L - -An extremely basic SOAP client module - just HTTP support, no encoding / decoding, -HTTP headers have to be set as arguments to 'new' - =item * A promising-looking approach derived from a cool functional DOM-based XML schema parser. @@ -629,6 +616,20 @@ Not yet finished at the time of writing - but you may wish to give it a try, esp if you need to adhere very closely to the XML Schema / WSDL specs. =back + +=head2 Sources of documentation + +=over + +=item * SOAP::WSDL homepage at sourceforge.net + +L + +=item * SOAP::WSDL forum at CPAN::Forum + +L + +=back =head1 ACKNOWLEDGMENTS @@ -661,9 +662,9 @@ Martin Kutter Emartin.kutter fen-net.deE =head1 REPOSITORY INFORMATION - $Rev: 143 $ + $Rev: 176 $ $LastChangedBy: kutterma $ - $Id: WSDL.pm 143 2007-08-13 18:43:20Z kutterma $ + $Id: WSDL.pm 176 2007-08-31 15:28:29Z kutterma $ $HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL.pm $ =cut diff --git a/lib/SOAP/WSDL/Base.pm b/lib/SOAP/WSDL/Base.pm index 5aceecc..629b8df 100644 --- a/lib/SOAP/WSDL/Base.pm +++ b/lib/SOAP/WSDL/Base.pm @@ -78,12 +78,15 @@ sub init { my @args = @_; foreach my $value (@args) { - die $value if (not defined ($value->{ Name })); + die @args if (not defined ($value->{ Name })); if ($value->{ Name } =~m{^xmlns\:}xms) { die $xmlns_of{ ident $self } if ref $xmlns_of{ ident $self } ne 'HASH'; + + # add namespaces $xmlns_of{ ident $self }->{ $value->{ Value } } = $value->{ LocalName }; + next; } elsif ($value->{ Name } =~m{^xmlns$}xms) { diff --git a/lib/SOAP/WSDL/Client.pm b/lib/SOAP/WSDL/Client.pm index fea5642..fab1f81 100644 --- a/lib/SOAP/WSDL/Client.pm +++ b/lib/SOAP/WSDL/Client.pm @@ -8,28 +8,42 @@ use LWP::UserAgent; use HTTP::Request; use Scalar::Util qw(blessed); -use SOAP::WSDL::Envelope; +use SOAP::WSDL::Factory::Serializer; +use SOAP::WSDL::Factory::Transport; use SOAP::WSDL::Expat::MessageParser; use SOAP::WSDL::SOAP::Typelib::Fault11; -# Package globals for speed... +# Package global for speed and memory savings. +# But should be factored out into serializer/deserializer... my $PARSER; my %class_resolver_of :ATTR(:name :default<()>); my %no_dispatch_of :ATTR(:name :default<()>); my %outputxml_of :ATTR(:name :default<()>); -my %proxy_of :ATTR(:name :default<()>); +my %transport_of :ATTR(:name :default<()>); +my %endpoint_of :ATTR(:name :default<()>); +my %soap_version_of :ATTR(:get :init_attr :default<'1.1'>); + my %fault_class_of :ATTR(:name :default); my %trace_of :ATTR(:set :init_arg :default<()> ); my %on_action_of :ATTR(:name :default<()>); -my %content_type_of :ATTR(:name :default); - -#/#trick editors +my %content_type_of :ATTR(:name :default); #/#trick editors +my %serializer_of :ATTR(:name :default<()>); # TODO remove when preparing 2.01 sub outputtree { warn 'outputtree is deprecated and' . 'will be removed before reaching v2.01 !' } + +sub BUILD { + my ($self, $ident, $attrs_of_ref) = @_; + + if (exists $attrs_of_ref->{ proxy }) { + $self->set_proxy( $attrs_of_ref->{ proxy } ); + delete $attrs_of_ref->{ proxy }; + } + +} sub get_trace { my $ident = ident $_[0]; @@ -39,6 +53,44 @@ sub get_trace { : sub { warn @_ } : () } + +sub get_proxy { + return $_[0]->get_transport(); +} + +sub set_proxy { + my ($self, @args_from) = @_; + my $ident = ident $self; + + # remember old value to return it later - Class::Std does so, too + my $old_value = $transport_of{ $ident }; + + # accept both list and list ref args + @args_from = @{ $args_from[0] } if ref $args_from[0]; + + # remember endpoint + $endpoint_of{ $ident } = $args_from[0]; + + # set transport - SOAP::Lite works similar... + $transport_of{ $ident } = SOAP::WSDL::Factory::Transport + ->get_transport( @args_from ); + + return $old_value; +} + +sub set_soap_version { + my $ident = ident shift; + + # remember old value to return it later - Class::Std does so, too + my $soap_version = $soap_version_of{ $ident }; + + # re-setting the soap version invalidates the + # serializer object + delete $serializer_of{ $ident }; + $soap_version_of{ $ident } = shift; + + return $soap_version; +} # Mimic SOAP::Lite's behaviour for getter/setter routines SUBFACTORY: { @@ -69,60 +121,79 @@ sub call { : (@_>1) ? { @_ } : $_[0]; + my $header = {}; - my $soap_action; + my ($soap_action, $operation); my $trace_sub = $self->get_trace(); - my $envelope = SOAP::WSDL::Envelope->serialize( $method, $data ); - - if (blessed $data - && $data->isa('SOAP::WSDL::XSD::Typelib::Builtin::anyType')) - { - # TODO replace by something derived from binding - this is just a - # workaround... - $soap_action = join '/', $data->get_xmlns(), $method; - } - else { - $envelope = SOAP::WSDL::Envelope->serialize( $method, $data ); - # TODO add something like SOAP::Lite's on_action mechanism - $soap_action = $on_action_of{$ident}->( $self, $method ) if ($on_action_of{$ident}); - } + + if (ref $method eq 'HASH') { + $soap_action = $method->{ soap_action }; + $operation = $method->{ operation } + } + else { + $operation = $method; + } + + + $serializer_of{ $ident } ||= SOAP::WSDL::Factory::Serializer->get_serializer({ + soap_version => $self->get_soap_version(), + }); + + my $envelope = $serializer_of{ $ident }->serialize({ + method => $operation, + body => $data, + header => $header, + }); return $envelope if $self->no_dispatch(); - # get response via transport layer - # maybe we should return a result with the following methods: - # - result: returns the result of the call (like SOAP::Lite, but as - # object tree) - # - header: returns the content of the SOAP header - # - fault: returns the result of the call if a SOAP fault is sent back - # by the server. Retuns undef (nothing) if the call has been - # processed without errors. - my $ua = LWP::UserAgent->new(); - my $request = HTTP::Request->new( 'POST', - $self->get_proxy(), - [ 'Content-Type', $content_type_of{ $ident }, - 'Content-Length', length($envelope), - 'SOAPAction', $soap_action, - ], - $envelope ); - - - $trace_sub->( $request->as_string() ) if $trace_of{ $ident }; # if for speed - my $response = $ua->request( $request ); - $trace_sub->( $response->as_string() ) if $trace_of{ $ident }; # if for speed - - return $response->content() if ($self->outputxml() ); + # try to guess soap_action if not given + if (not defined $soap_action) { + $soap_action = (blessed $data + && $data->isa('SOAP::WSDL::XSD::Typelib::Builtin::anyType')) + ? $soap_action = join '/', $data->get_xmlns(), $operation + : ($on_action_of{$ident}) + ? $soap_action = $on_action_of{$ident}->( $self, $operation ) + : ""; + } + + # always quote SOAPAction header. + # WS-I BP 1.0 R1109 + $soap_action =~s{\A(:?"|')?}{"}xms; + $soap_action =~s{(:?"|')?\Z}{"}xms; + + # get response via transport layer. + # Normally, SOAP::Lite's transport layer is used, though users + # may provide their own. + my $transport = $self->get_transport(); + my $response = $transport->send_receive( + endpoint => $self->get_endpoint(), + content_type => $content_type_of{ $ident }, + envelope => $envelope, + action => $soap_action, + on_receive_chunk => sub {} # optional, may be used for parsing large responses as they arrive. + # might not be supported by all transport layers... + # and, of course, only is of interest for chunk parsers - + # namely ExpatNB and XML::LibXML's Push parser interface... + ); + + return $response if ($self->outputxml() ); $PARSER->class_resolver( $self->get_class_resolver() ); - # if we had no success (Transport layer error status code) + # if we had no success (Transport layer error status code) # or if transport layer failed - if ($response->code() != 200) { + if ( ! $transport->is_success() ) { # Try deserializing response - there may be some - if ($response->content) { - eval { $PARSER->parse( $response->content() ); }; + if ( $response ) { + eval { $PARSER->parse( $response ); }; return $PARSER->get_data() if (not $@); - warn "could not deserialize response: $@"; + return $fault_class_of{$ident}->new({ + faultcode => 'soap:Server', + faultactor => 'urn:localhost', + faultstring => "Error deserializing message: $@. \n" + . "Message was: \n$response" + }); }; # generate & return fault if we cannot serialize response @@ -131,11 +202,10 @@ sub call { faultcode => 'soap:Server', faultactor => 'urn:localhost', faultstring => 'Error sending / receiving message: ' - . $response->message() - #$soap->transport->message() + . $transport->message() }); } - eval { $PARSER->parse( $response->content() ) }; + eval { $PARSER->parse( $response ) }; # return fault if we cannot deserialize response if ($@) { @@ -161,6 +231,31 @@ SOAP::WSDL::Client - SOAP::WSDL's SOAP Client =head1 METHODS =head2 call + + $soap->call( \%method, \@parts ); + +%method is a hash with the following keys: + + Name Description + ---------------------------------------------------- + operation operation name + soap_action SOAPAction HTTP header to use + style Operation style. One of (document|rpc) + use SOAP body encoding. One of (literal|encoded) + +The style and use keys have no influence yet. + +@parts is a list containing the elements of the message parts. + +For backward compatibility, call may also be called as below: + + $soap->call( $method, \@parts ); + +In this case, $method is the SOAP operation name, and the SOAPAction header +is guessed from the first part's namespace and the operation name (which is +mostly correct, but may fail). Operation style and body encoding are assumed to +be document/literal + =head2 Configuration methods @@ -286,9 +381,9 @@ Martin Kutter Emartin.kutter fen-net.deE =head1 REPOSITORY INFORMATION - $Rev: 139 $ + $Rev: 176 $ $LastChangedBy: kutterma $ - $Id: Client.pm 139 2007-08-12 19:15:59Z kutterma $ + $Id: Client.pm 176 2007-08-31 15:28:29Z kutterma $ $HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL/Client.pm $ =cut diff --git a/lib/SOAP/WSDL/Client/Base.pm b/lib/SOAP/WSDL/Client/Base.pm index 0e6f990..981a1b2 100644 --- a/lib/SOAP/WSDL/Client/Base.pm +++ b/lib/SOAP/WSDL/Client/Base.pm @@ -21,20 +21,35 @@ sub __create_new { } sub __create_methods { - my ($package, %parts_of) = @_; + my ($package, %info_of) = @_; no strict qw(refs); - for my $method (keys %parts_of){ + for my $method (keys %info_of){ + my ($soap_action, @parts); + + # up to 2.00_10 we had list refs... + if (ref $info_of{ $method }eq 'HASH') { + @parts = @{ $info_of{ $method }->{ parts } }; + $soap_action = $info_of{ $method }->{ soap_action }; + } + else { + @parts = @{ $info_of{ $method } }; + $soap_action = (); + } + *{ "$package\::$method" } = sub { my $self = shift; my @param = map { my $data = shift || {}; eval "require $_"; $_->new( $data ); - } @{ $parts_of{ $method } }; + } @parts; - return $self->SUPER::call( $method, @param ); + return $self->SUPER::call( { + operation => $method, + soap_action => $soap_action, + }, @param ); } } } @@ -47,13 +62,40 @@ __END__ =head1 NAME -SOAP::WSDL::Client::Base - Base client for WSDL-based SOAP access +SOAP::WSDL::Client::Base - Factory class for WSDL-based SOAP access =head1 SYNOPSIS - package MySoapClient; + package MySoapInterface; use SOAP::WSDL::Client::Base; + __PACKAGE__->__create_new( + proxy => 'http://somewhere.over.the.rainbow', + class_resolver => 'Typemap::MySoapInterface' + ); __PACKAGE__->__create_methods( qw(one two three) ); 1; -=cut \ No newline at end of file +=head1 DESCRIPTION + +Factory class for creating interface classes. Should probably be renamed to +SOAP::WSDL::Factory::Interface... + +=head1 LICENSE + +Copyright 2004-2007 Martin Kutter. + +This file is part of SOAP-WSDL. You may distribute/modify it under +the same terms as perl itself + +=head1 AUTHOR + +Martin Kutter Emartin.kutter fen-net.deE + +=head1 REPOSITORY INFORMATION + + $Rev: 176 $ + $LastChangedBy: kutterma $ + $Id: Base.pm 176 2007-08-31 15:28:29Z kutterma $ + $HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL/Client/Base.pm $ + +=cut diff --git a/lib/SOAP/WSDL/Definitions.pm b/lib/SOAP/WSDL/Definitions.pm index 353abad..43c5fa9 100644 --- a/lib/SOAP/WSDL/Definitions.pm +++ b/lib/SOAP/WSDL/Definitions.pm @@ -4,7 +4,7 @@ use strict; use warnings; use Carp; use File::Basename; -use File::Path; +use File::Path; use List::Util qw(first); use Class::Std::Storable; use base qw(SOAP::WSDL::Base); @@ -116,7 +116,17 @@ sub _create_interface { # my %operations = (); for my $operation ( @{ $operation_ref } ) { - my $operation_name = $operation->get_name(); + my $operation_name = $operation->get_name(); + my $soap_operation = $operation->first_operation(); + + $operations{ $operation_name }->{ style } = $soap_operation + ? $soap_operation->get_style() + : undef; + + $operations{ $operation_name }->{ soap_action } = $soap_operation + ? $soap_operation->get_soapAction() + : undef; + my $port_op = first { $_->get_name() eq $operation_name } @{ $port_operation_ref }; $operations{ $operation_name }->{ documentation } = $port_op->get_documentation(); @@ -151,9 +161,6 @@ sub _create_interface { } } -# use Data::Dumper; -# die Dumper \%operations; - my $template = <<'EOT'; package [% interface_prefix %][% service.get_name.replace('\.', '::') %]; @@ -174,9 +181,14 @@ sub new { } __PACKAGE__->__create_methods( - [% FOREACH name = operations.keys -%] - [% name %] => [ [% FOREACH class = operations.$name.input.class %]'[% class %]', [% END %]], - [% END %] +[% FOREACH name = operations.keys -%] + [% name %] => { + parts => [ [% FOREACH class = operations.$name.input.class %]'[% class %]', [% END %]], + soap_action => '[% operations.$name.soap_action %]', + style => '[% operations.$name.style %]', + # use => '', # use not implemented yet + }, +[% END %] ); 1; diff --git a/lib/SOAP/WSDL/Expat/MessageParser.pm b/lib/SOAP/WSDL/Expat/MessageParser.pm index 4b3e940..390e3a0 100644 --- a/lib/SOAP/WSDL/Expat/MessageParser.pm +++ b/lib/SOAP/WSDL/Expat/MessageParser.pm @@ -28,8 +28,7 @@ sub _initialize { my $current = undef; my $ignore = [ 'Envelope', 'Body' ]; # top level elements to ignore my $list = []; # node list - my $path = []; # current path (without - # number) + my $path = []; # current path my $skip = 0; # skip elements # use "globals" for speed @@ -84,7 +83,7 @@ sub _initialize { $current = $_class->new({ %_attrs }); # set new current object # remember top level element - defined $self->{ data } + exists $self->{ data } or ($self->{ data } = $current); }, @@ -143,6 +142,13 @@ sub parsefile { return $_[0]->{ data }; } +# SAX-like aliases +sub parse_string; +*parse_string = \&parse; + +sub parse_file; +*parse_file = \&parsefile; + sub get_data { return $_[0]->{ data }; } @@ -202,9 +208,9 @@ This module may be used under the same terms as perl itself. $ID: $ - $LastChangedDate: $ - $LastChangedRevision: $ - $LastChangedBy: $ + $LastChangedDate: 2007-08-31 17:28:29 +0200 (Fr, 31 Aug 2007) $ + $LastChangedRevision: 176 $ + $LastChangedBy: kutterma $ - $HeadURL: $ + $HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL/Expat/MessageParser.pm $ diff --git a/lib/SOAP/WSDL/Expat/MessageStreamParser.pm b/lib/SOAP/WSDL/Expat/MessageStreamParser.pm index 0665707..dbb194a 100644 --- a/lib/SOAP/WSDL/Expat/MessageStreamParser.pm +++ b/lib/SOAP/WSDL/Expat/MessageStreamParser.pm @@ -67,9 +67,9 @@ This module may be used under the same terms as perl itself. $ID: $ - $LastChangedDate: $ - $LastChangedRevision: $ - $LastChangedBy: $ + $LastChangedDate: 2007-08-31 17:28:29 +0200 (Fr, 31 Aug 2007) $ + $LastChangedRevision: 176 $ + $LastChangedBy: kutterma $ - $HeadURL: $ + $HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL/Expat/MessageStreamParser.pm $ diff --git a/lib/SOAP/WSDL/Expat/MessageSubParser.pm b/lib/SOAP/WSDL/Expat/MessageSubParser.pm new file mode 100644 index 0000000..ebbbf55 --- /dev/null +++ b/lib/SOAP/WSDL/Expat/MessageSubParser.pm @@ -0,0 +1,213 @@ +#!/usr/bin/perl +package SOAP::WSDL::Expat::MessageSubParser; +use strict; +use warnings; +use SOAP::WSDL::XSD::Typelib::Builtin; +use XML::Parser::Expat; + +sub new { + my ($class, $args) = @_; + my $self = {}; + bless $self, $class; + return $self; +} + +# create handlers via currying - XML::Compiled is a good teacher... +# +# A handler has to know +# - the order of it's child elements +# - the classes for these child elements +# - the handlers for these child elements (sub refs) + +# order is checked if provided + +sub start_tag { + my $self = shift; + my $arg_ref = shift; + + my $CHILD_ORDER = $arg_ref->{ order } || []; + my $CHILD_CLASS = $arg_ref->{ class_of } || {}; + my $CHILD_HANDLER = $arg_ref->{ handler_of }; + my $CHILD_OCCURS = $arg_ref->{ occurs_of } || {}; + + my $CHILD_INDEX = 0; + + + return sub { + # parser, element, attrs + my ($prefix, $localname) = split m{:}xms , $_[1]; + $localname ||= $_[1]; + +=pod + +# # implement better checks... +# if (@{ $CHILD_ORDER }) { +# if ($CHILD_ORDER->[$CHILD_INDEX] ne $localname) { +# if (! $CHILD_ORDER->[++$CHILD_INDEX] +# || $CHILD_ORDER->[$CHILD_INDEX] ne $localname) { +# die "misplaced xml element " . $parser->recognized_string() +# . " at line " +# . $parser->current_line() +# . " column " . $parser->current_column() , "\n" +# , "Element order: " . join(',' , @{ $CHILD_ORDER }), "\n" +# } +# } +# } +# +# if (%{ $CHILD_OCCURS }) { +# die "too many occurances of $localname at line " +# . $parser->current_line() +# . " column " . $parser->current_column() , "\n" +# if (not --$CHILD_OCCURS->{ $localname }->{ max }); +# +# # min must be checked in end_element ! +# $CHILD_OCCURS->{ $localname }->{ min }-- +# if ($CHILD_OCCURS->{ $localname }->{ min }); +# } + +=cut + + # remove this some day + return if ($localname eq 'Envelope'); + return if ($localname eq 'Body'); + + # step down in tree (remember current) + push @{ $self->{ list } }, $self->{ current }; + $self->{ current } = $CHILD_CLASS->{ $localname }->new({ @_[2..$#_] }); + + # Set (and remember) next state + push @{ $self->{ handlers } }, $CHILD_HANDLER->{ $localname }; + $_[0]->setHandlers( %{ $CHILD_HANDLER->{ $localname } } ); + }; +} + +# characters is a good candidate for replacement when not needed - +# expat calls it for those whitespaces in non-mixed-content-elements, too +sub characters { + my $self = shift; + return sub { $self->{ characters } .= $_[1] }; +} + +# end_tag is a somewhat generic thingy - don't know whether we should +# curry it, and whether this will speed us up... +sub end_tag { + my $self = shift; + + return sub { + # step down handler hierarchy + pop @{ $self->{ handlers } }; + + # restore state: set handler to last handler + $_[0]->setHandlers( %{ $self->{ handlers }->[ -1 ] } ); + + my ($prefix, $localname) = split m{:}xms , $_[1]; + $localname ||= $_[1]; # for non-prefixed elements + + # we only have characters if we need them - if not Char handler + # has to be set to undef + $self->{ current }->set_value( $self->{ characters } ) + if ($self->{ characters }); + + # empty temp characters + undef $self->{ characters }; + + # return if we're top node + # This one easily handles ignores for us, too... + # + # Hmm... could be replaced by something else, maybe ??? + # Maybe by defining an empty end_tag handler for the top node ? + # Can we do this ??? + return if not defined $self->{ list }->[-1]; + + # set appropriate attribute in last element + # multiple values must be implemented in base class + my $method = "add_$localname"; + $self->{ list }->[-1]->$method( $self->{ current } ); + + # step up in object hierarchy... + $self->{ current } = pop @{ $self->{ list } }; + }; +} + +sub end_top_tag { + my $self = shift; + return sub {}; +} + +sub initialize { + my ($self, $handler_of_ref, $parser ) = @_; + $parser ||= XML::Parser::Expat->new(); + $self->{ list } = undef; + $self->{ current } = undef; + $self->{ characters } = q{}; # empty characters + $self->{ handlers } = [ $handler_of_ref ]; + $parser->setHandlers( %$handler_of_ref ); + return $parser; +} + +sub get_data { + return $_[0]->{ current }; +} + +1; + +=pod + +=head1 NAME + +SOAP::WSDL::Expat::MessageParser - Convert SOAP messages to custom object trees + +=head1 SYNOPSIS + + my $parser = SOAP::WSDL::Expat::MessageParser->new({ + class_resolver => 'My::Resolver' + }); + $parser->parse( $xml ); + my $obj = $parser->get_data(); + +=head1 DESCRIPTION + +Real fast expat based SOAP message parser. + +See L for details. + +=head2 Skipping unwanted items + +Sometimes there's unneccessary information transported in SOAP messages. + +To skip XML nodes (including all child nodes), just edit the type map for +the message and set the type map entry to '__SKIP__'. + +=head1 Bugs and Limitations + +=over + +=item * Ignores all namespaces + +=item * Does not handle mixed content + +=item * The SOAP header is ignored + +=back + +=head1 AUTHOR + +Replace the whitespace by @ for E-Mail Address. + + Martin Kutter Emartin.kutter fen-net.deE + +=head1 COPYING + +This module may be used under the same terms as perl itself. + +=head1 Repository information + + $ID: $ + + $LastChangedDate: 2007-08-31 17:28:29 +0200 (Fr, 31 Aug 2007) $ + $LastChangedRevision: 176 $ + $LastChangedBy: kutterma $ + + $HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL/Expat/MessageSubParser.pm $ + + diff --git a/lib/SOAP/WSDL/Expat/SubParser.pm b/lib/SOAP/WSDL/Expat/SubParser.pm new file mode 100644 index 0000000..169264d --- /dev/null +++ b/lib/SOAP/WSDL/Expat/SubParser.pm @@ -0,0 +1,219 @@ +#!/usr/bin/perl +package SOAP::WSDL::Expat::MessageSubParser; +use strict; +use warnings; +use SOAP::WSDL::XSD::Typelib::Builtin; +use XML::Parser::Expat; + +sub new { + my ($class, $args) = @_; + my $self = { + class_resolver => $args->{ class_resolver } + }; + bless $self, $class; + return $self; +} + +sub class_resolver { + my $self = shift; + $self->{ class_resolver } = shift; +} + +sub _start; + +sub _initialize { + my ($self, $parser) = @_; + + delete $self->{ data }; + + my $characters; + my $current = undef; + my $ignore = [ 'Envelope', 'Body' ]; # top level elements to ignore + my $list = []; # node list + my $path = []; # current path (without + # number) + my $skip = 0; # skip elements + + # use "globals" for speed + my ($_prefix, $_localname, $_element, $_method, + $_class, $_parser, %_attrs) = (); + + no strict qw(refs); + + my $start_sub = sub { + ($_parser, $_element, %_attrs) = @_; + ($_prefix, $_localname) = split m{:}xms , $_element; + + # $parser->setHandlers( Start => \&_start ); + + $_localname ||= $_element; # for non-prefixed elements + + # ignore top level elements + if (@{ $ignore } && $_localname eq $ignore->[0]) { + shift @{ $ignore }; + return; + } + + push @{ $path }, $_localname; # step down in path + return if $skip; # skip inside __SKIP__ + + # resolve class of this element + $_class = $self->{ class_resolver }->get_class( $path ) + or die "Cannot resolve class for " + . join('/', @{ $path }) . " via $self->{ class_resolver }"; + + # maybe write as "return $skip = join ... if (...)" ? + # would save a BLOCK... + return $skip = join('/', @{ $path }) if ($_class eq '__SKIP__'); + + push @$list, $current; # step down in tree ()remember current) + + $characters = q{}; # empty characters + + # Check whether we have a primitive - we implement them as classes + # We could replace this with UNIVERSAL->isa() - but it's slow... + # match is a bit faster if the string does not match, but WAY slower + # if $class matches... + + if (index $_class, 'SOAP::WSDL::XSD::Typelib::Builtin', 0 < 0) { + # check wheter there is a CODE reference for $class::new. + # If not, require it - all classes required here MUST + # define new() + # This is the same as $class->can('new'), but it's way faster + *{ "$_class\::new" }{ CODE } + or eval "require $_class" ## no critic qw(ProhibitStringyEval) + or die $@; + } + + $current = $_class->new({ %_attrs }); # set new current object + + # remember top level element + defined $self->{ data } + or ($self->{ data } = $current); + }; + + my $char_sub = sub { + return if $skip; + $characters .= $_[1]; + }; + + my $end_sub = sub { + $_element = $_[1]; + + ($_prefix, $_localname) = split m{:}xms , $_element; + $_localname ||= $_element; # for non-prefixed elements + + pop @{ $path }; # step up in path + + if ($skip) { + return if $skip ne join '/', @{ $path }, $_localname; + $skip = 0; + return; + } + + # This one easily handles ignores for us, too... + return if not ref $$list[-1]; + + # set characters in current if we are a simple type + # we may have characters in complexTypes with simpleContent, + # too - maybe we should rely on the presence of characters ? + # may get a speedup by defining a ident method in anySimpleType + # and looking it up via exists &$class::ident; + if ( $current->isa('SOAP::WSDL::XSD::Typelib::Builtin::anySimpleType') ) { + $current->set_value( $characters ); + } + + # set appropriate attribute in last element + # multiple values must be implemented in base class + $_method = "add_$_localname"; + $$list[-1]->$_method( $current ); + + $current = pop @$list; # step up in object hierarchy... + }; + + $parser->setHandlers( + Start => sub { + $_[0]->setHandlers( Start => $start_sub ); + $start_sub->(@_) }, + Char => $char_sub, + End => $end_sub, + ); + return $parser; +} + +sub parse { + $_[0]->_initialize( XML::Parser::Expat->new() )->parse( $_[1] ); + return $_[0]->{ data }; +} + +sub parsefile { + $_[0]->_initialize( XML::Parser::Expat->new() )->parsefile( $_[1] ); + return $_[0]->{ data }; +} + +sub get_data { + return $_[0]->{ data }; +} + +1; + +=pod + +=head1 NAME + +SOAP::WSDL::Expat::MessageParser - Convert SOAP messages to custom object trees + +=head1 SYNOPSIS + + my $parser = SOAP::WSDL::Expat::MessageParser->new({ + class_resolver => 'My::Resolver' + }); + $parser->parse( $xml ); + my $obj = $parser->get_data(); + +=head1 DESCRIPTION + +Real fast expat based SOAP message parser. + +See L for details. + +=head2 Skipping unwanted items + +Sometimes there's unneccessary information transported in SOAP messages. + +To skip XML nodes (including all child nodes), just edit the type map for +the message and set the type map entry to '__SKIP__'. + +=head1 Bugs and Limitations + +=over + +=item * Ignores all namespaces + +=item * Does not handle mixed content + +=item * The SOAP header is ignored + +=back + +=head1 AUTHOR + +Replace the whitespace by @ for E-Mail Address. + + Martin Kutter Emartin.kutter fen-net.deE + +=head1 COPYING + +This module may be used under the same terms as perl itself. + +=head1 Repository information + + $ID: $ + + $LastChangedDate: 2007-08-31 17:28:29 +0200 (Fr, 31 Aug 2007) $ + $LastChangedRevision: 176 $ + $LastChangedBy: kutterma $ + + $HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL/Expat/SubParser.pm $ + + diff --git a/lib/SOAP/WSDL/Expat/WSDLParser.pm b/lib/SOAP/WSDL/Expat/WSDLParser.pm new file mode 100644 index 0000000..dddd5b6 --- /dev/null +++ b/lib/SOAP/WSDL/Expat/WSDLParser.pm @@ -0,0 +1,175 @@ +package SOAP::WSDL::Expat::WSDLParser; +use strict; +use warnings; +use Carp; +use SOAP::WSDL::TypeLookup; +use XML::Parser::Expat; + +sub new { + my ($class, $args) = @_; + my $self = {}; + bless $self, $class; + return $self; +} + +sub _initialize { + my ($self, $parser) = @_; + + # init object data + $self->{ parser } = $parser; + delete $self->{ data }; + + # setup local variables for keeping temp data + my $characters = undef; + my $current = undef; + my $list = []; # node list + + # TODO skip non-XML Schema namespace tags + $parser->setHandlers( + Start => sub { + my ($parser, $localname, %attrs) = @_; + + $characters = q{}; + + my $action = SOAP::WSDL::TypeLookup->lookup( + $parser->namespace($localname), + $localname + ); + return if not $action; + + if ($action->{ type } eq 'CLASS') { + eval "require $action->{ class }"; + croak $@ if ($@); + + my $obj = $action->{ class }->new({ parent => $current }) + ->init( _fixup_attrs( $parser, %attrs ) ); + + if ($current) { + # inherit namespace, but don't override + $obj->set_targetNamespace( $current->get_targetNamespace() ) + if not $obj->get_targetNamespace(); + + # push on parent's element/type list + my $method = "push_$localname"; + + no strict qw(refs); + $current->$method( $obj ); + + # remember element for stepping back + push @{ $list }, $current; + } + else { + $self->{ data } = $obj; + } + # set new element (step down) + $current = $obj; + } + elsif ($action->{ type } eq 'PARENT') { + $current->init( _fixup_attrs($parser, %attrs) ); + } + elsif ($action->{ type } eq 'METHOD') { + my $method = $action->{ method } || $localname; + + no strict qw(refs); + # call method with + # - default value ($action->{ value } if defined, + # dereferencing lists + # - the values of the elements Attributes hash + # TODO: add namespaces declared to attributes. + # Expat consumes them, so we have to re-add them here. + $current->$method( defined $action->{ value } + ? ref $action->{ value } + ? @{ $action->{ value } } + : ($action->{ value }) + : _fixup_attrs($parser, %attrs) + ); + } + }, + + Char => sub { $characters .= $_[1] }, + + End => sub { + my ($parser, $localname) = @_; + + my $action = SOAP::WSDL::TypeLookup->lookup( + $parser->namespace( $localname ), + $localname + ) || {}; + + return if not ($action->{ type }); + if ( $action->{ type } eq 'CLASS' ) { + $current = pop @{ $list }; + } + elsif ($action->{ type } eq 'CONTENT' ) { + my $method = $action->{ method }; + + # normalize whitespace + $characters =~s{ ^ \s+ (.+) \s+ $ }{$1}xms; + $characters =~s{ \s+ }{ }xmsg; + + no strict qw(refs); + $current->$method( $characters ); + } + } + ); + return $parser; +} + +# make attrs SAX style +sub _fixup_attrs { + my ($parser, %attrs_of) = @_; + + my @attrs_from = map { $_ = + { + Name => $_, + Value => $attrs_of{ $_ }, + LocalName => $_ + } + } keys %attrs_of; + + # add xmlns: attrs. expat eats them. + push @attrs_from, map { + # ignore xmlns=FOO namespaces - must be XML schema + # Other nodes should be ignored somewhere else + ($_ eq '#default') + ? () + : + { + Name => "xmlns:$_", + Value => $parser->expand_ns_prefix( $_ ), + LocalName => $_ + } + } $parser->new_ns_prefixes(); + return @attrs_from; +} + +sub parse { + $_[0]->_initialize( XML::Parser::Expat->new( + Namespaces => 1 + ) )->parse( $_[1] ); + $_[0]->{ parser }->release(); + return $_[0]->{ data }; +} + +sub parsefile { + $_[0]->_initialize( XML::Parser::Expat->new( + Namespaces => 1 + ) )->parsefile( $_[1] ); + $_[0]->{ parser }->release(); + return $_[0]->{ data }; +} + +# aliases to make it more SAX-like +sub parse_file; +*parse_file = \&parsefile; + +sub parse_string; +*parse_string = \&parse; + + +sub get_data { + return $_[0]->{ data }; +} + +1; + diff --git a/lib/SOAP/WSDL/Factory/Serializer.pm b/lib/SOAP/WSDL/Factory/Serializer.pm new file mode 100644 index 0000000..177b9fc --- /dev/null +++ b/lib/SOAP/WSDL/Factory/Serializer.pm @@ -0,0 +1,128 @@ +package SOAP::WSDL::Factory::Serializer; +use strict; +use warnings; + +my %SERIALIZER = ( + '1.1' => 'SOAP::WSDL::Serializer::SOAP11', +); + +# class method +sub register { + my ($class, $ref_type, $package) = @_; + $SERIALIZER{ $ref_type } = $package; +} + +sub get_serializer { + my ($self, $args_of_ref) = @_; + eval "require $SERIALIZER{ $args_of_ref->{ soap_version } }" or die $@; + return $SERIALIZER{ $args_of_ref->{ soap_version } }->new(); +} + +1; + +=pod + +=head1 NAME + +SOAP::WSDL::Factory::Serializer - factory for retrieving serializer objects + +=head1 SYNOPSIS + + # from SOAP::WSDL::Client: + $serializer = SOAP::WSDL::Factory::Serializer->get_serializer({ + soap_version => $soap_version, + }); + + # in serializer class: + package MyWickedSerializer; + use SOAP::WSDL::Factory::Serializer; + + # u don't know the SOAP 1.2 recommendation? poor boy... + SOAP::WSDL::Factory::Serializer->register( '1.2' , __PACKAGE__ ); + +=head1 DESCRIPTION + +SOAP::WSDL::Factory::Serializer serves as factory for retrieving +serializer objects for SOAP::WSDL. + +The actual work is done by specific serializer classes. + +SOAP::WSDL::Serializer tries to load one of the following classes: + + a) the class registered for the scheme via register() + +=head1 METHODS + +=head2 register + + SOAP::WSDL::Serializer->register('1.1', 'MyWickedSerializer'); + +Globally registers a class for use as serializer class. + +=head2 get_serializer + +Returns an object of the serializer class for this endpoint. + +=head1 WRITING YOUR OWN SERIALIZER CLASS + +Serializer classes may register with SOAP::WSDL::Factory::Serializer. + +Serializer objects may also be passed directly to SOAP::WSDL::Client +by using the set_serializer method. Note that serializers objects set +via SOAP::WSDL::Client's set_serializer method are discarded when the +SOAP version is changed via set_soap_version. + +Registering a serializer class with SOAP::WSDL::Factory::Serializer +is done by executing the following code where $version is the +SOAP version the class should be used for, and $class is the class +name. + + SOAP::WSDL::Factory::Serializer->register( $version, $class); + +To auto-register your transport class on loading, execute register() +in your tranport class (see L above). + +Serializer modules must be named equal to the serializer +class they contain. There can only be one serializer class per +serializer module. + +Serializer class must implement the following methods: + +=over + +=item * new + +Constructor. + +=item * serialize + +Serializes data to XML. The following named parameters are passed to +the serialize method in a anonymous hash ref: + + { + method => $operation_name, + header => $header_data, + body => $body_data, + } + +=back + +=head1 LICENSE + +Copyright 2004-2007 Martin Kutter. + +This file is part of SOAP-WSDL. You may distribute/modify it under +the same terms as perl itself + +=head1 AUTHOR + +Martin Kutter Emartin.kutter fen-net.deE + +=head1 REPOSITORY INFORMATION + + $Rev: 176 $ + $LastChangedBy: kutterma $ + $Id: Serializer.pm 176 2007-08-31 15:28:29Z kutterma $ + $HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL/Factory/Serializer.pm $ + +=cut diff --git a/lib/SOAP/WSDL/Factory/Transport.pm b/lib/SOAP/WSDL/Factory/Transport.pm new file mode 100644 index 0000000..934f07d --- /dev/null +++ b/lib/SOAP/WSDL/Factory/Transport.pm @@ -0,0 +1,230 @@ +package SOAP::WSDL::Factory::Transport; +use strict; +use warnings; + +# class data +my %registered_transport_of = (); + +# Local constants +# Could be made readonly, but that's just for the paranoid... +my %SOAP_LITE_TRANSPORT_OF = ( + ftp => 'SOAP::Transport::FTP', + http => 'SOAP::Transport::HTTP', + https => 'SOAP::Transport::HTTPS', + mailto => 'SOAP::Transport::MAILTO', + 'local' => 'SOAP::Transport::LOCAL', + jabber => 'SOAP::Transport::JABBER', + mq => 'SOAP::Transport::MQ', +); + +my %SOAP_WSDL_TRANSPORT_OF = ( + http => 'SOAP::WSDL::Transport::HTTP', + https => 'SOAP::WSDL::Transport::HTTP', +); + +# class methods only +sub register { + my ($class, $scheme, $package) = @_; + $registered_transport_of{ $scheme } = $package; +} + +sub get_transport { + my ($class, $scheme, %attrs) = @_; + + $scheme =~s{ \A ([^\:]+) \: .+ }{$1}smx; + + if (exists $registered_transport_of{ $scheme }) { + eval "require $registered_transport_of{ $scheme }" or die $@; + + # try "foo::Client" class first - SOAP::Tranport always requires + # a package withoug the ::Client appended, and then + # instantiates a ::Client object... + # ... pretty weird ... + # ... must be from some time when the max number of files was a + # sparse resource ... + # ... but we've decided to mimic SOAP::Lite... + + my $protocol_class = $SOAP_LITE_TRANSPORT_OF{ $scheme } . '::Client'; + my $transport; + eval { + $transport = $protocol_class->new( %attrs ); + }; + return $transport if not $@; + return $registered_transport_of{ $scheme }->new( %attrs ); + } + + # try SOAP::Lite's Transport module - just skip if not require'able + SOAP_Lite: { + if (exists $SOAP_LITE_TRANSPORT_OF{ $scheme }) { + eval "require $SOAP_LITE_TRANSPORT_OF{ $scheme }" + or last SOAP_Lite; + my $protocol_class = $SOAP_LITE_TRANSPORT_OF{ $scheme } . '::Client'; + return $protocol_class->new( %attrs ); + } + } + + if (exists $SOAP_WSDL_TRANSPORT_OF{ $scheme }) { + eval "require $SOAP_WSDL_TRANSPORT_OF{ $scheme }" or die $@; + return $SOAP_WSDL_TRANSPORT_OF{ $scheme }->new( %attrs ); + } + + die "no transport class found for scheme <$scheme>"; +} + +1; + +=pod + +=head1 NAME + +SOAP::WSDL::Factory::Transport - factory for retrieving transport objects + +=head1 SYNOPSIS + + # from SOAP::WSDL::Client: + $transport = SOAP::WSDL::Factory::Transport->get_transport( $url, @opt ); + + # in transport class: + package MyWickedTransport; + use SOAP::WSDL::Factory::Transport; + + # u don't know the httpr protocol? poor boy... + SOAP::WSDL::Factory::Transport->register( 'httpr' , __PACKAGE__ ); + SOAP::WSDL::Factory::Transport->register( 'https' , __PACKAGE__ ); + +=head1 DESCRIPTION + +SOAP::WSDL::Transport serves as factory for retrieving +transport objects for SOAP::WSDL. + +The actual work is done by specific transport classes. + +SOAP::WSDL::Transport tries to load one of the following classes: + + a) the class registered for the scheme via register() + b) the SOAP::Lite class matching the scheme + c) the SOAP::WSDL class matching the scheme + +=head1 METHODS + +=head2 register + + SOAP::WSDL::Transport->register('https', 'MyWickedTransport'); + +Globally registers a class for use as transport class. + +=head2 proxy + + $trans->proxy('http://soap-wsdl.sourceforge.net'); + +Sets the proxy (endpoint). + +Returns the transport for this protocol. + +=head2 set_transport + +Sets the current transport object. + +=head2 get_transport + +Gets the current transport object. + +=head1 WRITING YOUR OWN TRANSPORT CLASS + +Transport classes must be registered with SOAP::WSDL::Factory::Transport. + +This is done by executing the following code where $scheme is the +URL scheme the class should be used for, and $module is the class' +module name. + + SOAP::WSDL::Factory::Transport->register( $scheme, $module); + +To auto-register your transport class on loading, execute register() +in your tranport class (see L above). + +Multiple protocols ore multiple classes are registered by multiple calls to +register(). + +You may only use transport classes whose name is either +the module name or the module name with '::Client' appended. + +Transport classes must implement the interface required for +SOAP::Lite transport classes. + +See L for details, +L +for an example. + +Transport modules must implement the following methods: + +=over + +=item * new + +=item * send_receive + +Dispatches a request and returns the content of the response. + +=item * code + +Returns the status code of the last send_receive call (if any). + +=item * message + +Returns the status message of the last send_receive call (if any). + +=item * status + +Returns the status of the last send_receive call (if any). + +=item * is_success + +Returns true after a send_receive was successful, false if it was not. + +=back + +SOAP::Lite requires transport modules to pack client and server +classes in one file, and to follow this naming scheme: + + Module name: + "SOAP::Transport::" . uc($scheme) + + Client class (additional package in module): + "SOAP::Transport::" . uc($scheme) . "::Client" + + Server class (additional package in module): + "SOAP::Transport::" . uc($scheme) . "::Client" + +SOAP::WSDL does not require you to follow these restrictions. + +There is only one restriction in SOAP::WSDL: + +You may only use transport classes whose name is either +the module name or the module name with '::Client' appended. + +SOAP::WSDL will try to instantiate an object of your +transport class with '::Client' appended to allow using transport +classes written for SOAP::Lite. + +This may lead to errors when a different module with the name +of your transport module suffixed with ::Client is also loaded. + +=head1 LICENSE + +Copyright 2004-2007 Martin Kutter. + +This file is part of SOAP-WSDL. You may distribute/modify it under +the same terms as perl itself + +=head1 AUTHOR + +Martin Kutter Emartin.kutter fen-net.deE + +=head1 REPOSITORY INFORMATION + + $Rev: 176 $ + $LastChangedBy: kutterma $ + $Id: Transport.pm 176 2007-08-31 15:28:29Z kutterma $ + $HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL/Factory/Transport.pm $ + +=cut diff --git a/lib/SOAP/WSDL/Manual/Glossary.pod b/lib/SOAP/WSDL/Manual/Glossary.pod index 8cdabb9..5088f9f 100644 --- a/lib/SOAP/WSDL/Manual/Glossary.pod +++ b/lib/SOAP/WSDL/Manual/Glossary.pod @@ -11,9 +11,12 @@ some internet protocol, typically via HTTP(S). =head2 SOAP -SOAP (the Simple Object Access Protocol) is a specification for -defining RPC interfaces, including (but not neccessarily limited to) -web services. +SOAP is an acronym for Simple Object Access Protocol. +SOAP is a W3C recommendation. The latest version of the SOAP +specification may be found at L. + +SOAP defines a protocoll for message exchange between applications. +The most popular usage is to use SOAP for remote procedure calls (RPC). While one of the constituting aspects of a web service is its reachability via some internet protocol, you might as well define @@ -26,15 +29,52 @@ carry your pet. =head2 WSDL -WSDL (Web Service Definition Language) is a XML-based markup language -for defining web service interfaces. +WSDL is an acronym for Web Services Description Language. +WSDL is a W3C recommendation. The latest version of the WSDL specification +may be found at L. + +WSDL defines a XML-based language for describing web service interfaces, +including SOAP interfaces. =head2 WS-I -WS-I (Web Service Interoperability) is a industry consortium dedicated -to finding interoperability rules for web services. +WS-I (Web Services Interoperability Organization) is an open industry +organisation chartered to promote Web service interoperability across +platforms, operating systems, and programming languages. -SOAP::WSDL aims to be a WS-I compliant SOAP client. +WS-I publishes profiles, which provide implementation guidelines for +how related Web services specifications should be used together for +best interoperability. To date, WS-I has finalized the Basic Profile, +Attachments Profile and Simple SOAP Binding Profile. + +SOAP::WSDL aims at complying to the Basic Profile (but does not +implement full support yet). + +=head2 SOAP message styles + +=head3 rpc + +Meant for transporting a RPC message. All contents of the SOAP body are +put into a top-level node named equal to the SOAP operation. + +WS-I Basic Profile allows the use of rpc message style. + +SOAP::WSDL does not support rpc message style yet. + +SOAP::Lite supports rpc message style only. + +=head3 document + +Meant for transporting arbitrary content. No additional nodes are inserted +between the SOAP body and the actual content. + +WS-I Basic Profile allows the use of document message style. + +=head2 SOAP encoding styles + +=head3 encoded + +=head3 literal =head1 LICENSE diff --git a/lib/SOAP/WSDL/Manual/WS_I_BasicProfile_Compliance.pod b/lib/SOAP/WSDL/Manual/WS_I_BasicProfile_Compliance.pod new file mode 100644 index 0000000..426aa9f --- /dev/null +++ b/lib/SOAP/WSDL/Manual/WS_I_BasicProfile_Compliance.pod @@ -0,0 +1,1248 @@ +=pod + +=head1 NAME + +SOAP::WSDL WS-I Basic Profile Compliance - How SOAP::WSDL complies to WS-I Basic Profile 1.0 + +=head1 DESCRIPTION + +This document gives an overview about how SOAP::WSDL confirms to the rules of +the WS-I Basic Profile 1.0 found at +L + +Errata are not yet worked in. + +You may find rules mis-categorized, especially in the "not applicable" section. + +Such mis-categorizations are documentation bugs, please feel free to report +them. + +Rules are categorized into the following sections: + +=over + +=item * RULES CONFIRMED + +This section contains rules SOAP::WSDL follows. Conformance to these rules may +be assured by a test. + +=item * RULES NOT CONFIRMED + +This section contains rules SOAP::WSDL does not follow yet. These may be +considered as bugs. + +=item * RULES NOT APPLICABLE + +WS-I Basic Profile contains rules for web services as a whole. SOAP::WSDL only +plays the part of one layer in a Web Service CONSUMER, thus does not implement +some parts the WS-I Basic Profile references. + +This section contains rules not applicable for SOAP::WSDL, because they refer +parts to web service SOAP::WSDL does not implement. + +=back + +=head1 RULES CONFIRMED + + + +=head2 R1005 + + A MESSAGE MUST NOT contain soap:encodingStyle attributes on any of the elements + whose namespace name is "http://schemas.xmlsoap.org/soap/envelope/". + +SOAP::WSDL::Serializer::SOAP11 does not add soap:encodingStyle attributes on any +element. + +=head2 R1006 + + A MESSAGE MUST NOT contain soap:encodingStyle attributes on any element that is + a child of soap:Body. + +SOAP::WSDL::Serializer::SOAP11 does not add soap:encodingStyle attributes on any +element. + +=head2 R1008 + + A MESSAGE MUST NOT contain a Document Type Declaration. + +SOAP::WSDL::Serializer::SOAP11 does not DTDs. + +=head2 R1009 + + A MESSAGE MUST NOT contain Processing Instructions. + +SOAP::WSDL::Serializer::SOAP11 does not Processing Instructions + +=head2 R1010 + + A RECEIVER MUST accept messages that contain an XML Declaration. + +SOAP::WSDL::Expat::MessageParser allows the use of XML Declarations. + +=head2 R1011 + + A MESSAGE MUST NOT have any element children of soap:Envelope following + the soap:Body element. + +SOAP::WSDL::Serializer::SOAP11 does emit children of soap:Envelope following +the soap:Body element. Other serializers may behave differentls. + +=head2 R1012 + + A MESSAGE MUST be serialized as either UTF-8 or UTF-16. + +SOAP::WSDL::Serializer::SOAP11 serializes messages as UTF-8. + +=head2 R1018 + + The media type of a MESSAGE's envelope MUST indicate the correct character + encoding, using the charset parameter. + +SOAP::WSDL::Transport::HTTP sets the Content-type header to +"text/xml; charset=utf8". SOAP::Transport::Lite does, too. Other transport +backends may behave different. + +=head2 R1014 + + The children of the soap:Body element in a MESSAGE MUST be namespace + qualified. + +SOAP::WSDL::Serializer::SOAP11 emits namespace-qualified child elements +of the soap:Body element. + +=head2 R1017 + + A RECEIVER MUST NOT mandate the use of the xsi:type attribute in messages + except as required in order to indicate a derived type (see XML Schema + Part 1: Structures, Section 2.6.1). + +SOAP::WSDL::Expat::MessageParser does not require the use of xsi:type +attributes, but uses typemaps instead. + +Other deserializers may not comply to this rule. + +=head2 R1028 + + When a Fault is generated by a RECEIVER, further processing SHOULD NOT be + performed on the SOAP message aside from that which is necessary to rollback, + or compensate for, any effects of processing the message prior to the + generation of the Fault. + +A fault is generated when an error occurs processing the message. +SOAP::WSDL::Deserializer::SOAP11 does not perform any additional processing +after an error occured. + +=head2 R1029 + + Where the normal outcome of processing a SOAP message would have resulted + in the transmission of a SOAP response, but rather a SOAP Fault is generated + instead, a RECEIVER MUST transmit a SOAP Fault message in place of the + response. + +A fault is generated when an error occurs processing the message. + +=head2 R1030 + + A RECEIVER that generates a SOAP Fault SHOULD notify the end user that a + SOAP Fault has been generated when practical, by whatever means is deemed + appropriate to the circumstance. + +Via return value. + +=head2 R1140 + + A MESSAGE SHOULD be sent using HTTP/1.1. + +SOAP::WSDL::Transport::HTTP uses HTTP/1.1 + +=head2 R1141 + + A MESSAGE MUST be sent using either HTTP/1.1 or HTTP/1.0. + +SOAP::WSDL::Transport::HTTP uses HTTP/1.1 + +=head2 R1107 + + A RECEIVER MUST interpret SOAP messages containing only a soap:Fault element + as a Fault. + +SOAP::WSDL::Deserializer::SOAP11 does this. + +=head2 R1132 + + A HTTP request MESSAGE MUST use the HTTP POST method. + +Both SOAP::WSDL::Transport::HTTP and SOAP::Transport::HTTP use POST. + +=head2 R1108 + + A MESSAGE MUST NOT use the HTTP Extension Framework (RFC2774). + +SOAP::WSDL::Transport::HTTP does not use the HTTP Extension framework, +however SOAP::Transport::HTTP use M-POST if POST was not successful. + +To be sure you comply to this rule, use SOAP::WSDL::Transport::HTTP as +transport backend. + +=head2 R1109 + + The value of the SOAPAction HTTP header field in a HTTP request + MESSAGE MUST be a quoted string. + +SOAP::WSDL::Client always quotes the SOAPAction header. + +=head2 R1119 + + A RECEIVER MAY respond with a Fault if the value of the SOAPAction + HTTP header field is not quoted. + +SOAP::WSDL does not apply any processing on the SOAPAction header +field. + +=head2 R1131 + + A CONSUMER MAY automatically redirect a request when it encounters a + "307 Temporary Redirect" HTTP status code in a response. + +LWP::UserAgent (used by SOAP::WSDL::Transport::HTTP and +SOAP::Transport::HTTP) accepts up to 7 levels of redirect by default. + +=head2 R2113 + + A MESSAGE containing serialized arrays MUST NOT include the + soapenc:arrayType attribute. + +SOAP::WSDL does not natively support soapenc::arrayType. + +=head2 R2114 + + The target namespace for WSDL definitions and the target namespace for + schema definitions in a DESCRIPTION MAY be the same. + +SOAP::WSDL does not impose any constraints on the target namespace for +WSDL definitions or schema definitions. + +=head2 R2301 + + The order of the elements in the soap:body of a MESSAGE MUST be the same + as that of the wsdl:parts in the wsdl:message that describes it. + +SOAP::WSDL obeys the part order. + +=head2 R2712 + + A document-literal binding MUST be represented on the wire as a + MESSAGE with a soap:Body whose child element is an instance of the + global element declaration referenced by the corresponding wsdl:message + part. + +If defined accordinglyin tehe DESCRIPTION, SOAP::WSDL issues +document-literal binding operation MESSAGES conforming to this rule. + +=head2 R2748 + + A CONSUMER MUST NOT interpret the presence of the wsdl:required attribute + on a soapbind extension element with a value of "false" to mean the extension + element is optional in the messages generated from the WSDL description. + +SOAP::WSDL does not imterpret the wsdl:required attribute at all. + +=head2 R5000 + + An INSTANCE MAY require the use of HTTPS. + +SOAP::WSDL supports https. + +=head2 R5010 + + An INSTANCE MAY require the use of HTTPS with mutual authentication. + +SOAP::WSDL supports all kinds of authentication known to LWP::UserAgent + +=head2 R2742 + + A MESSAGE MAY contain a fault detail entry in a SOAP fault that is not + described by a wsdl:fault element in the corresponding WSDL description. + +SOAP::WSDL does not emit such faults. Such faults can be processed by adding +custom maps to the type maps for SOAP::WSDL::Expat::MessageParser. + +=head2 R2744 + + A HTTP request MESSAGE MUST contain a SOAPAction HTTP header field with a + quoted value equal to the value of the soapAction attribute of + soapbind:operation, if present in the corresponding WSDL description. + +SOAP::WSDL uses the soapAction attribute from soapbind:operation as SOAPAction +header in generated code. + +Alternative WSDL parsers / code generator have to assure they pass the correct +soap_action to SOAP::WSDL::Client. + +The interpreting SOAP::WSDL client does not conform to this rule, but "guesses" +the SOAPAction header from the operation name and the top node's namespace. + +=head2 R2745 + + A HTTP request MESSAGE MUST contain a SOAPAction HTTP header field with a + quoted empty string value, if in the corresponding WSDL description, the + soapAction of soapbind:operation is either not present, or present with an + empty string as its value. + +SOAP::WSDL::Client always assures the SOAPaction header is quoted, thus +automatically inserts the empty string if no SOAPAction header is defined. + + + +=head1 RULES NOT CONFIRMED + + + +=head2 R4001 + + A RECEIVER MUST accept messages that include the Unicode Byte Order Mark + (BOM). + +May automatically work with XML::Parser::Expat, but is not testet yet. + +TODO write test. If not confirmed, add encoding support. + +=head2 R1002 + + A RECEIVER MUST accept fault messages that have any number of elements, + including zero, appearing as children of the detail element. Such children + can be qualified or unqualified. + +Partially confirmed: This only works when the fault detail elements are added to +the deserializer's typemap. + +TODO add processing of arbitrary content of faults to SOAP::WSDL::Expat::MessageParser + +=head2 R1003 + + A RECEIVER MUST accept fault messages that have any number of qualified or + unqualified attributes, including zero, appearing on the detail element. + The namespace of qualified attributes can be anything other than + "http://schemas.xmlsoap.org/soap/envelope/". + +TODO add processing of arbitrary attributes to SOAP::WSDL::SOAP::Typelib::Fault11 + +=head2 R1016 + + A RECEIVER MUST accept fault messages that carry an xml:lang attribute on + the faultstring element. + +TODO add processing of the xml:lang attribute to SOAP::WSDL::SOAP::Typelib::Fault11 + +=head2 R1007 + + A MESSAGE described in an rpc-literal binding MUST NOT contain soap:encodingStyle + attribute on any elements are grandchildren of soap:Body. + +SOAP::WSDL::Serializer::SOAP11 does not add soap:encodingStyle attributes on any +element. + +However, rpc-literal bindings are not supported, yet. + +TODO support rpc-literal bindings. + +=head2 R1015 + + A RECEIVER MUST generate a fault if they encounter a message whose document + element has a local name of "Envelope" but a namespace name that is not + "http://schemas.xmlsoap.org/soap/envelope/". + +SOAP::WSDL::Expat::MessageParser does not check the namespace of the SOAP envelope. + +TODO implement checking namespace of the SOAP envelope and emit fault if not "http://schemas.xmlsoap.org/soap/envelope/". + +=head2 R2008 + + In a DESCRIPTION the value of the location attribute of a wsdl:import element + SHOULD be treated as a hint. + +SOAP::WSDL's schema parser does not handle import elements yet. + +TODO implement support for wsdl:import in SOAP::WSDL::Expat::WSDLParser. + +=head2 R4002 + + A DESCRIPTION MAY include the Unicode Byte Order Mark (BOM). + +TODO Test. + +=head2 R4003 + + A DESCRIPTION MUST use either UTF-8 or UTF-16 encoding. + +TODO Test whether UTF-16 works. + +=head2 R2020 + + The wsdl:documentation element MAY occur as a child of the wsdl:import + element in a DESCRIPTION. + +SOAP::WSDL's schema parser does not handle import elements yet. + +TODO implement support for wsdl:import in SOAP::WSDL::Expat::WSDLParser. + +=head2 R2024 + + The wsdl:documentation element MAY occur as a first child of the + wsdl:definitions element in a DESCRIPTION. + +TODO Test. + +=head2 R2027 + + If during the processing of an element in the WSDL namespace in a + description, a consumer encounters a WSDL extension element amongst + its element children, that has a wsdl:required attribute with a boolean + value of "true" that the consumer does not understand or cannot process, + the CONSUMER MUST fail processing of that element in the WSDL namespace. + +TODO Implement support for wsdl:required + +=head2 R2750 + + A CONSUMER MUST ignore a SOAP response carried in a response from a + one-way operation. + +SOAP::WSDL does not ignore the SOAP response from a one way operation yet. + +TODO Define operation type signature, and ignore result from one way operations. + +=head2 R2747 + + A CONSUMER MUST understand and process all WSDL 1.1 SOAP Binding extension + elements, irrespective of the presence or absence of the wsdl:required + attribute on an extension element; and irrespective of the value of the + wsdl:required attribute, when present. + +SOAP::WSDL does not implement all WSDL 1.1 SOAP Binding extension yet. + +TODO check and implement. + +=head2 R2800 + + A DESCRIPTION MAY use any construct from XML Schema 1.0. + +SOAP::WSDL's WSDL parser doen not allow all contructs from XML Schema 1.0 to +be used. + +TODO become "minimal conformant". + + + +=head1 RULES NOT APPLICABLE + + + +=head2 R0004 + + A MESSAGE MAY contain conformance claims, as specified in the conformance claim schema. + +SOAP::WSDL::Serializer::SOAP11 does not add conformance claims. +Other serializers may act different. + +=head2 R0005 + + A MESSAGE's conformance claims MUST be carried as SOAP header blocks. + +SOAP::WSDL::Serializer::SOAP11 does not add conformance claims. +Other serializers may act different. + +=head2 R0006 + + A MESSAGE MAY contain conformance claims for more than one profile. + +SOAP::WSDL::Serializer::SOAP11 does not add conformance claims. +Other serializers may act different. + + +=head2 R0007 + + A SENDER MUST NOT use the soap:mustUnderstand attribute when sending a SOAP + header block containing a conformance claim. + +SOAP::WSDL::Serializer::SOAP11 does not add conformance claims. +Other serializers may act different. + +=head2 R3020 + + REGDATA of type uddi:tModel claiming conformance with a Profile MUST be + categorized using the ws-i-org:conformsTo:2002_12 taxonomy. + +SOAP::WSDL does not publish web services yet. + +=head2 R3030 + + REGDATA of type uddi:tModel claiming conformance with a Profile MUST use + the ws-i-org:conformsTo:2002_12 categorization value corresponding to + the conformance claim URI for that Profile. + +SOAP::WSDL does not publish web services yet. + +=head2 R3021 + + A REGISTRY MUST support the WS-I Conformance category system by adding + the ws-i-org:conformsTo:2002_12 tModel definition to its registry content. + +SOAP::WSDL does not publish web services yet. + +=head2 R3005 + + REGDATA other than uddi:tModel elements representing conformant Web service + types MUST NOT be categorized using the ws-i-org:conformsTo:2002_12 + taxonomy and a categorization of "http://ws-i.org/profiles/basic/1.0". + +SOAP::WSDL does not publish web services yet. + +=head2 R3004 + + REGDATA of type uddi:tModel MUST be constructed so that the conformance + claim it makes is consistent with the conformance claim made by the + wsdl:binding to which it refers. + +SOAP::WSDL does not publish web services yet. + +=head2 R1000 + + When a MESSAGE contains a soap:Fault element, that element MUST NOT have element + children other than faultcode, faultstring, faultactor and detail. + +SOAP::WSDL does not send fault messages. However, SOAP::WSDL::SOAP::Typelib::Fault11 +complies to this rule. + +=head2 R1001 + + When a MESSAGE contains a soap:Fault element its element children MUST be + unqualified. + +SOAP::WSDL does not send fault messages. However, SOAP::WSDL::SOAP::Typelib::Fault11 +complies to this rule. + +=head2 R1004 + + When a MESSAGE contains a faultcode element the content of that element + SHOULD be one of the fault codes defined in SOAP 1.1 or a namespace qualified + fault code. + +SOAP::WSDL does not send fault messages. However, the fault issued by +SOAP::WSDL::Deserializer comply to this rule. + +=head2 R1031 + + When a MESSAGE contains a faultcode element the content of that element SHOULD + NOT use of the SOAP 1.1 "dot" notation to refine the meaning of the Fault. + +SOAP::WSDL does not send fault messages. However, the fault issued by +SOAP::WSDL::Deserializer comply to this rule. + +=head2 R1013 + + A MESSAGE containing a soap:mustUnderstand attribute MUST only use the lexical + forms "0" and "1". + +SOAP::WSDL does not add soap:mustUnderstand attributes. + +=head2 R1025 + + A RECEIVER MUST handle messages in such a way that it appears that all + checking of mandatory header blocks is performed before any actual + processing. + +SOAP::WSDL does not check mandatory header blocks yet. + +=head2 R1027 + + A RECEIVER MUST generate a "soap:MustUnderstand" fault when a message + contains a mandatory header block (i.e., one that has a soap:mustUnderstand + attribute with the value "1") targeted at the receiver (via soap:actor) + that the receiver does not understand. + +SOAP::WSDL does not check mandatory header blocks yet. + +=head2 R1110 + + An INSTANCE MAY accept connections on TCP port 80 (HTTP) + +SOAP::WSDL does not act as server yet. + +=head2 R1124 + + An INSTANCE MUST use a 2xx HTTP status code for responses that + indicate a successful outcome of a request. + +SOAP::WSDL does not act as server yet. + +=head2 R1111 + + An INSTANCE SHOULD use a "200 OK" HTTP status code for responses + that contain a SOAP message that is not a SOAP fault. + +SOAP::WSDL does not act as server yet. + +=head2 R1112 + + An INSTANCE SHOULD use either a "200 OK" or "202 Accepted" HTTP + status code for a response that does do not contain a SOAP message + but indicates successful HTTP outcome of a request. + +SOAP::WSDL does not act as server yet. + +=head2 R1130 + + An INSTANCE MUST use HTTP status code "307 Temporary Redirect" + when redirecting a request to a different endpoint. + +SOAP::WSDL does not act as server yet. + +=head2 R1125 + + An INSTANCE MUST use a 4xx HTTP status code for responses that indicate + a problem with the format of the request. + +SOAP::WSDL does not act as server yet. + +=head2 R1113 + + An INSTANCE SHOULD use a "400 Bad Request "HTTP status code, if the + request message is a malformed HTTP request, or not well-formed XML. + +SOAP::WSDL does not act as server yet. + +=head2 R1114 + + An INSTANCE SHOULD use a "405 Method not Allowed" HTTP status code if the + request method was not "POST". + +SOAP::WSDL does not act as server yet. + +=head2 R1115 + + An INSTANCE SHOULD use a "415 Unsupported Media Type" HTTP status code if + the Content-Type HTTP request header did not have a value consistent with + the value specified for the corresponding binding of the input message. + +SOAP::WSDL does not act as server yet. + +=head2 R1120 + + An INSTANCE MAY use the HTTP state mechanism ("Cookies"). + +SOAP::WSDL does not act as server yet. + +=head2 R1122 + + An INSTANCE using Cookies SHOULD conform to RFC2965. + +SOAP::WSDL does not act as server yet. + +=head2 R1121 + + An INSTANCE SHOULD NOT require consumer support for Cookies in order to + function correctly + +SOAP::WSDL does not act as server yet. + +=head2 R1123 + + The value of the cookie MUST be considered to be opaque by the CONSUMER. + +SOAP::WSDL does not act as server yet. + +=head2 R2028 + + A DESCRIPTION using the WSDL namespace (prefixed "wsdl" in this Profile) + MUST be valid according to the XML Schema found at + "http://schemas.xmlsoap.org/wsdl/2003-02-11.xsd". + +See 2029. + +=head2 R2029 + + A DESCRIPTION using the WSDL SOAP binding namespace (prefixed "soapbind" + in this Profile) MUST be valid according to the XML Schema found at + "http://schemas.xmlsoap.org/wsdl/soap/2003-02-11.xsd". + +Although the Profile requires WSDL descriptions to be Schema valid, +it does not require consumers to validate WSDL documents. + +It is the responsibility of a WSDL document's author to assure that it +is Schema valid. + +=head2 R2001 + + A DESCRIPTION MUST only use the WSDL "import" statement to import another + WSDL description. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2002 + + To import XML Schema Definitions, a DESCRIPTION MUST use the XML Schema + "import" statement. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2003 + + A DESCRIPTION MUST use the XML Schema "import" statement only within the + xsd:schema element of the types section. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2004 + + A DESCRIPTION MUST NOT use the XML Schema "import" statement to import a + Schema from any document whose root element is not "schema" from the + namespace "http://www.w3.org/2001/XMLSchema". + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2009 + + An XML Schema directly or indirectly imported by a DESCRIPTION MAY include + the Unicode Byte Order Mark (BOM). + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2010 + + An XML Schema directly or indirectly imported by a DESCRIPTION MUST + use either UTF-8 or UTF-16 encoding. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2011 + + An XML Schema directly or indirectly imported by a DESCRIPTION MUST use + version 1.0 of the eXtensible Markup Language W3C Recommendation. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2007 + + A DESCRIPTION MUST specify a non-empty location attribute on the wsdl:import + element. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2022 + + When they appear in a DESCRIPTION, wsdl:import elements MUST precede all + other elements from the WSDL namespace except wsdl:documentation. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2023 + + When they appear in a DESCRIPTION, wsdl:types elements MUST precede all + other elements from the WSDL namespace except wsdl:documentation and + wsdl:import. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R4004 + + A DESCRIPTION MUST use version 1.0 of the eXtensible Markup Language W3C + Recommendation. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2005 + + The targetNamespace attribute on the wsdl:definitions element of a + description that is being imported MUST have same the value as the + namespace attribute on the wsdl:import element in the importing + DESCRIPTION. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2021 + + The wsdl:documentation element MAY occur as a child of the wsdl:part + element in a DESCRIPTION. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2025 + + A DESCRIPTION containing WSDL extensions MUST NOT use them to + contradict other requirements of the Profile. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2026 + + A DESCRIPTION SHOULD NOT include extension elements with a wsdl:required + attribute value of "true" on any WSDL construct (wsdl:binding, + wsdl:portType, wsdl:message, wsdl:types or wsdl:import) that claims + conformance to the Profile. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2101 + + A DESCRIPTION MUST NOT use QName references to elements in namespaces that + have been neither imported, nor defined in the referring WSDL document. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2102 + + A QName reference to a Schema component in a DESCRIPTION MUST use the + namespace defined in the targetNamespace attribute on the xsd:schema + element, or to a namespace defined in the namespace attribute on an + xsd:import element within the xsd:schema element. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2105 + + All xsd:schema elements contained in a wsdl:types element of a + DESCRIPTION MUST have a targetNamespace attribute with a valid and non-null + value, UNLESS the xsd:schema element has xsd:import and/or + xsd:annotation as its only child element(s). + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2110 + + In a DESCRIPTION, array declarations MUST NOT extend or restrict the + soapenc:Array type. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2111 + + In a DESCRIPTION, array declarations MUST NOT use wsdl:arrayType attribute + in the type declaration. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2112 + + In a DESCRIPTION, array declaration wrapper elements SHOULD NOT be named + using the convention ArrayOfXXX. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2201 + + A document-literal binding in a DESCRIPTION MUST, in each of its + soapbind:body element(s), have at most one part listed in the parts + attribute, if the parts attribute is specified. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2210 + + If a document-literal binding in a DESCRIPTION does not specify the parts + attribute on a soapbind:body element, the corresponding abstract + wsdl:message MUST define zero or one wsdl:parts. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2202 + + A wsdl:binding in a DESCRIPTION MAY contain soapbind:body element(s) that + specify that zero parts form the soap:Body. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2203 + + An rpc-literal binding in a DESCRIPTION MUST refer, in its soapbind:body + element(s), only to wsdl:part element(s) that have been defined using the + type attribute. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2211 + + A MESSAGE described with an rpc-literal binding MUST NOT have the xsi:nil + attribute with a value of "1" or "true" on the part accessors. + +=head2 R2207 + + A wsdl:message in a DESCRIPTION MAY contain wsdl:parts that use the + elements attribute provided those wsdl:parts are not referred to by a + soapbind:body in an rpc-literal binding. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2204 + + A document-literal binding in a DESCRIPTION MUST refer, in each of its + soapbind:body element(s), only to wsdl:part element(s) that have been + defined using the element attribute. + +SOAP::WSDL has no means of generating WSDL definitions. + +Note: SOAP::WSDL requires that a DESCRIPTION confirms to these rules. + +=head2 R2208 + + A binding in a DESCRIPTION MAY contain soapbind:header element(s) that + refer to wsdl:parts in the same wsdl:message that are referred to by its + soapbind:body element(s). + +=head2 R2205 + + A wsdl:binding in a DESCRIPTION MUST refer, in each of its soapbind:header, + soapbind:headerfault and soapbind:fault elements, only to wsdl:part + element(s) that have been defined using the element attribute. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2209 + + A wsdl:binding in a DESCRIPTION SHOULD bind every wsdl:part of a + wsdl:message in the wsdl:portType to which it refers to one of + soapbind:body, soapbind:header, soapbind:fault or soapbind:headerfault. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2206 + + A wsdl:message in a DESCRIPTION containing a wsdl:part that uses the + element attribute MUST refer, in that attribute, to a global element + declaration. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2302 + + A DESCRIPTION MAY use the parameterOrder attribute of an + wsdl:operation element to indicate the return value and method + signatures as a hint to code generators. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2303 + + A DESCRIPTION MUST NOT use Solicit-Response and Notification type + operations in a wsdl:portType definition. + +=head2 R2304 + + A wsdl:portType in a DESCRIPTION MUST have operations with distinct + values for their name attributes. + +Note: SOAP::WSDL requires that a DESCRIPTION confirms to these rules. + +=head2 R2305 + + A wsdl:portType in a DESCRIPTION MUST be constructed so that the + parameterOrder attribute, if present, omits at most 1 wsdl:part + from the output message. + +=head2 R2306 + + A wsdl:message in a DESCRIPTION MUST NOT specify both type and + element attributes on the same wsdl:part. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2401 + + A wsdl:binding element in a DESCRIPTION MUST use WSDL SOAP + Binding as defined in WSDL 1.1 Section 3. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2701 + + The wsdl:binding element in a DESCRIPTION MUST be constructed so + that its soapbind:binding child element specifies the transport + attribute. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2702 + + A wsdl:binding element in a DESCRIPTION MUST specify the HTTP + transport protocol with SOAP binding. Specifically, the transport + attribute of its soapbind:binding child MUST have the value + "http://schemas.xmlsoap.org/soap/http". + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2705 + + A wsdl:binding in a DESCRIPTION MUST use either be a rpc-literal + binding or a document-literal binding. + +SOAP::WSDL has no means of generating WSDL definitions. + +Note: SOAP::WSDL does not support rpc-literal bindings yet. + +=head2 R2706 + + A wsdl:binding in a DESCRIPTION MUST use the value of "literal" + for the use attribute in all soapbind:body, soapbind:fault, + soapbind:header and soapbind:headerfault elements. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2707 + + A wsdl:binding in a DESCRIPTION that contains one or more + soapbind:body, soapbind:fault, soapbind:header or soapbind:headerfault + elements that do not specify the use attribute MUST be interpreted as + though the value "literal" had been specified in each case. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2709 + + A wsdl:portType in a DESCRIPTION MAY have zero or more wsdl:bindings + that refer to it, defined in the same or other WSDL documents. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2710 + + The operations in a wsdl:binding in a DESCRIPTION MUST result in wire + signatures that are different from one another. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2711 + + A DESCRIPTION SHOULD NOT have more than one wsdl:port with the same + value for the location attribute of the soapbind:address element. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2714 + +For one-way operations, an INSTANCE MUST NOT return a HTTP response +that contains a SOAP envelope. Specifically, the HTTP response +entity-body must be empty. + +SOAP::WSDL does not act as a server, yet. + +=head2 R2727 + + For one-way operations, a CONSUMER MUST NOT interpret a successful + HTTP response status code (i.e., 2xx) to mean the message is valid + or that the receiver would process it. + +SOAP::WSDL regards a successful HTTP status code for a one-way operation +as an acknowledgement of the RECEIVER having receive (not processed!) +the message. + +SOAP::WSDL makes no assumptions about the processing of SOAP messages, +but higher level clients may do. + +=head2 R2716 + + A document-literal binding in a DESCRIPTION MUST NOT have the + namespace attribute specified on contained soapbind:body, + soapbind:header, soapbind:headerfault and soapbind:fault elements. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2717 + + An rpc-literal binding in a DESCRIPTION MUST have the namespace attribute + specified, the value of which MUST be an absolute URI, on + contained soapbind:body elements. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2726 + + An rpc-literal binding in a DESCRIPTION MUST NOT have the namespace + attribute specified on contained soapbind:header, soapbind:headerfault + and soapbind:fault elements. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2718 + + A wsdl:binding in a DESCRIPTION MUST have the same set of + wsdl:operations as the wsdl:portType to which it refers + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2719 + + A wsdl:binding in a DESCRIPTION MAY contain no soapbind:headerfault + elements if there are no known header faults. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2740 + + A wsdl:binding in a DESCRIPTION SHOULD contain a soapbind:fault describing + each known fault. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2741 + + A wsdl:binding in a DESCRIPTION SHOULD contain a soapbind:headerfault + describing each known header fault. + +SOAP::WSDL has no means of generating WSDL definitions. + +=head2 R2743 + + A MESSAGE MAY contain the details of a header processing related fault in a + SOAP header block that is not described by a wsdl:headerfault element in the + corresponding WSDL description. + +=head2 R2720 + + A wsdl:binding in a DESCRIPTION MUST use the attribute named part with a + schema type of "NMTOKEN" on all contained soapbind:header and + soapbind:headerfault elements. + +=head2 R2749 + + A wsdl:binding in a DESCRIPTION MUST NOT use the attribute named parts on + contained soapbind:header and soapbind:headerfault elements. + +=head2 R2721 + + A wsdl:binding in a DESCRIPTION MUST have the name attribute specified on all + contained soapbind:fault elements. + +=head2 R2754 + + In a DESCRIPTION, the value of the name attribute on a soapbind:fault element + MUST match the value of the name attribute on its parent wsdl:fault element. + +=head2 R2722 + + A wsdl:binding in a DESCRIPTION MAY specify the use attribute on contained + soapbind:fault elements. + +=head2 R2723 + + If in a wsdl:binding in a DESCRIPTION the use attribute on a contained + soapbind:fault element is present, its value MUST be "literal". + +=head2 R2728 + + A wsdl:binding in a DESCRIPTION that omits the use attribute on a contained + soapbind:fault element MUST be interpreted as though use="literal" had been + specified. + +=head2 R2724 + + If an INSTANCE receives a message that is inconsistent with its WSDL + description, it SHOULD generate a soap:Fault with a faultcode of "Client", + unless a "MustUnderstand" or "VersionMismatch" fault is generated. + +=head2 R2725 + + If an INSTANCE receives a message that is inconsistent with its WSDL + description, it MUST check for "VersionMismatch", "MustUnderstand" and + "Client" fault conditions in that order. + +=head2 R2729 + + A MESSAGE described with an rpc-literal binding that is a response message + MUST have a wrapper element whose name is the corresponding wsdl:operation + name suffixed with the string "Response". + +=head2 R2735 + + A MESSAGE described with an rpc-literal binding MUST place the part accessor + elements for parameters and return value in no namespace. + +=head2 R2737 + + A MESSAGE described with an rpc-literal binding MUST namespace qualify the + children of part accessor elements for the parameters and the return value + with the targetNamespace in which their types are defined. + +=head2 R2738 + + A MESSAGE MUST include all soapbind:headers specified on a wsdl:input or + wsdl:output of a wsdl:operation of a wsdl:binding that describes it. + +=head2 R2739 + + A MESSAGE MAY contain SOAP header blocks that are not described in the + wsdl:binding that describes it. + +=head2 R2753 + + A MESSAGE containing SOAP header blocks that are not described in the + appropriate wsdl:binding MAY have the mustUnderstand attribute on such SOAP + header blocks set to '1'. + +=head2 R2751 + + The order of soapbind:header elements in soapbind:binding sections of a + DESCRIPTION MUST be considered independent of the order of SOAP header blocks + in the message. + +=head2 R2752 + + A MESSAGE MAY contain more than one instance of each SOAP header block for + each soapbind:header element in the appropriate child of soapbind:binding in + the corresponding description. + +=head2 R2801 + + A DESCRIPTION MUST use XML Schema 1.0 Recommendation as the basis of user + defined datatypes and structures. + +=head2 R3100 + + REGDATA of type uddi:bindingTemplate representing a conformant INSTANCE MUST + contain the uddi:accessPoint element. + +=head2 R3002 + + REGDATA of type uddi:tModel representing a conformant Web service type MUST + use WSDL as the description language. + +=head2 R3003 + + REGDATA of type uddi:tModel representing a conformant Web service type MUST be + categorized using the uddi:types taxonomy and a categorization of "wsdlSpec". + +=head2 R3010 + + REGDATA of type uddi:tModel representing a conformant Web service type MUST + follow V1.08 of the UDDI Best Practice for Using WSDL in a UDDI Registry. + +=head2 R3011 + + The wsdl:binding that is referenced by REGDATA of type uddi:tModel MUST itself + conform to the Profile. + +=head2 R5001 + + If an INSTANCE requires the use of HTTPS, the location attribute of the + soapbind:address element in its wsdl:port description MUST be a URI whose + scheme is "https"; otherwise it MUST be a URI whose scheme is "http". + +SOAP::WSDL has no means of generating WSDL definitions. + +=head1 LICENSE + +This file contains quotes from +L. To these +quotes, the legal notice from the document source applies. + +Rest of this file: Copyright 2007 Martin Kutter. + +This file is part of SOAP-WSDL. You may distribute/modify it under +the same terms as perl itself + +=head1 AUTHOR + +Martin Kutter Emartin.kutter fen-net.deE + +=cut + diff --git a/lib/SOAP/WSDL/Parser.pod b/lib/SOAP/WSDL/Parser.pod index ec53512..ed81607 100644 --- a/lib/SOAP/WSDL/Parser.pod +++ b/lib/SOAP/WSDL/Parser.pod @@ -6,8 +6,8 @@ SOAP::WSDL::Parser - How SOAP::WSDL parses XML messages =head1 Which XML message does SOAP::WSDL parse ? -Naturally, there are two kinds of XMLdocuments (or messages) SOAP::WSDL -has to parse: +Naturally, there are two kinds of XML documents (or messages) +SOAP::WSDL has to parse: =over @@ -19,13 +19,55 @@ has to parse: =head1 Parser implementations -There are different parser implementations available for SOAP messages - -currently there's only one for WSDL definitions. +There are different parser implementations available for SOAP messages +and WSDL definitions. + +Historically, SOAP::WSDL used SAX for parsing XML. The SAX handlers +were implemented as L handlers, which +also worked with L. + +The use of SAX and L in SOAP::WSDL is +deprecated for the following reasons: + +=over + +=item * Speed + +L is faster than +L - at least when optimized for speed. + +=item * Availability + +L is more popular than +L. + +=item * Stability + +XML::LibXML is based on the libxml2 library. Several versions of +libxml2 are known to have specific bugs. As a workaround, there are +often several versions of libxml2 installed on one system. This may +lead to problems on operating systems which cannot load more than +one version of a shared library simultaneously. + +=item * SOAP::Lite uses XML::Parser + +L uses L if available. +SOAP::WSDL should not require users to install both L +and L. + +=back =head2 WSDL definitions parser =over +=item * SOAP::WSDL::Expat::WSDLParser + +A parser for WSDL definitions based on L. + + my $parser = SOAP::WSDL::Expat::WSDLParser->new(); + my $wsdl = $parser->parse_file( $filename ); + =item * SOAP::WSDL::SAX::WSDLHandler This is a SAX handler for parsing WSDL files into object trees SOAP::WSDL @@ -132,6 +174,19 @@ L and L based parser. This is the fastest +parser for most SOAP messages and the default for SOAP::WSDL::Client. + +=item * SOAP::WSDL::Expat::MessageStreamParser + +A XML::Parser::ExpatNB based parser. Useful for parsing huge HTTP responses, +as you don't need to keep everything in memory. + +See L +for details. + =item * SOAP::WSDL::SAX::MessageHandler This is a SAX handler for parsing WSDL files into object trees SOAP::WSDL @@ -144,18 +199,6 @@ Can be used for parsing both streams (chunks) and documents. See L for details. -=item * SOAP::WSDL::Expat::MessageParser - -A L based parser. This is the fastest -parser for most SOAP messages and the default for SOAP::WSDL::Client. - -=item * SOAP::WSDL::Expat::MessageStreamParser - -A XML::Parser::ExpatNB based parser. Useful for parsing huge HTTP responses, -as you don't need to keep everything in memory. - -See L for details. - =back =head3 Performance diff --git a/lib/SOAP/WSDL/RELEASE_NOTES b/lib/SOAP/WSDL/RELEASE_NOTES new file mode 100644 index 0000000..505e05a --- /dev/null +++ b/lib/SOAP/WSDL/RELEASE_NOTES @@ -0,0 +1,71 @@ +Release notes for SOAP::WSDL 2.00_11 +------- + +I'm happy to present a new pre-release version of SOAP::WSDL. + +The following features were added (the numbers in brackets are the tracker IDs +from https://sourceforge.net/tracker/?group_id=111978&atid=660924): + + * [1767963] Transport plugins via SOAP::WSDL::Factory::Transport. + SOAP::WSDL uses SOAP::Lite's tranport modules as default, with a + lightweight HTTP(S) transport plugin as fallback. + Custom transport modules can be registered via + SOAP::WSDL::Factory::Transport. + + * [ 1772730 ] Serializer plugins via SOAP::WSDL::Factory::Serializer + The default serializer for SOAP1.1 is SOAP::WSDL::Serializer::SOAP11. + Custom serializers classes can be registered via + SOAP::WSDL::Factory::Serializer or set via SOAP::Lite's set_serializer + method. + +The following bugs have been fixed (the numbers in brackets are the tracker IDs +from https://sourceforge.net/tracker/?group_id=111978&atid=660921): + + * [ 1764854 ] Port WSDL parser to expat and remove XML::LibXML dependency + SOAP::WSDL now requires only XML::Parser to be installed. + XML::LibXML is not required any more, though XML::LibXML based modules still + exist. + +The following uncategorized improvements have been made + + * The number of dependencies has been reduced. SOAP::WSDL no longer requires the + following modules to be installed: + - XML::SAX::Base + - XML::SAX::ParserFactory + - Pod::Simple::Text + + * The missing prerequisite Template has been added. + * Documentation has been improved. + +The following changes were made in former pre-relase versions: + +2.00_10 +---- + * Changed Makefile.PL to use Module::Build (passthrough mode) + * fixed element ref="" handling + +2.00_09 +---- + * SOAP::WSDL::XSD::Typelib::Builtin::boolean objects now return their numerical + value in bool context, not "true" or "false" (always true...) + * date/time test are now timezone-sensitive + * examples added + +2.00_08 +--- + * SOAP message parser may skip unwanted parts of the message - see + SOAP::WSDL::Expat::MessageParser for details. + * HTTP Content-Type is configurable now + * SOAP::WSDL::XSD::Typelib::ComplexType based objects now accept a + list ref of hash refs as parameter to set_value. + * SOAP::WSDL::XSD::Typelib::Builtin::dateTime and ::date now converts date + strings into XML date strings + * SOAP::WSDL::Definitions::create now + - converts '.' in service names to '::' (.NET class separator to perl class + separator) + - outputs Typemaps and Interface classes in UTF8 to allow proper inclusion + of UTF8 documentation from WSDL + * WSDLHandler now handles tags + * SOAP::WSDL::Definitions now includes some usable doc in generated interface classes + * fixed explain in SimpleType, ComplexType and Element (someway) + \ No newline at end of file diff --git a/lib/SOAP/WSDL/SAX/MessageHandler.pm b/lib/SOAP/WSDL/SAX/MessageHandler.pm index ccc3711..b9198f7 100644 --- a/lib/SOAP/WSDL/SAX/MessageHandler.pm +++ b/lib/SOAP/WSDL/SAX/MessageHandler.pm @@ -273,9 +273,9 @@ This module may be used under the same terms as perl itself. $ID: $ - $LastChangedDate: $ - $LastChangedRevision: $ - $LastChangedBy: $ + $LastChangedDate: 2007-08-31 17:28:29 +0200 (Fr, 31 Aug 2007) $ + $LastChangedRevision: 176 $ + $LastChangedBy: kutterma $ - $HeadURL: $ + $HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL/SAX/MessageHandler.pm $ diff --git a/lib/SOAP/WSDL/Envelope.pm b/lib/SOAP/WSDL/Serializer/SOAP11.pm similarity index 76% rename from lib/SOAP/WSDL/Envelope.pm rename to lib/SOAP/WSDL/Serializer/SOAP11.pm index bd8460e..bf59369 100644 --- a/lib/SOAP/WSDL/Envelope.pm +++ b/lib/SOAP/WSDL/Serializer/SOAP11.pm @@ -1,13 +1,17 @@ #!/usr/bin/perl -w -package SOAP::WSDL::Envelope; -use strict; -use base qw/SOAP::WSDL::Base/; +package SOAP::WSDL::Serializer::SOAP11; +use strict; +use warnings; +use Class::Std::Storable; +# use base qw/SOAP::WSDL::Base/; my $SOAP_NS = 'http://schemas.xmlsoap.org/soap/envelope/'; my $XML_INSTANCE_NS = 'http://www.w3.org/2001/XMLSchema-instance'; sub serialize { - my ($self, $name, $data, $opt) = @_; + my ($self, $args_of_ref) = @_; + + my $opt = $args_of_ref->{ options }; if (not $opt->{ namespace }->{ $SOAP_NS }) { @@ -32,8 +36,9 @@ sub serialize { # TODO insert encoding $xml.='>'; - $xml .= $self->serialize_header($name, $data, $opt); - $xml .= $self->serialize_body($name, $data, $opt); + $xml .= $self->serialize_header($args_of_ref->{ method }, $args_of_ref->{ header }, $opt); + $xml .= "\n" if ($opt->{ readable }); + $xml .= $self->serialize_body($args_of_ref->{ method }, $args_of_ref->{ body }, $opt); $xml .= "\n" if ($opt->{ readable }); $xml .= ''; $xml .= "\n" if ($opt->{ readable }); diff --git a/lib/SOAP/WSDL/Transport/HTTP.pm b/lib/SOAP/WSDL/Transport/HTTP.pm new file mode 100644 index 0000000..045d154 --- /dev/null +++ b/lib/SOAP/WSDL/Transport/HTTP.pm @@ -0,0 +1,107 @@ +package SOAP::WSDL::Transport::HTTP; +use strict; +use base qw(LWP::UserAgent); + +# create methods normally inherited from SOAP::Client +SUBFACTORY: { + no strict qw(refs); + foreach my $method ( qw(code message status is_success) ) { + *{ $method } = sub { + my $self = shift; + return $self->{ $method } if not @_; + return $self->{ $method } = shift; + }; + } +} + +sub send_receive { + my ($self, %parameters) = @_; + my ($envelope, $soap_action, $endpoint, $encoding, $content_type) = + @parameters{qw(envelope action endpoint encoding content_type)}; + + $encoding = defined($encoding) + ? 'utf8' + : lc($encoding); + + # TODO check whether we need this with current LWP::UserAgent - we're + # not here to fix LWP::UserAgent bugs... + # + # what's this all about? + # unfortunately combination of LWP and Perl 5.6.1 and later has bug + # in sending multibyte characters. LWP uses length() to calculate + # content-length header and starting 5.6.1 length() calculates chars + # instead of bytes. 'use bytes' in THIS file doesn't work, because + # it's lexically scoped. Unfortunately, content-length we calculate + # here doesn't work either, because LWP overwrites it with + # content-length it calculates (which is wrong) AND uses length() + # during syswrite/sysread, so we are in a bad shape anyway. + # + # what to do? we calculate proper content-length (using + # bytelength() function from SOAP::Utils) and then drop utf8 mark + # from string (doing pack with 'C0A*' modifier) if length and + # bytelength are not the same + + # use bytes is lexically scoped + my $bytelength = do { use bytes; length $envelope }; + $envelope = pack('C0A*', $envelope) + if length($envelope) != $bytelength; + + # END TODO + + my $request = HTTP::Request->new( 'POST', + $endpoint, + [ 'Content-Type', "$content_type; charset=$encoding", + 'Content-Length', $bytelength, + 'SOAPAction', $soap_action, + ], + $envelope ); + + use Data::Dumper; + warn Dumper $request; + + my $response = $self->request( $request ); + + warn Dumper $response; + + + $self->code( $response->code); + $self->message( $response->message); + $self->is_success($response->is_success); + $self->status($response->status_line); + + return $response->content(); +} + +1; + +=pod + +=head1 NAME + +SOAP::WSDL::Transport::HTTP - Fallback http(s) transport class + +=head1 DESCRIPTION + +Provides a thin transport class used by SOAP::WSDL::Transport when +SOAP::Lite is not available. + +=head1 LICENSE + +Copyright 2004-2007 Martin Kutter. + +This file is part of SOAP-WSDL. You may distribute/modify it under +the same terms as perl itself + +=head1 AUTHOR + +Martin Kutter Emartin.kutter fen-net.deE + +=head1 REPOSITORY INFORMATION + + $Rev: 176 $ + $LastChangedBy: kutterma $ + $Id: HTTP.pm 176 2007-08-31 15:28:29Z kutterma $ + $HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL/Transport/HTTP.pm $ + +=cut + diff --git a/lib/SOAP/WSDL/XSD/ComplexType.pm b/lib/SOAP/WSDL/XSD/ComplexType.pm index 33fcb25..eadb046 100644 --- a/lib/SOAP/WSDL/XSD/ComplexType.pm +++ b/lib/SOAP/WSDL/XSD/ComplexType.pm @@ -269,7 +269,7 @@ methods: [% element.get_name -%] [% END %] -=head1 Object structure +[% head1 %] Object structure [% FOREACH element=self.get_element; IF (element.get_type); diff --git a/lib/SOAP/WSDL/XSD/Typelib/Builtin/boolean.pm b/lib/SOAP/WSDL/XSD/Typelib/Builtin/boolean.pm index 86511f7..3bc2c8d 100644 --- a/lib/SOAP/WSDL/XSD/Typelib/Builtin/boolean.pm +++ b/lib/SOAP/WSDL/XSD/Typelib/Builtin/boolean.pm @@ -1,6 +1,7 @@ package SOAP::WSDL::XSD::Typelib::Builtin::boolean; use strict; use warnings; +use Class::Std::Storable; my %pattern_of :ATTR(:name :default<()>); my %whiteSpace_of :ATTR(:name :default<()>); @@ -9,7 +10,7 @@ my %value_of :ATTR(:get :init_attr :default<()>); # Speed up. Class::Std::new is slow - and we don't need it's functionality... BEGIN { - use Class::Std::Storable; +# use Class::Std::Storable; use base qw(SOAP::WSDL::XSD::Typelib::Builtin::anySimpleType); no warnings qw(redefine); diff --git a/lib/SOAP/WSDL/XSD/Typelib/Builtin/date.pm b/lib/SOAP/WSDL/XSD/Typelib/Builtin/date.pm index b4edc3e..588caf7 100644 --- a/lib/SOAP/WSDL/XSD/Typelib/Builtin/date.pm +++ b/lib/SOAP/WSDL/XSD/Typelib/Builtin/date.pm @@ -53,7 +53,9 @@ sub set_value { # We leave out the optional nanoseconds part, as it would always be empty. else { # strptime sets empty values to undef - and strftime doesn't like that... - my @time_from = map { ! defined $_ ? 0 : $_ } strptime($_[1]); + my @time_from = map { ! defined $_ ? 0 : $_ } strptime($_[1]); +# use Data::Dumper; +# die Dumper \@time_from; my $time_str = strftime( '%Y-%m-%d%z', @time_from ); substr $time_str, -2, 0, ':'; $_[0]->SUPER::set_value($time_str); diff --git a/lib/SOAP/WSDL/XSD/Typelib/ComplexType.pm b/lib/SOAP/WSDL/XSD/Typelib/ComplexType.pm index 18b9d63..bb208a3 100644 --- a/lib/SOAP/WSDL/XSD/Typelib/ComplexType.pm +++ b/lib/SOAP/WSDL/XSD/Typelib/ComplexType.pm @@ -14,6 +14,32 @@ my %ELEMENTS_FROM; my %ATTRIBUTES_OF; my %CLASSES_OF; +# STORABLE_ methods for supporting Class::Std::Storable. +# We could also handle them via AUTOMETHOD, +# but AUTOMETHOD should always croak... +sub STORABLE_freeze_pre { +} + +sub STORABLE_freeze_post { +} + +sub STORABLE_thaw_pre { +} + +sub STORABLE_thaw_post { +} + +# for error reporting. Eases working with data objects... +sub AUTOMETHOD { + my ($self, $ident, @args_from) = @_; + + my $class = ref $self || $self; + confess "Can't locate object method \"$_\" via package \"$class\". \n" + . "Valid methods are: " + . join(', ', map { ("get_$_" , "set_$_") } keys %{ $ATTRIBUTES_OF{ $class } }) + . "\n" +} + # we store per-class elements. # call as __PACKAGE__->_factory sub _factory { diff --git a/t/001_use.t b/t/001_use.t index b5a8e97..a970680 100644 --- a/t/001_use.t +++ b/t/001_use.t @@ -15,7 +15,6 @@ my @modules = qw( SOAP::WSDL::Port SOAP::WSDL::PortType SOAP::WSDL::Types - SOAP::WSDL::SAX::WSDLHandler SOAP::WSDL::XSD::Builtin SOAP::WSDL::XSD::ComplexType SOAP::WSDL::XSD::SimpleType diff --git a/t/002_parse_wsdl.t b/t/002_parse_wsdl.t new file mode 100644 index 0000000..c3928c5 --- /dev/null +++ b/t/002_parse_wsdl.t @@ -0,0 +1,333 @@ +#!/usr/bin/perl -w +use strict; +use warnings; +use Test::More tests => 18; # qw/no_plan/; # TODO: change to tests => N; +use lib '../lib'; + +use XML::LibXML; + +eval { + require Test::XML; + import Test::XML; +}; + +use_ok(qw/SOAP::WSDL::SAX::WSDLHandler/); + +my $filter; + +ok($filter = SOAP::WSDL::SAX::WSDLHandler->new( +), "Object creation"); + +my $parser = XML::LibXML->new(); +$parser->set_handler( $filter ); + +$parser->parse_string( xml() ); + +my $wsdl; +ok( $wsdl = $filter->get_data() , "get object tree"); + +my $types = $wsdl->first_types(); + +is $types->get_parent(), $wsdl , 'types parent'; + +my $serializer_options = { + readable => 1, + autotype => 1, + namespace => { 'urn:myNamespace' => 'tns', + "http://www.w3.org/2001/XMLSchema" => 'xsd' }, + typelib => $wsdl->first_types(), + indent => "\t", +}; + +my $xml; +my $type = $types->find_type( 'urn:myNamespace', 'testSimpleType1' ); + + +ok($xml = $type->serialize( 'test', 1 , $serializer_options ), + "serialize simple Type" +); + +# print $xml; + +SKIP: { + skip_without_test_xml(); + is_xml( $xml, '1', + "content compare" ); +}; + +$type = $types->find_type( 'urn:myNamespace', 'testSimpleList' ); +ok($xml = $type->serialize( 'testList', [ 1, 2, 3 ] , $serializer_options ), + "serialize simple list type" +); +SKIP: { + skip_without_test_xml(); + is_xml( $xml, '1 2 3', + "content compare" ); +}; + +$type = $types->find_element( 'urn:myNamespace', 'TestElement' ); + +ok($xml = $type->serialize( undef, 1 , $serializer_options ), + "serialize simple element"); +SKIP: { + skip_without_test_xml(); + is_xml( $xml, '1', + "content compare" ); +}; + +ok( $xml = $types->find_type( 'urn:myNamespace', 'length3')->serialize( + 'TestComplex', { size => -13, unit => 'BLA' } , + $serializer_options + ), + "serialize complex type"); + +SKIP: { + skip_without_test_xml(); + is_xml( $xml, q{ + + -13 + BLA + }, + "content compare" ); +}; + +ok($xml = $types->find_element( 'urn:myNamespace', 'TestElementComplexType') + ->serialize( + undef, { size => -13, unit => 'BLA' } , $serializer_options ), + "serialize element with complex type" +); +SKIP: { + skip_without_test_xml(); + is_xml( $xml, q{ + + -13 + BLA + + }, + "content compare" ); +}; + + +ok($xml = $types->find_type( 'urn:myNamespace', 'complex')->serialize( + 'complexComplex', + { 'length' => { size => -13, unit => 'BLA' }, 'int' => 1 }, + $serializer_options ), + "serialize complex type with complex content" +); +SKIP: { + skip_without_test_xml(); + is_xml( $xml, q{ + + + -13 + BLA + + 1 + + }, + "content compare" ); +} +ok($xml = $wsdl->find_message('urn:myNamespace', 'testRequest') + ->get_part()->[0]->serialize( + undef, + { test => { length => { size => -13, unit => 'BLA' } , int => 3 } }, + $serializer_options ), + "serialize part" +); +SKIP: { + skip_without_test_xml(); + is_xml( $xml, q{ + + + -13 + BLA + + 3 + + }, + "content compare") +}; + +my $opt = { + typelib => $types, + readable => 1, + autotype => 0, + namespace => { 'urn:myNamespace' => 'tns', + 'http://www.w3.org/2001/XMLSchema' => 'xsd', + 'http://schemas.xmlsoap.org/wsdl/' => 'wsdl', + }, + indent => "", + wsdl => $wsdl, +}; + +# ok $wsdl->explain($opt) =~ m/#optional/m; + +sub skip_without_test_xml { + skip("Test::XML not available", 1) if (not $Test::XML::VERSION); +} + +sub xml +{ + return q{ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SimpleType Test + + + + + + + + + SimpleType Union test + + + + + + + + + + + + + + + + + + + + + + + Test-Methode + + + + + + + + Test-Methode + + + + + + + + + + Test-Methode + + + + + + + + + + Test-Methode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +}; + +} + diff --git a/t/002_sax.t b/t/002_sax.t index a0fbb9f..6c687ea 100644 --- a/t/002_sax.t +++ b/t/002_sax.t @@ -1,9 +1,15 @@ #!/usr/bin/perl -w use strict; use warnings; -use Test::More tests => 18; # qw/no_plan/; # TODO: change to tests => N; +use Test::More; use lib '../lib'; -use XML::SAX::ParserFactory; + +if (eval "require XML::LibXML") { + plan tests => 18; +} +else { + plan skip_all => "Cannot test without XML::LibXML"; +} eval { require Test::XML; @@ -15,12 +21,10 @@ use_ok(qw/SOAP::WSDL::SAX::WSDLHandler/); my $filter; ok($filter = SOAP::WSDL::SAX::WSDLHandler->new( - { base => 'XML::SAX::Base' } ), "Object creation"); -my $parser = XML::SAX::ParserFactory->parser( - Handler => $filter -); +my $parser = XML::LibXML->new(); +$parser->set_handler( $filter ); $parser->parse_string( xml() ); diff --git a/t/003_sax_serializer.t b/t/003_sax_serializer.t index 356091d..54186e2 100644 --- a/t/003_sax_serializer.t +++ b/t/003_sax_serializer.t @@ -1,7 +1,13 @@ -use Test::More tests => 11; -use Data::Dumper; +use Test::More; use lib '../lib'; -use XML::LibXML; + +if (eval "require XML::LibXML") { + plan tests => 11; +} +else { + plan skip_all => "Cannot test without XML::LibXML"; +} + use_ok(qw/SOAP::WSDL::SAX::WSDLHandler/); diff --git a/t/003_wsdl_based_serializer.t b/t/003_wsdl_based_serializer.t new file mode 100644 index 0000000..2550bc6 --- /dev/null +++ b/t/003_wsdl_based_serializer.t @@ -0,0 +1,256 @@ +use Test::More tests => 11; +use Data::Dumper; +use lib '../lib'; +use XML::LibXML; + +use_ok(qw/SOAP::WSDL::SAX::WSDLHandler/); + +my $filter; + +ok($filter = SOAP::WSDL::SAX::WSDLHandler->new(), "Object creation"); + +my $parser = XML::LibXML->new(); +$parser->set_handler( $filter ); + +eval { $parser->parse_string( xml() ) }; +if ($@) +{ + fail("parsing WSDL"); + die "Can't test without parsed WSDL"; +} +else +{ + pass("parsing XML"); +} + +my $wsdl; +ok( $wsdl = $filter->get_data() , "get object tree"); + + +my $schema = $wsdl->first_types(); + +my $opt = { + readable => 0, + autotype => 1, + namespace => $wsdl->get_xmlns(), + indent => "\t", + typelib => $schema, +}; + +is( $schema->find_type( 'myNamespace', 'testSimpleType1' )->serialize( + 'test', 1 , $opt ), + q{1} , "serialize simple type"); + +is( $schema->find_type( 'myNamespace', 'testSimpleList' )->serialize( + 'testList', [ 1, 2, 3 ] , $opt), + q{1 2 3}, + "serialize simple list type" +); + +is( $schema->find_element( 'myNamespace', 'TestElement' )->serialize( + undef, 1 , $opt), + q{1}, "Serialize element" +); + +$opt->{ readable } = 0; + +is( $schema->find_type( 'myNamespace', 'length3')->serialize( + 'TestComplex', { size => -13, unit => 'BLA' } , + $opt ), + q{} + . q{-13} + . q{BLA} + , "serialize complex type" ); + +is( $schema->find_element( 'myNamespace', 'TestElementComplexType')->serialize( + undef, { size => -13, unit => 'BLA' } , + $opt ), + q{} + . q{-13} + . q{BLA}, + "element with complex type" +); + +is( $schema->find_type( 'myNamespace', 'complex')->serialize( + 'complexComplex', + { 'length' => { size => -13, unit => 'BLA' }, 'int' => 1 }, + $opt ), + q{} + . q{} + . q{-13} + . q{BLA} + . q{1}, + "nested complex type" +); + +is( $wsdl->find_message('myNamespace', 'testRequest')->first_part()->serialize( + undef, { test => { length => { size => -13, unit => 'BLA' } , int => 3 } }, + $opt ), + q{} + . q{} + . q{-13} + . q{BLA} + . q{3} + , "Message part" +); + + +exit; + +sub xml +{ + return q{ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SimpleType Test + + + + + + + + + SimpleType Union test + + + + + + + + + + + + + + + + + + + + + + + Test-Methode + + + + + + + + Test-Methode + + + + + + + + + + Test-Methode + + + + + + + + + + Test-Methode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +}; + +} + diff --git a/t/004_parse_wsdl.t b/t/004_parse_wsdl.t new file mode 100644 index 0000000..b01c0ab --- /dev/null +++ b/t/004_parse_wsdl.t @@ -0,0 +1,403 @@ +#!/usr/bin/perl -w +use strict; +use warnings; +use Test::More tests => 5; +use lib '../lib'; + +use XML::LibXML; + +eval { + require Test::XML; + import Test::XML; +}; + +use_ok(qw/SOAP::WSDL::SAX::WSDLHandler/); + +my $filter; + +ok($filter = SOAP::WSDL::SAX::WSDLHandler->new(), "Object creation"); + +my $parser = XML::LibXML->new(); +$parser->set_handler( $filter ); + +eval { $parser->parse_string( xml() ) }; +if ($@) +{ + fail("parsing WSDL"); + die "Can't test without parsed WSDL: $@"; +} +else +{ + pass("parsing XML"); +} + +my $wsdl; +ok( $wsdl = $filter->get_data() , "get object tree"); + +my $schema = $wsdl->get_types()->[0]->get_schema()->[0] || die "No schema !"; + +my $opt = { + typelib => $wsdl->first_types, + readable => 1, + autotype => 0, + namespace => { 'http://www.example.org/MessageGateway2/' => 'tns', + 'http://www.w3.org/2001/XMLSchema' => 'xsd', + 'http://schemas.xmlsoap.org/wsdl/' => 'wsdl', + }, + indent => "", +}; + +my $data = { EnqueueMessage => { + MMessage => { + MRecipientURI => 'anyURI', + MSenderAddress => 'a string', + MMessageContent => 'a string', + MSubject => 'a string', + MDeliveryReportRecipientURI => 'anyURI', + MKeepalive => { + MKeepaliveTimeout => 1234567, + MKeepaliveErrorPolicy => ' ( suppress | report ) ', + } + } +} + +}; + + +SKIP: { skip_without_test_xml(); + is_xml( $wsdl->find_message( + "http://www.example.org/MessageGateway2/" ,'EnqueueMessageRequest' + )->first_part()->serialize( 'test', $data, $opt ), + xml_message() + , "Serialized message part" + ); +} + +sub skip_without_test_xml { + skip("Test::XML not available", 1) if (not $Test::XML::VERSION); +} + +sub xml_message { + return +q{ + + anyURI + a string + a string + a string + anyURI + + 1234567 + ( suppress | report ) + + + +}; + +} + +sub xml { + return q{ + + + + + + + Enqueue message request element + + + + + + + A type containing all elements of a message to enqueue. + + + + + + + + The recipient in URI notaitions. Valid URI schemas are: mailto:, sms:, + phone:. Not all URI schemas need to be implemented at the current + implementation stage. + + + + + + + E-Mail sender address. Ignored for all but mailto: recipient URIs. + + + + + + + Message Content. + + + + + + + Message Subject. Ignored for all but mailto: URIs + + + + + + + + URI to send a delivery report to. May be of one of the following schemes: + mailto:, http:, https:. Reports to mailto: URIs are sent as plaintext, + reports to http(s) URIs are sent as SOAP requests following the + MessageGatewayClient service definition. + + + + + + + Container for keepalive information. May be missing. + + + + + + + + + + Type containing keeplive information. + + + + + + + Keepalive timeout. The keepalive timeout spezifies how long the sending of + a message will be delayed waiting for keepalive updates. If a keepalive + update is received during this period, the timeout will be reset. If not, + the message will be sent after the timeout has expired. + + + + + + + + Policy to comply to in case of system errors. Valid values are "suppress" + and "report". If the policy is set to "suppress", keepalive messages will + not be sent to their recipients in case of partial system failure, even if + the keepalive has expired. This may result in "false negatives", i.e. + messages may not be sent, even though their keepalive has expired. If the + value is "report", keepalive messages will be sent from any cluster node. + This may result in "false positive" alerts. + + + + + + + + + + + + + + + Type containing a message ID. + + + + + + + + + + + Type containing all elements of a keppalive update / remove request. + + + + + + + The ID for the message to update / remove + + + + + + + + The action to perform. Valid values are: "remove", "update". On "remove", + the message with the ID specified will be removed from the queue, thus it + will never be sent, even if it's timeout expires. On "update" the + keepalive timeout of the corresponding message will be reset. + + + + + + + + + + + + + + Keepalive message request element + + + + + Response element for a keepalive request + + + + + Enqueue message response element + + + + + + + + A complex type containing one element: The message to enqueue. + + + + + + + Element containing a message to enqueue. + + + + + + + + + + + + A complex type containing one element: The keepalive message to process. + + + + + + + + Element containing a keepalive message to process. + + + + + + + + + + + inputparameters for EnqueueMessag + + + + + + outputparameters for EnqueueMessag + + + + + + input parameters for KeepaliveMessag + + + + + output parameters for KeepaliveMessag + + + + + + generic port type for all methods required for sending messages over the mosaic + message gatewa + + + + This method is used to enqueue a normal (immediate send) or a delayed message with + keepalive functionality. + + + + + + + + This method is used to update or remove a + keepalive message. + + + + + + + + Generic binding for all (SOAP) port + + + + + + + + + + + + + + + + + + + + + + + + Web Service for sending messages over the mosaic message gatewa + + + + HTTP(S) port for the mosaic message gatewa + + + +}; +} diff --git a/t/004_sax_wsdl.t b/t/004_sax_wsdl.t index 2b279a4..f283e05 100644 --- a/t/004_sax_wsdl.t +++ b/t/004_sax_wsdl.t @@ -1,11 +1,15 @@ #!/usr/bin/perl -w use strict; use warnings; -use Test::More tests => 5; +use Test::More; use lib '../lib'; -use XML::SAX::ParserFactory; -use diagnostics; +if (eval "require XML::LibXML") { + plan tests => 5; +} +else { + plan skip_all => "Cannot test without XML::LibXML"; +} eval { require Test::XML; @@ -18,7 +22,6 @@ my $filter; ok($filter = SOAP::WSDL::SAX::WSDLHandler->new(), "Object creation"); -use XML::LibXML; my $parser = XML::LibXML->new(); $parser->set_handler( $filter ); diff --git a/t/005_parse_contributed.t b/t/005_parse_contributed.t new file mode 100644 index 0000000..f341128 --- /dev/null +++ b/t/005_parse_contributed.t @@ -0,0 +1,255 @@ +#!/usr/bin/perl -w +use strict; +use warnings; +use Test::More qw/no_plan/; # TODO: change to tests => N; +use Data::Dumper; +use lib '../lib'; +use XML::LibXML; + +use diagnostics; + +use_ok(qw/SOAP::WSDL::SAX::WSDLHandler/); + +my $filter; + +ok($filter = SOAP::WSDL::SAX::WSDLHandler->new(), "Object creation"); + +my $parser = XML::LibXML->new(); +$parser->set_handler( $filter ); + +eval { $parser->parse_string( xml() ) }; +if ($@) +{ + fail("parsing WSDL"); + die "Can't test without parsed WSDL: $@"; +} +else +{ + pass("parsing XML"); +} + +my $wsdl; +ok( $wsdl = $filter->get_data() , "get object tree"); + +my $opt = { + namespace => $wsdl->get_xmlns(), + style => 'perl', + wsdl => $wsdl, + readable => 1, +}; + +my $txt; +ok( $txt = $wsdl->explain( $opt ) , "explain WSDL" ); + +# print $txt; + +sub xml { + return q{ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +}; +} diff --git a/t/005_sax_contributed_wsdl.t b/t/005_sax_contributed_wsdl.t index f341128..fd8879e 100644 --- a/t/005_sax_contributed_wsdl.t +++ b/t/005_sax_contributed_wsdl.t @@ -1,10 +1,15 @@ #!/usr/bin/perl -w use strict; use warnings; -use Test::More qw/no_plan/; # TODO: change to tests => N; -use Data::Dumper; +use Test::More; # TODO: change to tests => N; use lib '../lib'; -use XML::LibXML; + +if (eval "require XML::LibXML") { + plan tests => 5; +} +else { + plan skip_all => "Cannot test without XML::LibXML"; +} use diagnostics; diff --git a/t/006_client.t b/t/006_client.t index 489f12d..efeae74 100644 --- a/t/006_client.t +++ b/t/006_client.t @@ -1,10 +1,8 @@ #!/usr/bin/perl -w use strict; use warnings; -use Pod::Simple::Text; use Test::More qw/no_plan/; # TODO: change to tests => N; use lib '../lib'; -use XML::SAX::ParserFactory; eval { require Test::XML; @@ -31,11 +29,17 @@ ok( $soap->no_dispatch( 1 ) , "Set no_dispatch" ); ok( $soap->explain() ); -my $pod = Pod::Simple::Text->new(); -my $output; -$pod->output_string( \$output ); -$pod->parse_string_document( $soap->explain() ); - +SKIP: { + + if (not eval "require Pod::Simple::Text") { + skip "cannot test parsing pod without Pod::Test::Simple", 1; + }; + + my $pod = Pod::Simple::Text->new(); + my $output; + $pod->output_string( \$output ); + ok $pod->parse_string_document( $soap->explain() ), 'parse explain pod'; +} # print $output; SKIP: { @@ -60,6 +64,3 @@ sub skip_without_test_xml { my $number = shift || 1; skip("Test::XML not available", $number) if (not $Test::XML::VERSION); } - -__END__ - diff --git a/t/009_data_classes.t b/t/009_data_classes.t index af7bb70..1f1b129 100644 --- a/t/009_data_classes.t +++ b/t/009_data_classes.t @@ -1,13 +1,14 @@ #!/usr/bin/perl -w use strict; +use warnings; use Test::More tests => 5; use lib 't/lib'; use lib '../lib'; use lib 'lib'; -use XML::Simple; + use SOAP::WSDL::SAX::WSDLHandler; use Cwd; -use XML::LibXML::SAX; + use_ok(qw/SOAP::WSDL::SAX::MessageHandler/); use SOAP::WSDL; @@ -15,22 +16,18 @@ use SOAP::WSDL::XSD::Typelib::Builtin; my $path = cwd; $path =~s|\/t\/?$||; # allow running from t/ and above (Build test) -$XML::Simple::PREFERRED_PARSER = 'XML::Parser'; -my $filter; -ok($filter = SOAP::WSDL::SAX::MessageHandler->new( { +my $parser; + +ok $parser = SOAP::WSDL::Expat::MessageParser->new({ class_resolver => FakeResolver->new(), -} ), "Object creation"); +}), "Object creation"; -my $parser = XML::LibXML->new(); -$parser->set_handler( $filter ); +# TODO factor out into bool test -$parser->parse_string( xml() ); +$parser->parse( xml() ); -# print $filter->get_data(); -# print $filter->get_data()->get_MMessage()->_DUMP(); - -if($filter->get_data()->get_MMessage()->get_MDeliveryReportRecipientURI()) { +if($parser->get_data()->get_MMessage()->get_MDeliveryReportRecipientURI()) { pass "bool context overloading"; } else @@ -38,6 +35,8 @@ else fail "bool context overloading" } +# TODO factor out into different test + my $soap = SOAP::WSDL->new( readable => 1, wsdl => 'file:///' . $path .'/t/acceptance/wsdl/006_sax_client.wsdl', @@ -86,6 +85,4 @@ BEGIN { : warn "no class found for $name"; }; }; - - }; diff --git a/t/014_sax_typelib.t b/t/014_sax_typelib.t index 73ae8ce..5f96c37 100644 --- a/t/014_sax_typelib.t +++ b/t/014_sax_typelib.t @@ -1,11 +1,15 @@ #!/usr/bin/perl -w use strict; use warnings; -use Test::More tests => 16; +use Test::More; use lib '../lib'; -use XML::SAX::ParserFactory; -use diagnostics; +if (eval "require XML::LibXML") { + plan tests => 16; +} +else { + plan skip_all => "Cannot test without XML::LibXML"; +} eval { require Test::XML; @@ -18,7 +22,6 @@ my $filter; ok($filter = SOAP::WSDL::SAX::WSDLHandler->new(), "Object creation"); -use XML::LibXML; my $parser = XML::LibXML->new(); $parser->set_handler( $filter ); diff --git a/t/015_to_typemap.t b/t/015_to_typemap.t index f5a4a34..df92ee4 100644 --- a/t/015_to_typemap.t +++ b/t/015_to_typemap.t @@ -1,11 +1,15 @@ #!/usr/bin/perl -w use strict; use warnings; -use Test::More tests => 5; +use Test::More; use lib '../lib'; -use XML::SAX::ParserFactory; -use diagnostics; +if (eval "require XML::LibXML") { + plan tests => 5; +} +else { + plan skip_all => "Cannot test without XML::LibXML"; +} eval { require Test::XML; @@ -18,7 +22,6 @@ my $filter; ok($filter = SOAP::WSDL::SAX::WSDLHandler->new(), "Object creation"); -use XML::LibXML; my $parser = XML::LibXML->new(); $parser->set_handler( $filter ); diff --git a/t/017_generator_expat.t b/t/017_generator_expat.t new file mode 100644 index 0000000..531490c --- /dev/null +++ b/t/017_generator_expat.t @@ -0,0 +1,412 @@ +#!/usr/bin/perl -w +use strict; +use warnings; +use Test::More tests => 19; +use lib '../lib'; +use SOAP::WSDL::Expat::WSDLParser; +use SOAP::WSDL::Expat::MessageParser; +use File::Path; +use File::Basename; + +my $path = dirname __FILE__; + +my $wsdl; +ok( $wsdl = SOAP::WSDL::Expat::WSDLParser->new() + ->parse_string( xml() ) , "get object tree"); + +$wsdl->create({ + base_path => "$path/testlib", + typemap_prefix => "Test::Typemap::", + type_prefix => "Test::Type::", + element_prefix => "Test::Element::", + interface_prefix => "Test::Interface::", +}); + +eval "use lib '$path/testlib'"; + +use_ok qw(Test::Element::EnqueueMessage); +use_ok qw(Test::Type::TMessage); +use_ok qw(Test::Typemap::MessageGateway); + +my $data = { + MMessage => { + MRecipientURI => 'anyURI', + MSenderAddress => 'a string', + MMessageContent => 'a string', + MSubject => 'a string', + MDeliveryReportRecipientURI => 'anyURI', + MKeepalive => { + MKeepaliveTimeout => 1234567, + MKeepaliveErrorPolicy => ' ( suppress | report ) ', + } + } +}; + +ok Test::Element::EnqueueMessage->new( $data ) , '(generated) object constructor'; + +my $message_parser = SOAP::WSDL::Expat::MessageParser->new({ + class_resolver => 'Test::Typemap::MessageGateway' +}); + +eval { $message_parser->parse_string( xml_message2() ) }; +ok ( !$@, 'parse XML message'); + + +TODO: { + local $TODO = 'support embedded atomic simpleType/complexType definitions'; + eval { $message_parser->parse_string( xml_message() ) }; + ok ( !$@, 'parse XML message using atomic type definitions'); +}; + +SKIP: { + eval "require Test::Pod"; + skip 'Cannot test generated POD without Test::POD' , 6 if $@; + + foreach my $module (Test::Pod::all_pod_files( "$path/testlib")) { + Test::Pod::pod_file_ok( $module ) + } +} + +# cleanup +rmtree "$path/testlib"; + +# print $wsdl->explain(); + +sub xml_message { + return +q{ + + anyURI + a string + a string + a string + anyURI + + 1234567 + ( suppress | report ) + + + +}; +} + +sub xml_message2 { + return +q{ + + anyURI + a string + a string + a string + anyURI + + +}; +} + + +sub xml { + return q{ + + + + + + + Enqueue message request element + + + + + + + A type containing all elements of a message to enqueue. + + + + + + + + The recipient in URI notaitions. Valid URI schemas are: mailto:, sms:, + phone:. Not all URI schemas need to be implemented at the current + implementation stage. + + + + + + + E-Mail sender address. Ignored for all but mailto: recipient URIs. + + + + + + + Message Content. + + + + + + + Message Subject. Ignored for all but mailto: URIs + + + + + + + + URI to send a delivery report to. May be of one of the following schemes: + mailto:, http:, https:. Reports to mailto: URIs are sent as plaintext, + reports to http(s) URIs are sent as SOAP requests following the + MessageGatewayClient service definition. + + + + + + + Container for keepalive information. May be missing. + + + + + + + + + + Type containing keeplive information. + + + + + + + Keepalive timeout. The keepalive timeout spezifies how long the sending of + a message will be delayed waiting for keepalive updates. If a keepalive + update is received during this period, the timeout will be reset. If not, + the message will be sent after the timeout has expired. + + + + + + + + Policy to comply to in case of system errors. Valid values are "suppress" + and "report". If the policy is set to "suppress", keepalive messages will + not be sent to their recipients in case of partial system failure, even if + the keepalive has expired. This may result in "false negatives", i.e. + messages may not be sent, even though their keepalive has expired. If the + value is "report", keepalive messages will be sent from any cluster node. + This may result in "false positive" alerts. + + + + + + + + + + + + + + + Type containing a message ID. + + + + + + + + + + + Type containing all elements of a keppalive update / remove request. + + + + + + + The ID for the message to update / remove + + + + + + + + The action to perform. Valid values are: "remove", "update". On "remove", + the message with the ID specified will be removed from the queue, thus it + will never be sent, even if it's timeout expires. On "update" the + keepalive timeout of the corresponding message will be reset. + + + + + + + + + + + + + + Keepalive message request element + + + + + Response element for a keepalive request + + + + + Enqueue message response element + + + + + + + + A complex type containing one element: The message to enqueue. + + + + + + + Element containing a message to enqueue. + + + + + + + + + + + + A complex type containing one element: The keepalive message to process. + + + + + + + + Element containing a keepalive message to process. + + + + + + + + + + + inputparameters for EnqueueMessag + + + + + + outputparameters for EnqueueMessag + + + + + + input parameters for KeepaliveMessag + + + + + output parameters for KeepaliveMessag + + + + + + generic port type for all methods required for sending messages over the mosaic + message gatewa + + + + This method is used to enqueue a normal (immediate send) or a delayed message with + keepalive functionality. + + + + + + + + This method is used to update or remove a + keepalive message. + + + + + + + + Generic binding for all (SOAP) port + + + + + + + + + + + + + + + + + + + + + + + + Web Service for sending messages over the message gatewa + + + + HTTP(S) port for the message gateway + + + +}; +} diff --git a/t/017_generator.t b/t/017_generator_libxml.t similarity index 98% rename from t/017_generator.t rename to t/017_generator_libxml.t index 94a043c..e7644b3 100644 --- a/t/017_generator.t +++ b/t/017_generator_libxml.t @@ -1,13 +1,19 @@ #!/usr/bin/perl -w use strict; use warnings; -use Test::More tests => 18; +use Test::More; use lib '../lib'; -use XML::LibXML; use SOAP::WSDL::SAX::WSDLHandler; use SOAP::WSDL::SAX::MessageHandler; use File::Path; use File::Basename; + +if (eval "require XML::LibXML") { + plan tests => 18; +} +else { + plan skip_all => "Cannot test without XML::LibXML"; +} my $path = dirname __FILE__; diff --git a/t/018_generator_expat.t b/t/018_generator_expat.t new file mode 100644 index 0000000..d4d273e --- /dev/null +++ b/t/018_generator_expat.t @@ -0,0 +1,49 @@ +#!/usr/bin/perl -w +use strict; +use warnings; +use Test::More tests => 12; +use lib '../lib'; +use SOAP::WSDL::Expat::WSDLParser; +use File::Find; +use File::Basename; + +my $path = dirname __FILE__; +my $wsdl; + +my $parser = SOAP::WSDL::Expat::WSDLParser->new(); +ok( $wsdl = $parser->parse_file( "$path/../example/wsdl/globalweather.xml" ) ); + +$wsdl->create({ + base_path => "$path/testlib", + typemap_prefix => "Test::Typemap::", + type_prefix => "Test::Type::", + element_prefix => "Test::Element::", + interface_prefix => "Test::Interface::", +}); + +# Check for created files (and dirs) - value is the number of entries +# with this (local) name +my %expected = ( + 'GetCitiesByCountry.pm' => 1, + 'GetCitiesByCountryResponse.pm' => 1, + 'GetWeather.pm' => 1, + 'GetWeatherResponse.pm' => 1, + 'string.pm' => 1, + 'Element' => 1, + 'Interface' => 1, + 'GlobalWeather.pm' => 2, + 'Typemap' => 1, + 'Test' => 1, +); + +File::Find::finddepth( + sub { + return if $_ eq '.'; + ok $expected{ $_ }--, $_; + unlink $_ if -f $_; + rmdir $_ if -d $_; + }, + "$path/testlib", +); + +rmdir "$path/testlib"; \ No newline at end of file diff --git a/t/018_generator.t b/t/018_generator_libxml.t similarity index 78% rename from t/018_generator.t rename to t/018_generator_libxml.t index b390be0..e12f12d 100644 --- a/t/018_generator.t +++ b/t/018_generator_libxml.t @@ -1,13 +1,19 @@ #!/usr/bin/perl -w use strict; use warnings; -use Test::More tests => 1; +use Test::More; use lib '../lib'; -use XML::LibXML; use SOAP::WSDL::SAX::WSDLHandler; use SOAP::WSDL::SAX::MessageHandler; use File::Path; use File::Basename; + +if (eval "require XML::LibXML") { + plan tests => 1; +} +else { + plan skip_all => "Cannot test without XML::LibXML"; +} my $path = dirname __FILE__; diff --git a/t/021_generator_element_ref_expat.t b/t/021_generator_element_ref_expat.t new file mode 100644 index 0000000..713a23c --- /dev/null +++ b/t/021_generator_element_ref_expat.t @@ -0,0 +1,58 @@ +#!/usr/bin/perl -w +use strict; +use warnings; +use Test::More tests => 10; +use File::Path; +use File::Basename; +use lib '../lib'; + +use_ok(qw/SOAP::WSDL::Expat::WSDLParser/); + +my $path = dirname __FILE__; + +my $parser = SOAP::WSDL::Expat::WSDLParser->new(); + +eval { $parser->parsefile( "$path/acceptance/wsdl/03_complexType-element-ref.wsdl" ) }; +if ($@) +{ + fail("parsing WSDL"); + die "Can't test without parsed WSDL: $@"; +} +else +{ + pass("parsing XML"); +} + +my $definitions = $parser->get_data(); + + +my $type = $definitions->first_types()->find_type('urn:Test', 'testComplexTypeRef'); +my $element = $definitions->first_types()->find_element('urn:Test', 'TestElement'); + +my $output = ''; +ok $element->to_class({ wsdl => $definitions, prefix => 'Test::', output => \$output }) + , 'generate element code'; +ok eval $output, 'eval generated code'; + +$output = ''; +ok $type->to_class({ wsdl => $definitions, prefix => 'Test::', output => \$output }) + , 'generate complexType code with element ref=""'; +ok eval $output, 'eval generated code'; + +my $obj = Test::testComplexTypeRef->new({ + TestRef => 'test_ref', + Test2 => 'test2', +}); + +is $obj, 'test_reftest2', 'serialization'; + +$element = $definitions->first_types()->find_element('urn:Test', 'TestRef'); + +$output = ''; + +ok $element->to_class({ wsdl => $definitions, prefix => 'Test::', output => \$output }) + , 'generate top level element ref code'; +ok eval $output, 'eval generated code' . $@; + +$obj = Test::TestRef->new({ value => 'test_ref' }); +is $obj, 'test_ref', 'serialization'; \ No newline at end of file diff --git a/t/021_generator_element_ref_libxml.t b/t/021_generator_element_ref_libxml.t new file mode 100644 index 0000000..32a8c8b --- /dev/null +++ b/t/021_generator_element_ref_libxml.t @@ -0,0 +1,76 @@ +#!/usr/bin/perl -w +use strict; +use warnings; +use Test::More; +use File::Path; +use File::Basename; +use lib '../lib'; + +if (eval "require XML::LibXML") { + plan tests => 11; +} +else { + plan skip_all => "Cannot test without XML::LibXML"; +} + +my $path = dirname __FILE__; + + +use_ok(qw/SOAP::WSDL::SAX::WSDLHandler/); + +my $filter; +my $parser = XML::LibXML->new(); +ok($filter = SOAP::WSDL::SAX::WSDLHandler->new(), "Object creation"); +$parser->set_handler( $filter ); + +eval { $parser->parse_file( "$path/acceptance/wsdl/03_complexType-element-ref.wsdl" ) }; +if ($@) +{ + fail("parsing WSDL"); + die "Can't test without parsed WSDL: $@"; +} +else +{ + pass("parsing XML"); +} + +my $definitions = $filter->get_data(); +my $type = $definitions->first_types()->find_type('urn:Test', 'testComplexTypeRef'); + +my $element = $definitions->first_types()->find_element('urn:Test', 'TestElement'); + +my $output; + +ok $element->to_class({ wsdl => $definitions, prefix => 'Test::', output => \$output }) + , 'generate element code'; + +ok eval $output, 'eval generated code'; + +$output = ''; + +ok $type->to_class({ wsdl => $definitions, prefix => 'Test::', output => \$output }) + , 'generate complexType code with element ref=""'; + +ok eval $output, 'eval generated code'; + +my $obj = Test::testComplexTypeRef->new({ + TestRef => 'test_ref', + Test2 => 'test2', +}); + +is $obj, 'test_reftest2', 'serialization'; + +$element = $definitions->first_types()->find_element('urn:Test', 'TestRef'); + +$output = ''; + +ok $element->to_class({ wsdl => $definitions, prefix => 'Test::', output => \$output }) + , 'generate top level element ref code'; + +ok eval $output, 'eval generated code' . $@; + +# print $output; + +$obj = Test::TestRef->new({ value => 'test_ref' }); + +is $obj, 'test_ref', 'serialization'; \ No newline at end of file diff --git a/t/Expat/01_expat.t b/t/Expat/01_expat.t index fc41055..2793f99 100644 --- a/t/Expat/01_expat.t +++ b/t/Expat/01_expat.t @@ -5,7 +5,6 @@ use Test::More tests => 2; use lib '../lib'; use lib 'lib'; use lib 't/lib'; -use XML::LibXML; use SOAP::WSDL::SAX::MessageHandler; use_ok(qw/SOAP::WSDL::Expat::MessageParser/); @@ -13,7 +12,6 @@ use_ok(qw/SOAP::WSDL::Expat::MessageParser/); use MyComplexType; use MyElement; use MySimpleType; -use Benchmark; my $xml = q{ @@ -26,13 +24,6 @@ my $parser = SOAP::WSDL::Expat::MessageParser->new({ class_resolver => 'FakeResolver' }); -my $libxml = XML::LibXML->new(); -my $handler = SOAP::WSDL::SAX::MessageHandler->new({ - class_resolver => 'FakeResolver', -}); -$libxml->set_handler( $handler ); - - $parser->parse( $xml ); is $parser->get_data(), q{} diff --git a/t/Expat/02_sub_parser.t b/t/Expat/02_sub_parser.t new file mode 100644 index 0000000..4a1b39e --- /dev/null +++ b/t/Expat/02_sub_parser.t @@ -0,0 +1,335 @@ +package TopElement; +use Class::Std::Storable; +use SOAP::WSDL::XSD::Typelib::Element; +use SOAP::WSDL::XSD::Typelib::ComplexType; +use Memoize; + +memoize('_get_handlers'); + +use base qw(SOAP::WSDL::XSD::Typelib::Element + SOAP::WSDL::XSD::Typelib::ComplexType +); +{ + my %TestElement_of :ATTR(); + my $CLASS_OF_REF = { TestElement => 'TestElement' }; + + __PACKAGE__->_factory( [ 'TestElement' ], + { 'TestElement' => \%TestElement_of, }, + { TestElement => 'TestElement' }, + ); + + sub get_xmlns { 'urn:Test' }; + __PACKAGE__->__set_name('TopElement'); + __PACKAGE__->__set_nillable(1); + + sub _get_handlers { + my $self = shift; + my $parser = shift; + + return { + Start => $parser->start_tag({ + class_of => $CLASS_OF_REF, + handler_of => { + TestElement => TestElement->_get_handlers( $parser ), + } + }), + End => $parser->end_top_tag( ), + Char => undef, + }; + } +} +1; + +package TestElement; +use Class::Std::Storable; +use SOAP::WSDL::XSD::Typelib::Element; +use SOAP::WSDL::XSD::Typelib::ComplexType; + +use Memoize; +memoize('_get_handlers'); + +use base qw( + SOAP::WSDL::XSD::Typelib::Element + SOAP::WSDL::XSD::Typelib::ComplexType +); + +{ + my %test_of :ATTR(); + my %test2_of :ATTR(); + + my $CLASS_OF_REF = { + test => 'SOAP::WSDL::XSD::Typelib::Builtin::string', + test2 => 'SOAP::WSDL::XSD::Typelib::Builtin::string' + }; + + __PACKAGE__->_factory( [ 'test', 'test2' ], + { test => \%test_of, test2 => \%test2_of, }, + $CLASS_OF_REF, + ); + + sub get_xmlns { 'urn:Test' }; + __PACKAGE__->__set_name('TestElement'); + __PACKAGE__->__set_nillable(1); + + sub _get_handlers { + my $self = shift; + my $parser = shift; + + return { + Start => $parser->start_tag({ + class_of => $CLASS_OF_REF, + handler_of => + { + map { ( $_ => $CLASS_OF_REF->{$_}->_get_handlers( $parser ) )} + keys %{ $CLASS_OF_REF } + }, + }), + End => $parser->end_tag(), + Char => undef, + }; + } +} +1; + +package TestResolver; + +sub get_class { + my $path = join('/', @{ $_[1] }); + my $class = { + 'TestElement' => 'TestElement', + 'TestElement/test' => 'SOAP::WSDL::XSD::Typelib::Builtin::string', + 'TestElement/test2' => 'SOAP::WSDL::XSD::Typelib::Builtin::string', + 'TopElement' => 'TopElement', + 'TopElement/TestElement' => 'TestElement', + 'TopElement/TestElement/test' => 'SOAP::WSDL::XSD::Typelib::Builtin::string', + 'TopElement/TestElement/test2' => 'SOAP::WSDL::XSD::Typelib::Builtin::string', + }; + return $class->{ $path }; +} + +1; + +package main; + +use Test::More qw/no_plan/; # TODO: change to tests => N; +use strict; +use warnings; +use lib '../../lib'; + +use_ok('SOAP::WSDL::Expat::MessageParser'); +use_ok('SOAP::WSDL::Expat::MessageSubParser'); +my $obj; + +ok($obj = SOAP::WSDL::Expat::MessageSubParser->new(), "Object creation"); + +#my $test = $obj->start_tag({ +# order => [], +# class_of => { +# test => 'SOAP::WSDL::XSD::Typelib::Builtin::string', +# test2 => 'SOAP::WSDL::XSD::Typelib::Builtin::string', +# }, +# handler_of => { +# test => { +# Char => $obj->characters(), +# }, +# test2 => { +# Char => $obj->characters(), +# }, +# } +#}); +# +#my $handlers = { +# Start => $test, +# End => $obj->end_tag(), +#}; +# +#my $parser = $obj->initialize( $handlers ); +# +#$parser->parsestring('Test'); +#is $obj->get_data(), 'Test', 'Parse simple XML'; +# +#my $element = $obj->start_tag({ +# order => [], +# class_of => { +# TestElement => 'TestElement', +# }, +# handler_of => { +# TestElement => { +# Start => $obj->start_tag({ +# order => [], +# class_of => { +# test => 'SOAP::WSDL::XSD::Typelib::Builtin::string', +# test2 => 'SOAP::WSDL::XSD::Typelib::Builtin::string', +# }, +# handler_of => { +# test => { +# Char => $obj->characters(), +# }, +# test2 => { +# Char => $obj->characters(), +# }, +# } +# }), +# End => $obj->end_tag(), +# Char => undef, +# } +# } +#}); +# +# +#$handlers = { +# Start => $element, +# End => $obj->end_tag(), +# Char => undef, +#}; +# +#$parser = $obj->initialize( TestElement->_get_parser( $obj ) ); +# +#my $xml = ' +# Test +# Test2 +#'; +# +#$parser->parsestring($xml); +# +#is $obj->get_data() +# , 'TestTest2' +# , 'Parse && serialize ComplexType Element'; +# + +#my $mp = SOAP::WSDL::Expat::MessageParser->new({ +# class_resolver => 'TestResolver', +#}); +# +#$mp->parse( $xml ); + +#use Benchmark; +# +#timethese 1000 , { +# mp => sub { $mp->parse($xml) }, +# 'sub_p' => sub { $obj->initialize( $handlers )->parse( $xml ) }, +# +#}; + +#my $top = $obj->start_tag({ +# order => [], +# class_of => { +# TopElement => 'TopElement', +# }, +# handler_of => { +# TopElement => { +# Start => $obj->start_tag({ +# order => [ 'TestElement', ], +# class_of => { +# TestElement => 'TestElement', +# }, +# handler_of => { +# TestElement => { +# Start => $obj->start_tag({ +# order => ['test', 'test2'], +# class_of => { +# test => 'SOAP::WSDL::XSD::Typelib::Builtin::string', +# test2 => 'SOAP::WSDL::XSD::Typelib::Builtin::string', +# }, +# handler_of => { +# test => { +# Char => $obj->characters(), +# }, +# test2 => { +# Char => $obj->characters(), +# }, +# }, +# occurs_of => { +# test => { max => 1 }, +# } +# }), +# End => $obj->end_tag(), +# Char => undef, +# } +# } +# }) +# } +# } +#}); + +my $top = $obj->start_tag({ + class_of => { + TopElement => 'TopElement', + }, + handler_of => { + TopElement => TopElement->_get_handlers( $obj ), + } +}); + +my $parser = $obj->initialize( { Start => $top , End => $obj->end_tag() , Char => undef } ); + +my $xml = ' + + + Test + Test2 + + + Test + Test2 + + + Test + Test2 + + + Test + Test2 + + + Test + Test2 + + + Test + Test2 + +'; + +$parser->parsestring($xml); + +# print $obj->get_data(); + +__END__ + +# TODO factor out into benchmark suite + +use XML::Simple; +use Benchmark; + +my $mp = SOAP::WSDL::Expat::MessageParser->new({ + class_resolver => 'TestResolver', +}); +$mp->parse( $xml ); + +$top = $obj->start_tag({ + class_of => { + TopElement => 'TopElement', + }, + handler_of => { + TopElement => TopElement->_get_handlers( $obj ), + } +}); +my $top_end = $obj->end_top_tag(); +$parser = $obj->initialize( { Start => $top , End => $top_end, , Char => undef } ); +$parser->parse( $xml ), + +print "DATA:" . $obj->get_data(), "\n"; + + +# $XML::Simple::PREFERRED_PARSER = 'XML::SAX::Expat'; +$XML::Simple::PREFERRED_PARSER = 'XML::Parser'; + +timethese 500 , { + 'typemap' => sub { $mp->parse($xml) }, + 'sub_tree' => sub { + my $parser = $obj->initialize( { Start => $top , End => $top_end, , Char => undef } ); + $parser->parse( $xml ), + }, + 'XML::Simple' => sub { XMLin( $xml ); } +}; diff --git a/t/Expat/03_wsdl.t b/t/Expat/03_wsdl.t new file mode 100644 index 0000000..b6cd2c3 --- /dev/null +++ b/t/Expat/03_wsdl.t @@ -0,0 +1,411 @@ +#!/usr/bin/perl -w +use strict; +use warnings; +use diagnostics; +use Test::More tests => 7; +use Data::Dumper; +use lib '../lib'; + +eval { + require Test::XML; + import Test::XML; +}; + +use_ok(qw/SOAP::WSDL::Expat::WSDLParser/); + +my $parser; +ok $parser = SOAP::WSDL::Expat::WSDLParser->new(), "Object creation"; + +$parser->parse( xml() ); + +eval { $parser->parse( xml() ) }; +if ($@) +{ + fail("parsing WSDL"); + die "Can't test without parsed WSDL: " , Dumper $@; +} +else +{ + pass("parsing XML"); +} + +my $wsdl; +ok $wsdl = $parser->get_data() , "get object tree"; + +my $schema = $wsdl->first_types()->get_schema()->[1] || die "No schema !"; + +my $element = $schema->find_element( + 'http://www.example.org/MessageGateway2/' + , 'EnqueueMessage' +); + +ok $element, 'find element'; +is $element->get_xmlns()->{ 'http://www.example.org/MessageGateway2/' }, 'tns', 'Namespace definition'; + + +my $opt = { + typelib => $wsdl->first_types, + readable => 1, + autotype => 0, + namespace => { 'http://www.example.org/MessageGateway2/' => 'tns', + 'http://www.w3.org/2001/XMLSchema' => 'xsd', + 'http://schemas.xmlsoap.org/wsdl/' => 'wsdl', + }, + indent => "", +}; + +my $data = { EnqueueMessage => { + MMessage => { + MRecipientURI => 'anyURI', + MSenderAddress => 'a string', + MMessageContent => 'a string', + MSubject => 'a string', + MDeliveryReportRecipientURI => 'anyURI', + MKeepalive => { + MKeepaliveTimeout => 1234567, + MKeepaliveErrorPolicy => ' ( suppress | report ) ', + } + } +} + +}; + + +SKIP: { skip_without_test_xml(); + is_xml( $wsdl->find_message( + "http://www.example.org/MessageGateway2/" ,'EnqueueMessageRequest' + )->first_part()->serialize( 'test', $data, $opt ), + xml_message() + , "Serialized message part" + ); +} + +sub skip_without_test_xml { + skip("Test::XML not available", 1) if (not $Test::XML::VERSION); +} + +sub xml_message { + return +q{ + + anyURI + a string + a string + a string + anyURI + + 1234567 + ( suppress | report ) + + + +}; + +} + +sub xml { + return q{ + + + + + + + Enqueue message request element + + + + + + + A type containing all elements of a message to enqueue. + + + + + + + + The recipient in URI notaitions. Valid URI schemas are: mailto:, sms:, + phone:. Not all URI schemas need to be implemented at the current + implementation stage. + + + + + + + E-Mail sender address. Ignored for all but mailto: recipient URIs. + + + + + + + Message Content. + + + + + + + Message Subject. Ignored for all but mailto: URIs + + + + + + + + URI to send a delivery report to. May be of one of the following schemes: + mailto:, http:, https:. Reports to mailto: URIs are sent as plaintext, + reports to http(s) URIs are sent as SOAP requests following the + MessageGatewayClient service definition. + + + + + + + Container for keepalive information. May be missing. + + + + + + + + + + Type containing keeplive information. + + + + + + + Keepalive timeout. The keepalive timeout spezifies how long the sending of + a message will be delayed waiting for keepalive updates. If a keepalive + update is received during this period, the timeout will be reset. If not, + the message will be sent after the timeout has expired. + + + + + + + + Policy to comply to in case of system errors. Valid values are "suppress" + and "report". If the policy is set to "suppress", keepalive messages will + not be sent to their recipients in case of partial system failure, even if + the keepalive has expired. This may result in "false negatives", i.e. + messages may not be sent, even though their keepalive has expired. If the + value is "report", keepalive messages will be sent from any cluster node. + This may result in "false positive" alerts. + + + + + + + + + + + + + + + Type containing a message ID. + + + + + + + + + + + Type containing all elements of a keppalive update / remove request. + + + + + + + The ID for the message to update / remove + + + + + + + + The action to perform. Valid values are: "remove", "update". On "remove", + the message with the ID specified will be removed from the queue, thus it + will never be sent, even if it's timeout expires. On "update" the + keepalive timeout of the corresponding message will be reset. + + + + + + + + + + + + + + Keepalive message request element + + + + + Response element for a keepalive request + + + + + Enqueue message response element + + + + + + + + A complex type containing one element: The message to enqueue. + + + + + + + Element containing a message to enqueue. + + + + + + + + + + + + A complex type containing one element: The keepalive message to process. + + + + + + + + Element containing a keepalive message to process. + + + + + + + + + + + inputparameters for EnqueueMessag + + + + + + outputparameters for EnqueueMessag + + + + + + input parameters for KeepaliveMessag + + + + + output parameters for KeepaliveMessag + + + + + + generic port type for all methods required for sending messages over the mosaic + message gatewa + + + + This method is used to enqueue a normal (immediate send) or a delayed message with + keepalive functionality. + + + + + + + + This method is used to update or remove a + keepalive message. + + + + + + + + Generic binding for all (SOAP) port + + + + + + + + + + + + + + + + + + + + + + + + Web Service for sending messages over the mosaic message gatewa + + + + HTTP(S) port for the mosaic message gatewa + + + +}; +} diff --git a/t/SOAP/WSDL/03_complexType-element-ref.t b/t/SOAP/WSDL/03_complexType-element-ref.t new file mode 100644 index 0000000..93f1e1a --- /dev/null +++ b/t/SOAP/WSDL/03_complexType-element-ref.t @@ -0,0 +1,43 @@ +use Test::More tests => 4; +use strict; +use warnings; +use lib '../lib'; +use lib 't/lib'; +use lib 'lib'; +use Cwd; +use File::Basename; + +my $path = cwd(); +my $name = basename $0; +$name =~s/\.t$//; +$name =~s/^t\///; + +$path =~s{(/t)?/SOAP/WSDL}{}xms; + +use_ok(qw/SOAP::WSDL/); + +print "# SOAP::WSDL Version: $SOAP::WSDL::VERSION\n"; + +my $xml; +my $soap; + +#2 +ok( $soap = SOAP::WSDL->new( + wsdl => 'file://' . $path . '/t/acceptance/wsdl/' . $name . '.wsdl', + readable => 1, + no_dispatch => 1, +), 'Instantiated object' ); + +ok ($xml = $soap->call('test', + testAll => { + Test2 => 'Test2', + TestRef => 'TestRef' + } +), 'Serialized complexType' ); + +is $xml, q{ + TestRef + Test2 + +} + , 'element ref="" serialization'; diff --git a/t/SOAP/WSDL/10_performance.t b/t/SOAP/WSDL/10_performance.t deleted file mode 100644 index 7e2becc..0000000 --- a/t/SOAP/WSDL/10_performance.t +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/perl -w -use strict; -use Test::More tests=> 5; -use Time::HiRes qw( gettimeofday tv_interval ); -use lib '../..'; -use Data::Dumper; -use Cwd; -use File::Basename; -use_ok qw/ SOAP::WSDL /; -use Benchmark; - -print "# Testing SOAP::WSDL ". $SOAP::WSDL::VERSION."\n"; -print "# Performance test with simple WSDL file\n"; -my $soap; -my $data = { - sayHello => { - name => 'Mein Name', - givenName => 'Vorname', - } -}; - -my $name = basename( $0 ); -$name =~s/\.(t|pl)$//; - -my $path = cwd; - -$path=~s{(/t)?/SOAP/WSDL}{}xms; - -my $cacheDir; -if ($^O =~ m/Win/) -{ - $cacheDir = 'C:/Temp/WSDL'; -} -else -{ - $cacheDir = '/tmp/'; -} - - -my $t0 = [gettimeofday]; -ok( - $soap=SOAP::WSDL->new( - wsdl => "file://$path/t/acceptance/wsdl/10_helloworld.asmx.xml", - no_dispatch => 1 - ), - "Create SOAP::WSDL object (".tv_interval ( $t0, [gettimeofday]) ."ms)" ); - -$soap->proxy('http://helloworld/helloworld.asmx'); - -$t0 = [gettimeofday]; -eval{ - $soap->wsdlinit( - caching => 1, - cache_directory => $cacheDir, - servicename => 'Service1' ) }; - -unless ($@) { - pass("wsdl file init (".tv_interval ( $t0, [gettimeofday]) ."s)"); -} else { - fail( $@ ); -} -$soap->readable(1); - -$t0 = [gettimeofday]; -ok( $soap->call("sayHello" , %{ $data }), - "1 x call pre-work (".tv_interval ( $t0, [gettimeofday]) ."s)") ; - -$t0 = [gettimeofday]; -ok($soap->call(sayHello => %{ $data }), - "1 x call pre-work (".tv_interval ( $t0, [gettimeofday]) ."s)" ); - -timethis 1000, sub { $soap->call(sayHello => %{ $data }) }; - -__END__ - -$t0 = [gettimeofday]; -for (my $i=1; $i<100; $i++) -{ - $soap->call(sayHello => %{ $data }); -} -ok(1, "100 x call pre-work (".tv_interval ( $t0, [gettimeofday]) ."s)"); - -chdir $cwd; \ No newline at end of file diff --git a/t/SOAP/WSDL/XSD/Typelib/Builtin/002_dateTime.t b/t/SOAP/WSDL/XSD/Typelib/Builtin/002_dateTime.t index 73d953e..62991a3 100644 --- a/t/SOAP/WSDL/XSD/Typelib/Builtin/002_dateTime.t +++ b/t/SOAP/WSDL/XSD/Typelib/Builtin/002_dateTime.t @@ -13,6 +13,8 @@ sub timezone { } use_ok('SOAP::WSDL::XSD::Typelib::Builtin::dateTime'); + +print "# timezone is " . timezone( scalar localtime(time) ) . "\n"; my $obj; my %dates = ( '2007-12-31 12:32' => '2007-12-31T12:32:00', @@ -25,14 +27,6 @@ while (my ($date, $converted) = each %dates ) { $obj = SOAP::WSDL::XSD::Typelib::Builtin::dateTime->new(); $obj->set_value( $date ); - is $obj->get_value() , $converted . timezone($date), 'conversion'; + is $obj->get_value() , $converted . timezone($date), 'conversion with timezone'; } $obj->set_value('2007-12-31T00:00:00.0000000+01:00'); - -# exit; - -#~ use Benchmark; -#~ timethese 10000, { - #~ xml => sub { $obj->set_value('2037-12-31T00:00:00.0000000+01:00') }, - #~ string => sub { $obj->set_value('2037-12-31') }, -#~ } \ No newline at end of file diff --git a/t/acceptance/wsdl/03_complexType-element-ref.wsdl b/t/acceptance/wsdl/03_complexType-element-ref.wsdl new file mode 100644 index 0000000..54582ce --- /dev/null +++ b/t/acceptance/wsdl/03_complexType-element-ref.wsdl @@ -0,0 +1,53 @@ + + + + + + + + + ComplexType Test + + + + + + + + + + + + + + + + + Test-Methode + + + + + + + + + + + + + + + + + + + + + + + +