This:
<xs:complexType name="CreateComputerParameters"
substitutionGroup="gb:CreateItemDefinition">
<xs:complexContent>
<xs:extension base="gb:AbstractCreateItemDefinition">
<xs:sequence>
<xs:element name="cpu_speed" type="xs:int"/>
<xs:element name="mb_ram" type="xs:int"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexContent>
<xs:extension base="gb:AbstractCreateItemDefinition">
<xs:sequence>
<xs:element name="cpu_speed" type="xs:int"/>
<xs:element name="mb_ram" type="xs:int"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
Should be this:
<xs:element name="CreateComputerParameters"
substitutionGroup="gb:CreateItemDefinition"
type="tns:CreateComputerParameters"/>
<xs:complexType name="CreateComputeParameters">
<xs:complexContent>
<xs:extension base="gb:AbstractCreateItemDefinition">
<xs:sequence>
<xs:element name="cpu_speed" type="xs:int"/>
<xs:element name="mb_ram" type="xs:int"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
type="tns:CreateComputerParameters"/>
<xs:complexType name="CreateComputeParameters">
<xs:complexContent>
<xs:extension base="gb:AbstractCreateItemDefinition">
<xs:sequence>
<xs:element name="cpu_speed" type="xs:int"/>
<xs:element name="mb_ram" type="xs:int"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
Anne
On 1/23/06, glenn bech <[EMAIL PROTECTED]> wrote:
Hi All,
This is a rather lengthy post, I hope someone will take the time to read it
through, as I've been struggling with the problem for a while. It describes
a complex, "real life", "business" scenario. This one is for you experts out
there! Novices, please skip this post .)
Here is a summary; When creating an application with messages involving
abstract schema types and substitution groups, Axis as a client serializes
messages wrong, ignoring the concrete implementations in the serialization
process using the generated base class for serialization".
I've currently been assigned to create a so called "provisioning" interface
to a company's internal database.
In practice, this means making the existing database modifiable through a
well defined web services interface. I've been trying out axis, but have
some major issues.
The company impose a "standard" for data provisioning, that manifests itself
as an abstract XML Schema, and an abstract WSDL file.
The WSDL file define very generic "Update", "Save" , "Delete" and "Create"
messages. It does not specify "what" to "Update", "Save", "Delete" etc. That
is deferred to implementations like mine. I've created an identical setup,
since I cannot reveal the identity of my customer.
First of all, there is a very generic XSD file that I cannot modify, It's
part of company policy.
It defines a complex type, "AbstractCreateItemDefinition". This is the base
message type for all messages that "create" items in the system.
The idea is to "extend" this Abstract type with create messages for real
items, i.e CreateComputerDefinition, CreateVacumCleanerDefinition.
Please also notice the ref="CreateItemDefinition", this is the "magic" that
lets us put in any element that "extends" AbstractCreateDefinition here.
<xs:schema
targetNamespace="http://www.glennbech.com/abstractiontest/abstract/"
xmlns=" http://www.glennbech.com/abstractiontest/abstract/"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="AbstractCreateItemDefinition" abstract="true"/>
<xs:element name="CreateItemDefinition"
type="AbstractCreateItemDefinition" abstract="true"/>
<xs:element name="Create">
<xs:complexType>
<xs:sequence>
<xs:element name="ItemType" type="xs:string"/>
<xs:element name="ItemID" type="xs:int"/>
<xs:element name="ItemAttributes" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element ref="CreateItemDefinition"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
<xs:element name="CreateResponse" type="xs:int"/>
The WSDL file defines the "Provisioning" port, with only one operation
"Create".
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/ "
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:xs="http://www.w3.org/2001/XMLSchema "
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/ "
xmlns:gb="http://www.glennbech.com/abstractiontest/abstract/"
targetNamespace=" http://www.glennbech.com/abstractiontest/abstract/">
<import namespace="http://www.glennbech.com/abstractiontest/abstract/"
location="abstract.xsd"/>
<import namespace="http://www.glennbech.com/abstraction/concrete/"
location="concrete.xsd"/>
<message name="CreateRequest">
<part name="parameters" element="gb:Create"/>
</message>
<message name="CreateResponse">
<part name="parameters" element="gb:CreateResponse"/>
</message>
<portType name="Provisioning">
<operation name="Create">
<input message="gb:CreateRequest"/>
<output message="gb:CreateResponse"/>
</operation>
</portType>
<binding name="Provisioning" type="gb:Provisioning">
<soap:binding style="document"
transport=" http://schemas.xmlsoap.org/soap/http"/>
<operation name="Create">
<soap:operation soapAction="gb#Create" style="document"/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="Provisioning">
<port name="Provisioning" binding="gb:Provisioning">
<soap:address
location="http://localhost:8888/axis/services/Provisioning "/>
</port>
</service>
There is only one XSD that I have to write, that is the one defining the
actual Items that I want to provision (Create Update Delete and Get)
Please note that they are declared as a part of a substitution group
gb:CreateItemDefinition, matching the "ref" defined in the abstract XML
schema listed previously,.
<xs:schema
targetNamespace=" http://www.glennbech.com/abstractiontest/concrete/"
xmlns="http://www.glennbech.com/abstractiontest/concrete/ "
xmlns:gb="http://www.glennbech.com/abstractiontest/abstract/"
xmlns:xs="http://www.w3.org/2001/XMLSchema ">
<xs:complexType name="CreateComputerParameters"
substitutionGroup="gb:CreateItemDefinition">
<xs:complexContent>
<xs:extension base="gb:AbstractCreateItemDefinition">
<xs:sequence>
<xs:element name="cpu_speed" type="xs:int"/>
<xs:element name="mb_ram" type="xs:int"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType
name="CreateDigitalCameraParameters"
substitutionGroup="gb:CreateItemDefinition">
<xs:complexContent>
<xs:extension base="gb:AbstractCreateItemDefinition">
<xs:sequence>
<xs:element name="megapixels" type="xs:int"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
I run WSDL2Java on the WSDL file
wsdl2java -S -s -W -D -a -o src\ web\abstract.wsdl
... successfully. Everything looks very nice. CreateConmputerParameters are
generated to extend the abstract class.
Generated files are listed here.
Directory of C-.....\src\com\glennbech\www\abstractiontest\concrete
23.01.2006 11:21 <DIR> .
23.01.2006 11:21 <DIR> ..
23.01.2006 11:21 4573 CreateComputerParameters.java
23.01.2006 11:21 3730 CreateDigitalCameraParameters.java
2 File(s) 8303 bytes
Directory of C:\.....\src\com\glennbech\www\abstractiontest\_abstract
23.01.2006 11:48 <DIR> .
23.01.2006 11:48 <DIR> ..
23.01.2006 11:21 2524 AbstractCreateItemDefinition.java
23.01.2006 11:42 6009 Create.java
23.01.2006 11:21 4315 CreateItemAttributes.java
23.01.2006 11:21 3973 deploy.wsdd
23.01.2006 11:21 492 Provisioning_BindingImpl.java
23.01.2006 11:21 10686 Provisioning_BindingStub.java
23.01.2006 11:21 408 Provisioning_PortType.java
23.01.2006 11:21 646 Provisioning_Service.java
23.01.2006 11:21 5703 Provisioning_ServiceLocator.java
23.01.2006 11:48 901 test.xml
23.01.2006 11:21 682 undeploy.wsdd
So I write a test class that invokes a call the service
public static void main(String[] args) throws Exception
{
final String nsURI =
" http://www.glennbech.com/abstractiontest/abstract/";
final String serviceName = "Provisioning";
final String endPointURI =
" http://localhost:8888/axis/services/Provisioning";
final String wsdlURI = "http://localhost:8888/axis/abstract.wsdl";
ServiceFactory serviceFactory = ServiceFactory.newInstance();
Service provisioningService = serviceFactory.createService(new
URL(wsdlURI), new QName(nsURI, serviceName));
Provisioning_BindingStub stub = new Provisioning_BindingStub(new
URL(endPointURI), provisioningService);
final int mhz = 3600;
final int mbRam = 1024;
// This is the really interesting line
Create createComputer = new Create("[EMAIL PROTECTED] ", 1, new Crea
teItemAttributes(new CreateComputerParameters(mhz, mbRam)));
stub.create(createComputer);
}
I deploy the service
adminclient -l http://localhost:9999/axis/services/AdminService
src\com\glennbech\www\abstractiontest\_abstract\deploy.wsdd
Now the trouble arrives... The Axis client side does not serialize my
request object correctly. It does not recognize that I've actually
constructed my "create" message with a CreateComputerParameters, but uses
the abstract class as a base for Serialization.
xis/services/Provisioning HTTP/1.0
Content-Type: text/xml; charset=utf-8
Accept: application/soap+xml, application/dime, multipart/related, text/*
User-Agent: Axis/1.3
Host: localhost:8888
Cache-Control: no-cache
Pragma: no-cache
SOAPAction: "gb#Create"
Content-Length: 543
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<Create xmlns="http://www.glennbech.com/abstractiontest/abstract/">
<ItemType xmlns=""> [EMAIL PROTECTED]</ItemType>
<ItemID xmlns="">1</ItemID>
<ItemAttributes xmlns="">
<ns1:CreateItemDefinition
xmlns:ns1=" http://www.glennbech.com/abstractiontest/abstract/"/>
</ItemAttributes>
</Create>
</soapenv:Body>
As you can see, the "Create" element has a nested "ItemAttributes" element,
that again nest a "CreateItemDefinition" instead of the
"CreateComputerParameters" that should have been serialized.
Is this setup too complex for Axis to handle? Is this setup just to compelx
in general? Should I call the standards department at my customer's company
and tell them to re-define the provisioning standard so it is possible to
implement it ?
All Advice are welcome !
Best regards,
Glenn Bech
