Inside the Axis2 Code Generator

Archived Content
This article is provided for historical perspective only, and may not reflect current conditions. Please refer to relevant product page for more up-to-date product information and resources.
  • By Ajith Ranabahu
  • 6 Feb, 2006

Introduction

An important part of any SOAP processing framework is code generation based on WSDL. Its generally categorized as a tool but its importance can be seen in two angles

  1. Convenience to users A code generation tool helps the users make use of the framework easily and efficiently. The ease of use of the code generator often is the crucial factor that determines the acceptability of the framework in the real world.
  2. Means of utilizing the full potential of the framework. This is the developer perception of the code generator. Generated code would represent the best use of the framework and its provided APIs. Hence the code generator is seen as a place where the APIs get their best use.

The usual expectation of the code generation tool is the ability to process WSDL's and produce code to implement either the service or the client. However the importance of tooling has grown throughout the years and there is more to such tools than the mere functionality. Following is a list of facts deemed important of a tool nowadays.

  1. Comprehensive and clean API Tools are not used as standalone components anymore. Most tools are available as plug-ins to IDEs and often used inside other complex components such as J2EE servers. For such uses a comprehensive and a clean API is important and is definitely a consideration when building a tool.
  2. Flexibility Flexibility of a tool refers to the ability to enhance its core functionality. Ease of extending the functionality and customization features amplify the use of the tool. A good example is the Eclipse framework, which can be extended by using plug-ins. It has been a huge success and others have followed the same structure.

All these extra factors have also been taken into account when building the Axis2 code generator.

More about Flexibility

One of the primary concerns of the Axis2 community is catering for third party data binding frameworks. The effort of Axis1 to supply its own data binding support has not been very successful and hence one of the primary design considerations of Axis2 has been the ability to cater for third party data binding frameworks. This has been the mantra for the code generator too. The generators core is not aware of the data binding process at all. Instead data binding is added as a non-core function through the use of an extension.

Flexibility of the tool comes at two levels.

  1. Extensions Extensions can be used to implement either simple functions like filtering WSDL's or more complex functions such as processing schemas. In fact the databinding support for the code generator tool is incorporated by using extensions. However modifying the internal workings of an extension is a full job for a developer rather than a user.
  2. Templates Templates provide a more user friendly way of customizing the actual text that would be generated. For a trivial usecase users can incorporate one of their own comments into the generated code by editing the templates. They can be used to even generate code for a completely different language by altering the template!

Another important feature of the tool is the API. Axis2's code generator provides a simple, easy to use API. This API is used by the command line version of the tool as well as the Eclipse and IDEA plug-ins to generate code. Any other party can also utilize this API and use the tool in a completely programmatic way.

The next few sections look more into these flexibility points and the default configuration of the Axis2 code generator.

Architecture at a glance

The architecture of the tool is quite simple and straightforward. It has a core that processes the WSDL and produces a “model” object. Code is generated by parsing the model against a template. The tool framework also has a configurable set of extensions that are processed before the core process starts. This is illustrated in figure1.


The model adopted in this case is XML and the templates are in XSL. Advantage of using XML as the core model is that the standard JRE's usually provides built in XML support and hence the tool has lesser dependencies on third party libraries. Also XML and XSL are widely used technologies with readily available expertise and hence any customizations can easily be incorporated.

The Code generation Engine

The code generation engine even though is the central component, does nothing other than simply calling the extensions one by one and then calling a component what is known as the Emitter . Emitter is the actual component that does the significant bit of work in the code generation process. Emitters are usually language dependent and hence one language has one emitter associated with it. This simple yet powerful architecture is depicted in the following illustration.


The configuration bound with the code generation engine is in the codegen-config.properties file. This file contains the list of extensions to process and the relevant emitters for each of the languages. The code generation engine gets all the configuration through a property file loader and keeps no 'default' values inside the code. The users can completely control the behavior of the Code generation engine by modifying the code codegen-config.properties file.

Emitters implement the org.apache.axis2.wsdl.codegen.emitter.Emitter interface. The emitter interface itself is simple and has only 4 methods. However a real implementation of an emitter contains significant code and is not trivial at all. A good example for a practical emitter is the org.apache.axis2.wsdl.codegen.emitter.MultiLanguageClientEmitter class, so called because it's written in a fashion that allows it to generate code for both Java and C#. (Note that C# is experimental and introduced only as a proof of concept).

The default behavior of the MultiLanguageClientEmitter is such that it loads the templates specified in the codegen-config.properties file and parses them against the relevant XML models. The power and value of having an XML model and a template is that usually the model is the same, regardless of the language the code is generated for. Hence the WSDL data extraction code can stay unchanged and modifications only take place inside the template. In fact the complete client API change in Axis2 that took place before the 0.94 release was incorporated into the code generator by changing only a single template!

Tweaking templates and Extensions

To understand the functioning of the codegenerator further and also to demonstrate the flexibility of the templates, consider one of the simplest templates, the skeleton template featured in Text1.This template is fairly simple and straight forward.

 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>

<xsl:template match="/interface">
/**
* <xsl:value-of select="@name"/>.java
*
* This file was auto-generated from WSDL
* by the Apache Axis2 version: #axisVersion# #today#
*/

package <xsl:value-of select="@package"/>;
/**
* <xsl:value-of select="@name"/>
* java skeleton for the axisService
*/

public interface <xsl:value-of select="@name"></xsl:value-of>
{
<xsl:for-each select="method">
<xsl:variable name="outputtype"><xsl:value-of
select="output/param/@type"></xsl:value-of></xsl:variable>

<!-- regardless of the sync or async status, the generated method
signature would be just a usual java method -->

/**
* Auto generated method signature
<!-- select only the body parameters -->
<xsl:for-each select="input/param[@location='body']">
<xsl:if test="@type!=''">* @param <xsl:value-of
select="@name"></xsl:value-of><xsl:text>
</xsl:text></xsl:if></xsl:for-each>
*/

public <xsl:if test="$outputtype=''">void</xsl:if><xsl:if
test="$outputtype!=''"><xsl:value-of select="$outputtype"/></xsl:if><xsl:text>
</xsl:text><xsl:value-of select="@name"/>

(<xsl:for-each select="input/param[@location='body']">
<xsl:if test="@type!=''"><xsl:if
test="position()>1">,</xsl:if><xsl:value-of
select="@type"/><xsl:text> </xsl:text><xsl:value-of
select="@name"/></xsl:if>

</xsl:for-each> );
</xsl:for-each>
}

</xsl:template>
</xsl:stylesheet>

Text 1: Text Sample 2 - The Modified template to generate an Interface

Imagine that a user wanted to generate an interface instead of a concrete class for the skeleton. The key here is that no extra information is needed from the WSDL. The interface vs the concrete class is merely a different arrangement of the java code! Text2 lists the new template that can be used to generate the interface.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>

<xsl:template match="/interface">
/**
* <xsl:value-of select="@name"/>.java
*
* This file was auto-generated from WSDL
* by the Apache Axis2 version: #axisVersion# #today#
*/

package <xsl:value-of select="@package"/>;

/**
* <xsl:value-of select="@name"/>
* java skeleton for the axisService
*/

public class <xsl:value-of select="@name"></xsl:value-of> {
<xsl:for-each select="method">
<xsl:variable name="outputtype"><xsl:value-of
select="output/param/@type"></xsl:value-of></xsl:variable>

<!-- regardless of the sync or async status,
the generated method signature would be just a usual java method -->

/**
* Auto generated method signature
<!-- select only the body parameters -->
<xsl:for-each select="input/param[@location='body']">
<xsl:if test="@type!=''">* @param <xsl:value-of
select="@name"></xsl:value-of><xsl:text>

</xsl:text></xsl:if></xsl:for-each>
*/

public <xsl:if test="$outputtype=''">void</xsl:if><xsl:if
test="$outputtype!=''"><xsl:value-of
select="$outputtype"/></xsl:if><xsl:text>
</xsl:text><xsl:value-of select="@name"/>

(<xsl:for-each select="input/param[@location='body']">
<xsl:if test="@type!=''"><xsl:if
test="position()>1">,</xsl:if><xsl:value-of
select="@type"/><xsl:text> </xsl:text><xsl:value-of select="@name"/></xsl:if>

</xsl:for-each> ){
//Todo fill this with the necessary business logic
<xsl:if test="$outputtype!=''">return null;</xsl:if>
}
</xsl:for-each>
}

</xsl:template>
</xsl:stylesheet>

Text 2: Text Sample 1 - The original skeleton template

Extensions posses a more powerful mode of interacting with the codegen engine. An extension needs to implement the org.apache.axis2.wsdl.codegen.extension.CodeGenExtension interface. This interface has two methods

  1. init method that is used to inject a codegen configuration object. This will be called at the creation of the Codegen engine.
  2. Engage method that is called when the actual codegeneration happens. The actual method call happens inside the generate method of the codegen engine.

For convenience, extension developers can use the org.apache.axis2.wsdl.codegen.extension.AbstractCodeGenerationExtension abstract class instead of the interface. This abstract class provides an implementation of the init method that assigns the injected configuration object to a protected variable.

As a demonstration of the power of extensions, imagine that an advanced user wanted to configure his code generator so that it would not process WSDL files that have no service declaration. Understandably this is not possible by simple modifications to the templates. A more deeper means of control is required.

As the first step of this modification, an extension is needed. Text3 shows a simple extension that can be used to test the WSDL for the lack of a service definition. Note that only the body of the class is listed.

 

public class ServiceValidatorExtension extends AbstractCodeGenerationExtension{

public void engage() throws CodeGenerationException {
Map servicesMap = configuration.getWom().getServices();
if (servicesMap.isEmpty()){
throw new CodeGenerationException("WSDLs without service
tag are not accepted!!");
}
}
}
Text 3: Sample Code - The validator extension

Writing of the extension is not enough to make it work. The extension needs to be registered in the codegen-config.properties file. This simply requires the fully qualified name of the extension to be entered at the list of extension under the codegen.extension property. However there are several important facts to keep in mind when putting this entry.

  1. The extensions need to be in the class path of the code generator in order to be invoked.
  2. The extensions are invoked in the lexical order. Hence the first extensions that appear early in the list gets invoked early

Also note that all extensions are invoked before the invocation of the main emitter. Hence extensions are only capable of doing pre-processing tasks.

Summary

The axis2 code generator is an important component of the Axis2 framework and has been extensively re-architectured. It posses the flexibility to be modified easily either to cater for simple customizations or deep integrations. It also features an easy to use API that allows convenient integrations with other tools and frameworks.

About Author

  • Ajith Ranabahu
  • Software Engineer
  • WSO2 Inc.