Is SOAP Easy Enough in Java?

by chromatic

Related link: http://use.perl.org/~geoff/journal/9844




SOAP::Lite makes web services amazingly easy in Perl. They're so easy, in fact, that you can focus on just getting your job done instead of thinking "Hey, I'm writing a web service." That's kind of Perlish.



I once worked a project with a wxPython frontend communicating with a Perl backend. My initial tests were wonderful, going from Perl to Perl through SOAP::Lite. As Geoff points out, this idiom Just Works:


use SOAP::Lite
+autodispatch =>
uri => 'http://my.server.com/My/Class',
proxy => 'http://my.server.com/soap';

my $o = My::Class->new('bar');
print $o->method('drink');


For the non-Perlers in the audience and the terminally lazy, this means to use SOAP::Lite, autodispatching unfound methods in the My::Class class to the remote server. It creates a new object of My::Class with the new() call, then calls method() on it. Very handy.



Of course, neither of the two SOAP toolkits the Python programmer could use supported this. To be fair, I'm not entirely certain it's part of the SOAP spec. Of course, we dumped the raw XML from both types of requests (Perl <-> Perl and Perl <-> Python), compared it, and could find no discernable difference.



We ended up passing a session token around as the first argument of all method calls. This was very easy to support with my authentication proxy approach.



Still, I agree with Geoff. There must be an easy way to accomplish this in Java or Python, mustn't there?



Have a solution? We're all ears.


5 Comments

anonymous2
2003-01-09 14:28:07
Yes, Electric Glue is pretty easy.
http://www.themindelectric.com/glue/


Basically you bind to the service and then start executing its methods.


Example:



// bind to the service
IProxy service = Registry.bind("http://server/service.wsdl");


// call service methods
List list = service.invoke("getNames");

rubys
2003-01-09 18:37:53
Apache Axis
This would be easier with WSDL, but using the JAX RPC DII interface would look something like this:


import javax.xml.namespace.*;
import javax.xml.rpc.*;


public class test {
public static void main(String[] args) throws Exception {
ServiceFactory factory = ServiceFactory.newInstance();
Service service = factory.createService(null);
Call call = service.createCall();


call.setTargetEndpointAddress("http://my.server.com/soap");
call.setOperationName(new QName("http://my.server.com/My/Class","method"));
call.invoke(new Object[] {"drink"});

}
}

anonymous2
2003-01-10 06:04:44
RE: Apache Axis
the Axis solution looks pretty clean. however, just calling methods isn't the problem. the class I presented requires you to call new() (with some arguments) which returns an object with some attributes. calling method() (with some arguments) then returns a value based on those attributes. from what I can tell, you're just calling method() directly outside of the constructor.


I could be wrong, but I can't actually run the code due to "NoClassDefFoundError: javax/naming/spi/ObjectFactory" errors. it compiles ok, though.


at any rate, I appreciate you taking the time to post at least the start of something. thanks.


--Geoff
rubys
2003-01-10 19:45:19
RE: Apache Axis
Object references must be a SOAP::Lite convention. If you can make available traces of what goes over the wire, I can try to find an Axis equivalent.


I ran the Axis sample I provided - it actually generated a request. javax.naming.spi.ObjectFactory
is part of the JDK, so I'm not sure why you can't locate it.

geoff
2003-01-13 06:01:06
RE: Apache Axis
ok, I upgraded to jdk 1.4.1 and got the example to work. changing the final line to


System.out.println(call.invoke(new Object[] {"drink"}));


prints "new: ", so we're getting closer :)


here is the trace of the envelopes when it's SOAP::Lite to SOAP::Lite (though the Content-Length isn't right since I'm editing the server name):



POST http://my.server.com/soap
Accept: text/xml
Accept: multipart/*
Content-Length: 526
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://my.server.com/My/Class#new"


<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/1999/XMLSchema" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><namesp1:new xmlns:namesp1="http://my.server.com/My/Class"><c-gensym3 xsi:type="xsd:string">bar</c-gensym3></namesp1:new></SOAP-ENV:Body></SOAP-ENV:Envelope>
HTTP/1.1 200 OK
Connection: close
Date: Mon, 13 Jan 2003 13:47:22 GMT
Server: Apache/1.3.24 (Unix) mod_perl/1.26
Content-Length: 636
Content-Type: text/xml; charset=utf-8
Client-Date: Mon, 13 Jan 2003 13:37:33 GMT
Client-Response-Num: 1
SOAPServer: SOAP::Lite/Perl/0.55


<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:namesp2="http://namespaces.soaplite.com/perl" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/1999/XMLSchema"><SOAP-ENV:Body><namesp1:newResponse xmlns:namesp1="http://my.server.com/My/Class"><My__Class xsi:type="namesp2:My__Class"><_new xsi:type="xsd:string">bar</_new></My__Class></namesp1:newResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>
POST http://my.server.com/soap
Accept: text/xml
Accept: multipart/*
Content-Length: 675
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://my.server.com/My/Class#method"


<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:namesp3="http://namespaces.soaplite.com/perl" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/1999/XMLSchema" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><namesp2:method xmlns:namesp2="http://my.server.com/My/Class"><My__Class xsi:type="namesp3:My__Class"><_new xsi:type="xsd:string">bar</_new></My__Class><c-gensym7 xsi:type="xsd:string">beer</c-gensym7></namesp2:method></SOAP-ENV:Body></SOAP-ENV:Envelope>
HTTP/1.1 200 OK
Connection: close
Date: Mon, 13 Jan 2003 13:47:24 GMT
Server: Apache/1.3.24 (Unix) mod_perl/1.26
Content-Length: 906
Content-Type: text/xml; charset=utf-8
Client-Date: Mon, 13 Jan 2003 13:37:34 GMT
Client-Response-Num: 1
SOAPServer: SOAP::Lite/Perl/0.55


<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:namesp2="http://namespaces.soaplite.com/perl" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/1999/XMLSchema"><SOAP-ENV:Header><namesp3:My__Class xmlns:namesp3="http://namespaces.soaplite.com/header" xsi:type="namesp2:My__Class"><_new xsi:type="xsd:string">bar</_new></namesp3:My__Class></SOAP-ENV:Header><SOAP-ENV:Body><namesp4:methodResponse xmlns:namesp4="http://my.server.com/My/Class"><s-gensym7 xsi:type="xsd:string">new: </s-gensym7><s-gensym9 xsi:type="xsd:string">bar</s-gensym9><s-gensym11 xsi:type="xsd:string">, method: beer</s-gensym11></namesp4:methodResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>


I hope this helps


--Geoff