Tuesday, March 24, 2009

Parsing WSDL 2.0 extensions with Woden

Web Services Description Language (WSDL) Version 2.0 Part 2: Adjuncts, specifies predefined extensions for WSDL2.0, Woden implements some of the predefined extensions such as WSDLX, RPC, SOAP, HTTP etc. But it is necessary to have a custom WSDL extension parsing mechanism to supports to other WS specifications such as WS-Security, WS-Policy etc. There are two ways to deal with extensions in Woden.

  • Use traditional Extensions handling mechanism.
I used the word "traditional” because this mechanism was originally developed for WSDL4J and Woden reuse the same concept. This wiki page provides comprehensive details about traditional Extensions handling mechanism architecture in Woden.
  • Use new ComponentExtensionContext based Extensions handling mechanism.
This new Extension handling mechanism was developed according to the feedbacks collected from Woden users and a much more simplified way to deal with WSDL extensions. This wiki page is a good resource about this mechanism.


In this post I'm going to discuss about how we can write set of classes in order to parse custom WSDL extension elements, instead of imaging a hypothetical scenario I will use a real world requirement derived from woden users list. Let’s see how we can use traditional extensions handling mechanism to parse WS-Policy definition available on a WSDL documents and how can retrieve those information as a Apache Neethi Policy or PolicyReference objects.


According to the Woden API we need to develop following classes to achieve our goal.
1. PolicyExtensionSerializer - This implements ExtensionSerializer interface and used to serialize WS-Policy elements.
2. PolicyExtensionDeserializer - This implements ExtensionDeserializer interface and used to deserialize WSDl elemnts in to WS-Policy.
3. PolicyExtension - This implements ExtensionElement and act as wrapper for WS-Policy components.
4. PolicyExtensionsImpl - implementation of above PolicyExtensionsImpl.
5. PolicyExtensionSample - practicality illustrate usage of above classes.


Here I have listed only some of the impotent points; you can download complete source code as a eclipse project from here.

PolicyExtensionSerializer

In the PolicyExtensionSerializer implementation, marshall () is the most significant method, but in our case we don’t need to worry about serialization so keep it as an empty method as below.

public void marshall(Class parentType, QName elementType,
ExtensionElement extension, PrintWriter pw,
DescriptionElement desc, ExtensionRegistry extReg)
throws WSDLException {
}


PolicyExtensionDeserializer
Once we parse WSDL document, WSDlReader query for ExtensionDeserializer on ExtensionRegistry when it encounter a non-WSDL elements or attribute, Here
unmarshall method is significant , in our case it perform following tasks
  1. Read the Policy definition
  2. Store policy elements as a XMLElemen so that we can create DOM element from it.
public ExtensionElement unmarshall(Class parentType, Object parent,
QName extType, XMLElement extEl, DescriptionElement desc,
ExtensionRegistry extReg) throws WSDLException {
PolicyExtension ele = (PolicyExtension) extReg.createExtElement(
parentType, extType);

ele.setExtensionType(extType);
ele.setXMLElement(extEl);
return ele;
}

PolicyExtension
Define following specific methods to deal with WS-Policy objects.

public void setXMLElement(XMLElement source) - to set WS-Policy element as a XML content.
public XMLElement getXMLElement() - to set WS-Policy element as a XML content.
public PolicyComponent getPolicy() - to set WS-Policy element as a Apache Neethi PolicyCompoent.


Our PolicyExtensionSample should perform following set of steps in a sequential manner.


1. Create a WSDLReader instance.

factory = WSDLFactory.newInstance();
WSDLReader reader = factory.newWSDLReader();
reader.setFeature(WSDLReader.FEATURE_VALIDATION, true);

2. retrieve the ExtensionRegistry from WSDLReader instance.

// QName to represent top level Policy Element.
QName type = new QName(
"http://schemas.xmlsoap.org/ws/2004/09/policy", "Policy");

// Retrieve ExtensionRegistry from WSDLReader
ExtensionRegistry reg = reader.getExtensionRegistry();



3. Register our Serializer, Deserializer and ExtElement with ExtensionRegistry.


// register the ExtensionSerializer
reg.registerSerializer(Description.class, type,
new PolicyExtensionSerializer());
// register the ExtensionDeserializer
reg.registerDeserializer(DescriptionElement.class, type,
new PolicyExtensionDeserializer());
// register the ExtElementType
reg.registerExtElementType(DescriptionElement.class, type,
PolicyExtensionsImpl.class);

4. Now we can parse our document and possible to retrive Policy objects as follows

Description descComp = reader
.readWSDL("/work/workspace/axis/wodenExt-eg/wsdl/test.wsdl");

// Retrieve ExtensionElements from DescriptionElement.
DescriptionElement descElem = descComp.toElement();
ExtensionElement[] extEls = descElem
.getExtensionElementsOfType(type);
for (int i = 0; i < extEls.length; i++) {
PolicyExtension policyExt = (PolicyExtension) extEls[0];
// Retrieve policy source as a DOM Element.
Element ele = (Element) policyExt.getXMLElement().getSource();
// Retrieve the policy definition as a Apache Neethi Policy
// instance.
Policy policy = (Policy) policyExt.getPolicy();
System.out.println(" policy " + policy.getName() + " :: "
+ policy.getId());

}


Download source codes from here

2 comments:

pradeep fernando said...

great work sagara. keep up the good work.
if it is possible please update the woden documentation. It would help the future users.

Anonymous said...

Hi Sagara,

Do you have any idea about parsing Types using WSDL extensions. I dont want to use schema based languages( XML Schema, OWL, RElaxNG).
Support for types like collections,maps etc.