blob: 8a60f3a78a3e89739a5b33efdb33a97d815772f1 [file] [log] [blame]
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=us-ascii" />
<title>ADB - Howto</title>
<link href="../../css/axis-docs.css" rel="stylesheet" type="text/css" media="all" />
</head>
<body lang="en" xml:lang="en">
<h1>Axis2 Databinding Framework</h1>
<p>This document aims to provide the architectural overview of the
Axis2 Databinding Framework (referred to as ADB from here onwards)
and be a guide to anyone who wants to use and modify ADB. The
information is presented under the following topics.</p>
<h2>Content</h2>
<ul>
<li><a href="#intro">Introduction</a></li>
<li><a href="#archi">Architectural Overview</a></li>
<li><a href="#code_depend">Code and Dependencies</a></li>
<li><a href="#code_gen">Invoking the ADB Code Generator</a>
<ul>
<li><a href="#schema_compiler">As a Stand-alone Schema
Compiler</a></li>
<li><a href="#api">Through the API</a></li>
</ul>
</li>
<li><a href="#gen_modes">Generation Modes</a></li>
<li><a href="#deep">Deep into Generated Code</a>
<ul>
<li><a href="#example">An Example!</a></li>
</ul>
</li>
<li><a href="#limitation">Known Limitations</a></li>
<li><a href="#more">Want to Learn More?</a></li>
</ul>
<a name="intro" id="intro"></a>
<h2>Introduction</h2>
<p>The objective of the Axis2 Databinding framework is to provide a
lightweight and simple schema compiler/ Java bean generator for
Axis2. By no means it's to be a fully functional schema compiler
like XMLBeans. Note that ADB is written in a fashion that allows it
to be used as a stand-alone schema compiler and also to be extended
to generate code for other languages.</p>
<a name="archi" id="archi"></a>
<h2>Architectural Overview</h2>
<p>ADB is built on a modular architecture that allows it to utilize
a pre configured writer depending on the configuration.The 'big
block diagram' for the code generator architecture is depicted
below</p>
<p><img src="images/ADB.jpg" alt="ADB architecture" /></p>
<p>ADB utilizes the WS-commons XmlSchema library for reading the
Schema. The object model for the schema comes in the form of an
XmlSchema object. The schema compiler keeps an instance of the
writer (in the default case it's the JavaBeanWriter) which actually
writes the classes. The writers may use whatever technique they
prefer, in the case of the JavaBeanWriter, it uses an XSLT
template. The SchemaCompiler also uses a typemapper object that
tells it what classnames to be used for the QNames that it
encounters. This type mapper is also part of the configuration and
the users can override the default type mapper by overriding the
property setting.</p>
<a name="code_depend" id="code_depend"></a>
<h2>Code and Dependencies</h2>
<p>As explained in the previous section, the schema compiler
depends on the WS-Commons XmlSchema library. The XSLT
transformations are dependent on the JVM's DOMimplementation
(either crimson or xerces) which means that the underlying JVM
should be 1.4 or higher. Apart from that ADB has no dependencies on
any other special jar files. The code for the schema compiler is
completely in the <strong>org.apache.axis2.schema.*</strong>
package. This package resides in the codegen module of the Axis2
source tree.</p>
<p>Following are the important classes and files:</p>
<ol>
<li><strong>SchemaCompiler</strong> - The work horse that really
compiles the schema into classes.</li>
<li><strong>BeanWriter</strong> - BeanWriter represents the kind of
interface the SchemaCompiler accepts as a writer. The writer needs
to handle the actual writing of the clasess</li>
<li><strong>JavaBeanWriter</strong> - The default implementation of
the BeanWriter interface.</li>
<li><strong>TypeMap</strong> - represents the interface that the
schema compiler looks towards to find classes</li>
<li><strong>JavaTypeMap</strong> - the default implementation of
the TypeMap</li>
<li><strong>ADBBeanTemplate.xsl</strong> - the XSLtemplate the
JavaBeanWriter uses.</li>
<li><strong>Schema-compile.properties</strong> - The property file
for the schema compiler</li>
</ol>
<p>The easiest way to obtain the ADB binaries is to run the maven
build for the Axis2 adb-codegen module. This will generate the
<strong>axis2-adb-codegen-{$version}.jar</strong> inside the target
folder which is directly usable when the ADB schema compiler is
required.</p>
<p>The runtime dependancies for the ADB generated classes is in the
Axis2 adb module and the kernal module. Hence to compile and work with the generated
classes the <strong>axis2-adb-{$version}.jar</strong> and <strong>axis2-kernal-{$version}.jar</strong> needs to be
in the classpath apart from other dependancies like the StAX,
Axiom,Commons-logging and javax.activation.</p>
<a name="code_gen" id="code_gen"></a>
<h2>Invoking the ADB Code Generator</h2>
<a name="schema_compiler"></a>
<h3>As a Standalone Schema Compiler</h3>
<p>ADB comes with a main class XSD2Java that allows the schemas to
be compiled just by giving the schema file reference.This main
class is pretty much primitive and does not provide much control
over the code generation process. This is bound to improve in the
near future.</p>
<p>Code generator accepts the following parameters</p>
<ol>
<li>The Schema file name - This should be a complete file name
pointing to the local file system</li>
<li>The output folder name - This should be the name of a folder
within the local file system</li>
</ol>
<p>Since the main class has no validations built in, the compiler
is likely to cough up an unexpected error message if these
parameters are not supplied properly.</p>
<a name="api" id="api"></a>
<h3>Through the API</h3>
<p>This is the only way to harness the full potential of the schema
compiler. The current Axis2 integration of ADB happens through this
API. The most important classes and methods of the Schema compiler
are as follows.</p>
<ul>
<li><strong>SchemaCompiler - Constructor</strong>
<p>The constructor of the schema compiler expects a CompilerOptions
object. This compilerOptions object is more of a holder for the
parameters that are passed to the SchemaCompiler. The only
mandatory parameter in the CompilerOptions is the output
directory</p>
</li>
<li><strong>SchemaCompiler - Compile(XMLSchema schema)</strong>
<p>The compile method to call for a single schema. The expected
object is a XMLSchema which is part of the XmlSchema library.</p>
</li>
<li><strong>SchemaCompiler - Compile(List schemaList)</strong>
<p>Similar to the previous method but accepts a list of schemas
instead of one.</p>
</li>
</ul>
<p>For a comprehensive code sample in invoking the schema compiler
through the API, the following classes would be helpful. One would
also need an understanding of the generation modes of the ADB
schema compiler when using it through the API. Hence the following
section includes a brief description of the generation modes .</p>
<ul>
<li><strong>org.apache.axis2.schema.XSD2Java</strong></li>
<li><strong>org.apache.axis2.schema.ExtensionUtility</strong></li>
</ul>
<a name="gen_modes" id="gen_modes"></a>
<h2>Generation Modes</h2>
<p>ADB extension provides several generation modes for the data
bound classes.</p>
<ol>
<li><strong>Integrated Mode</strong>
<p>In this mode the classes are generated as inner classes of the
stub, message receiver or the interface. The ADB framework refrains
from writing the classes but provides a map of DOM document objects
that contains the model for the databinding class. The implementers
are free to use the models for their needs. The Axis2 codegen
engine parses these documents within its own XSLT parser to create
the necessary code.</p>
<p>Integrated mode is supposed to be used by the tool builders.</p>
</li>
<li><strong>Wrapped Mode</strong>
<p>In the wrapped mode, the ADB databinder generates one class that
contains all the databound classes. This is convenient when the
number of classes need to be limited.</p>
</li>
<li><strong>Expanded Mode</strong>
<p>This is the usual mode where the codegenerator generates a class
for each of the outer elements and the named complex types. The
command line tool (XSD2Java) always generates code in the expanded
mode.</p>
</li>
</ol>
<p>The rules for generating code (described in the next section)
applies regardless of the mode. Switching these modes can be done
by passing the correct options via the CompilerOptions object. The
following is table lists the options and the consequences of using
them.</p>
<table border="1" summary="Options and descriptions">
<tbody>
<tr>
<td><strong>Field Name in Options</strong></td>
<td><strong>Description</strong></td>
</tr>
<tr>
<td>writeOutput</td>
<td>This determines whether to write the output or not. If the flag
is on then the classes will be written by ADB. The default is
off.</td>
</tr>
<tr>
<td>wrapClasses</td>
<td>This determines whether to wrap the generated classes. If the
flag is on then a single class (with adb added to the end of the
specified package) will be generated. The default is off.</td>
</tr>
<tr>
<td>mapperClassPackage</td>
<td>The package name for the mapper class. Please see the advanced
section for details of the mapper class</td>
</tr>
<tr>
<td>helperMode</td>
<td>The switch that determines whether to switch to helper mode or
not. Please see the advanced section for details of the helper
mode</td>
</tr>
<tr>
<td>ns2PackageMap</td>
<td>A map that stores the namespace name against the package name
These details are used to override the default packages</td>
</tr>
</tbody>
</table>
<a name="deep" id="deep"></a>
<h2>Deep into Generated Code</h2>
<p>When the schema compiler is invoked (one-way or another) it
generates code depending on the following rules</p>
<ol>
<li>All named complex types become bean classes. Any attribute or
element encapsulated in this complex type will become a field in
the generated class. Note that the support for constructs other
than the sequence and all is not yet implemented.</li>
<li>All top level elements become classes. This is a rather
questioning feature since unless classes are generated for the top
level elements the handling of elements become difficult and
messy!</li>
<li>SimpleType restrictions are handled by replacing the relevant
type with the basetype</li>
</ol>
<p>Once the code is generated according to the rules it looks like
the following. Consider the following piece of schema</p>
<pre>
&lt;schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://soapinterop.org/types" targetNamespace="http://soapinterop.org/types"
elementFormDefault="qualified" &gt;
&lt;import namespace="http://schemas.xmlsoap.org/soap/encoding/"/&gt;
&lt;complexType name="SOAPStruct"&gt;
&lt;sequence&gt;
&lt;element name="varString" type="xsd:string"/&gt;
&lt;element name="varInt" type="xsd:int"/&gt;
&lt;element name="varFloat" type="xsd:float"/&gt;
&lt;/sequence&gt;
&lt;/complexType&gt;
&lt;element name="myElement" type="tns:SOAPStruct"/&gt;
&lt;/schema&gt;
</pre>
<p>For comprehension let us consider the expanded mode for the code
generator. Unless specifically mentioned, the rest of this document
assumes that the expanded mode of the code generation is used. This
particular schema generates the following two classes in the
designated package, which in this case would be
<strong>org.soapinterop.types</strong>. This package is derived
from the target namespace of the schema.</p>
<ol>
<li>MyElement.java</li>
<li>SOAPStruct.java</li>
</ol>
<p>As explained earlier, SOAPStruct refers to the complexType.
MyElement is the class that refers to the element. Just as
expected, the SOAPStruct bean has getters and setters for
varString, varInt and varFloat which are String, int and float
respectively. MyElement on the other hand has a single field
representing the SOAPStruct object that it encapsulates.</p>
<p>The most important aspect of the generated code is that it
encapsulates two methods for creation and serializing the beans.
Note that to make this work, the generated beans implement the
<strong>org.apache.axis2.databinding.ADBBean</strong> interface</p>
<p>The creator and serializer methods look like the following</p>
<ul>
<li>
<pre>
public javax.xml.stream.XMLStreamReader
getPullParser(javax.xml.namespace.QName qName)
</pre>
<p>This method returns a pull parser that throws the right events
for this particular object. However there is a subtle difference
between element based classes and complexType based classes</p>
<ol>
<li>An element based bean class (like MyElement.java in the
example) will <strong><em>ignore the passed in QName</em></strong>.
Instead of using the passed in QName it'll utilize it's own QName
which is embedded in the class under the constant MY_QNAME, during
the code generation. Hence it is usual to call getPullparser with a
null for the elements.</li>
<li>A ComplexType based bean class(like SOAPStruct.java in the
example) will use the passed in QName to return an instance of the
ADBpullparser. This will effectively wrap the elements inside with
an element having the passed QName</li>
</ol>
</li>
<li>
<pre>
public org.apache.axiom.om.OMElement getOMElement(
final javax.xml.namespace.QName parentQName,
final org.apache.axiom.om.OMFactory factory){
</pre>
<p>This method returns an OMElement representing the ADB bean object.</p>
<ol>
<li>There is an annonymous ADBDataSource class has implemented, in side the getOMElement method.
This annonymous class implements the serialize method where the serializing logic is written,
for that pirticular bean class. Fianlly an OMSourcedElementImpl object with the
above annonymous class type object as the data source, is
returned.
</li>
</ol>
</li>
<li>
<pre>
public static [Object].Factory.
parse(javax.xml.stream.XMLStreamReader reader)
throws java.lang.Exception
</pre>
<p>This method returns a populated instance of the class in
question. Note that</p>
<pre>
[Object]
</pre>
will be replaced by the actual class that contains this method. Say
for SOAPStruct the method looks like
<pre>
public static SOAPStruct.Factory.
parse(javax.xml.stream.XMLStreamReader reader)
throws java.lang.Exception
</pre>
<p>Also note that the above parse method is available in the
<strong>Factory</strong> class generated into the relevant top
level class.Hence one will have to get the static Factory instance
before calling the parse methods</p>
</li>
</ul>
<a name="example" id="example"></a>
<h3>An Example!</h3>
<p>Consider the following XML fragment</p>
<pre>
&lt;myElement xmlns="http://soapinterop.org/types"&gt;
&lt;varInt&gt;5&lt;/varInt&gt;
&lt;varString&gt;Hello&lt;/varString&gt;
&lt;varFloat&gt;3.3&lt;/varFloat&gt;
&lt;/myElement&gt;
</pre>
<p>Enthusiastic readers might already have figured out that this
piece of XML complies to the Schema mentioned above. The following
piece of code shows how to build a populated instance of MyElement
with this fragment of XML</p>
<pre>
XMLStreamReader reader = XMLInputFactory.newInstance().
createXMLStreamReader(
new ByteArrayInputStream(xmlString.getBytes()));
MyElement elt = MyElement.Factory.parse(reader);
</pre>
<p>
Optionally above xml fragment can be reproduced with the following
code fragment
<P>
<pre>
OMElement omElement = myElement.getOMElement
(MyElement.MY_QNAME, OMAbstractFactory.getSOAP12Factory());
String xmlString = omElement.toStringWithConsume();
</pre>
<p>Although this example takes on the tedious effort of creating a
reader out of the String, inside the Axis2 environment an
XMLStreamReader can be direclty asked from the OMElement! Hence, the
parse method becomes a huge advantage for hassle free object
creation.</p>
<p>Similarly the reader obtained from the object can also be
utilized as needed. The following code fragment shows how to
utilize the getPullParser method to create an OMElement :</p>
<pre>
XMLStreamReader reader = elt.getPullParser(null);
OMElement omElt = new StAXOMBuilder(reader).getDocumentElement();
</pre>
<p>That's all to it! If you are interested in learning more on ADB
the following documents may also be helpful. However, be sure to
check the limitations section that follows if you are planning to
use ADB for something serious.</p>
<a name="limitation" id="limitation"></a>
<h2>Known Limitations</h2>
<p>ADB is meant to be a 'Simple' databinding framework and was not meant to compile all types of schemas. The following limitations
are the most highlighted.</p>
<ol>
<li>Complex Extensions and Restrictions.</li>
</ol>
<a name="more" id="more"></a>
<h2>Want to Learn More?</h2>
<ul>
<li><a href="adb-advanced.html">Advanced features of the ADB code
generator</a> - explains xsi:type based desrialization and helper
mode</li>
<li><a href="adb-tweaking.html">Tweaking the ADB Code
Generator</a> - explains available mechanisms to extend ADB and
possibly adopt it to compile schemas to support other
languages.</li>
<li><a href="adb-codegen-integration.html">ADB and Axis2
Integration</a> - explains how the ADB schema compiler was attached
to the Axis2 framework</li>
</ul>
</body>
</html>