Michael Sobczak
Michael Sobczak

Reputation: 1085

Apache Axis: no containing element

I received the following WSDL from a vendor. The sample service behind it runs on Microsoft .NET. I need to create a web service in Java based on this WSDL.

<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" 
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" 
xmlns:tns="http://www.somecompany.com/" 
xmlns:s="http://www.w3.org/2001/XMLSchema" 
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" 
targetNamespace="http://www.somecompany.com/" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
  <wsdl:types>
    <s:schema elementFormDefault="qualified" targetNamespace="http://www.somecompany.com/">
    <s:import namespace="http://www.w3.org/2001/XMLSchema" schemaLocation="http://www.w3.org/2001/XMLSchema.xsd" />
      <s:element name="getInventoryStatus">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="0" maxOccurs="1" name="DealerCode" type="s:string" />
            <s:element minOccurs="0" maxOccurs="1" name="SupplierCode" type="s:string" />
            <s:element minOccurs="0" maxOccurs="1" name="PartNumber" type="s:string" />
            <s:element minOccurs="1" maxOccurs="1" name="Quantity" type="s:int" />
            <s:element minOccurs="0" maxOccurs="1" name="DeliveryLocation" type="s:string" />
          </s:sequence>
        </s:complexType>
      </s:element>
      <s:element name="getInventoryStatusResponse">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="0" maxOccurs="1" name="getInventoryStatusResult">
              <s:complexType>
                <s:sequence>
                  <s:element ref="s:schema" />
                  <s:any />
                </s:sequence>
              </s:complexType>
            </s:element>
          </s:sequence>
        </s:complexType>
      </s:element>
    </s:schema>
  </wsdl:types>
  <wsdl:message name="getInventoryStatusSoapIn">
    <wsdl:part name="parameters" element="tns:getInventoryStatus" />
  </wsdl:message>
  <wsdl:message name="getInventoryStatusSoapOut">
    <wsdl:part name="parameters" element="tns:getInventoryStatusResponse" />
  </wsdl:message>
  <wsdl:portType name="InventoryInquirySoap">
    <wsdl:operation name="getInventoryStatus">
      <wsdl:input message="tns:getInventoryStatusSoapIn" />
      <wsdl:output message="tns:getInventoryStatusSoapOut" />
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="InventoryInquirySoap" type="tns:InventoryInquirySoap">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
    <wsdl:operation name="getInventoryStatus">
      <soap:operation soapAction="http://www.somecompany.com/getInventoryStatus" style="document" />
      <wsdl:input>
        <soap:body use="literal" />
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal" />
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="InventoryInquiry">
    <wsdl:port name="InventoryInquirySoap" binding="tns:InventoryInquirySoap">
      <soap:address location="http://www.somecompany.com/InventoryInquiry.asmx" />
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

I modified the WSDL I received to include the following line so that Eclipse would recognize the WSDL as valid:

<s:import namespace="http://www.w3.org/2001/XMLSchema" schemaLocation="http://www.w3.org/2001/XMLSchema.xsd" />  <!--  added for Eclipse-->

I've included this WSDL file in a new Dynamic Web Project. I used the New Web Service wizard to create a new top down web service based on the WSDL.

When I deploy the project to Tomcat and call the web service, Apache Axis reports back the following:

AXIS error

Sorry, something seems to have gone wrong... here are the details:

Fault - makeTypeElement() was told to create a type "{http://www.somecompany.com/}>>getInventoryStatusResponse>getInventoryStatusResult", with no containing element

AxisFault faultCode: {http://schemas.xmlsoap.org/soap/envelope/}Server.generalException faultSubcode: faultString: makeTypeElement() was told to create a type "{http://www.somecompany.com/}>>getInventoryStatusResponse>getInventoryStatusResult", with no containing element faultActor: faultNode: faultDetail: {http://xml.apache.org/axis/}hostname:HOME-DELL

The demo web service provided by the vendor returns the following:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <soap:Body>
      <GetInventoryStatusResponse xmlns="http://ctire.aktion.com/">
         <GetInventoryStatusResult>
            <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
               <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
                  <xs:complexType>
                     <xs:choice minOccurs="0" maxOccurs="unbounded">
                        <xs:element name="InventoryStatus">
                           <xs:complexType>
                              <xs:sequence>
                                 <xs:element name="InStock" type="xs:int" minOccurs="0"/>
                                 <xs:element name="EstDeliveryDate" type="xs:string" minOccurs="0"/>
                                 <xs:element name="EstDeliveryTime" type="xs:string" minOccurs="0"/>
                                 <xs:element name="DeliveryLocation" type="xs:string" minOccurs="0"/>
                              </xs:sequence>
                           </xs:complexType>
                        </xs:element>
                     </xs:choice>
                  </xs:complexType>
               </xs:element>
            </xs:schema>
            <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
               <NewDataSet xmlns="">
                  <InventoryStatus diffgr:id="InventoryStatus1" msdata:rowOrder="0" diffgr:hasChanges="inserted">
                     <InStock>36</InStock>
                     <EstDeliveryDate>09/27/2016</EstDeliveryDate>
                     <EstDeliveryTime>12:00 PM</EstDeliveryTime>
                     <DeliveryLocation>883620750</DeliveryLocation>
                  </InventoryStatus>
               </NewDataSet>
            </diffgr:diffgram>
         </GetInventoryStatusResult>
      </GetInventoryStatusResponse>
   </soap:Body>
</soap:Envelope>

I think I need to reference a schema for the NewDataSet in the WSDL, but I'm not sure how to do that.

Upvotes: 6

Views: 1752

Answers (2)

Sergio Otero Lopez
Sergio Otero Lopez

Reputation: 282

It's recommended to use JAX-WS, which is a Java Standard. It cooperates easily with JAXB, which is also needed here.

In this case, the server has a dynamic response which includes an schema definition and a free object, but it seems that is an diffgram node (from a Microsoft XSD) and an object instance that complies with the previous XSD definition and some diffgram attributes.

This solution ignores the diffgram node (but not it's contents) because i don't have the appropiate XSD from Microsoft (it's supposed to be in "msdata.xsd from Visual Studio %InstallRoot%\Xml\Schemas directory). It's only a matter of putting the right XSD and following the steps.

Steps to create the service:

  • Download http://www.apache.org/dyn/closer.lua/cxf/2.7.18/apache-cxf-2.7.18.zip
  • In Eclipse -> Window -> Preferences -> CXF -> Add and then select + apply
  • Create a Dynamic Web Project and put the WSDL in src
  • Web Services -> Generate Java Skeleton -> Runtime CXF -> Finish
  • Put in the schema definition from the sample response in diffgram-v1.xsd

  • Generate JAXB classes in a command line with "xjc diffgram-v1.xsd" (from java bin classpath)

  • Change GetInventoryStatusResponse.GetInventoryStatusResult adding before class definition "@XmlSeeAlso({NewDataSet.class})" to support returning this object via JABX in the service
  • Implement InventoryInquirySoapImpl.getInventoryStatus returning the XSD parsed and an instance of NewDataSet:

        InventoryStatus ie = new InventoryStatus();
        ie.setDeliveryLocation("del");
        ie.setInStock(36);
        ie.setEstDeliveryDate("09/27/2016");
        ie.setDeliveryLocation("883620750");
    
        NewDataSet nds = new NewDataSet();
        nds.getInventoryStatus().add(ie);
    
        GetInventoryStatusResponse.GetInventoryStatusResult _return = new GetInventoryStatusResponse.GetInventoryStatusResult();
    
        _return.setSchema(parseDiffgramSchema());
        _return.setAny(nds);
        return _return;
    
  • parseDiffgramSchema can be implemented with JABX:

    // TODO cache
    URL file = this.getClass().getClassLoader()
            .getResource("diffgram-v1.xsd");
    
    JAXBContext jaxbContext = JAXBContext.newInstance(Schema.class);
    
    Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
    
    Schema schema = (Schema) jaxbUnmarshaller.unmarshal(file);
    
    return schema;
    

Full example in my GIT https://github.com/sergio-otero/TestJAXWS/tree/master/TestJAXWS

Upvotes: 0

actc
actc

Reputation: 682

Do you know soapUI? You can import your WSDL and make some requests against the demo service. Just to check that your infrastructure works properly.

If everything seems to work, try this: Have Java generate the classes from the WSDL via the "wsimport" command like this:

%JAVA_HOME%/bin/wsimport -d [RELATIVE_PATH_FOR_GENERATED_CLASSES] -encoding UTF-8 -keep -verbose [RELATIVE_PATH_OF_YOUR_WSDL]

In your code try to use these generated classes and deploy again.

You can get the full documentation of wsimport from here

Hope that helps in any way.

Upvotes: 0

Related Questions