Java and PHP interoperability - a web services fable
August 2, 2007
By definition Web Services (WS) have been designed to support interoperable Machine to Machine interaction over a network. In order to promote interoperability of Web Services, in 2002 the Web Services Interoperability Organization (WS-I) was founded which basically is an industry consortium that publishes profiles. A profile is a set of core specifications (SOAP, WSDL, etc.) in a specific version (SOAP 1.1, UDDI 2, etc.) with some additional requirements to restrict the use of the core specifications.
One of the three profiles you can actually find in their deliverables is the Basic Profile (official abbreviation is BP), which uses Web Services Description Language (WSDL) to enable the description of services as sets of endpoints operating on messages. Almost everybody is BP compliant: Glassfish Metro (JAX-WS RI), IBM WebSphere, Apache Axis 1.2+, JBossWS, ASP.NET 2.0.
The keyword here is “almost”…
My Project in a Nutshell
There is a team at my workplace that administers the Greek School Network Directory Service which currently contains more than 170,000 entries including school accounts for email and dialup access, teacher accounts and several student accounts. For various reasons that you can find at my colleague’s blog there was a need to perform LDAP operations over WSs – in fact we had to “Move LDAP writes to Web Services”.
The server-point
The server-point would actually perform the LDAP “writes” to the Directory Server and have a PHP WSs interface. For the PHP implementation, NuSOAP was chosen. NuSOAP is probably the most popular PHP SOAP implementation and is widely used, eg. in Amazon Web Services.
It is a group of PHP classes that allow developers to create and consume SOAP web services. It does not require any special PHP extensions. The current release version of NuSOAP at the time supports much of the SOAP specification. It can generate WSDL and also consume it for use in serialization. Both rpc/encoded and document/literal services are supported.
Here follows the skeleton of the PHP configuration for our deployment:
<?php
// The library
require_once('lib/nusoap.php');
// The services exposed
require_once('myinterface.functions.php');
$server = new soap_server();
$server->configureWSDL('Interface',"http://server/interface.php");
$server->wsdl->schemaTargetNamespace="http://server/interface.php?wsdl";
$server->register('ExistsUser',
array('SubsystemID' => 'xsd:integer', 'UserNumber' => 'xsd:string'),
array('Status' => 'xsd:integer',
'ErrorMessage' => 'xsd:string', 'UserName' => 'xsd:string'),
"http://server/interface.php",false,false,'literal',
'ExistsUser will return Status=0 if user does not exist,
Status=1 if user exists and set UserName accordingly,
Status=-1 and set ErrorMeessage if an error occurs. It
should be used to check if user exists before creating
username. UserNumber is the number the user has in the
subsystem. SubsystemID is the numerical ID of the subsystem');
$server->service($HTTP_RAW_POST_DATA);
?>
<Spoiler/>
NuSOAP was not BP compliant until a few days ago when CVS revision 109 of nusoap.php was introduced. The motivation for this article was the hard way we had to find out…
The client-point
The system my team was responsible for was the client which would have to wrap the WS related code into Java POJOs that would either be used as library code or through portlets. Implementing the functionality we needed in Jetspeed portlets was another issue but it goes beyond the scope of this post.
For the Java WS framework there were several candidates like Apache Axis and JAX-RPC but we choose JAX-WS 2.1, both because of its elegant programming model and the fact that in the newly published Java EE 6 proposal JAX-RPC will be proposed for future deprecation.
Our development platform was NetBeans 5.5 which provided a powerful wizard that starting from the WSDL that NuSOAP published, created the necessary Java stub code for our operations.
This is a small portion of the WSDL for the operation ExistsUser:
… <message name="ExistsUserRequest"> <part name="SubsystemID" type="xsd:integer" /> <part name="UserNumber" type="xsd:string" /> </message> <message name="ExistsUserResponse"> <part name="Status" type="xsd:integer" /> <part name="ErrorMessage" type="xsd:string" /> <part name="UserName" type="xsd:string" /> </message> … <operation name="ExistsUser"> <soap:operation soapAction="http://server/interface.php/ExistsUser" style="rpc"/> <input> <soap:body use="literal" namespace="http://server/interface.php"/> </input> <output> <soap:body use="literal" namespace="http://server/interface.php"/> </output> </operation> …
Of course to debug Web Services you need tools like:
- Wireshark which is a network protocol analyzer and can give you a print out of the complete TCP stream for a given set of WS calls and
- XMLSpy which for me is the easiest tool to create WS clients and debug your WS without writing code.
Of course the fact that the above development stack was found appropriate for our project doesn’t mean that it is suitable for every WS project. BTW a nice introduction on making similar technical decisions for Java projects can be found in the book Expert One-on-One J2EE Design and Development (AKA “The J2EE Bible”) by Rod Johnson in chapter 2 entitled “J2EE Projects: Choices and Risks”.
Holder <T> and Java’s heavy burden from C
Java Web Services make use of the Holder concept that was introduced since WSDL can specify interfaces that return multiple parameters (rather than just one single return value). In Java you can only return directly a single new object through a return value. To return multiple objects you have to return a collection object (which is still only a single object) or some other "container" object. To return a new object through a parameter, you need a holder object. Java’s object reference parameters only allow the modification of existing object instances.
Holders are necessary because the Java language designers stuck with the "pass-by-value" semantics of the C-family of languages. If a parameter is a simple type its value is copied, if it is an object instance the reference (value) to it is copied. As a result you are unable to modify the value in the original simple type or the reference (value) to the object from the called method (while you can change the passed instance, you cannot replace the passed instance). The holder mimics "pass-by-reference" semantics which in C/C++ is is done with a pointer-to-a-pointer and in C# directly through the ref keyword.
Some consider attempts to imitate call by reference in OO languages a sign of poor object-oriented design. Dale King points out that attempts to fake call by reference are usually a sign of poor object-oriented design: “a function should not be trying to return more than one thing”. He uses the term thing because it is proper to return more than one value (e.g. returning a Point that contains two values). If you are trying to return two values, the test he like to apply is whether you can come up with a logical name for the values as a group. If you can’t, you had better look to see if maybe you what you have is really two functions lumped together. WSDL never strived towards OO so that is where this mismatch comes from. It may have been a better idea for Java to wrap the WSDL method return value and all of the OUT parameters into a single wrapper object which becomes the return value of the Java interface method.
For our implementation we had the WS method:
@WebMethod(operationName = "ExistsUser", action = "http://server/interface.php/ExistsUser") public void existsUser( @WebParam(name = "SubsystemID", partName = "SubsystemID") BigInteger subsystemID, @WebParam(name = "UserNumber", partName = "UserNumber") String userNumber, @WebParam(name = "Status", mode = Mode.INOUT, partName = "Status") Holder status, @WebParam(name = "ErrorMessage", mode = Mode.OUT, partName = "ErrorMessage") Holder errorMessage, @WebParam(name = "UserName", mode = Mode.OUT, partName = "UserName") Holder userName);
This method would return the status in the client:
BigInteger status = new BigInteger("0", 10);
Holder statusHolder = new Holder(status);
…
// Actual call of the WS
port.existsUser(subsystemID, userNumber, statusHolder, errorMessage, userName);
…
status = statusHolder.value
System.out.println(status);
If you fire up the JAX-WS wizard in NetBeans and feed it with the WSDL you get 100% of the necessary code for an “almost” working demo.
Again the keyword is “almost”…
Bumps on the Road
If you have Java SE 6 installed and start of with NetBeans and JAX-WS there is a big chance you’ll run into problems. Java 6 ships with JAX-WS 2.0 API in rt.jar (so as we had to find out) you need to download the latest stable version of JAX-WS (2.1.1) and copy jaxws-api.jar and jaxb-api.jar into JRE endorsed directory. Obviously you still need other JAX-WS jars in your classpath.
The above problem was relatively simple to solve compared to the fact that statusHolder.value would not alter after the WS invocation no matter what!
Although the WS would get invoked properly on the server and we would receive a SOAP response:
<?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope …> <SOAP-ENV:Body> <ExistsUserResponse xmlns="http://server/interface.php"> <Status>1</Status> <ErrorMessage></ErrorMessage> <UserName>john</UserName> </ExistsUserResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
the @$%$# statusHolder.value would remain the same!
Weeks of debugging passed during which we had to dig into specs, JAX-WS RI code and forums to find out that:
- The SOAP response we got from NuSOAP was not compliant with BP since according to WS-I “An ENVELOPE described with an rpc-literal binding MUST place the part accessor elements for parameters and return value in no namespace.” In our case "Status" is in http://server/interface.php" namespace instead of no namespace, and
- Since JAX-WS RI 2.1 would encounter a response not valid according to BP, would simply ignore it without even spawning an error message.
Number one (1) has been reported to NuSOAP mailing list and we can confirm that it been fixed in CVS revision 109 of nusoap.php that should now conform to the WS-I Basic Profile (thanks Scott).
Number two (2) has been filled as an “enhancement” of JAX-WS RI for the version 2.1.3: “Ignore rpc/lit part accessors’ namespace, there are quite a few implementations that do not obey BP”.
The Morale of the Story
At this point I cannot help but to quote Dave Podnar’s Five Stages of Dealing with Web Services:
- Denial - It’s Simple Object Access Protocol, right?
- Over Involvement - OK, I’ll read the SOAP, WSDL, WS-I BP, JAX-RPC, SAAJ, JAX-P,… specs. next, I’ll check the Wiki and finally follow an example showing service and client sides.
- Anger - I can’t believe those #$%&*@s made it so difficult!
- Guilt - Everyone is using Web Services, it must be me, I must be missing something.
- Acceptance - It is what it is, Web Services aren’t simple or easy.
Social Bookmarks:
















August 3, 2007 at 12:25 am
I’d like to mention step 6 (as other have already done int the aforementioned blog):
Nirvana - find out that using XMLRPC or REST is exactly as simple and effective as the hype that got your attention in the first place
August 3, 2007 at 1:11 am
Knowing even more details about my project than can be described in a a blog, I have to agree with you that there would be no theoretical reason to go with a heavy-weight solution (XML-RPC could theoretically do fine). There would be though several practical ones like the fact that many of the implementations you mention require a larger up front commitment and risk and also the fact that until the last time I had seen the available PHP implementations, they were more of a POC than production SW. After your comment I will have to revisit these projects and see if they have evolved.
August 3, 2007 at 1:13 am
Web Services are both simple and easy if you use ASP.NET/C#…
Why did you choose Java?
August 3, 2007 at 6:47 am
Thanks for the detailed recount.
The first SOAP implementation I wrote was based on a SOAP 0.9.something spec. The spec was about 4 pages. Its spirit and intention could be easily understood, and it was quite possible for a single person to write code that implemented virtually everything in it.
Life was still pretty good with the 1.0 spec, the first submitted to W3C. However, as multiple people wrote implementations and tried to get them to work together, it became clear that the spec needed to be enhanced, and those who had worked on RPCs before knew that some sort of interface definition was necessary (which became WSDL).
Unfortunately, at this point SOAP was hijacked by (1) lovers of all things XML and (2) lovers of big-bang distributed computing (namely DCE and DCOM technology).
I was a developer on Apache SOAP, which implemented the SOAP spec, but not even WSDL, let alone the other specs that were already being envisioned by the people who gave birth to the Apache Axis project. As Microsoft, IBM, Sun, et al. implemented all the specs being generated, those of us who had worked on small SOAP implementations knew we had been outflanked and were fighting a losing battle. There was no way we could keep up.
I subsequently needed SOAP for a PHP project, discovered NuSOAP, got to know Dietrich through the mailing list, contributed code, and became a developer on the project. NuSOAP aims about as high as a small part-time team can: implement as much of SOAP 1.1 and WSDL 1.1 as people really seem to need, react to new needs and issues as best as possible, and hope that Microsoft and the rest of them don’t stop supporting these earlier specs.
August 3, 2007 at 4:13 pm
@Jon
Since the project was based on infrastructure that was already there (eg. Jetspeed portal) Java was the only solution, but even if I had to design the whole thing from scratch I would still make similar technical decisions.
The reasons why one would go open source or Java for WS in 2007 should be self-evident
August 8, 2007 at 10:18 pm
[...] Java and PHP interoperability - a web services fable « thoughts.iterator() (tags: synodinos.wordpress.com 2007 at_tecp java webservices) [...]
August 16, 2007 at 2:57 pm
@Jon
You completely missed the purpose of web services. It’s a “simple” way to communicate data between interfaces (here languages) through HTTP (eliminating firewall issues, etc.). An entire application written on a J2EE platform, running an untold number of servlets isn’t (and shouldn’t) jump and buy a Windows box so they can “easily” implement web services with C#.
Here are three reasons companies use Java are:
1. It can run on Linux. (don’t scream Mono here, it’s only a good theory).
2. It’s free.
4. It’s more popular for web development
When I’m writing a Windows desktop app, C# is my choice almost every time, but I’m specifically targeting Windows’ users.
November 5, 2007 at 5:11 pm
[...] read more | digg story [...]