rekoil (rekoil) wrote in perl,
rekoil
rekoil
perl

SOAP::Lite madness!

There's obviously something very fundamental I'm missing when if comes to object-oriented programming using SOAP::Lite.



First off, this is how I'm used to building objects locally - nothing fancy here:

/usr/bin/perl -w

BEGIN   {

   package TestClass;

   sub new {
       my $class = shift;
       my $self = {};
       $self->{testval} = "test";
       return (bless ($self, $class));
   }

   sub test    {
       my $self = shift;
       return $self->{testval};
   }
}

my $testobj = new TestClass;

print $testobj->test() . "\n";


Running this returns the "test" string as it should.

However, the same function adapted for a SOAP call using SOAP::Lite gives me errors with similar syntax:

Server side:

#!/usr/bin/perl -w

use strict;

use SOAP::Transport::HTTP;

my $daemon = new SOAP::Transport::HTTP::Daemon (LocalPort => 8080);
$daemon->dispatch_to('Test');
$daemon->handle;

BEGIN   {
       package Test;

       sub new {
               my $class = shift;
               my $self = {};
               $self->{testval} = "test";
               return (bless ($self, $class));
       }

       sub test        {
               my $self = shift;
               return $self->{testval};
       }

}


Client side:

#!/usr/bin/perl -w
use strict;
use SOAP::Lite;

my $testobj = new SOAP::Lite
   ->ns('http://test.server.com:8080/Test')
   ->proxy('http://test.server.com:8080');

my $query = $testobj->test();

if ($query->fault)  {
          print "Error: (" . $query->faultcode() . ") " . $query->faultstring() . "\n";
}

print $query->result . "\n";


When I run this I get:

Error: (soap:Server) Can't use string ("Test") as a HASH ref while "strict refs" in use at soaptestserver2.pl line 23.


Sure enough, if I add the line "print Data::Dumper($self) in the test() function, I get:

$VAR1 = 'Test';


So it's obvious that no actual object is getting passed around, just the class name.

I'm obviously missing something rather fundamental here. Is it even possible to do what I'm trying to do? If so, what am I doing wrong?


  • Post a new comment

    Error

    default userpic
  • 6 comments
The only instance of "Test" (upper case T) I see is here:

$daemon->dispatch_to('Test');

...could it be that dispatch_to() expects and object and not a string?
I've never used SOAP, in any form, on any system, or anything, so please take this comment with a grain of salt, but how does $daemon->dispatch_to(…) know what method is the constructor? Does it require new, à la C++ and Java and such? Because that's not a very Perl-y restriction. Or, does it do some sort of code analysis and see which method uses bless? That would be error-prone, and also very complicated for no reason.

From the POD embedded in SOAP/Transport/HTTP.pm, my impression is that if you just pass in the name of a package, it will arbitrarily (not really arbitrarily, but arbitrarily from the programmer's standpoint) choose a method to use as the constructor. In your case, it's apparently choosing test. And, as you're obviously aware from the way you wrote your new, the first argument to a constructor (or any method invoked as Package_name->method_name) is the name of the package, as a string.

… all of which is a long-winded way of saying that I think you want to write $daemon->dispatch_to('Test::new'); instead of $daemon->dispatch_to('Test');.

Oh, and RTFM. :-P
I got it working - you are correct that the new() constructor wasn't being called, but not for the reason you suspect - the problem was that I wasn't calling the Test package. By using autodispatch, I was able to direct the "new Test" method across the network as a SOAP call, and I'm now working:


#!/usr/bin/perl -w

use strict;
use SOAP::Lite;
use Data::Dumper;

use SOAP::Lite +autodispatch =>
ns => 'http://test.server.com:8080/Test',
proxy => 'http://test.server.com:8080';

my $soap = new Test;

print $soap->test() . "\n";
Glad to hear it.

From my reading of the doc, though, it still seems that my suggestion should work; did you try it and find that it didn't? (Obviously you're under no obligation to try any suggestions, but you've piqued my curiosity. :-)
Yes it works

the code i used is
use strict;

use SOAP::Transport::HTTP;

my $daemon = new SOAP::Transport::HTTP::Daemon (LocalPort => 8899);
my $var = new Test();
$daemon->dispatch_to($var);
$daemon->handle;

BEGIN {
package Test;

sub new {
my $class = shift;
my $self = {};
$self->{testval} = "test";
return (bless ($self, $class));
}

sub test {
my $self = shift;
return $self->{testval};
}

}


Regards
Sooraj
...блок BEGIN исполняется как только так сразу (чуть ли не при компилляции) и тут же уничтожается интерпретатором. т.е. строчка $daemon->dispatch_to('Test') просто напросто обращается в пустоту - нету никакого Test. вот если бы он вынес "package Test;" и определение функции test за BEGIN, то наверно сработало бы.