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

Converting a Web App Into a SOAP Client: Part I

DZone's Guide to

Converting a Web App Into a SOAP Client: Part I

In this series, Eli Corrales takes us through converting a web app into SOAP client.

· Web Dev Zone
Free Resource

Get deep insight into Node.js applications with real-time metrics, CPU profiling, and heap snapshots with N|Solid from NodeSource. Learn more.

Introduction

We have been moving along this imaginary journey of organically growing what began as a very humble, simple piece of "useful" (let's pretend) software, that has undergone through enhancements and stages, and you can read about all of that in these past articles.

Although each article, or a sub-group of them, has a focus, it makes the most sense when you have the complete context by having reviewed all of them.

Our goal is to cover older, current, and newer technologies that are typically still brought into play in the life of a software system, and we can use the ongoing, make-believe story... sort of a "day-in-the-life-of-a-software-engineer" as a motivation.

Hopefully, we'll discover or highlight some gotchas and pitfalls along the way, or different ways of doing something.

The near-future target we have in mind is securing web services and how clients would interact with them.

The Story Continues...

So you have delivered various iterations of this software, and the last was a combined SOAP-REST web service "wrapper" around the core piece, which is the Shape Calculator.

The original command-line app, and the web app, need to be upgraded/modified to use the latest web service.  Right now, both the command-line and the web app are tightly coupled to the Shape Calculator.  They call its operations directly;  they have the jar.

One goal you would like to achieve is to be able to possibly make internal improvements to the calculator component, without forcing the other people/departments that are using these apps, too have to get an updated copy of the Shape Calculator jar.

Another improvement is that you would like to have only one focal point or source for runtime.  One server running the calculator - not various copies all over the place.

A resulting third benefit would be that there wouldn't be different versions "in the wild" , and everyone would quickly become aware if they are not running the latest version.

Also, your department is going to restrict access to the Shape Calculator project - to other departments; they will not have access to the source.

Remember that you've already delivered these first-iteration services to a department that is trying them out, and is going to incorporate them into their own system processes...

..so, by you developing and converting these clients, you may expose some weaknesses or something that is missing, before the other departments do, and also these clients could become a good way to test/validate/manage the services.

Another possibility could be that you deliver these converted apps and other departments can use them as starting point upon which to layer whatever else they need.

You could later add features that are only available to your department, via your new management apps.  Perhaps you'll want to collect metrics... who's using the services, how often, what's the traffic, etc., etc. Perhaps you'll want to make the web services secure.

The Technologies

As we have been all along this series of articles, we will be using:

  • Java 8
  • Maven 3.3.9
  • CXF 3.1.7
  • Spring 4.3.2
  • and Eclipse (Neon) (trivial)

Command-Line Client Update

In our story, we've given control/ownership of the command-line client over to another department, and advised them to modify it to use the running SOAP service and do away with the direct dependence on the Shape Calculator jar(s).

(What we cover during this phase carries over when we go to convert the web application,so this part is not a waste.)

Get Latest Code

We will be converting the previous release of the command-line app. You can get the code here.

The converted app will be communicating with the combo SOAP-REST web service that we just completed in the most recent articles. The code is here.

Everything we have covered and discussed in all of the articles hinges on the core Shape Calculator project. The SOAP-REST service wraps and exposes it to the outside world.  The code is here.

We will be borrowing from, tweaking, or converting all of the above.

The Conversion To SOAP Client

Image title

So, everywhere in the main app class that you see "calculator", it will be replaced with "soapClient".

We Start - New Project - Command-Line App, Version 3

I am actually going to create a new project for this phase, to make it easier to show the steps, and whatever we might find interesting to share... and I will copy files over from version 2 as needed.

So we begin with a straight Java project in Eclipse, and we convert it to a Maven project.  (Feel free to do it your way).

Before bringing in any of the previous version's files, let's set up our POM so that we can prove we are generating our SOAP-related code.

Starting 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>1-cmdline-app-soap-client-p1</groupId>
    <artifactId>1-cmdline-app-soap-client-p1</artifactId>
    <version>0.0.1-SNAPSHOT</version>

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

        <!-- ================  more stuff (to come) here ========================== --> 

    </properties>

    <dependencies>

        <!-- =========== logging dependencies ================= -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>1.7.21</version>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.1.7</version>
        </dependency>

    </dependencies>



    <build>

        <plugins>

        <!-- ================  CLEAN ========================== --> 


               ......    more here .....


        <!-- ================  WSDL2JAVA ========================== --> 


               ......    more here .....


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

        <!-- ================  EXE JAR ========================== --> 

               ......    more here .....


        </plugins>

    </build>

</project>

In the previous command-line app's POM, we had a dependency to the Shape Calculator project.  Not anymore.

POM: WSDL2Java

Now we add a key piece.... we are going to have this next version of the command-line app use generated classes to handle the SOAP communication...

            <!-- Generate Java classes from WSDL during build -->
            <plugin>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-codegen-plugin</artifactId>
                <version>${cxf.version}</version>
                <executions>
                    <execution>
                        <id>generate-sources</id>
                        <phase>generate-sources</phase>
                        <configuration>

                            <!-- which source folder the generated classes should be placed in 
                                a package -->

                            <sourceRoot>${project.basedir}/src/main/java</sourceRoot>
                            <wsdlOptions>
                                <wsdlOption>

                                    <!-- get the wsdl file from this location -->

                                    <wsdl>${web-service-wsdl-url}</wsdl>
                                    <extraargs>
                                        <extraarg>-client</extraarg>
                                    </extraargs>
                                </wsdlOption>
                            </wsdlOptions>
                        </configuration>
                        <goals>
                            <goal>wsdl2java</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

Notice the $<wsdl>{web-service-wsdl-url}</wsdl> .   We are going to have our plugin use a live URL, not a file.

Also, we are going to have the generated source code go right into the project's src/main/java folder.

That means we need a running SOAP service.  This where the afore-mentioned SOAP-REST service comes into play.

Start Service, Check It

As detailed or mentioned in just about every previous article, make sure you are running MySQL.

After we start, we see an error-free Eclipse console output.  We use a browser to check for a proper WSDL (and grab the URL)...

Image title

....looks good.

POM: WSDL URL

Ok,  we use that URL as the WSDL location in the client app's POM...

    <properties>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <cxf.version>3.1.7</cxf.version>
        <!-- ================  WSDL URL here ========================== --> 
        <web-service-wsdl-url>
          http://localhost:8080/1-ws-rest-p3/services/soap/shapecalc?wsdl
        </web-service-wsdl-url>
    </properties>

Maven

Here is what the new project tree-structure looks like before we do anything else..

Image title

We do a Maven install (it hits the live service)... and here is the updated project...

Image title

POM: Clean

Let's add a way to clean that generated code from our source folder...

            <plugin>
                <artifactId>maven-clean-plugin</artifactId>
                <version>3.0.0</version>
                <configuration>
                    <filesets>
                        <fileset>
                            <directory>src/main/java/com/eli/calc/shape/service</directory>
                            <followSymlinks>false</followSymlinks>
                        </fileset>
                    </filesets>
                </configuration>
            </plugin>

Maven Clean

As a test, if we run that, we see all the generated files disappear.  Ok, let's move on.

Copy Code From Previous App

The main file in the command-line application is the SimpleComandLineMenuDrivenShapeCalcApp; we should rename it to something a bit simpler. How about: CmdLineShapeCalcApp. We also bring over a helper class (ShapeCalculationReports) from the previous app version.

Here's what we have so far:

Image title

New Package, Same Classes

If you take a look at the classes in the generated  com.eli.calc.shape.service.ws  package, there is a ShapeName and CalcType. These are equivalent to the classes on the server-side (our running SOAP service), via the imported Shape Calculator jar, but they are in  a different package.

Below is our running service.

Image title

So, inside CmdLineShapeCalcApp, remove the old imports for ShapeName and CalcType, and re-import the new package(s).

SOAP Stub Entry Point

If we do another Maven install to re-generate the SOAP-related code, we see that the most important Java class in the generated code is the  

ShapeCalculatorWebService_ShapeCalculatorWebServiceImplPort_Client.

It is this class that will be our liaison / entry point / stub (use your own words) to communicate with the SOAP service.  Our main application class (pre-exists from before) will use this entry point, instead of the "calculator" references that you now see (before any changes) throughout the main application code.

Taking a look inside the above-mentioned generated class, we see a main() method that initializes, then invokes each of the SOAP service's public service methods, and each invocation exists inside a block "{ }". 

What we are going to do first is to copy the class over from its current package over to the  apps  package alongside our main application class.

After that, we move some of the initialization code into a (new) constructor for that class.

Then, we take each of the service-operation-invocation blocks and make those public methods.

Here, as an example, is just one of the generated code blocks, as-is with no changes:

        {
        System.out.println("Invoking getPendingRequests...");
        com.eli.calc.shape.service.ws.PendingRequestsResponse _getPendingRequests__return = port.getPendingRequests();
        System.out.println("getPendingRequests.result=" + _getPendingRequests__return);


        }

And here is the equivalent code, converted, and refined into a method:

    public List<CalculationRequest> getPendingRequests() {

            System.out.println("Invoking getPendingRequests...");
            com.eli.calc.shape.service.ws.PendingRequestsResponse _getPendingRequests__return = port.getPendingRequests();

            if (!_getPendingRequests__return.getCode().equals(StatusCode.SUCCESS)) {
                throw new RuntimeException("\n\n\n"
                        +"Service returned error:\n"
                        +"descrp:"+_getPendingRequests__return.getDescription()
                        +"errMsg:"+_getPendingRequests__return.getErrMsg()
                        +"clazz:"+_getPendingRequests__return.getClazz()
                        );
            }

            List<CalculationRequest> pending = _getPendingRequests__return.getPendingRequests();

            return pending;
    }

And we would repeat the above for all the operations. At the end of this article, you can get links to the source, and you can compare the generated(untouched) class to the working, modified copy.

CmdLineShapeCalcApp — From Calculator to SOAP Client

The main class we copied over from the previous (version 2) of the Command-Line App, has a reference to a calculator reference everywhere we need to invoke the Shape Calculator methods, and we also had the calculator  @Autowired , thus we needed a Spring Application context. 

We can do away with the Spring-related code and annotations and calculator, and instead, we replace the class-scope calculator with  soapClient, of type:

ShapeCalculatorWebService_ShapeCalculatorWebServiceImplPort_Client.

POM: Exe Jar

We segmented the <plugins>.....</plugins>    section of the POM into four areas and we have covered all but the last one.

So now we add the following:

        <!-- ================  EXE JAR ========================== --> 
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.0.0</version>
                <configuration>
                    <outputDirectory>${project.build.directory}/jarDir</outputDirectory>
                    <finalName>1-cmdline-app-soap-client-p1</finalName>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <mainClass>com.eli.calc.shape.apps.CmdLineShapeCalcApp</mainClass>
                            <classpathPrefix>lib/</classpathPrefix>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>

The above assists us in running the app from outside Eclipse.

Maven Install

I am being a bit brief here... there is more information here, and in other articles.

Image title

Image title

Image title

Image title

Image title

Image title

Image title

We can see that it works just like it did when it was a stand-alone application, including the Shape Calculator (and Hibernate, MySQL, etc.).

Get Latest Code

Get the very latest code (converted to SOAP-client) version of the command-line application here.

This next part is just a repeat of what is near the start of this article....

Here is the code to the previous (version 2) command-line application that depends on the core Shape Calculator project, and here is the latest code to the most recent software we delivered, the combo SOAP-REST web service.   We will be borrowing from all of these.

Next?

There are some improvements and changes we could make, so let's continue exploring this command-line app.  We can then apply the same thing when we convert the web application.

See you next time!

Node.js application metrics sent directly to any statsd-compliant system. Get N|Solid

Topics:
soap ,cxf ,wsdl ,maven ,web dev

Opinions expressed by DZone contributors are their own.

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

{{ parent.tldr }}

{{ parent.urlSource.name }}