Chapter 4 System Implementation
4.3 Gateway Service: onDesc()
The Gateway Service onDesc() is responsible for transforming the MIDL document from WSDL document, and returning it to MOSP clients. We choose to create the MIDL document in Gateway Service constructor, with a WSDL URL string as the input argument. It is because the MIDL document is generated from WSDL URL. If the constructor contains the WSDL URL string as input argument, we can set up the MIDL document for later use once creating the Gateway Service.
To parse a WSDL document, we build a Java class which imports WSDL4J, JDOM and Castor project. First of all, with WSDL4J, we can use the method
readWSDL(String WSDL_URL) from class javax.wsdl.xml.WSDLReader to read a WSDL document and parse it to a javax.wsdl.Definition object. It is named
“Definition” because a WSDL document is XML based, which ordinarily with a root element named “definition”, as the sample WSDL document shown in Figure 4-5.
The definition element has child elements, with the same architecture as shown in Figure 2-8, which are types, message, portType, binding and service as Figure 4-5 shows. With the Definition object, we can easily get those child elements as Java objects by method call.
As we mentioned in Section 3.1.3, to transform WSDL into MIDL, we need to focus on the Service Interface Definition part, the types and message and portType elements shown in Figure 4-5. Figure 4-6 shows these three parts we abstracted from the WSDL document in Figure 4-5. First we can get the operations provided from portType, and each operation contains an input and an output message, each of which relates to one of the message elements by its name. Each message contains a message part, which relates to an “element” element in the child element schema of types by element name. Each element relates its type to a complexType by the complexType name. Furthermore, each complexType contains one or more elements, and each of which contains a type relating to another complexType or a defined type, such as XML string type shown in the first complexType in Figure 4-6 (xs:string represents the string type in namespace xs, which is the XML schema defined in the definition element of this WSDL document). Note that the name of each xml element differentiates from its local name and namespace, for instance, tns represents the namespace of the WSDL document itself, such that tns:getCountry refers to the complexType getCountry defined by this WSDL document. All these elements will be parsed to Java objects, which can be abstracted from the Definition object.
With the above steps, we can read the WSDL document in Figure 4-6 as follows.
The portType element says that there is one service named getCountryService, which provides an operation named getCountry, with input message getCountry
and output message getCountryResponse. The input message getCountry relates to the complexType getCountry, which contains an XML string array named city
(maxOccurs represents the max occurrence times of this element, unbounded means the occurrence time is unbounded. We can see the elements whose maxOccus is more than 1 or unbounded as an array); the output message getCountryResponse relates to complexType getCountryResponse, which contains the complexType country.
country contains an XML string named name and another XML string named
president. It means that the operation getCountry input parameter is the string
city, and the return type is a complexType with two string parameters. We can transform WSDL into MIDL as shown in Figure 4-7.
As we can see in this MIDL document, it provides a more intuitive way of describing a service. To transform WSDL into MIDL document, we first transform each portType into a MIDL document, and then transform each operation in portType into the operation in the MIDL document. Then we set the return type and input arguments of each operation from the WSDL input/output message and types.
In WSDL Types element, there are some redundant complexType in a WSDL document, and we can trim it with the algorithm shown in Table 4-2 when transforming WSDL Types into MOSP types.
// On WSDL input message:
Get input message element in_msg_elem;
MOSPType[] in_mosp_types;
if ( in_msg_elem.getType().isComplexType() ) {
element[] elems = in_msg_elem.getType().getSubElements();
if ( no elem in elems is ComplexType ){
// On WSDL output message:
Get output message element type out_msg_elem;
MOSPType out_mosp_type;
if ( out_msg_elem.getType().isComplexType() ) {
element[] elems = out_msg_elem.getType.getSubElements();
if ( elems.size()==1 AND !elems[0].isComplexType() ) {
out_mosp_type = to_mosp_type(elem); // expends out_msg_elem
} } else {
out_mosp_type = to_mosp_type(out_msg_elem);
}
Table 4-2: The WSDL input/output message type to MOSP type
MOSPType to_mosp_type( element element ) { MOSPType mospType;
mospType.name = element.name;
// XML primitive data types to MOSP primitive data types if ( element.getType().isPrimitiveType() ) {
mospType = to_mosp_prim_type(element.getType());
// The transformation rule is listed in Table 4-4 and Table 4-5 }
// XML complexTypes to MOSP struct types
else if ( element.getType().isComplexType() ) { mospType = createMOSPStruct(element.getType());
}
// XML array types to MOSP array types
if ( element.maxOccurs > 1 OR element.maxOccurs.isUnbounded() ) { mospType.toArrayType(); // append #[] sign to the end
}
return mospType;
}
MOSPStruct createMOSPStruct( complexType complexType ) { MOSPStruct MOSP_st;
// MOSPStruct extends MOSPType and contains primitive and struct type // arguments in its argument_List
MOSP_st.type = complexType.name;
element[] elems = complexType.getSubElements();
for each ( elem in elems ) {
if ( elem.getType().isPrimitiveType() ) { MOSPPrim arg;
arg.name = elem.name;
arg.type = to_mosp_prim_type(elem.getType());
MOSP_st.argList.add(arg);
}
else if ( elem.isComplexType() ) MOSP_st.name = elem.name;
MOSP_st.argList.add(createMOSPStruct(elem.getType()));
}
return MOSP_st;
}
Table 4-3: The type transformation algorithm
We have described the meaning of each element in MIDL in Section 2.2.3. Some data type transformation rules needs to be made during the transformation. First is the transformation between XML primitive data types and MOSP primitive data types.
Then is the transformation between XML array types and MOSP array types. Last is the transformation between XML complexTypes and MOSP struct types. We list the type transformation algorithm in Table 4-3.
We define an OperationInfo class to record each operation name, and its return type and input arguments while parsing the Definition object of WSDL. The input arguments and return type is a list with MOSPArg object or MOSPStruct object. We define MOSPArg and MOSPStruct classes to record the argument types, which are primitive type and struct type respectively. MOSPStruct may contain one or more MOSPArg or MOSPStruct objects, just as complexType which may contain one or more primitive type arguments or complexType arguments. This transformation is listed in the second part of Table 4-3.
To get the operation information we mentioned above, as we know, we need to get the portType information first. With Definition.getPortTypes(), we can get the PortType objects; with PortType.getOperations(), we can get Operation objects.
With Operation object, we can finally get the information such as operation name and input/output message.
To transform input/output message into arguments, we need to parse Message and Types object, from Definition.getMessages() and Definition.getTypes()
respectively. Types object only contains a DOM object of the schema element, thus we use JDOM to transform this DOM object into JDOM object, and then use Castor project to transform JDOM object into Schema object, which contains objects such as Element and ComplexType. With Schema object, we can thus get argument information from method calls. With the information we need, we can transform WSDL data types into MIDL data types with the algorithm shown in Table 4-3.
Now, we can finally transform WSDL document into MIDL document. However, there exist some limitations. For example, element may contain some attributes such as minOccurs (minOccurs represents the minimum occurrence time of this element) or nillable (nillable is a boolean value, representing if this element can be set to null), which we can not transform into MIDL since MIDL does not contain these properties.
After generating the MIDL document, Gateway service will directly marshal it to MOSP response message transferred to MOSP clients.
<definitions xmlns= “http://schemas.xmlsoap.org/wsdl/” xmlns:xs= “http://www.w3.org/2001/XMLSchema” ...
xmlns:tns= “http://service/” targetNamespace=“http://service/”>
<types>
<portType name=“getCountry”>
<operation name=“…”>
<service name=“getCountryService”>
<port name=“…” binding=“…”>
<soap:address location=“…”/>
</port>
</service>
</definitions>
Figure 4-5: A sample of WSDL document
<types>
<schema>
<element name=“getCountry” type=“tns:getCountry”/>
<element name=“getCountryResponse” type=“tns:getCountryResponse”/>
<complexType name=“getCountry”>
<part name=“parameters” element=“tns:getCountry”/>
</message>
<message name=“getCountryResponse”>
<part name=“parameters” element=“tns:getCountryResponse”/>
</message>
<portType name=“getCountryService”>
<operation name=“getCountry”>
<input message=“tns:getCountry”/>
<output message=“tns:getCountryResponse”/>
</operation>
</portType>
Figure 4-6: The description part of a WSDL document
<midl role=“instance” xmlns=“mt:/val/xml/midl”>
<op name=“getCountry” type=“#country”>
<arg type=“mt:/val/str#[]” name=“city”/>
</op>
<st name=“country”>
<arg type=“mt:/val/str” name=“name”/>
<arg type=“mt:/val/str” name=“president”/>
</st>
</midl>
Figure 4-7: An MIDL document transformed from WSDL document
XML Data Type MOSP Data Type
Table 4-4: Mappings between XML and MOSP data types – 1
XML MOSP
Table 4-5: Mappings between XML and MOSP data types – 2
When deciding the mappings between XML and MOSP data types, we face a dilemma of getting more precise types or clarifying the inheritance relationship between types. For instance, xml unsignedLong type is actually derived from
unsignedInteger and contains value space from 0 to 18,446,744,073,709,551,615, while long value space is - 9,223,372,036,854,775,808 to 9,223,372,036,854,775,807.
If we let unsignedLong inherits from long in MOSP data type hierarchy, its value space will limit from 0 to 9223372036854775807, which is half of the original value space. After consideration, we think the value space is already sufficient for users.
Clearer inheritance relationship is more important for MOSP users.