[Catalyst-commits] r7562 - in Catalyst-Controller-SOAP/1.0/trunk: lib/Catalyst/Controller t t/PostApp/lib/PostApp/Controller

ruoso at dev.catalyst.perl.org ruoso at dev.catalyst.perl.org
Fri Apr 4 19:04:57 BST 2008


Author: ruoso
Date: 2008-04-04 19:04:56 +0100 (Fri, 04 Apr 2008)
New Revision: 7562

Added:
   Catalyst-Controller-SOAP/1.0/trunk/t/PostApp/lib/PostApp/Controller/WithWSDL3.pm
   Catalyst-Controller-SOAP/1.0/trunk/t/hello3.wsdl
Modified:
   Catalyst-Controller-SOAP/1.0/trunk/lib/Catalyst/Controller/SOAP.pm
   Catalyst-Controller-SOAP/1.0/trunk/t/PostApp.t
Log:
[C-C-SOAP] Support for the WSDLPort attribute... Still some things to clear...

Modified: Catalyst-Controller-SOAP/1.0/trunk/lib/Catalyst/Controller/SOAP.pm
===================================================================
--- Catalyst-Controller-SOAP/1.0/trunk/lib/Catalyst/Controller/SOAP.pm	2008-04-04 16:09:50 UTC (rev 7561)
+++ Catalyst-Controller-SOAP/1.0/trunk/lib/Catalyst/Controller/SOAP.pm	2008-04-04 18:04:56 UTC (rev 7562)
@@ -7,18 +7,42 @@
     use UNIVERSAL qw(isa);
 
     use constant NS_SOAP_ENV => "http://schemas.xmlsoap.org/soap/envelope/";
+    use constant NS_WSDLSOAP => "http://schemas.xmlsoap.org/wsdl/soap/";
 
-    our $VERSION = '0.6';
+    our $VERSION = '0.7';
 
-    __PACKAGE__->mk_accessors qw(wsdlobj decoders encoders);
+    __PACKAGE__->mk_accessors qw(wsdlobj decoders encoders ports);
 
-    sub _parse_SOAP_attr {
-        my ($self, $c, $name, $value) = @_;
+    # XXX - This is here as a temporary fix for 
+    sub _parse_attrs {
+        my ( $self, $c, $name, @attrs ) = @_;
 
+        my @others = grep { $_ !~ /^WSDLPort/ } @attrs;
+        my $final = $self->SUPER::_parse_attrs($c, $name, @others);
+
+
+        my ($attr) = grep { $_ && $_ =~ /^WSDLPort/ } @attrs;
+        return $final unless $attr;
+
+        if ( my ( $key, $value ) = ( $attr =~ /^(.*?)(?:\(\s*(.+?)\s*\))?$/ ) ) #* emacs bug
+        {
+            if ( defined $value ) {
+                ( $value =~ s/^'(.*)'$/$1/ ) || ( $value =~ s/^"(.*)"/$1/ );
+            }
+            my %ret = $self->_parse_WSDLPort_attr($c, $name, $value);
+            push( @{ $final->{$_} }, $ret{$_} ) for
+              keys %ret;
+        }
+
+
+        return $final;
+    }
+
+
+    sub __init_wsdlobj {
+        my ($self, $c) = @_;
+
         my $wsdlfile = $self->config->{wsdl};
-        my $compile_opts = $self->config->{xml_compile} || {};
-        $compile_opts->{reader} ||= {};
-        $compile_opts->{writer} ||= {};
 
         if ($wsdlfile) {
             if (!$self->wsdlobj) {
@@ -42,8 +66,67 @@
                     $self->wsdlobj->importDefinitions($schema)
                 }
             }
+        }
 
-            my $operation = $self->wsdlobj->operation($name)
+        return $self->wsdlobj ? 1 : 0;
+    }
+
+    sub _parse_WSDLPort_attr {
+        my ($self, $c, $name, $value) = @_;
+
+        die 'Cannot use WSDLPort without WSDL.'
+          unless $self->__init_wsdlobj;
+
+        $self->ports({}) unless $self->ports();
+        $self->ports->{$name} = $value;
+        my $operation = $self->wsdlobj->operation($name,
+                                                  port => $value,
+                                                  service => $self->config->{wsdlservice})
+          or die 'Every operation should be on the WSDL when using one.';
+
+        # TODO: Use more intelligence when selecting the address.
+        my ($path) = $operation->endPointAddresses();
+
+        $path =~ s#^[^:]+://[^/]+##;
+
+        # Finding out the style and input body use for this operation
+        my $binding = $self->wsdlobj->find(binding => $operation->port->{binding});
+        my $style = $binding->{'{'.NS_WSDLSOAP.'}binding'}[0]->getAttribute('style');
+        my ($use) = map { $_->{input}{'{'.NS_WSDLSOAP.'}body'}[0]->getAttribute('use') }
+          grep { $_->{name} eq $name } @{ $binding->{operation} || [] };
+
+        $style = $style =~ /document/i ? 'Document' : 'RPC';
+        $use = $use =~ /literal/i ? 'Literal' : 'Encoded';
+
+        if ($style eq 'Document') {
+           return
+           (
+            Path => $path,
+            $self->_parse_SOAP_attr($c, $name, $style.$use)
+           )
+        } else {
+           return $self->_parse_SOAP_attr($c, $name, $style.$use)
+        }
+    }
+
+    sub _parse_SOAP_attr {
+        my ($self, $c, $name, $value) = @_;
+
+        my $wsdlfile = $self->config->{wsdl};
+        my $wsdlservice = $self->config->{wsdl_service};
+        my $compile_opts = $self->config->{xml_compile} || {};
+        $compile_opts->{reader} ||= {};
+        $compile_opts->{writer} ||= {};
+
+        if ($wsdlfile) {
+
+            die 'WSDL initialization failed.'
+              unless $self->__init_wsdlobj;
+
+            $self->ports({}) unless $self->ports();
+            my $operation = $self->wsdlobj->operation($name,
+                                                      port => $self->ports->{$name},
+                                                      service => $wsdlservice)
               or die 'Every operation should be on the WSDL when using one.';
             my $portop = $operation->portOperation();
 
@@ -251,6 +334,17 @@
     # See Catalyst::Controller::SOAP::RPC.
     sub index :Local SOAP('RPCEndpoint') {}
 
+    # When using a WSDL, you can just specify the Port name, and it
+    # will infer the style and use. To do that, you just need to use
+    # the WSDLPort attribute instead of the SOAP attribute. This might
+    # be required if your service has more than one port.  When using
+    # this attribute with document-style bindings, this operation will
+    # be made available using the path part of the location attribute
+    # of the port definition. This attribute must be used for RPC
+    # operations too, but you still need to define the RPCEndpoint.
+    sub servicefoo : WSDLPort('ServicePort') {}
+
+
 =head1 ABSTACT
 
 Implements SOAP serving support in Catalyst.
@@ -344,10 +438,32 @@
 the schema key is an arrayref, it will result in several calls to
 importDefinition.
 
-Also, when using wsdl, you can also define the response using
+When using WSDL with more than one service or port,
+XML::Compile::WSDL11 needs extra hints. You should:
 
 =over
 
+=item __PACKAGE__->config->{wsdlservice} = 'ServiceName'
+
+This option is required whenever your WSDL have more than one service.
+
+=item sub foo : WSDLPort('PortName') { }
+
+When the service has more than one port, you must set the port
+name. For your convenince, the WSDLPort attribute not only sets it but
+also infer which is the style of the binding and the use of the input
+body. If this is a Document-style binding, it will also declare the
+Path for this operation based on the location of the port.
+
+RPC bindings must also use this attribute in multi-port WSDLs, but it
+won't declare the path for this operation and you still 
+
+=back
+
+Also, when using wsdl, you can define the response using:
+
+=over
+
 =item $c->stash->{soap}->compile_return($perl_structure)
 
 In this case, the given structure will be transformed by XML::Compile,

Added: Catalyst-Controller-SOAP/1.0/trunk/t/PostApp/lib/PostApp/Controller/WithWSDL3.pm
===================================================================
--- Catalyst-Controller-SOAP/1.0/trunk/t/PostApp/lib/PostApp/Controller/WithWSDL3.pm	                        (rev 0)
+++ Catalyst-Controller-SOAP/1.0/trunk/t/PostApp/lib/PostApp/Controller/WithWSDL3.pm	2008-04-04 18:04:56 UTC (rev 7562)
@@ -0,0 +1,23 @@
+package PostApp::Controller::WithWSDL3;
+
+use strict;
+use warnings;
+use base 'Catalyst::Controller::SOAP';
+
+__PACKAGE__->config->{wsdl} = 't/hello3.wsdl';
+
+sub Greet : WSDLPort('Greet') {
+    my ( $self, $c, $args ) = @_;
+    my $who = $args->{parameters}{who};
+    my $grt = $args->{parameters}{greeting};
+    $c->stash->{soap}->compile_return({ details => { greeting => $grt.' '.$who.'!' }});
+}
+
+sub Shout : WSDLPort('Shout') {
+    my ( $self, $c, $args ) = @_;
+    my $who = $args->{parameters}{who};
+    my $grt = $args->{parameters}{greeting};
+    $c->stash->{soap}->compile_return({ details => {greeting => uc($grt).' '.uc($who).'!!' }});
+}
+
+1;

Modified: Catalyst-Controller-SOAP/1.0/trunk/t/PostApp.t
===================================================================
--- Catalyst-Controller-SOAP/1.0/trunk/t/PostApp.t	2008-04-04 16:09:50 UTC (rev 7561)
+++ Catalyst-Controller-SOAP/1.0/trunk/t/PostApp.t	2008-04-04 18:04:56 UTC (rev 7562)
@@ -1,4 +1,4 @@
-use Test::More tests => 9;
+use Test::More tests => 11;
 use File::Spec::Functions;
 use HTTP::Response;
 use IPC::Open3;
@@ -87,7 +87,35 @@
 like($response->content, qr/Fault/, 'Fault for uncaugh exception: '.$response->content);
 # diag("/ws/bar: ".$response->content);
 
+$response = soap_xml_post
+  ('/hello/Greet',
+   '<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
+      <Body>
+        <GreetingSpecifier>
+          <who>World</who>
+          <greeting>Hello</greeting>
+        </GreetingSpecifier>
+      </Body>
+    </Envelope>'
+  );
+like($response->content, qr/greeting\>Hello World\!\<\//, ' using WSDLPort response: '.$response->content);
+# diag("/withwsdl/Greet: ".$response->content);
 
+$response = soap_xml_post
+  ('/hello/Shout',
+   '<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
+      <Body>
+        <GreetingSpecifier>
+          <who>World</who>
+          <greeting>Hello</greeting>
+        </GreetingSpecifier>
+      </Body>
+    </Envelope>'
+  );
+like($response->content, qr/greeting\>HELLO WORLD\!\!\<\//, ' using WSDLPort response: '.$response->content);
+# diag("/withwsdl/Shout: ".$response->content);
+
+
 sub soap_xml_post {
     my $path = shift;
     my $content = shift;

Added: Catalyst-Controller-SOAP/1.0/trunk/t/hello3.wsdl
===================================================================
--- Catalyst-Controller-SOAP/1.0/trunk/t/hello3.wsdl	                        (rev 0)
+++ Catalyst-Controller-SOAP/1.0/trunk/t/hello3.wsdl	2008-04-04 18:04:56 UTC (rev 7562)
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<wsdl:definitions
+    xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
+    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
+    xmlns:s="http://www.w3.org/2001/XMLSchema"
+    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
+    xmlns:hello="http://example.com/hello"
+    xmlns="http://example.com/hello"
+    targetNamespace="http://example.com/hello">
+
+  <wsdl:types>
+    <s:schema elementFormDefault="qualified" targetNamespace="http://example.com/hello">
+      <s:element name="GreetingSpecifier">
+        <s:complexType>
+          <s:sequence>
+            <s:element minOccurs="0" maxOccurs="1" name="who" type="s:string"/>
+            <s:element minOccurs="0" maxOccurs="1" name="greeting" type="s:string"/>
+          </s:sequence>
+        </s:complexType>
+      </s:element>
+      <s:element name="GreetingResponse">
+        <s:complexType>
+          <s:sequence>
+            <s:element minOccurs="0" maxOccurs="1" name="greeting" type="s:string"/>
+          </s:sequence>
+        </s:complexType>
+      </s:element>
+    </s:schema>
+  </wsdl:types>
+  <wsdl:message name="AskGreeting">
+    <wsdl:part name="parameters" element="hello:GreetingSpecifier"/>
+  </wsdl:message>
+  <wsdl:message name="GiveGreeting">
+    <wsdl:part name="details" element="hello:GreetingResponse"/>
+  </wsdl:message>
+  <wsdl:portType name="Greeting">
+    <wsdl:operation name="Greet">
+      <wsdl:input message="hello:AskGreeting"/>
+      <wsdl:output message="hello:GiveGreeting"/>
+    </wsdl:operation>
+  </wsdl:portType>
+  <wsdl:portType name="Shouting">
+    <wsdl:operation name="Shout">
+      <wsdl:input message="hello:AskGreeting"/>
+      <wsdl:output message="hello:GiveGreeting"/>
+    </wsdl:operation>
+  </wsdl:portType>
+  <wsdl:binding name="Greeting" type="hello:Greeting">
+    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
+    <wsdl:operation name="Greet">
+      <soap:operation style="document"/>
+      <wsdl:input>
+        <soap:body use="literal"/>
+      </wsdl:input>
+      <wsdl:output>
+        <soap:body use="literal"/>
+      </wsdl:output>
+    </wsdl:operation>
+  </wsdl:binding>
+  <wsdl:binding name="Shouting" type="hello:Shouting">
+    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
+    <wsdl:operation name="Shout">
+      <soap:operation style="document"/>
+      <wsdl:input>
+        <soap:body use="literal"/>
+      </wsdl:input>
+      <wsdl:output>
+        <soap:body use="literal"/>
+      </wsdl:output>
+    </wsdl:operation>
+  </wsdl:binding>
+  <wsdl:service name="Greet">
+    <wsdl:port name="Greet" binding="hello:Greeting">
+      <soap:address location="http://localhost:3000/hello/Greet"/>
+    </wsdl:port>
+    <wsdl:port name="Shout" binding="hello:Shouting">
+      <soap:address location="http://localhost:3000/hello/Shout"/>
+    </wsdl:port>
+  </wsdl:service>
+</wsdl:definitions>
\ No newline at end of file




More information about the Catalyst-commits mailing list