Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Exploring A Top-Down SOAP Service: Part IV

DZone's Guide to

Exploring A Top-Down SOAP Service: Part IV

Eli Corrales takes us through the next steps in exploring a top-down SOAP service.

· Web Dev Zone
Free Resource

Tips, tricks and tools for creating your own data-driven app, brought to you in partnership with Qlik.

Last time...

When we left off in Part III, we had a basic web service running with one simple operation that can return an integer (of how many calculations were performed). It will also return a SOAP fault if there is an exception (such as the database not available).

Latest Code

You can get the latest code for the web service here. And for our dependency on our child (Shape Calculator project), here. And if you want to read all of the chronological articles that have led us to this one, you can go here.

A Brief Review

I hope that by having followed along from Part I through this point, you see that not only does a WSDL definition have certain key sections, but there is a dependency trail, in the sense that in order to generate the sources, you need a service. But for a service, you'll need a binding. And for a binding, a portType, and so on.  I display the sections below, with their inner workings removed for simplicity.

Image title

The operation(s), parameters, and responses, exist within several namespaces, and there is some dependency.  In the next section below we construct an example using these namespaces.

Image title

Side Trip - Multiple Schemas and Namespaces

Part 1 - Just Two elements, A Parameter, and A Response

Before we continue with the real development that we need to do, let's play a bit with some simple types and use multiple schemas and namespaces.

Temporarily, let's make our single operation accept an integer parameter and return its integer response. So we begin by adding the integer parameter to the request message of the operation, and we show both:

    <wsdl:message name="runAllPendingRequestsNoStopOnError">
        <wsdl:part name="parameters" element="RunAllParams" />
    </wsdl:message>

    <wsdl:message name="runAllPendingRequestsNoStopOnErrorResponse">
        <wsdl:part name="response" element="RunAllResponse" />
    </wsdl:message>

We already have the response defined in the schema, but we need to define the parameters.

    <wsdl:types>
        <xsd:schema 
            xmlns:xsd="http://www.w3.org/2001/XMLSchema">
            <xsd:element name="RunAllParams" type="xsd:int" />
            <xsd:element name="RunAllResponse" type="xsd:int" />
        </xsd:schema>
    </wsdl:types>

Generate Sources

The short story is that now the service interface, and the implementation, both, of course, show an int parameter for our runAllPendingRequestsNoStopOnError() method.

You will notice quite a bit of difference if you were to compare our working interface with the most recent generated one.  However, we have held off and kept ours. And I will still hold off.

Reconcile

Our code reconciliation consists of just adding an int parameter to our working copies.

Build.Deploy

We do a Maven install and make sure the Tomcat server has the latest copy.

Start

Make sure MySQL is running, check for clean start in console.

WSDL

Grab the WSDL URL (and why not see that it shows the integer param)... plop it in a new SOAPUI project.

Test

Invoke the operation.

Image title

Looks good.

Part 2 - Separate  Namespaces and Schemas

Soooo... let's see if we can place our parameter in one schema, our response in another, and both be in different namespaces from the operation's namespace.

    <wsdl:types>
        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
            <xsd:element name="RunAllParams" type="xsd:int" />
        </xsd:schema>

        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
            <xsd:element name="RunAllResponse" type="xsd:int" />
        </xsd:schema>
    </wsdl:types>

The above is missing something.  We want separate schemas, and we need each to reference  xsd:  because otherwise, we'll not get the xsd:int  type. But they both look the same. And there's nothing that indicates they're in a separate namespace from the operation/message space.

That is where targetNamespace comes in.

    <wsdl:types>
        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
            targetNamespace="http://parms.ws.service.shape.calc.eli.com/" >

            <xsd:element name="RunAllParams" type="xsd:int" />

        </xsd:schema>

        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
            targetNamespace="http://resp.ws.service.shape.calc.eli.com/" >

            <xsd:element name="RunAllResponse" type="xsd:int" />

        </xsd:schema>
    </wsdl:types>

Observe that the targetNamespace is different for each. If you compare that with the <wsdl:definitions .....>  heading, you'll notice they are different from the base namespace.

Generate Sources


[ERROR] Part <response> in Message <{http://ws.service.shape.calc.eli.com/}runAllPendingRequestsNoStopOnErrorResponse> referenced Type <RunAllResponse> can not be found in the schemas

[ERROR] Part <parameters> in Message <{http://ws.service.shape.calc.eli.com/}runAllPendingRequestsNoStopOnError> referenced Type <RunAllParams> can not be found in the schemas

Why not?  Because in the <wsdl:message><wsdl:part....> , we haven't specified the namespace for these elements.

But how can we?  What is the namespace prefix?  It can be whatever you want. Let's stick with what we have: parms and resp .

We do this:

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions 
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:tns="http://ws.service.shape.calc.eli.com/" 
    targetNamespace="http://ws.service.shape.calc.eli.com/" 
    V------------------------- NEW ----------------------------V
    xmlns:parms="http://parms.ws.service.shape.calc.eli.com/" 
    xmlns:resp="http://resp.ws.service.shape.calc.eli.com/" 
    ^------------------------- NEW ----------------------------^
    >

    <wsdl:types>
        ....  types defined here already....
    </wsdl:types>

    <wsdl:message name="runAllPendingRequestsNoStopOnError">
    <wsdl:part name="parameters" element="parms:RunAllParams" />
    </wsdl:message>

    <wsdl:message name="runAllPendingRequestsNoStopOnErrorResponse">
    <wsdl:part name="response" element="resp:RunAllResponse" />
    </wsdl:message>

At the top, we give labels to the new namespaces (the URIs better match), and within each message part, we use those labels as prefixes.

Voila, that worked.

Analyze / Reconcile Code

Image title

Taking a look at the two main generated files, we do not see any change in the implementation.  The interface has some annotations that specify the new namespaces.

We probably can leave our working copies as-is.

The above was just an exercise; we won't be using those particular parameters and responses.

Next, let's separate out all of the schema(s) into separate files from the WSDL, and just reference them.

Part 3 - Separate Schema File(s)

At the moment, our WSDL has the schema defined within:

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions 
    ...... more wsdl stuff here.....
    >

    <wsdl:types>
        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
             ....... definitions here......
        </xsd:schema>
    </wsdl:types>

    ...... more wsdl stuff here.....

We want to change the above portion that is within the<schema ..>.....</schema>, from defining our types, to just being a reference to another file (XSD) that defines our types.

    <wsdl:types>
        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
            <xsd:import namespace="http://resp.ws.service.shape.calc.eli.com/" 
                        schemaLocation="./ShapeCalcResp.xsd" />
        </xsd:schema>
    </wsdl:types>

We introduced a new tag: <xsd:import....>...</xsd:import>.  It references the (yet-to-be-created) external XSD file.  Note the namespace attribute.

Two ways of referencing schema files external to the WSDL file, is to use import, or use include. One difference between the two is that with import, it must be in a different namespace. We want import because we want our custom types to end up in different Java packages from our service operation package.

Now let's create the new, external XSD file.

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    targetNamespace="http://resp.ws.service.shape.calc.eli.com/"  
    xmlns:resp="http://resp.ws.service.shape.calc.eli.com/"
    elementFormDefault="qualified"
    >

    <xsd:element name="RunAllResponse" type="xsd:int"/>

</xsd:schema>

Notice we have moved our RunAllResponse to this file.

The last thing we need to do is back at our WSDL, and change the namespace and prefix.

And I also want to do one bit of cleanup on our input message.

For this single operation we have at the moment, we do not really need a parameter for the input message, so let's clean that up before moving on.  It becomes very simple:

    <wsdl:message name="RunAllPendingRequestsNoStopOnError" />

Here now is the updated first portion of the WSDL:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions 
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    targetNamespace="http://ws.service.shape.calc.eli.com/"
    xmlns:tns="http://ws.service.shape.calc.eli.com/" 
    xmlns:resp="http://resp.ws.service.shape.calc.eli.com/" 
    >

    <wsdl:types>
        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
            <xsd:import namespace="http://resp.ws.service.shape.calc.eli.com/" 
                schemaLocation="./ShapeCalcResp.xsd" />
        </xsd:schema>
    </wsdl:types>


    <wsdl:message name="RunAllPendingRequestsNoStopOnError" />

    <wsdl:message name="RunAllPendingRequestsNoStopOnErrorResponse">
        <wsdl:part name="response" element="resp:RunAllResponse" />
    </wsdl:message>

So we have the  xmlns:resp  prefix, we have the import with the proper namespace, and we reference a type from that namespace in the response message part.

Generate Sources

[INFO] ------------------------------------------------------------------------

[INFO] BUILD SUCCESS

[INFO] ------------------------------------------------------------------------

Next....

Let's start the real work of creating the parameters and responses to meet our requirements.

See you next time!

Note: Normally at the end of an article, this section has links to the latest code to this point in our progress, however, that is not the case with this article.  I will have that for you at the end of the next article. I apologize.

Explore data-driven apps with less coding and query writing, brought to you in partnership with Qlik.

Topics:
java 8 ,j2ee ,soap ,wsdl ,schema ,xsd ,wsdl2java ,web services ,cxf ,namespaces

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}