Posted on

Advanced JAX-WS Web services sample chapter


 

Once that you have installed all the required tools, we can start building our first Web Service endpoint. Actually, multiple approaches actually exist for Web Service development, which can be grouped in two broad categories:

  • Top-down Web Services: means that you start with a Web Service definition (described in the WSDL) and then create all the necessary scaffolding in Java all the way down.
  • Bottom-up Web Services: means you start with a Java class and generate the WSDL from it.

We will start by the latter approach, which is the simplest choice for a developer, whilst we will defer top-down Web Services in the next chapter.

Bottom-up Web Service endpoints

The first and most straightforward approach for developing a Web Service endpoint (bottom-up) is to rely on an existing Java Bean (POJO, Plain Old Java Object); that could be part of the application business logic or written from scratch for the sake of creating the Web Service endpoint. The bean can be easily turned into a Web Service Endpoint Implementation by properly annotating it.

This approach is usually the preferred one when existing business components need to be made available as Web Service endpoints too and there’s no actual requirement on the contract that will be published for them.

On containers supporting the full JavaEE specification set (for instance WildFly), EJB 3 beans can be annotated the same way as POJOs and exposed as Web Service endpoint.

Our Web Service will be included in a Java EE 7 Web project; hence, it will be deployed as part of a Web application. Both Eclipse and NetBeans have some wizards to create some initial Web application projects: as we will choose a vanilla approach, based on Maven, we can create our initial project named ws-demo, which is derived from the webapp-javaee7 archetype:

So from a command prompt execute the following shell:

mvn -DarchetypeGroupId=org.codehaus.mojo.archetypes -DarchetypeArtifactId=webapp-javaee7  -DarchetypeVersion=0.4-SNAPSHOT -DarchetypeRepository=https://nexus.codehaus.org/content/repositories/snapshots  -DgroupId=com.itbuzzpress.chapter1 -DartifactId=ws-demo -Dversion=1.0 -Dpackage=com.itbuzzpress.chapter1  -Darchetype.interactive=false --batch-mode --update-snapshots archetype:generate

The following structure will be generated in a folder named ws-demo:

$ tree ws-demo

├───src

    └───main

        ├───java

        │   └───com

        │       └───itbuzzpress

        │           └───chapter1

        └───webapp

            └───WEB-INF

Now, we will add our first Web Service endpoint, named HelloWorld under the src/main/java/com/itbuzzpress/chapter1 folder:

package com.itbuzzpress.chapter1;  import javax.jws.WebMethod;  import javax.jws.WebService;    @WebService  public class HelloWorld {     @WebMethod     public String echo(String input) {        return “Hi “+input;     }  }

As you can see, this basic Web Service contains an annotation within it, named @javax.jws.WebService. Java Beans annotated, with @WebService end up being exposed as endpoints once the application they’re included in is deployed on a target container supporting JAX-WS. At deployment time, the container processes the annotated beans and generates the WSDL document describing the service contract.

The @WebService annotation actually has some optional attributes to control the published contract, as well as to specify an endpoint interface. An explicit endpoint interface is used to clearly state the methods that are to be part of the service contract, perhaps when the bean is quite complex.

The javax.jws.WebMethod annotation can be used on both endpoint bean and interface methods to tell the container to include them in the service contract. All method parameters and return types must either be simple Java types or be compatible with the JAXB 2 specification.

There are sensible defaults for all the JSR-181 annotations, defining the container behavior when they’re not used.  

A Java Bean is actually exposed as Web Service endpoint by annotating it with javax.jws.WebService or javax.jws.WebServiceProvider. @WebServiceProvider lets users directly define the SOAP messages to be exchanged by the endpoint, bypassing the container marshalling/unmarshalling of JAXB style classes used as method parameters.

Building, Packaging and Deploying the Service

A relevant aspect of web services application development is how to build, package and deploy them. Different target containers come with different requirements on the deployment archive to provide, which affects the way applications are to be built and packaged. However, there are common steps and requirements for creating proper deployments containing JAX-WS endpoints. Below you find some directions on the main aspect regarding packaging:

Deployment type

Different containers have different requirements on the kind of archive to produce. On Java EE compliant containers, JAR or WAR archives are expected, depending on the type of endpoints which are included (POJO Web Service endpoints are to be packaged into WAR archives whilst EJB endpoints can be packaged as well in JAR archives).

Deployment contents

In terms of which class files to include, a JAX-WS endpoint deployment must contain the web Service Endpoint Implementation class and its interface (if any), as well as any class used for operation parameters and results.

Some containers may require portable JAX-WS artifacts to be generated and included in the deployment, by running a java-to-wsdl tool if the endpoint has been developed following a bottom-up approach. Those artifacts usually include the generated WSDL for the endpoint interface, as well as request and response wrapper classes (which are needed by containers for some type of contracts).

The JAX-WS 2.2 specification allows endpoints to be discovered in the deployment even if no descriptor is provided (as a matter of fact WAR archives can have no web.xml). If included, the content of the web.xml file, as well as any additional descriptor, depends on the actual target container where the archive is meant to be deployed.

When it comes to WildFly, no additional java-to-wsdl tool run is required, as the container will process the deployment contents at runtime and automatically generates any needed wrapper class as well as the published WSDL document.

Building and packaging with Maven

Since we have created our project with Maven, we will use it for building up and packaging the Web Service contained in it. The pom.xml which has been generated by the archetype:generate method is quite verbose so we will not include all its sections here (You can inspect for the source code of this example on GitHub at: https://github.com/asoldano/jaxws-book/tree/master/chapter1/ws-demo)

The most relevant section of it, is contained at the beginning of the pom.xml file:

<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>com.itbuzzpress.chapter1</groupId>      <artifactId>ws-demo</artifactId>      <version>1.0</version>      <packaging>war</packaging>      <name>ws-demo</name>      <properties>          <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>          <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>      </properties>         <dependencies>          <dependency>              <groupId>javax</groupId>              <artifactId>javaee-web-api</artifactId>              <version>7.0</version>              <scope>provided</scope>          </dependency>      </dependencies>  . . . . . .

As you can see from the packaging element, war (Web application archive) will be generated by packaging this application. The only dependency included in this example is the javaee-web-api. Please note provided dependency scope is selected, as the dependency is not meant to be transitive and, very important, is not to be included in the application archive produced by the build.

If no JAX-WS implementation is transitively pulled by the specified dependencies, the JAX-WS reference implementation included in the JDK is used.

As we are not including any API in our application, we rely on the server classloader to load the JAX-WS API implementation available on the server side. Conversely, on Web Service client applications, the Maven project dependencies concur in defining the classpath the application classloader is derived from. It is hence critical to verify which JAX-WS implementation is pulled in by the specified dependencies.

A Maven project described by the above pom.xml and including the sources as per Maven conventions (following the Maven standard directory layout), is built simply running the following command:

mvn clean package

Deploying the application

The target application archive is finally to be deployed to the target container. This is achieved differently depending on the actual selected container.

On WildFly multiple deploy mechanisms are available, but the most straightforward one is probably to hot deploy the WAR archive by copying it into the standalone/deployment folder of the server instance.

$ cp ws-demo-1.0.war /usr/share/wildfly-8.1.0.Final/standalone/deployments

The application server will now start deploying your application and activate the Web Service endpoint, as it’s evident from the following log:

Adding service endpoint metadata: id=com.itbuzzpress.chapter1.HelloWorld

 address=http://localhost:8080/ws-demo-1.0/HelloWorld

 implementor=com.itbuzzpress.chapter1.HelloWorld

 serviceName={http://chapter1.itbuzzpress.com/}HelloWorldService

 portName={http://chapter1.itbuzzpress.com/}HelloWorldPort

 annotationWsdlLocation=null

You can check that the WSDL has been correctly generated by opening the Administration console of the application server, which is available by default at the following address: http://localhost:9990

Testing the application

In order to test a Web Service there are many available options: you can either code a Web Service client in your favorite language (Java, PHP, Ruby etc.) or use a tool for testing your Web Service endpoints. We will choose at first the latter option, that is installing a testing tool, whilst next chapter will focus on creating native Java Web Service clients.

The tool that we will use for this purpose is SoapUI (http://www.soapui.org/) which is a popular User Interface for testing SOAP based Web Services, although it is able as well to act as a client for RESTFul Web Services and much more. SoapUI is available both as standalone application and as Eclipse Plugin. The downloads of SoapUI Community version are hosted on SourceForge at: http://sourceforge.net/projects/soapui/files/ .

Once that you have installed the version which is appropriate with your system, launch SoapUI. From the File Menu select New SOAP Project.

jax-ws tutorial 

This will open a New SOAP Project dialog. In the Initial WSDL field, enter the location where the WSDL contract is contained, as displayed by the following picture:

jax-ws tutorial 

Click OK. You should now see that the WSDL was successfully added to the project by seeing the operations in the Web Service in the navigator.

jax-ws tutorial 

Double click on the Request1 tree element: the soapUI Request Perspective will appear where you can fill up the named parameters:

jax-ws tutorial 

In the corresponding Response Window, you will check the result of your Web Service invocation:

jax-ws tutorial 

As you can see, we successfully tested our first Web Service deployed on WildFly server.

Exposing EJB 3 as Web Services

So far, we have seen how you can promote your Java classes to Web Services by merely adding some annotations at the class level; however, the JAX-WS specification also allows exposing a Stateless Session Bean as Web Services almost in the same way you would do with a POJO.

Here is for example, how you can expose the initial example as Stateless EJB:

package com.itbuzzpress.chapter1;  import javax.jws.WebMethod;  import javax.jws.WebService;  import javax.ejb.Stateless     @WebService  @Stateless  public class HelloWorld {     @WebMethod     public String echo(String input) {        return “Hi “+input;     }  }

Although being quite similar to the POJO counterpart, using EJB 3 as endpoint has some peculiarities: for example you can use annotations to define both the Context Root and the Url Pattern that will be use to bind the Web Service. In the former example, we could set:

@WebService  @WebContext( contextRoot = "/webservices" , urlPattern="/HelloWorldService" )  @Stateless  public class HelloWorld {  . . .  }

In the above example, when deploying the Web Service endpoint, we would bind it to http://locallhost:8080/webservices/HelloWorldService