package SOAP::WSDL::Generator::Template::XSD; use strict; use Template; use Class::Std::Fast::Storable; use File::Basename; use File::Spec; use version; our $VERSION = qv('2.00.01'); use SOAP::WSDL::Generator::Visitor::Typemap; use SOAP::WSDL::Generator::Visitor::Typelib; use SOAP::WSDL::Generator::Template::Plugin::XSD; use base qw(SOAP::WSDL::Generator::Template); my %output_of :ATTR(:name :default<()>); my %typemap_of :ATTR(:name :default<({})>); sub BUILD { my ($self, $ident, $arg_ref) = @_; $self->set_EVAL_PERL(1); $self->set_RECURSION(1); $self->set_INCLUDE_PATH( exists $arg_ref->{INCLUDE_PATH} ? $arg_ref->{INCLUDE_PATH} : do { # ignore uninitialized warnings - File::Spec warns about # uninitialized values, probably because we have no filename local $SIG{__WARN__} = sub { return if ($_[0]=~m{\buninitialized\b}); CORE::warn @_; }; # makeup path for the OS we're running on my ($volume, $dir, $file) = File::Spec->splitpath( File::Spec->rel2abs( dirname __FILE__ ) ); $dir = File::Spec->catdir($dir, $file, 'XSD'); # return path put together... my $path = File::Spec->catpath( $volume, $dir , q{}); # Fixup path for windows - / works fine, \ does # not... if ( eval { &Win32::BuildNumber } ) { $path =~s{\\}{/}g; } $path; } ); } # construct object on call to allow late binding of prefix_resolver class # and namespace maps (not used yet) sub get_name_resolver { my $self = shift; return SOAP::WSDL::Generator::Template::Plugin::XSD->new({ prefix_resolver => $self->get_prefix_resolver_class()->new({ namespace_prefix_map => { 'http://www.w3.org/2001/XMLSchema' => 'SOAP::WSDL::XSD::Typelib::Builtin', }, namespace_map => { }, prefix => { attribute => $self->get_attribute_prefix, interface => $self->get_interface_prefix, element => $self->get_element_prefix, server => $self->get_server_prefix, type => $self->get_type_prefix, typemap => $self->get_typemap_prefix, } }) }); } sub generate { my $self = shift; my $opt = shift; $self->generate_typelib( $opt ); $self->generate_typemap( $opt ); } sub generate_typelib { my ($self, $arg_ref) = @_; my @schema = exists $arg_ref->{ schema } ? @{ $arg_ref->{schema} } : @{ $self->get_definitions()->first_types()->get_schema() }; for my $type (map { @{ $_->get_type() } , @{ $_->get_element() }, @{ $_->get_attribute() } } @schema[1..$#schema] ) { $type->_accept( $self ); } return; } sub _generate_interface { my $self = shift; my $arg_ref = shift; my $template_name = delete $arg_ref->{ template_name }; my $name_method = delete $arg_ref->{ name_method }; for my $service (@{ $self->get_definitions->get_service }) { for my $port (@{ $service->get_port() }) { # Skip ports without (known) address next if not $port->first_address; next if not $port->first_address->isa('SOAP::WSDL::SOAP::Address'); my $port_name = $port->get_name; $port_name =~s{ \A .+\. }{}xms; my $output = $arg_ref->{ output } ? $arg_ref->{ output } : $self->_generate_filename( $self->get_name_resolver()->can($name_method)->( $self->get_name_resolver(), $service, $port, )); print "Creating interface class $output\n"; $self->_process($template_name, { service => $service, port => $port, NO_POD => $arg_ref->{ NO_POD } ? 1 : 0 , }, $output, binmode => ':utf8'); } } } sub generate_server { my ($self, $arg_ref) = @_; $arg_ref->{ template_name } = 'Server.tt'; $arg_ref->{ name_method } = 'create_server_name'; $self->_generate_interface($arg_ref); } sub generate_client { my ($self, $arg_ref) = @_; $arg_ref->{ template_name } = 'Interface.tt'; $arg_ref->{ name_method } = 'create_interface_name'; $self->_generate_interface($arg_ref); } sub generate_interface; *generate_interface = \&generate_client; sub generate_typemap { my ($self, $arg_ref) = @_; my $visitor = SOAP::WSDL::Generator::Visitor::Typemap->new({ type_prefix => $self->get_type_prefix(), element_prefix => $self->get_element_prefix(), definitions => $self->get_definitions(), typemap => { 'Fault' => 'SOAP::WSDL::SOAP::Typelib::Fault11', 'Fault/faultcode' => 'SOAP::WSDL::XSD::Typelib::Builtin::anyURI', 'Fault/faultactor' => 'SOAP::WSDL::XSD::Typelib::Builtin::token', 'Fault/faultstring' => 'SOAP::WSDL::XSD::Typelib::Builtin::string', 'Fault/detail' => 'SOAP::WSDL::XSD::Typelib::Builtin::string', %{ $typemap_of{ident $self }}, }, resolver => $self->get_name_resolver(), }); use SOAP::WSDL::Generator::Iterator::WSDL11; my $iterator = SOAP::WSDL::Generator::Iterator::WSDL11->new({ definitions => $self->get_definitions }); for my $service (@{ $self->get_definitions->get_service }) { $iterator->init({ node => $service }); while (my $node = $iterator->get_next()) { $node->_accept( $visitor ); } my $output = $arg_ref->{ output } ? $arg_ref->{ output } : $self->_generate_filename( $self->get_name_resolver()->create_typemap_name($service) ); print "Creating typemap class $output\n"; $self->_process('Typemap.tt', { service => $service, typemap => $visitor->get_typemap(), NO_POD => $arg_ref->{ NO_POD } ? 1 : 0 , }, $output); } } sub _generate_filename :PRIVATE { my ($self, $name) = @_; $name =~s{ \. }{::}xmsg; $name =~s{ \- }{_}xmsg; $name =~s{ :: }{/}xmsg; return "$name.pm"; } sub visit_XSD_Attribute { my ($self, $attribute) = @_; my $output = defined $output_of{ ident $self } ? $output_of{ ident $self } : $self->_generate_filename( $self->get_name_resolver()->create_xsd_name($attribute) ); $self->_process('attribute.tt', { attribute => $attribute } , $output); } sub visit_XSD_Element { my ($self, $element) = @_; my $output = defined $output_of{ ident $self } ? $output_of{ ident $self } : $self->_generate_filename( $self->get_name_resolver()->create_xsd_name($element) ); $self->_process('element.tt', { element => $element } , $output); } sub visit_XSD_SimpleType { my ($self, $type) = @_; my $output = defined $output_of{ ident $self } ? $output_of{ ident $self } : $self->_generate_filename( $self->get_name_resolver()->create_xsd_name($type) ); $self->_process('simpleType.tt', { simpleType => $type } , $output); } sub visit_XSD_ComplexType { my ($self, $type) = @_; my $output = defined $output_of{ ident $self } ? $output_of{ ident $self } : $self->_generate_filename( $self->get_name_resolver()->create_xsd_name($type) ); $self->_process('complexType.tt', { complexType => $type } , $output); } 1;