Full disclosure: I once wrote SOAP services, I even wrote WSDL for them. Actually, it was while writing WSDL that I decided that SOAP was really complicated for something I didn’t want to spend too much time thinking about. That lingering ‘smell’ and the resulting server load when we were servicing 1000s of fine grained RPC requests was about the time I began to really hate SOAP.
Fast forward to now, and I’m a huge fan of infinite resources and finite actions, aka REST. Why? My experiences with well designed REST interfaces is that they become intuitive once you know the domain model that the service is exposing. You ask for domain information in a kind of WYSIWIG (what you SAY is what you get) way, and that’s that. Yes, you can still maim your server with fine grained calls, but that is an orthogonal issue.
While I think that most of the rest of the world feels the same way about REST vs SOAP, i.e. Amazon AWS serves 85% of their requests over REST, that (sadly) is not the case. This weekend, I found myself in the unfortunate position of having to make a bunch of SOAP calls to a service that publishes documents. While most services circa 2008 would use RSS/Atom to do this, these guys haven’t quite made the conceptual leap. Maybe they’re still trying to figure out the whole series of tubes thing, I know I am.
The thing is that I’ve killed the brain cells that were responsible for all things SOAP. I mean it was more a case of ‘put them out of their misery with a few stiff pints’, but death is death, and that information had left my building. So I amped up the metal tunes and googled away for a while.
My (very modest) goals for the weekend, given that it was really nice out and I wanted to play with my kids and ride my bike:
(1) generate client code from the company’s WSDL file.
(2) do this as part of a build process.
Pretty basic stuff, I needed to find a Java client generation tool and hook it into Maven. I figured that lots of people had done this already and I would be standing on the shoulders of giants. Well, that turned out to be the case, sort of…
One problem I have with WS* in general is that there are so many different tools claiming to do the same thing. In the case of WS*, there are many different tools released by Apache that all generate clients from WSDL using their own baked versions of wsdl2java, a tool used to generate the server proxies from WSDL.
Muse: “The Apache Muse Project is a Java-based implementation of the WS-ResourceFramework (WSRF), WS-BaseNotification (WSN), and WS-DistributedManagement (WSDM) specifications. It is a framework upon which users can build web service interfaces for manageable resources without having to implement all of the “plumbing” described by the aforementioned standards.” WOW. Still reeling from all the T&FLAs in that sentence. I think Muse might be helpful, but I don’t know how much I end up getting ‘for free’.
Axis: Apache Axis is an implementation of the SOAP (“Simple Object Access Protocol”) submission to W3C. Hey, that sounds pretty straightforward. But wait, that doesn’t really tell me much! Do they handle client and server side dev? Also, what is the difference between Axis and Axis2?
CXF: Apache CXF is an open source services framework. CXF helps you build and develop services using frontend programming APIs, like JAX-WS. These services can speak a variety of protocols such as SOAP, XML/HTTP, RESTful HTTP, or CORBA and work over a variety of transports such as HTTP, JMS or JBI. Hmmm, again with the TLAs. Also, I don’t need the swiss army knife here, I’m not writing a multi protocol service, I’m writing a dumb as crap service consumer.
All three frameworks above claim to have something called wsdl2java, which does what it says. Lacking any other differentiation points, I decided to try them all. I was taking the “I don’t want to know sh*t about the underlying technology approach”. In other words, I really didn’t care about WSDL, I just wanted to generate some damn code and be done with it.
Try #1: Muse: whoops, it didn’t like my WSDL because there were 2 port elements:
~/muse/bin/wsdl2java.sh -wsdl newsdatasecure.asmx.xml -proxy
java.lang.RuntimeException: [ID = 'OnePortPerWSDL'] The resource inspector can only process WSDLs with one port element. The WSDL can have multiple portTypes, but only one concrete service and port.
Wait a minute. WTF is a port element? Damn, I need to read up on WSDL. (Later….) OK, here are my notes.
Next Up: Apache CXF or Axis? Who’s got more Maven Love?
So it was pretty obvious that short of hacking the provider WSDL, I wasn’t going to get the love I needed from Muse. That left two choices, CXF, which felt very framework-wonkish, and Axis/Axis2, which felt very vague. I decided to step back a little bit and see what kind of support both approaches had in the build world. After all, I wanted to integrate client side codegen into a build process, where WSDL changes would immediately show up as compilation failures.
This was the quintessential Yak Shaving exercise. Which might be a great way to spend a cold, blustery day, but not a sunny (in Seattle!?!) 75 degrees day. Turns out CXF and Axis2 have maven plugins.
Axis2 has the wsdl2code plugin. CXF has a wsdl2java plugin. At this point I was thinking I was out the door. My previous maven experiences with integrating plugins were largely a cut, paste, and go exercises, using mvnrepository.com or other maven POM file syntax I could get from the documentation.
I tried CXF and quite simply couldn’t get it to work. Specifically mvn generate-sources, or any of the variants proposed in various bug lists didn’t work.
My next option was Axis2. I got it working, but only after some effort detailed below.
The wsdl2code plugin from Axis2 claims to generate code as long as you simply follow the plugin instructions and insert the following plugin config information into your POM:
<build> <plugins> <plugin> <groupId>org.apache.axis2.maven2</groupId> <artifactId>axis2-wsdl2code-maven-plugin</artifactId> <executions> <execution> <goals> <goal>wsdl2code</goal> </goals> </execution> <configuration> <packageName>com.foo.myservice</packageName> </configuration> </executions> </plugin> </plugins> </build>
Unfortunately, that isnt valid POM schema. You need to embed the configuration element in the execution element:
<build> <plugins> <plugin> <groupId>org.apache.axis2.maven2</groupId> <artifactId>axis2-wsdl2code-maven-plugin</artifactId> <executions> <execution> <goals> <goal>wsdl2code</goal> </goals> <configuration> <packageName>com.foo.myservice</packageName> </configuration> </execution> </executions> </plugin> </plugins> </build>
That at least produces a valid POM. However, when I ran
mvn clean install
I recieved the following error:
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
CRAP! You mean the plugin is puking because it can’t resolve a dependency? Christ, isnt this the stuff that maven is supposed to resolve?
I did some more thread googling, and found here that I needed to add the following dependency as well as change the groupID and add a specific version number:
Now I had WSDL code generated in Maven, but that code didn’t actually compile…hmmm. No good.
My last gasp effort to generate some client stubs was to use Axis, which has noted here, has now been replaced with Axis2.
However, desperation leads to an open attitude, and when I downloaded axis-1.4, and did the following:
java -cp ./lib/axis.jar:./lib/commons-discovery-0.2.jar:./lib/commons-logging-1.0.4.jar:./lib/saaj.jar:./lib/jaxrpc.jar:
I generated WSDL that actually compiled, and ran. Moral of the story? Stay the F*ck away from SOAP, it’s 2008 after all!