spatterson has asked for the wisdom of the Perl Monks concerning the following question:

I'm creating a SOAP server using custom types (currently hashes) and with Pod::WSDL to provide the WSDL.

There's 1 method "Report" (in its own module file) and separate module files for the ReportRequest & ReportResponse custom types.

SOAP calls fail with the error: "Denied access to method (Report) in class (main)" though that method exists in the loaded module 'Report'

#!/usr/bin/perl # SOAP CGI server (method loaded from module 'Report') use strict; use warnings; use Data::Dumper; use SOAP::Transport::HTTP; use lib 'lib'; use Report; my $server = SOAP::Transport::HTTP::CGI ->dispatch_to('urn:Report') ->handle; 1;

Remaining module code follows. This is currently almost a no-op for testing

Report.pm

package Report; use Data::Dumper; use strict; use warnings; use ReportRequest; use ReportResponse; =begin WSDL _IN Report $ReportRequest a ReportRequest object _RETURN $ReportResponse a ReportResponse object _DOC Request or retreive a bandwidth report =cut sub Report { =begin WSDL _IN request $ReportRequest a ReportRequest type (this is in the metho +d) _DOC Method: Report =cut # my $class = shift(); # my $self = {}; # my %in = @_; open LOG, ">>soapservice.log"; print LOG "Report method\n"; print LOG Dumper(@_); close LOG; return "fluff"; # bless ($self, $class); } 1;

ReportRequest

package ReportRequest; =pod =begin WSDL _ATTR authuser $string valid username _ATTR authpass $string valid password _ATTR date_from $dateTime report start date (ISO YYYYMMDDTHH:MM) =end WSDL =cut sub new { open LOG, ">>/soapservice.log"; print LOG "ReportRequest:\n"; print LOG Dumper(@_); close LOG; return "ReportRequest"; } 1;

ReportResponse

package ReportResponse; use Data::Dumper; =pod =begin WSDL _ATTR result $boolean resultcode, 1 on success, 0 on failure _ATTR message $string error message (only on failure) =end WSDL =cut sub new { open LOG, ">>/tmp/bandwidthservice.log"; print LOG "Response\n"; print LOG Dumper(@_); close LOG; my $class = "ReportResponse"; my %in = @_; my $self = {}; $self->{result} => $in{result}; $self->{message} => $in{message}; bless $self, $class; return $self; } 1;

and, in case its any use, the wsdl

<?xml version="1.0" encoding="UTF-8"?> <!-- WSDL for http://api.dolphinmp.co.uk/new_bandwidth.cgi created by +Pod::WSDL version: 0.05 on Sat Jan 3 18:47:32 2009 --> <wsdl:definitions targetNamespace="http://api.dolphinmp.co.uk/Report" +xmlns:impl="http://api.dolphinmp.co.uk/Report" xmlns:wsdlsoap="http:/ +/schemas.xmlsoap.org/wsdl/soap/" xmlns:wsdl="http://schemas.xmlsoap.o +rg/wsdl/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" x +mlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns1="http://api.do +lphinmp.co.uk/Report"> <wsdl:types> <schema targetNamespace="http://api.dolphinmp.co.uk/Re +port" xmlns="http://www.w3.org/2001/XMLSchema"> <import namespace="http://schemas.xmlsoap.org/ +soap/encoding/" /> <complexType name="ReportResponse"> <sequence> <element name="result" nillabl +e="true" type="xsd:boolean"> <annotation> <documentation +>resultcode, 1 on success, 0 on failure</documentation> </annotation> </element> <element name="message" nillab +le="true" type="xsd:string"> <annotation> <documentation +>error message (only on failure)</documentation> </annotation> </element> </sequence> </complexType> <complexType name="ReportRequest"> <sequence> <element name="authuser" nilla +ble="true" type="xsd:string"> <annotation> <documentation +>valid username</documentation> </annotation> </element> <element name="authpass" nilla +ble="true" type="xsd:string"> <annotation> <documentation +>valid password</documentation> </annotation> </element> <element name="date_from" nill +able="true" type="xsd:dateTime"> <annotation> <documentation +>report start date (ISO YYYYMMDDTHH:MM)</documentation> </annotation> </element> </sequence> </complexType> </schema> </wsdl:types> <wsdl:message name="ReportRequest"> <wsdl:part name="Report" type="tns1:ReportRequest"> <wsdl:documentation>a ReportRequest object</ws +dl:documentation> </wsdl:part> </wsdl:message> <wsdl:message name="ReportResponse"> <wsdl:part name="ReportReturn" type="tns1:ReportRespon +se"> <wsdl:documentation>a ReportResponse object</w +sdl:documentation> </wsdl:part> </wsdl:message> <wsdl:portType name="ReportHandler"> <wsdl:operation name="Report" parameterOrder="Report"> <wsdl:documentation>Request or retreive a band +width report</wsdl:documentation> <wsdl:input message="impl:ReportRequest" name= +"ReportRequest" /> <wsdl:output message="impl:ReportResponse" nam +e="ReportResponse" /> </wsdl:operation> </wsdl:portType> <wsdl:binding name="ReportSoapBinding" type="impl:ReportHandle +r"> <wsdlsoap:binding style="rpc" transport="http://schema +s.xmlsoap.org/soap/http" /> <wsdl:operation name="Report"> <wsdlsoap:operation soapAction="" /> <wsdl:input name="ReportRequest"> <wsdlsoap:body encodingStyle="http://s +chemas.xmlsoap.org/soap/encoding/" namespace="http://api.dolphinmp.co +.uk/Report" use="encoded" /> </wsdl:input> <wsdl:output name="ReportResponse"> <wsdlsoap:body encodingStyle="http://s +chemas.xmlsoap.org/soap/encoding/" namespace="http://api.dolphinmp.co +.uk/Report" use="encoded" /> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="ReportHandlerService"> <wsdl:port binding="impl:ReportSoapBinding" name="Repo +rt"> <wsdlsoap:address location="http://api.dolphin +mp.co.uk/new_bandwidth.cgi" /> </wsdl:port> </wsdl:service> </wsdl:definitions>

just another cpan module author

Replies are listed 'Best First'.
Re: SOAP::Transport::HTTP::CGI checking wrong namespace for method
by kennethk (Abbot) on Jan 13, 2009 at 15:41 UTC

    I note that while you do use Report; in your script, you do not export any subroutines from your Report module. This means that main will not import the subroutine by default, and hence you won't find it in the main namespace. I've never used these modules before, but that seems to be what your error is pointing to. To export the Report subroutine, include the following code at the top of your Report module:

    package Report; use Data::Dumper; use strict; use warnings; use ReportRequest; use ReportResponse; use Exporter; our @ISA = (Exporter); our @EXPORT = qw(Report);

    and repeat that for both ReportRequest and ReportResponse. Better practice suggests you should use optional importing, which is done by changing @EXPORT to @EXPORT_OK and changing use Report; to use Report qw(Report);, as a user of your module may not necessarily want you modifying their namespace. See Exporter and perlmod for more details. You may also want to use vars in place of our for your global declaration for backward compatibility.

Re: SOAP::Transport::HTTP::CGI checking wrong namespace for method
by spatterson (Pilgrim) on Jan 14, 2009 at 11:24 UTC

    I needed 1 more change in addition to that suggested above by kennethk

    In the CGI script, change the dispatch_to setting to:

    my $server = SOAP::Transport::HTTP::CGI ->dispatch_to('lib', 'Report') ->handle;

    Where 'lib' is the directory containing the Report, ReportResponse & ReportRequest modules.


    just another cpan module author