Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

Using Perl's SOAP::Lite to talk to Python

by Ovid (Cardinal)
on Jul 17, 2002 at 22:26 UTC ( #182618=perlquestion: print w/replies, xml ) Need Help??
Ovid has asked for the wisdom of the Perl Monks concerning the following question:

I don't know squat about SOAP. Now I've been asked to write SOAP servers in Perl (using SOAP::Lite) and having a Python client be able to interact with them. I have a SOAP::Lite server that works just fine. My SOAP::Lite Perl client has no problem calling new() and then making method calls. However, the actual client needs to be written in Python :( My coworker is using ZSI for his Python SOAP client. While my Perl code works, he can't seem to do anything with his Python client.

This is my server code:

#!D:/perl/bin/perl.exe -w use strict; use SOAP::Transport::HTTP; SOAP::Transport::HTTP::CGI -> dispatch_to( 'Temperatures' ) -> handle; package Temperatures; sub f2c { my ( $self, $f, $format ) = @_; my $fmt = $format || $self->{_format}; return sprintf $fmt, (5/9 * ($f - 32)); } sub c2f { my ( $self, $c, $format ) = @_; my $fmt = $format || $self->{_format}; return sprintf $fmt, (32 + $c*9/5); } sub format { my ( $self, $format ) = @_; $self->{_format} = $format if $format; $self->{_format}; } sub new { my $class = shift; bless { _format => '%.2f' }, $class; }

And this is my client (I stripped out the HTML part). Notice that I appear to be instantiating a new Temperature object and then calling methods on it. However, my co-worker cannot do anything with the returned data.

#!D:/perl/bin/perl.exe -wT use strict; use CGI qw/:standard/; use SOAP::Lite +autodispatch => uri => 'http://192.168.1.26/Temperatures', proxy => 'http://192.168.1.26/soap/temper.cgi'; my $temp = param( 'temp' ); my $type = param( 'type' ) || ''; my $format = param( 'format' ) || ''; $temp = '' if ! defined $temp; ($temp) = $temp =~ /([\d.]+)/; ($type) = $type =~ /([cf])/; my $temp_result; if ( $temp ) { my $temperature = Temperatures->new; $temperature->format( $format ) if $format; $temp_result = $type eq 'c' ? $temperature->c2f( $temp ) : $temperature->f2c( $temp ); }

Here's the XML response he gets when he calls new():

<SOAP-ENV:Body> <namesp1:newResponse xmlns:namesp1="http://192.168.1.26/Temperatures +"> <Temperatures xsi:type="namesp1:Temperatures"> <_format xsi:type="xsd:string">%.2f</_format> </Temperatures> </namesp1:newResponse> </SOAP-ENV:Body>

Frankly, I have no idea where to look next. I've done a lot of Web searching, but to no avail. Since I know nothing about SOAP, is it possible that I am just totally misunderstanding the way things work? Is it not possible for a Python client to call a Perl constructor via SOAP? If that's the case, does this mean that the Simple Object Access Protocol isn't really for accessing objects?

Note that if I recode everything in a functional style, Python has no problem communicating with my server.

Cheers,
Ovid

Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

Replies are listed 'Best First'.
Re: Using Perl's SOAP::Lite to talk to Python
by mitd (Curate) on Jul 18, 2002 at 00:10 UTC
    The problem is you are asking SOAP to do more than it is capable of. SOAP is not a distributed object framework it is Simply an Object Access Protocol :).

    Think of your methods on the service (server) side as services or helpers for a remote client object.

    So with this in mind have your Python friend create a class on his client side that uses your services/methods to help his class fulfil its needs.

    The idea of Object/Class Services is a powerful one. and takes a little getting use too but as a guy who has spent the last 3 months in Java Enterprise Bean hell I really have come to appreciate the simplicity of SOAP and the idea of services vs full blown distribute objects.

    Hope this helps.

    BTW, on a technical note the reason your code did not work as expected is you tried to pass what in reality was a reference to an object which SOAP just can't do.

    mitd-Made in the Dark
    'Interactive! Paper tape is interactive!
    If you don't believe me I can show you my paper cut scars!'

      Well you can actually do this, but the client needs to support using the object as a Flyweight object. This is exactly why the Perl client worked, as it does support flyweights directly - most (maybe all) other SOAP implementations don't, so you have to implement that yourself.

      Basically all a flyweight does in this case is holds an object ID, and on the server end the SOAP server holds a list of pre-constructed objects matched to IDs. When your client wants to call a method on that object-id, AUTOLOAD kicks in and asks the remote end for the right method on the object matching that id value.

      Then there's some stuff about Object reaping that you don't need to worry too much about.

      Hope that helps - the soaplite list is a really good place to ask these sorts of questions.

        The fact that Ovid's app broke as soon as a non-SOAP::Lite client was used is proof to me that using these SOAP::Lite specific features is only a good idea in closed environments.

        Its inevitable that folks will use SOAP to build' yet another distributed object framework'. Eric Raymond points out in this open letter why this probably not a good idea.

        mitd-Made in the Dark
        'Interactive! Paper tape is interactive!
        If you don't believe me I can show you my paper cut scars!'

Re: Using Perl's SOAP::Lite to talk to Python
by runrig (Abbot) on Jul 17, 2002 at 22:41 UTC
    Is there no way for him to create an object from that data structure (looks like he needs to research how to make his client behave)? Anyway, if this is the real problem and not just an example, I'd do the thing in one call rather that three method calls. You're making three trips to the http server when it you could do it in one.

      This is just sample code. The actual application will be much larger and will probably require session ids so that a SOAP "conversation" can be started.

      As far as I can tell, he has stopped working on his end of it (from the OO point of view). I know nothing of Python, so I really can't help him out there. I could post his Python code, but am leery of starting a flame war :)

      Cheers,
      Ovid

      Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

Re: Using Perl's SOAP::Lite to talk to Python
by jepri (Parson) on Jul 17, 2002 at 23:46 UTC
    I have a very vague memory of reading something that made me feel slightly cheated because I couldn't access objects properly over SOAP. I'll see if I can dig it up, but don't hold your breath.

    Update: I still haven't been able to find any references to using objects written in a different language. I'm beginning to think that it would be very difficult to write such code, since it would involve, e.g. a Java server translating a Python object reference into a Java reference. For a language without Perl's flexible symbol table it would be quite difficult and messy.

    ____________________
    Jeremy
    I didn't believe in evil until I dated it.

      I have coerced Python into talking to a Perl SOAP server in the past (about 1 year ago), but the code is long gone. The main problem i had was with complex Perl structures. The reason i am replying, however, is because i did indeed have troubles coercing Python into dealing with a complex Perl data structure.

      For those who don't already know, a reference/data structure in one language is translated to another language through SOAP via XML elements. For example, here is what a SOAP::Lite string looks like:

      $arg = 'Hello SOAP' <s-gensym3 xsi:type="xsd:string">Hello SOAP</s-gensym3>
      Python's SOAP.py library encodes a string like so:
      <Result xsi:type="xsd:string">Hello SOAP</Result>
      Here is a Perl array (or hash):
      @arg = qw(foo bar baz qux) <s-gensym3 xsi:type="xsd:string">foo</s-gensym3> <s-gensym5 xsi:type="xsd:string">bar</s-gensym5> <s-gensym7 xsi:type="xsd:string">baz</s-gensym7> <s-gensym9 xsi:type="xsd:string">qux</s-gensym9>
      Which is very similar to a Python array:
      <item xsi:type="xsd:string" id="i3" SOAP-ENC:root="0">foo</item> <item xsi:type="xsd:string" id="i4" SOAP-ENC:root="0">bar</item> <item xsi:type="xsd:string" id="i5" SOAP-ENC:root="0">baz</item> <item xsi:type="xsd:string" id="i6" SOAP-ENC:root="0">qux</item>
      But the problem creeps in when you start dealing with references to arrays and hashes:
      $arg = [foo=>bar=>baz=>'qux'] <SOAP-ENC:Array SOAP-ENC:arrayType="xsd:string[4]" xsi:type="SOAP-ENC: +Array"> <item xsi:type="xsd:string">foo</item> <item xsi:type="xsd:string">bar</item> <item xsi:type="xsd:string">baz</item> <item xsi:type="xsd:string">qux</item> </SOAP-ENC:Array> $arg = {foo=>bar=>baz=>'qux'} <s-gensym3 xsi:type="namesp1:SOAPStruct"> <foo xsi:type="xsd:string">bar</foo> <baz xsi:type="xsd:string">qux</baz> </s-gensym3>
      If i recall correctly, Python's SOAP.py module handles these fine, but chokes on nested references, such as:
      $arg = {foo=>{bar=>{baz=>['qux']}},bar=>[bar=>{baz=>'qux'}]} <s-gensym3 xsi:type="namesp2:SOAPStruct"> <foo xsi:type="namesp2:SOAPStruct"> <bar xsi:type="namesp2:SOAPStruct"> <baz SOAP-ENC:arrayType="xsd:string[1]" xsi:type="SOAP-ENC:Array"> <item xsi:type="xsd:string">qux</item> </baz> </bar> </foo> <bar SOAP-ENC:arrayType="xsd:ur-type[2]" xsi:type="SOAP-ENC:Array"> <item xsi:type="xsd:string">bar</item> <item xsi:type="namesp2:SOAPStruct"> <baz xsi:type="xsd:string">qux</baz> </item> </bar> </s-gensym3>
      But, that was a year ago and maybe ZSI is more robust. I have no idea how Java handles such issues. My excitement about SOAP was quelled upon hearing such news reported at nodes like SOAP::Lite and Security (Phrack #58), but now that these security issues have allegedly beed fixed (see Soap::Lite Security Update - Version 0.55 Released), i think i'll start delving back into SOAP. Maybe i'll even have time to write a tutorial on Perl communicating with Java and Python if i am successful. :)

      Oh, i would like to add that working with SOAP::Lite really allowed me to understand Perl Objects. Before, i always thought of objects as containers for methods and attributes. Whenever you slung an object around, it carried its methods and attributes as luggage, so to speak. I was shocked to find out that when you transfer a [Perl] object across the SOAP wire, only the attributes went with it. So, how does a client access an object's methods? It really doesn't - instead it sends a request to the server to access that method, and the server sends the results. This translates to everyday Perl OO when you sling an object reference around, you are only transfering a ref to the attributes - the methods are accessed through the symbol table, not the reference. Likewise, when you observe a Data::Dumper dump of an object. You don't see the methods, just the 'attributes'.

      jeffa

      L-LL-L--L-LL-L--L-LL-L--
      -R--R-RR-R--R-RR-R--R-RR
      B--B--B--B--B--B--B--B--
      H---H---H---H---H---H---
      (the triplet paradiddle with high-hat)
      

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://182618]
Approved by grep
Front-paged by mitd
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (9)
As of 2018-07-16 20:39 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    It has been suggested to rename Perl 6 in order to boost its marketing potential. Which name would you prefer?















    Results (349 votes). Check out past polls.

    Notices?