Stateful Web Services - They really work!

by Scott Balmos

About a month ago, I wrote a blog entry here discussing stateful web services, and how EJB3 more or less removed the commonly used J2EE hack, in using the serialized EJB2.1 Stateful Session Bean Handle as a session token of sorts. I mentioned how JAX-WS added support for a WS-Addressing-based stateful SOAP endpoint - the first truly “automated” and SOAP-compliant manner of providing sessions in SOAP. Now… we have sample code! It really is dead-simple, a testament to the WSIT group (Project Tango), working between Sun and Microsoft to make JAX-WS and the Windows Communication Framework in .Net 3.0 play nicely.

First, the client code. This is run under JAX-WS 2.1.2 running in Glassfish v2 Beta 2. As part of the deployment, we won’t run wsgen to build the WSDL file or server artifacts, leaving that to deployment time auto-generation (all hail JEE 5). So, you can also run this example in WebLogic 10, if you updated the JAX-WS components in it to at least 2.1 (WL10 comes with JAX-WS 2.0 if I remember correctly). The JBoss crowd probably will work also under a JBoss 5 beta, as long as you use the JAX-WS libs. JBossWS will not work (at least not as pretty).

The stateful service:

Nothing glamorous here. This is a near-direct rip from the original sample code that Kohsuke provided in his blog back in October of last year (http://weblogs.java.net/blog/kohsuke/archive/2006/10/stateful_web_se.html) - thanks Kohsuke for the great writeup back then!

Now the session factory service:

Again, nothing glamorous, nearly a rip again from the original writeup.

Note that I prefer to take all the defaults, which usually are sane, omitting all of the unnecessary @WebMethod, @SOAPBinding, and other annotations. Compile everything (referencing lib/webservices-rt.jar and lib/javaee.jar in Glassfish), package it up in a WAR named SOAPTest.war, putting the classes under WEB-INF/classes, and deploy the WAR. Off you go with the server side of things. No WSDL generation, no web.xml, nothing.

The fun comes with the C# client. You’ll need the .Net Framework 3.0 and the Microsoft Windows SDK for Windows Vista (a slight misnomer, since this SDK also handles .Net 3.0). It’s the SDK that includes the ever-important updated version of SvcUtil.exe .

First, run the following two SvcUtil.exe commands to build the client proxies:

C:\Program Files\Microsoft SDKs\Windows\v6.0\Bin\SvcUtil.exe
/namespace:*,ConsoleApplication1 /config:Client.exe.config http://localhost:8080/SOAPTest/SOAPSessionFactoryService?wsdl

C:\Program Files\Microsoft SDKs\Windows\v6.0\Bin\SvcUtil.exe
/namespace:*,ConsoleApplication1 /mergeConfig /config:Client.exe.config http://localhost:8080/SOAPTest/SOAPSessionService?wsdl

This gives you Client.exe.config, SOAPSessionFactoryService.cs, and SOAPSessionService.cs . Note the use of /mergeConfig on the second run.

This is so that the endpoint metadata of the second service is merged into the existing config file. Otherwise, it overwrites the metadata from the first run (e.g. the metadata of the SOAPSessionFactoryService).

Also, the /namespace switch maps all XML namespaces to the ConsoleApplication1 CLR namespace. It just keeps the code more organized. You’ll get a warning on the second run about not handling the UsingAddressing optional WSDL extension. That’s okay, ignore it.

Finally, the actual client code:

The cool magic happens in the first three lines. First, we get a reference to our factory service. And then we create two separate sessions. Note the second parameter, which takes a System.ServiceModel.EndpointReference type, which is near exactly what is returned by our startSession() method in the server (it returns an EndpointReference10 type, corresponding to the exact version of WS-Addressing we’re using). A simple ToEndpointAddress() call later, and we’re off and going. We now have, in three lines of code, two separate SOAP sessions going. No XML manipulation. No SOAP header addition.

Nothing. Magic, isn’t it?

Compile everything, referencing the System.ServiceModel.dll assembly in the .Net Framework 3.0, and fire away.

It gets even easier if you use Visual Studio 2005 and install the November 2006 Visual Studio 2005 extension for .Net 3.0 . These are little tidbits that are unsupported by MS, but are backports from the upcoming Orcas release of Visual Studio. If you have these, then life’s really good. Bypass the SvcUtil commands, and notice in the Project menu, right below Add Web Reference, is now Add Service Reference. Need I say more? :)
One major gotcha: Remember to always use the concrete generated FooServiceClient class, *NOT* the FooService interface, when declaring your service variable. If you’re like me, following “proper” OO, you try to always use what looks like an interface when declaring variables, in case there are multiple concrete classes. DO NOT DO THAT in this case. I found out that the service interface is written in unwrapped document/literal form, while the actual client class is written in standard document/literal/wrapped form. Thus, if you use the interface, you’d have to mess with the whole unwrapped mess of creating explicit body message types, using the return message type, etc. See below for the hideousness of one call to startSession():

Save yourself the pain, and go against your well-developed coding instincts in this case. Use the concrete service class in your declarations.

So there you have it. A dead-simple server, with no XML voodoo, with a dead-simple client, with its own lack of voodoo or messiness. Just a clean API like we’re usually used to. And in the background, we’re using “proper SOAP”, with WS-Addressing taking care of the gory mess of keeping track of which session goes where.

2 Responses to “Stateful Web Services - They really work!”

  1. Arun Ramakrishnan Says:

    This is lovely concept.
    You should check out Apache Muse. A full implementation of a number of WS-* specifications.
    Addressing, notifications, metadata exchange and so on.
    Also check out WSDM which is a specification that covers a lot of this. Web Services Distributed Management.

  2. Phil Barr Says:

    Having used the “Add Service” functionality you mention, I’ve noticed that depending on the WSDL you import, sometimes the code generated won’t compile. This seems to be due to duplicate code being generated, so I’ve just been commenting it out. Seems to work so far….!


Leave a Reply