<?xml version="1.0" encoding="UTF-8"?> | |
<!-- | |
~ Licensed to the Apache Software Foundation (ASF) under one | |
~ or more contributor license agreements. See the NOTICE file | |
~ distributed with this work for additional information | |
~ regarding copyright ownership. The ASF licenses this file | |
~ to you under the Apache License, Version 2.0 (the | |
~ "License"); you may not use this file except in compliance | |
~ with the License. You may obtain a copy of the License at | |
~ | |
~ http://www.apache.org/licenses/LICENSE-2.0 | |
~ | |
~ Unless required by applicable law or agreed to in writing, | |
~ software distributed under the License is distributed on an | |
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
~ KIND, either express or implied. See the License for the | |
~ specific language governing permissions and limitations | |
~ under the License. | |
--> | |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" | |
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |
<html xmlns="http://www.w3.org/1999/xhtml"> | |
<head> | |
<meta name="generator" content= | |
"HTML Tidy for Windows (vers 14 June 2007), see www.w3.org" /> | |
<meta http-equiv="content-type" content="" /> | |
<title>Axis2 RPC Support</title> | |
</head> | |
<body> | |
<h1>Axis2 RPC Support</h1> | |
<p>This document describes Axis2's Remote Procedure Call support in | |
a set of easy to understand implementation steps.</p> | |
<h2>Introduction</h2> | |
<p>Axis2 Remote Procedure Call (RPC) support may seem somewhat | |
tricky and confusing at first glance. However, Axis2 RPC strategy | |
is based on a set of well defined rules. This document aims to | |
drill down to the details of the strategy and resolve most of the | |
unknown bits and pieces. Note that Axis2 currently does not support | |
the rpc/encoded style. But it fully supports the rpc/literal | |
style.</p> | |
<p>We will discuss the Axis2 RPC strategy in the following | |
steps</p> | |
<h2>Step 1 - Converting RPC Style WSDL's into Doc/Lit Style | |
WSDL</h2> | |
<p>This is probably the most confusing part of the RPC strategy. | |
Since the Axis2 code generator is based on pure doc/lit style, the | |
first step of the code generation process is to generate a wrapper | |
schema. This wrapper generation can be easily explained by using an | |
example.</p> | |
<p>Take the following piece of WSDL</p> | |
<pre> | |
..... | |
<message name="requestMessage"> | |
<part name="part1" type="xs:string"/> | |
<part name="part2" type="xs:int"/> | |
</message> | |
<message name="responseMessage"> | |
<part name="part1" type="xs:string"/> | |
</message> | |
<portType name="echoPortType"> | |
<operation name="echo"> | |
<input message="y:requestMessage"/> | |
<output message="y:responseMessage"/> | |
</operation> | |
</portType> | |
<binding name="echoBinding" type="y:echoPortType"> | |
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> | |
<operation name="echo"> | |
<soap:operation soapAction="echo"/> | |
<input> | |
<soap:body use="literal"/> | |
</input> | |
<output> | |
<soap:body use="literal"/> | |
</output> | |
</operation> | |
</binding> | |
..... | |
</pre> | |
<p>The binding says rpc/lit is required and in this case the | |
message parts will need wrapping in the following order:</p> | |
<ol> | |
<li>The first element needs to have the operation name as the local | |
name and the operation namespace. (This happens to be the namespace | |
of the porttype - in this case the targetnamespace of the | |
WSDL.)</li> | |
<li>The children of this element are non namespace qualified | |
elements with the part names as local names (referred to as | |
<strong>part element</strong>)</li> | |
<li>In case the part refers to a standard type like the example | |
WSDL, the content of the part element would be of that type. If the | |
part refers to a complex type defined in the schema, the content of | |
the part element becomes of that type. Having an element reference | |
in the part when the binding is rpc is invalid.</li> | |
</ol> | |
<p>For example, the input wire message for the echo operation | |
mentioned in the above WSDL fragment would look like this:</p> | |
<pre> | |
<op:<strong>echo</strong> xmlns:op="porttype namespace"> | |
<<strong>part1</strong>>Hello World</part1> | |
<<strong>part2</strong>>123</part2> | |
</op:echo> | |
</pre> | |
<p>Note that the element name is in bold. The first one is the | |
operation name, the second and third are part names. It can be seen | |
that it is possible to generate a schema representing this | |
structure, and then treat the whole service as a pure doc/lit | |
service. In this case, the following piece of schema is generated | |
to make the rpc to doc conversion. Note that in this case the wire | |
message stays unchanged. It is only a different WSDL authoring | |
style</p> | |
<pre> | |
<xs:element name="echo"> | |
<xs:complexType> | |
<xs:sequence> | |
<xs:element name="part1" type="xs:string" /> | |
<xs:element name="part2" type="xs:int" /> | |
</xs:sequence> | |
</xs:complexType> | |
</xs:element> | |
</pre> | |
<p>What the Axis2 code generator does is exactly this. By looking | |
at the binding style, it generates a wrapper schema in places | |
required before handing over the Axis* hierarchy to the code | |
generator engine. In every case (even when the schema needs to be | |
unwrapped) this wrapping part will take place!</p> | |
<h2>Step 2 - Unwrapping the Schema</h2> | |
<p>If the schema needs to be unwrapped, it brings up a few issues. | |
This is mainly because the only thing that the emitters rely on | |
when generating code is a mapping table.</p> | |
<ol> | |
<li>When the schema is unwrapped, where will the unwrapping | |
information remain? | |
<p>There has to be a store to keep the information seperated. The | |
Axis * hierarchy can be used for this. It has nicely separated | |
information holders and a parameter store that can hold an | |
information bean.</p> | |
</li> | |
<li>How do we maintain uniqueness among message part names? | |
<p>Part names are only unique across a message and not globally. | |
However, due to the fact that we have a global mapping table, we | |
need a way to differentiate between parts of different messages. | |
The technique used here is to generate a QName that has the | |
operation name as a namespace and a suffix (like _input) appended | |
to the local name.</p> | |
</li> | |
</ol> | |
<p>Given these solutions, the first step in unwrapping is to walk | |
the schema and figure out the unwrappable items. The key player of | |
the unwrapping process is the unwrapping extension. It walks a | |
given schema and figure out the unwrappable parts if there are | |
any.</p> | |
<p>The current unwrapper looks for the following patterns and fails | |
if it is not found!</p> | |
<pre> | |
< element > | |
< complexType > | |
< sequence > | |
< element /> | |
< /sequence > | |
< /complexType > | |
< /element > | |
</pre> | |
<p>Once this pattern is detected, the unwrapper details will be | |
added to the relevant AxisMessage component.</p> | |
<h2>Step 3 - Populate Type Information</h2> | |
<p>The next step is to populate the Type information for the parts. | |
This has to be explicitly done by the data binding extensions, and | |
currently the ADB and XMLbeans extensions populate the relevant | |
AxisMessage by looking up their generated type systems. This type | |
information goes into the AxisMessage inside a | |
MessagePartInformationHolder instance.</p> | |
<p>The following code fragment from the ADB extension shows how the | |
AxisMessages get populated with the relevant type information. The | |
code is almost the same for the XMLBeans extension. Note the items | |
in bold.</p> | |
<pre> | |
if (message.getParameter(Constants.UNWRAPPED_KEY) != null) { | |
XmlSchemaType schemaType = message.getSchemaElement().getSchemaType(); | |
if (schemaType instanceof XmlSchemaComplexType) { | |
XmlSchemaComplexType cmplxType = (XmlSchemaComplexType) schemaType; | |
XmlSchemaParticle particle = cmplxType.getParticle(); | |
if (particle instanceof XmlSchemaSequence) { | |
XmlSchemaObjectCollection items = | |
((XmlSchemaSequence) particle).getItems(); | |
for (Iterator i = items.getIterator(); i.hasNext();) { | |
Object item = i.next(); | |
if (item instanceof XmlSchemaElement) { | |
XmlSchemaElement xmlSchemaElement = (XmlSchemaElement) item; | |
XmlSchemaType eltSchemaType = xmlSchemaElement.getSchemaType(); | |
if (eltSchemaType != null) { | |
<strong>populateClassName(eltSchemaType,mapper,opName,xmlSchemaElement.getName());</strong> | |
} else if (xmlSchemaElement.getSchemaTypeName() != null) { | |
eltSchemaType = findSchemaType(schemaMap, | |
xmlSchemaElement.getSchemaTypeName()); | |
if (eltSchemaType!=null){ | |
populateClassName(eltSchemaType,mapper,opName,xmlSchemaElement.getName()); | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
</pre> | |
<p>The populateClassName looks like this</p> | |
<pre> | |
private static void populateClassName(XmlSchemaType eltSchemaType, | |
TypeMapper typeMap, | |
String opName, | |
String partName) { | |
Map metaInfoMap = eltSchemaType.getMetaInfoMap(); | |
if (metaInfoMap != null) { | |
<strong>String className = (String) metaInfoMap. | |
get(SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY); | |
QName partQName = WSDLUtil.getPartQName(opName, | |
WSDLConstants.INPUT_PART_QNAME_SUFFIX, | |
partName); | |
typeMap.addTypeMappingName(partQName,className);</strong> | |
if (Boolean.TRUE.equals( | |
metaInfoMap.get(SchemaConstants. | |
SchemaCompilerInfoHolder.CLASSNAME_PRIMITVE_KEY))){ | |
//this type is primitive - add that to the type mapper status | |
//for now lets add a boolean | |
typeMap.addTypeMappingStatus(partQName,Boolean.TRUE); | |
} | |
} | |
} | |
</pre> | |
<h2>Step 4 - Generate Code with Unwrapped Parameters</h2> | |
<p>The next step is generating the actual code. The | |
AxisServiceBasedMultiLanguageEmitter has a method that generates | |
the XML model for the input parameters, and that method includes | |
the relevant part parameters inside the relavant top level input | |
parameter element.</p> | |
<p>The relevant part of the XML model looks like this. Note that | |
this intermediate XML model is the one that is parsed against the | |
Stylesheets to generate the code.</p> | |
<pre> | |
<input> | |
<param name="param4" type="com.example.www.ServiceNameStub.Echo" shorttype="Echo" value="null" location="body" opname="echo"> | |
<param name="param5" type="java.lang.String" shorttype="String" value="null" location="body" opname="echo" partname="Part1" | |
primitive="yes"/> | |
<param name="param6" type="int" shorttype="int" value="0" location="body" opname="echo" partname="Part2" primitive="yes"/> | |
</param> | |
</input> | |
</pre> | |
<p>The next part is handled by the template. Basically, the | |
template looks after the generation of multiple parameters into the | |
method signatures, and then the generating of the relevant | |
serialization and deserialization code for the parameters.</p> | |
<h2>Bringing the Parameters Together and Exploding Them</h2> | |
<p>This is a somewhat controversial area. The current Axis2 code | |
generator does the wrapping and unwrapping at the object level and | |
not the XML level. In short, the exploded parameters are only a | |
convenience and the explosion does not run down to the XML level. | |
The following example of generated source code makes this | |
clear:</p> | |
<pre> | |
private org.apache.axiom.soap.SOAPEnvelope toEnvelope( | |
org.apache.axiom.soap.SOAPFactory factory, java.lang.String param1, | |
int param2, boolean optimizeContent) { | |
<strong>com.example.www.ServiceNameStub.Echo wrappedType = new com.example.www.ServiceNameStub.Echo(); | |
wrappedType.setPart1(param1); | |
wrappedType.setPart2(param2);</strong> | |
rg.apache.axiom.soap.SOAPEnvelope emptyEnvelope = factory.getDefaultEnvelope(); | |
emptyEnvelope.getBody().addChild(wrappedType.getOMElement( | |
com.example.www.ServiceNameStub.Echo.MY_QNAME, factory)); | |
return emptyEnvelope; | |
} | |
</pre> | |
<p>Note the lines in bold. The wrapped class will anyway be | |
instantiated and used at the end, but what the user sees is | |
different. Exploding the parameters happens in a similar way!</p> | |
<h2>Conclusion</h2> | |
<p>Axis2 RPC support is sort of a misty area, but it is based on a | |
well defined set of rules which makes it not <em>that</em> misty | |
after all!</p> | |
<hr /> | |
</body> | |
</html> |