JAX-WS Handlers

Web service handlers are not a new concept. One obvious issue with developing a web service is catering for common behaviour. If each operation requires the same set of services, such as security or logging, how do you provide those services? A web service handler is the solution for both common client-side as well as server-side behaviour. Handlers allow you to process SOAP messages before and after the message is sent through the network.

Web service handlers are a part of the JAX-RPC specification, and the JAX-WS specification caters for the same concept, but in a slightly different way. There are some handler examples on the net but most just deal with logging the request and response. This article will introduce something a bit more complicated, putting a Software As A Service handler on the Dice web service. For an overview of JAX-WS handler infrastructure, as well as the difference between SOAPHandler and LogicalHandler see the excellent Handlers Introduction on java.net.

In this Dice SAAS example JDeveloper 11g Technology Preview 2 is used. It supports JAX-WS and has an embedded OC4J server for running the web service. To get started, download the Dice project, which is ready to go with the annotated web service code and add it to your JDev workspace. Details about the Dice web service and how it is constructed can be found in a previous article.


The first thing to do is test that the web service works in your environment. To do this launch the Test Web Service utility by right clicking on the Dice web service in the Application Navigator.

This will start the embedded OC4J server, deploy the web service and launch the HTTP Analyzer with the WSDL for the Dice web service loaded. In the SOAP Structure panel enter a number of sides for the Die and press the Send Request button. Of course you can choose to add more Die by clicking on the + symbol beside the die: Array, or editing the request in the HTTP Content panel.

After pressing the Send Request button you should see the response showing each Die and their value after rolling.

Once you have that working you can move on to writing a handler class and configure the web service to use it. In this example, the SOAP handler class will use resource injection (i.e. @Resource annotation and environment entry elements) for initialisation parameters rather than using the init-params element in the deployment descriptor. This is a little emphasised difference between JAX-RPC and JAX-WS.

There is one more download to get for this example, the handler class and the handler chain descriptor which refers to it. A handler chain defines a set of handlers that should be used for the web service. The web service implementation will have an annotation stating where the handler chain descriptor file is. Extract these two files to the project. To use them add the following to the Dice.java, just after the @WebService annotation:

@HandlerChain(file = “DiceService-HandlerChain.xml”)

Note that you will need to import javax.jws.HandlerChain.

The SaaSServerHandler class in this case checks that the calling client is allowed to invoke the web service by looking in the SOAP header for a ‘key’ element with a namespace of urn:soastation:saas. It will also check that the value matches a ‘ValidKeyValue’ environment entry in the web app deployment descriptor. You could further modify the handler to only allow a single Die element in the SOAP envelope if no valid key is provided. That is, a client with the key can use multiple Die while a client without, such as a guest or demonstration client can only use one. Alternatively you could keep track of registered keys and usage. The software as a service options are endless.

Back to the example, looking at the SaaSServerHandler the handleMessage method checks if the message is inbound (request coming in) or outbound (response going out). If the handler was being used for a web service client the outbound message would be the request being sent and the inbound message would be the response beng received. In our example we are interested in the inbound message because we are expecting a particular element. Note that the handler class has a instance variable called saasKeyValue which is set be the ‘ValidKeyValue’ environment entry. To set this, edit the web.xml and add the following:



eValidKeyValue
java.lang.String
soastation

Test the web service as before. You should get the following fault:

javax.xml.ws.WebServiceException: Invalid service key in SOAP Header. Expecting {urn:soastation:saas}key

Now test it again, but add the required element to the SOAP header. To do this edit the request in the HTTP Content tab. The request should look like this:




soastation







The corresponding result should be the same as when you originally tested the web service before adding the handler. If so, you have successfully implemented the soap handler.

This article discussed how to implement a server side JAX-WS SOAP Handler using the second technology preview of JDeveloper. It has provided code examples of how the handler concept work, including externalising properties in the environment entry elements. Also mentioned were ideas for further development such as reducing the capabilities for ‘guest’ clients. There really is a lot one can do with web service handlers.

ModuleException http:101216 on WebLogic

A number of people have asked about the ‘ModuleException: [HTTP:101216]Servlet:’ error I came across as part of the multi-platform Dice Service example. The experiences are covered in three (first problem, second problem, solved) separate articles which I will collate and summerise here.

Use ant to build web app
Some JEE 5 containers allow you to define your annotated classes and then drop them in an ‘autodeploy’ folder. Not with WebLogic Server v10 though, an ant script is required to do some more work on the web application. Interestingly, the WLS documentation does not refer to autodeploy for web services, in fact according to the WLS Web Service documentation a weblogic ant task ‘JwscTask’ is needed to compile the annotated web service and produce the necessary WAR and EAR for deployment.

Without the JwscTask, simply dropping a JAX-WS web app in the deplopyment folder will give you an deployment error like this:


The deployment error is:
weblogic.application.ModuleException:
[HTTP:101216]Servlet: "DiceServicePort"
failed to preload on startup in Web application:
"WebServices.war".
javax.servlet.ServletException: Servlet class:
'soastation.jaxwsdice.Dice' does not implement
javax.servlet.Servlet

Tell JwscTask the type
Not only is an ant script required to invoke weblogic.wsee.tools.anttasks.JwscTask but when using it with JAX-WS web services you must set the type attribute. The guidelines in the WLS documentation states that the ant tasks need to have a type=”JAXWS” attribute set. Without this, WLS will treat the web service as a JAX-RPC service.







Summary
To deploy JAX-WS web services on WebLogic Server v10 use JwscTask, with type=”JASWS”, in an ant script. Of course, if you are going to the effort of putting an ant script together to build the web application, it might as well have it deploy the web app too.

Dice service working on WLS

As mentioned in a previous post the Dice service, which is my JAX-WS example for a cross platform service implementation, was not working on BEA WebLogic Servier v10. It turns out I missed a key part of JAX-WS & WLS documentation when putting the build script together. The guidelines in the WLS documentation states that the ant tasks need to have a type=”JAXWS” attribute set. Without this, WLS was treating the web service as a JAX-RPC one and that was the cause of the strange WSDL and the runtime exception.

The build-service target now looks like this:







So the only change is setting the type attribute to JAXWS. The WSDL generated for this service is identical to the one generated on Glassfish.

Greater web service independence with JEE 5

One of the reasons I did the Dice web service example was to see if it really was possible to build a JEE 5 POJO web service (all be it a simple one) and deploy it in different JEE 5 containers without having to maintain separate deployment descriptors, or test classes, for the target platforms. The answer is a yes! Although it is a slightly qualified yes. More on that below, here are the target platforms first:

  • OC4J 11g Technology Preview (standalone version packaged in JDeveloper)
  • Glassfish v1 ur1 p01
  • JBoss 4.2.0 GA

The same WAR file built in JDeveloper 11g Technology Preview will deploy on all three containers without modification. To create the WAR file I followed the steps in the HelloService tutorial. However, I did have to change the project properties to set the output directory to public_html/WEB-INF/classes/ otherwise the classes would not be packaged in the WAR.

Deploying the web service on OC4J is covered in the tutorial. Deploying on the other platforms is just as easy, just take advantage of the auto deploy features by dropping the WAR file into the relavant directory of the running server:

  • Glassfish: glassfish/domains/domain1/autodeploy
  • JBoss: jboss-4.2.0.GA/server/default/deploy

It is worth taking a look at the WAR file as the only things in it are the classes (Dice and Die) and the web.xml which registers Dice as a servlet (DiceServicePort). It is the JAX-WS annotations on the Dice class that tell the container it is a web service and the container takes it from there generating WSDL, etc.

The service works on all three platforms without modification, which is good. However, there is difference in the WSDL files for each platform and that’s the qualification mentioned earlier. The end point structures are different. JBoss and OC4J keeping the servlet url-pattern and Glassfish opting for the service name (i.e. DiceService). This is only a slight difference as everything else remains the same. In fact you could generate a web service proxy client from one WSDL and use those proxy client classes for invoking the service on another platform. Just change the ENDPOINT_ADDRESS_PROPERTY. This is reassuring as the code and interface have not changed, only the platform. This is not a problem at all if test cases have the web service end point externalised.

One thing I need to point out here for those wanting to reproduce the excercise, I had to use JDeveloper 10.1.3.2 to generate the DiceServiceProxy classes because 11g Technology Preview version would treat the service ‘roll’ operation as a one way method and not return a response.

So there you have it. JEE 5 has brought us a step closer to build and test enterprise software components without the overhead of maintaining platform specific artefacts. Given more time I would try some more JEE 5 containers. Suggestions welcome.

JAX-WS & JAXB rock and roll…

During his Wednesday keynote at the JavaOne conference last week, Oracle Senior Vice President Thomas Kurian unveiled the next-generation architecture for Oracle Fusion Middleware. The 11g Technology Preview of JDeveloper and OC4J are currently available. Also available are some nifty tutorials and demos like Web Services Development in Oracle JDeveloper which shows off some great JEE 5 features like JAX-WS and JAXB 2.0. Although the latter is not really focused on much in the tutorial, it is the basis of what gets your java objects to and from XML.

What these two standards bring to the table from a web service development point of view is a more lightweight POJO oriented way of developing services. They will not make for better SOA in the enterprise though. In fact, they may even make things worse since a poorly designed interface can easily get a false SOA badge of credibility amongs the uninitiated by being exposed as a web service. Enough with the rant already, on with the example…

I thought it would be interesting to expand upon the bottom up HelloService tutorial by making things a bit more complicated with some old world technology: Dice. The Dice class in this example has a roll(List) operation that rolls the dice (plural of die) passed to it and returns the result. So there are really only two classes in this example:

  • Die represents (you guessed it) a die. It has two properties, number of sides and value.
  • Dice provides the collective operation of rolling dice.

This is the Die source:

package soastation.jaxwsdice;

public class Die {
protected int numberOfSides;
protected int value;
public Die() {
this(6); //Default number of sides is Six;
}
public Die(int sides) {
if (sides < 2)
throw new throw new IllegalArgumentException();
this.numberOfSides = sides;
}
public int getNumberOfSides() {
return numberOfSides;
}

public int getValue() {
return value;
}

public void roll() {
int rollValue = (int) (this.getNumberOfSides() * Math.random()) + 1;
if (rollValue > this.getNumberOfSides())
rollValue -= 1;
this.value = rollValue;
}
}

Note that the number of sides property is immutable and the value defaults to zero until the die is first rolled. It would seem natural to extend something like Integer to hold the ‘value’. This can’t be done in Java as these classes (Number, Integer, BigInteger, etc) are immutable so changing the value on every roll is not a runner. Besides, Integer is final so can’t be extended anyway.

You’ll probably also note the lack of comments on the code too. Tell me if you are for or against comments in code!

Here is the Dice source:

package soastation.jaxwsdice;

import java.util.Iterator;
import java.util.List;

public class Dice {

public List roll(List dice) {
Iterator diceIterator = dice.iterator();
while (diceIterator.hasNext()) {
Die die = diceIterator.next();
die.roll();
}
return dice;
}
}

The rest of the steps are identical to the HelloService example (which you can also get to from the Build Web Service link on the Start page of the JDeveloper 11 Technology Preview ).

  1. Add an @WebService annotation to the Dice class
  2. In the code fix menu select Configure project for web services
  3. Choose the Java EE 1.5 option and press OK
  4. Add an @WebMethod annotation to the roll method
  5. Right click on Dice service (note that the icon has changed) and select Test Web Service
  6. Gaze in awe at the handy HTTP Analyzer with Web Service support. That’s all you can do at this stage because JAX-WS doesn’t know what to do with the Die class.

This is where JAXB really comes into play. We want the properties of the Die object to be properly represented in the web service. Lets make the number of sides an attribute and the value of the Die appear as the value of the element. Do this by:

  1. Add @XmlAttribute(name=”sides”) to the numberOfSides field.
  2. Add @XmlValue to the value field.

Now you can test the web service again by right clicking on the Dice service in the Applications Navigator and selecting Test Web Service. In the HTTP Analyzer window you can enter the details of each die you want to roll. By clicking on the plus sign you can add more die to the SOAP request. The value attribute is in the schema but has no relavance to the operation (unless you want to implement a LoadedDie object?). Actually, you could leave the number of sides blank too as it will default to 6.

This example takes advantage of convention over configuration features of JEE 5. The property inspector in JDeveloper 11g Technology Preview provides some great tooling around the annotations. It is worth playing with it to see the extent of configuration possible.

We can improve the WSDL and XML representations with annotations. In the Dice class add a @WebResult(name=”die”) annotation to the roll method so that the result is not called ‘result’ by default. Also, in the roll method arguments add @WebParam(name=”die”) annotation so that the die element does not get call ‘arg0’ by default.

These JAX-WS and JAXB annotations make the web service and XML representation of the java operation and classes much more suitable. Of course these simple examples only scratch the surface of what can be achieved. It is a good idea to get familiar with capabilities of both technologies.

Let me know how you get on.