Over a million developers have joined DZone.

The Java Web App Journey... SOAP Services (Part 1)

If you've been following along with this multi-part series, your Java app has been web-enabled. Now let's get it talking with a SOAP service.

· Java Zone

Microservices! They are everywhere, or at least, the term is. When should you use a microservice architecture? What factors should be considered when making that decision? Do the benefits outweigh the costs? Why is everyone so excited about them, anyway?  Brought to you in partnership with IBM.

Introduction

Our continuing make-believe story:  You work in a team of developers, and some time ago, you took some code that was very useful to you (albeit somewhat simple), and you realized it might be resuable. You made it into a separate project, and later, you wrapped it in a simple command-line application. Some of your teammates saw it and suggested you should have it persist the data, which you did, also delivering round two of the improved command-line application.

Later on, other people either in your department, or elsewhere, asked if you could web-enable it, as they weren't "command-line savvy."

This article is the next one of a series that took us through the above story in steps.

Last article, we completed a web application suitable for in-house use.

You have been recently approached by other people who like and want to use the Shape Calculator, but they need it as part of a workflow; they have no use for a web UI; they want to hook into it via a web service.

We begin this article exploring a SOAP service for your Shape Calculator.

Requirements

Requirement #1

The powers that be have decreed that thou shalt not touch the Shape Calculator project for any external reasons. In other words, no changes or additions related to web services.  (Example: No adding any annotations related to web services). Any changes to the project would be because they improve the Calculator in a general sense. An example could be adding another feature. Or maybe adding the ability to handle more shapes.

Requirement #2

The other department that is interested in using our Calculator via a web service has a requirement — to make sure that any and all operations return in a standard format.  The exact response is negotiable, but they want something like below:

<response>
    <returnStatus>SUCCESS</returnStatus>
    <!-- or :   ERROR -->
    <returnStatusDesc>The operation succeeded ...blah .. blah...blah</returnStatusDesc>
    <returnedResult>
        ...... anything normally returned by the Calculator
    </returnResult>
</response>

Requirement #3

This is an extension or result of #2. No public methods at the web service's most outer layer will return or declare exceptions. We will only return errors. There are only three possible responses from our service calls:

  1. Success (plus optional data).

  2. A specific error.

  3. All other errors.

Development Approach

We can choose to tackle exposing the Calculator using a bottom-up (Java-first) approach, and we can also do a top-down (WSDL-first) approach.

Let's do Java-first for now, and then later, we can start again with WSDL-first.

Simulate Actual Development

I think most articles we read seem to flow from start to finish without any hiccups. No errors. Step 1, Step 2, Step 3, and voila! It works!  Beautiful, right? But we are human, and we probably might be in a rush at work to get something accomplished, or we might miss something, or we didn't really understand what we were doing, or we just didn't bother to delve into things. So, I want to approach things a bit differently. (I have already more or less been doing this from the first article of this series, but I really am emphasizing it here.) I want to set forth the idea that someone might not get things correct on the first try, and that they are going to take incremental steps toward success.

And so, I will tend to not add anything just because I'm supposed to — until it screams, "REQUIRED!" That way, we can learn about possible errors. Hopefully in the future, if you encounter some of these errors, you will remember you saw that error once before, and it was while following an article — and so this could be a reference for you.

Yes, it makes for a longer article. I will have to break them up in parts that make some sense.

Hopefully, with enough section headings, you can speed past whatever you don't need to view.

Which SOAP Framework

There are several frameworks available. Here is an article that discusses three.

I chose to go with Apache CXF, version 3.x.

Start Project

Just as in all of the previous articles of the series, I will be using Eclipse (Neon, not that I think that matters too much), and so let's create a Dynamic Web Project (or whatever suits you).

We could name it something like "web-service-soap-bottom-up" (in reality, I will be doing something different because I need to freeze the code for each article. I will have something like web-service-soap-bottom-up-p1, -p2, -p3, etc)

For more details on the step-by-step, check out the previous articles. I am going to move a bit faster here.

I removed the original "src" source folder and created a few of the expected Maven source folders.

Let's convert it to a Maven project.

We need to add some things to the project POM.

Our immediate need is to add the dependency to the Shape Calculator project, which has been the focal point for the entire article series.

If you have been following along, you can use your own project, but if not, you can get the code from here.

And so I added the Shape Calculator dependency to the new (SOAP) project:

<dependency>
    <groupId>shape-calc-jpa-hibernate</groupId>
    <artifactId>shape-calc-jpa-hibernate</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>


We need Spring:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>${spring.version}</version>
</dependency>


We also need Apache CXF.

<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-frontend-jaxws</artifactId>
    <version>${cxf.version}</version>
</dependency>


We are good enough for now, although we'll most likely have to add more things to the POM in a while.

Here's what my project's POM looks like at the moment:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>web-service-soap-bottom-up-p1</groupId>
    <artifactId>web-service-soap-bottom-up-p1</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
        <spring.version>4.3.2.RELEASE</spring.version>
        <cxf.version>3.1.7</cxf.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>

        <dependency>
            <groupId>shape-calc-jpa-hibernate</groupId>
            <artifactId>shape-calc-jpa-hibernate</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>${cxf.version}</version>
            <!-- <scope>${cxf.scope}</scope> -->
        </dependency>

    </dependencies>


    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>${maven.compiler.source}</source>
                    <target>${maven.compiler.target}</target>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <warSourceDirectory>WebContent</warSourceDirectory>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

I did a Maven update, checked the libraries folder, and saw the jars present. We seem to be ready for some real development now.

Create Our Own Wrapper

Based on the two requirements mentioned, we will create a wrapper for our Shape Calculator.

If we take a look at the Shape Calculator project classes, we see the main starting point is the ShapeCalculatorService (interface) and ShapeCalculatorServiceImpl.

I am going to use the interface as a starting template. I copied that interface from the shape-calc-jpa-hibernate project and placed it in a new package created in our new SOAP service project. I also renamed the class a bit.

Image title

Next, we need to change the returns of all the operations, as per requirement #2. This can be in flux, but let's take a stab at it.

For all the operations returning either void or int, I chose to return an as-of-yet-undefined SuccessOrErrorResponse type. Then, there are two other types we need to define, which could be sub-classes of the SuccessOrErrorResponse.

Image title

Create Our Wrapper Response Types

And so here are the empty beginnings of the new return types:

Image title


@WebService

This annotation is required on the implementation. Our interface is not even a requirement, but it is suggested. If so, it, too, should have the annotation.  There are some attributes you can specify with @WebService, but for now, the defaults seem to do just fine.

Once we have added this annotation to both (class-level), we are ready to work on generating a WSDL.

Setup Java-to-WSDL

It is time to test-drive if we can generate a WSDL from the little code we have written.

In order to generate the WSDL, we need to add a plugin to our POM:

<groupId>org.apache.cxf</groupId>
<artifactId>cxf-java2ws-plugin</artifactId>


Java2WS Plugin

We can add it as part of our Maven build process. So, here is the plugin configuration:

<plugin>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-java2ws-plugin</artifactId>
    <version>${cxf.version}</version>
    <executions>
        <execution>
            <id>process-classes</id>
            <phase>process-classes</phase>
            <configuration>
                <className>com.eli.calc.shape.service.ws.ShapeCalculatorWebService</className>
                <serviceName>ShapeCalculatorWebService</serviceName>
                <address>http://localhost:8080/web-service-soap-bottom-up/services/ws/ShapeCalculatorWebService</address>
                <genWsdl>true</genWsdl>
                <genWrapperbean>false</genWrapperbean>
                <verbose>true</verbose>
                <argline>
                    -createxsdimports -s ${project.build.directory}/generated/src -classdir ${project.build.outputDirectory}
                </argline>
                <soap12>true</soap12>
            </configuration>
            <goals>
                <goal>java2ws</goal>
            </goals>
        </execution>
    </executions>
</plugin>


Plugin Management

However, it will not run as-is. There will be a lifecycle complaint. So, we will add a <pluginManagement> ..... </pluginManagement>  block as well:

<pluginManagement>
    <plugins>
        <plugin>
            <groupId>org.eclipse.m2e</groupId>
            <artifactId>lifecycle-mapping</artifactId>
            <version>1.0.0</version>
            <configuration>
                <lifecycleMappingMetadata>
                    <pluginExecutions>
                        <pluginExecution>
                            <pluginExecutionFilter>
                                <groupId>org.apache.cxf</groupId>
                                <artifactId>cxf-java2ws-plugin</artifactId>
                                <versionRange>[${cxf.version},)</versionRange>
                                <goals>
                                    <goal>java2ws</goal>
                                </goals>
                            </pluginExecutionFilter>
                            <action>
                                <execute />
                            </action>
                        </pluginExecution>
                    </pluginExecutions>
                </lifecycleMappingMetadata>
            </configuration>
        </plugin>
    </plugins>
</pluginManagement>


The Complete POM

Here is the latest, complete POM:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>web-service-soap-bottom-up-p1</groupId>
    <artifactId>web-service-soap-bottom-up-p1</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
        <spring.version>4.3.2.RELEASE</spring.version>
        <cxf.version>3.1.7</cxf.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>

        <dependency>
            <groupId>shape-calc-jpa-hibernate</groupId>
            <artifactId>shape-calc-jpa-hibernate</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>${cxf.version}</version>
        </dependency>

    </dependencies>


    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.eclipse.m2e</groupId>
                    <artifactId>lifecycle-mapping</artifactId>
                    <version>1.0.0</version>
                    <configuration>
                        <lifecycleMappingMetadata>
                            <pluginExecutions>
                                <pluginExecution>
                                    <pluginExecutionFilter>
                                        <groupId>org.apache.cxf</groupId>
                                        <artifactId>cxf-java2ws-plugin</artifactId>
                                        <versionRange>[${cxf.version},)</versionRange>
                                        <goals>
                                            <goal>java2ws</goal>
                                        </goals>
                                    </pluginExecutionFilter>
                                    <action>
                                        <execute />
                                    </action>
                                </pluginExecution>
                            </pluginExecutions>
                        </lifecycleMappingMetadata>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>


        <plugins>

            <plugin>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-java2ws-plugin</artifactId>
                <version>${cxf.version}</version>
                <executions>
                    <execution>
                        <id>process-classes</id>
                        <phase>process-classes</phase>
                        <configuration>
                            <className>com.eli.calc.shape.service.ws.ShapeCalculatorWebService</className>
                            <serviceName>ShapeCalculatorWebService</serviceName>
                            <address>http://localhost:8080/web-service-soap-bottom-up/services/ws/ShapeCalculatorWebService</address>
                            <genWsdl>true</genWsdl>
                            <genWrapperbean>false</genWrapperbean>
                            <verbose>true</verbose>
                            <argline>
                                -createxsdimports -s ${project.build.directory}/generated/src -classdir ${project.build.outputDirectory}
                            </argline>
                            <soap12>true</soap12>
                        </configuration>
                        <goals>
                            <goal>java2ws</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>${maven.compiler.source}</source>
                    <target>${maven.compiler.target}</target>
                </configuration>
            </plugin>

            <plugin>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <warSourceDirectory>WebContent</warSourceDirectory>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>

        </plugins>

    </build>

</project>

Some items of note in the POM:

<genWsdl>true</genWsdl>
<genWrapperbean>false</genWrapperbean>
<verbose>true</verbose>
<argline>
    -createxsdimports -s ${project.build.directory}/generated/src -classdir ${project.build.outputDirectory}
</argline>

  • We are generating the WSDL.

  • We are NOT generating Wrapper/Fault Bean (we'll come back to this later).

  • We are going to create a separate schema file from the WSDL.

Run Maven

Now we do a Maven clean install, and it should compile our new, basic classes, then run the java2ws, and then generate the war file.

We can then go to <project base dir>target/generated/wsdl and see the wsdl and schema files have been generated.

Image title


To Be Continued...

I will provide a link to the latest code when we arrive at article Part 3 of exploring a SOAP service.

Stay tuned for the next article!

Discover how the Watson team is further developing SDKs in Java, Node.js, Python, iOS, and Android to access these services and make programming easy. Brought to you in partnership with IBM.

Topics:
spring ,soap ,wsdl ,java

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

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

{{ parent.tldr }}

{{ parent.urlSource.name }}