Metro JAX-WS – SOAP based Web Service using Top-Down approach

In this article, we will learn and implement a JAX-WS based SOAP Web Service using Metro (JAX-WS + WSIT = Project Tango) Reference Implementation\

1. SOAP based Web Service approaches:

Basically, we got two options while developing/implementation of SOAP Web Service

  • Top-Down approach or Contract first
  • Bottom-UP approach or Code first

We will concentrate on the first approach i.e.; Top-Down approach. Although bottom-up approach is comparatively quite simpler to develop, but developer in collaboration with designer should prefer to implement Top-Down approach as it is advantageous and involves writing contact document first i.e.; WSDL

In this approach, XSD i.e.; XML Schema and WSDL i.e.; Web Service Description Language are designed/written before implementation. Later, using maven plugins (wsimport/wsdl2java goals), we can generate required Java artifacts and extend/use these classes to implement the business functionalities

Note: For simple use case, we can use command line interface to generate java artifacts

2. Technology Used:

  • Java 1.7
  • Eclipse Luna IDE
  • jaxws-rt-2.2.8
  • webservices-rt-2.3
  • Apache Maven 3.2.1
  • Apache Tomcat-8.0.15
  • Oracle Weblogic server 12c

3. Mavenize or download required jars

Add jaxws-rt & webservices-rt dependencies to pom.xml

pom.xml

<!-- properties -->
<properties>
	<sun.jaxws.version>2.2.8</sun.jaxws.version>
	<metro.jaxws.version>2.3</metro.jaxws.version>
	<jaxws.scope>compile</jaxws.scope> <!-- provided(weblogic) / compile(tomcat) -->
	<compileSource>1.7</compileSource>
	<maven.compiler.source>1.7</maven.compiler.source>
	<maven.compiler.target>1.7</maven.compiler.target>
	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>

	<!-- jax-ws runtime from sun -->
	<dependency>
		<groupId>com.sun.xml.ws</groupId>
		<artifactId>jaxws-rt</artifactId>
		<version>${sun.jaxws.version}</version>
		<scope>${jaxws.scope}</scope>
	</dependency>

	<!-- jax-ws runtime from glassfish Metro - project tango -->
	<dependency>
		<groupId>org.glassfish.metro</groupId>
		<artifactId>webservices-rt</artifactId>
		<version>${metro.jaxws.version}</version>
		<scope>${jaxws.scope}</scope>
	</dependency>

</dependencies>

Folks who aren’t familiar with Maven concepts or don’t require maven for their project, can download the below jars individually from the central repository or maven repository or maven2 and include them in the classpath

4. Steps to generate Java artifacts from WSDL/XSD

  • write/design XML Schema (XSD)
  • similarly, write/design WSDL document including above XSD for Type attributes
  • configure maven plugins (wsimport/wsdl2java goal) in pom.xml with correct and complete path of the wsdlFile
  • Run maven command “mvn generate-sources” from project’s context-root
  • java artifacts will be generated under “generated” folder within specified targetNamespace
1_Metro-JAX-WS-Top-Down_web_service_resources

Let us understand above steps in more detail

5. Write/design well-formed XML Schema

Book.xsd (src/main/resources/com/jaxws/series/top/down/approach/entities)

Below XSD contains two elements with name “BookRequestType” and “BookResponseType”

  • BookRequestType contains single string called isbnNumber
  • BookResponseType contains four sub-elements namely bookISBN, bookName, author and category

Book.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
	targetNamespace="http://benchresources.in/entities/Book" 
	xmlns:tns="http://benchresources.in/entities/Book"
	elementFormDefault="qualified">

	<!-- Book Request Type -->
	<xsd:element name="BookRequestType">
		<xsd:complexType>
			<xsd:sequence>
				<xsd:element name="isbnNumber" type="xsd:string" />
			</xsd:sequence>
		</xsd:complexType>
	</xsd:element>

	<!-- Book Response Type -->
	<xsd:element name="BookResponseType">
		<xsd:complexType>
			<xsd:sequence>
				<xsd:element name="bookISBN" type="xsd:string" />
				<xsd:element name="bookName" type="xsd:string" />
				<xsd:element name="author" type="xsd:string" />
				<xsd:element name="category" type="xsd:string" />
			</xsd:sequence>
		</xsd:complexType>
	</xsd:element>

</xsd:schema>

 

6. Write/design well-formed WSDL

BookService.wsdl (src/main/resources/com/jaxws/series/top/down/approach/services)

This is the contract document for Book Service exposing one operation called “getBookByISDNRequestNumber” whose input argument is “BookRequestType” and return type is “BookResponseType

BookService.wsdl

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
	xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
	xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
	targetNamespace="http://benchresources.in/services/BookService/"
	xmlns:tns="http://benchresources.in/services/BookService/" 
	xmlns:book="http://benchresources.in/entities/Book"
	name="BookService">

	<wsdl:types>
		<xsd:schema targetNamespace="http://benchresources.in/services/BookService/">
			<xsd:import namespace="http://benchresources.in/entities/Book"
				schemaLocation="../entities/book.xsd" />
		</xsd:schema>
	</wsdl:types>

	<wsdl:message name="BookRequest">
		<wsdl:part element="book:BookRequestType" name="parameters" />
	</wsdl:message>
	<wsdl:message name="BookResponse">
		<wsdl:part element="book:BookResponseType" name="parameters" />
	</wsdl:message>

	<wsdl:portType name="IBookService">
		<wsdl:operation name="getBookByISDNRequestNumber">
			<wsdl:input message="tns:BookRequest" />
			<wsdl:output message="tns:BookResponse" />
		</wsdl:operation>
	</wsdl:portType>

	<wsdl:binding name="BookServiceSOAPBinding" type="tns:IBookService">
		<soap:binding style="document"
			transport="http://schemas.xmlsoap.org/soap/http" />
		<wsdl:operation name="getBookByISDNRequestNumber">
			<soap:operation soapAction="" />
			<wsdl:input>
				<soap:body use="literal" />
			</wsdl:input>
			<wsdl:output>
				<soap:body use="literal" />
			</wsdl:output>
		</wsdl:operation>
	</wsdl:binding>

	<wsdl:service name="BookService">
		<wsdl:port name="BookServicePort" binding="tns:BookServiceSOAPBinding">
			<soap:address
				location="http://localhost:8080/Metro-JAX-WS-Top-Down/services/BookService" />
		</wsdl:port>
	</wsdl:service>
</wsdl:definitions>

7. Configure maven plugin in pom.xml (wsimport goal)

This plugin which defines wsimport goal from jaxws-maven-plugin generates java artifacts from the supplied WSDL file under resources folder

pom.xml

<!-- plugin 4-maven wsimport goal -->
<plugin>
	<groupId>org.jvnet.jax-ws-commons</groupId>
	<artifactId>jaxws-maven-plugin</artifactId>
	<version>2.3</version>
	<executions>
		<execution>
			<id>basic</id>
			<phase>generate-sources</phase>
			<goals>
				<goal>wsimport</goal>
			</goals>
		</execution>
	</executions>
	<configuration>
		<keep>true</keep>
		<wsdlDirectory>${basedir}\src\main\resources</wsdlDirectory>
		<wsdlFiles>
			<wsdlFile>com\jaxws\series\top\down\approach\services\BookService.wsdl
			</wsdlFile>
		</wsdlFiles>
		<sourceDestDir>${basedir}\generated\java\source</sourceDestDir>
		<verbose>true</verbose>
		<target>2.1</target>
	</configuration>
</plugin>

8. Run “mvn generate-sources”

Look at the generated java source files in the generated folder

After running above maven command, you will get to see below generated java files

2_Metro-JAX-WS-Top-Down_generated_java_artifacts
  • IBookService.java
  • BookRequestType.java
  • BookResponseType.java
  • BookService.java
  • ObjectFactory.java
  • package-info.java

BookRequestType.java

package in.benchresources.entities.book;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

/**
 * <p>Java class for anonymous complex type.
 *
 * <p>The following schema fragment specifies the expected content contained within this class.
 *
 * <pre>
 * &lt;complexType>
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *         &lt;element name="isbnNumber" type="{http://www.w3.org/2001/XMLSchema}string"/>
 *       &lt;/sequence>
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/complexType>
 * </pre>
 *
 *
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "isbnNumber"
})
@XmlRootElement(name = "BookRequestType")
public class BookRequestType {

    @XmlElement(required = true)
    protected String isbnNumber;

    /**
     * Gets the value of the isbnNumber property.
     *
     * @return
     *     possible object is
     *     {@link String }
     *
     */
    public String getIsbnNumber() {
        return isbnNumber;
    }

    /**
     * Sets the value of the isbnNumber property.
     *
     * @param value
     *     allowed object is
     *     {@link String }
     *
     */
    public void setIsbnNumber(String value) {
        this.isbnNumber = value;
    }

}

BookResponseType.java

package in.benchresources.entities.book;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

/**
 * <p>Java class for anonymous complex type.
 *
 * <p>The following schema fragment specifies the expected content contained within this class.
 *
 * <pre>
 * &lt;complexType>
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *         &lt;element name="bookISBN" type="{http://www.w3.org/2001/XMLSchema}string"/>
 *         &lt;element name="bookName" type="{http://www.w3.org/2001/XMLSchema}string"/>
 *         &lt;element name="author" type="{http://www.w3.org/2001/XMLSchema}string"/>
 *         &lt;element name="category" type="{http://www.w3.org/2001/XMLSchema}string"/>
 *       &lt;/sequence>
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/complexType>
 * </pre>
 *
 *
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "bookISBN",
    "bookName",
    "author",
    "category"
})
@XmlRootElement(name = "BookResponseType")
public class BookResponseType {

    @XmlElement(required = true)
    protected String bookISBN;
    @XmlElement(required = true)
    protected String bookName;
    @XmlElement(required = true)
    protected String author;
    @XmlElement(required = true)
    protected String category;

    /**
     * Gets the value of the bookISBN property.
     *
     * @return
     *     possible object is
     *     {@link String }
     *
     */
    public String getBookISBN() {
        return bookISBN;
    }

    /**
     * Sets the value of the bookISBN property.
     *
     * @param value
     *     allowed object is
     *     {@link String }
     *
     */
    public void setBookISBN(String value) {
        this.bookISBN = value;
    }

    /**
     * Gets the value of the bookName property.
     *
     * @return
     *     possible object is
     *     {@link String }
     *
     */
    public String getBookName() {
        return bookName;
    }

    /**
     * Sets the value of the bookName property.
     *
     * @param value
     *     allowed object is
     *     {@link String }
     *
     */
    public void setBookName(String value) {
        this.bookName = value;
    }

    /**
     * Gets the value of the author property.
     *
     * @return
     *     possible object is
     *     {@link String }
     *
     */
    public String getAuthor() {
        return author;
    }

    /**
     * Sets the value of the author property.
     *
     * @param value
     *     allowed object is
     *     {@link String }
     *
     */
    public void setAuthor(String value) {
        this.author = value;
    }

    /**
     * Gets the value of the category property.
     *
     * @return
     *     possible object is
     *     {@link String }
     *
     */
    public String getCategory() {
        return category;
    }

    /**
     * Sets the value of the category property.
     *
     * @param value
     *     allowed object is
     *     {@link String }
     *
     */
    public void setCategory(String value) {
        this.category = value;
    }

}

IBookService.java

package in.benchresources.services.bookservice;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.xml.bind.annotation.XmlSeeAlso;
import in.benchresources.entities.book.BookRequestType;
import in.benchresources.entities.book.BookResponseType;
import in.benchresources.entities.book.ObjectFactory;

/**
 * This class was generated by the JAX-WS RI.
 * JAX-WS RI 2.2.8
 * Generated source version: 2.1
 *
 */
@WebService(name = "IBookService", 
targetNamespace = "http://benchresources.in/services/BookService/")
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
@XmlSeeAlso({
    ObjectFactory.class
})
public interface IBookService {

    /**
     *
     * @param parameters
     * @return
     *     returns in.benchresources.entities.book.BookResponseType
     */
    @WebMethod
    @WebResult(name = "BookResponseType", 
    targetNamespace = "http://benchresources.in/entities/Book", partName = "parameters")
    public BookResponseType getBookByISDNRequestNumber(
        @WebParam(name = "BookRequestType", 
        targetNamespace = "http://benchresources.in/entities/Book", partName = "parameters")
        BookRequestType parameters);

}

package-info.java

@javax.xml.bind.annotation.XmlSchema(namespace = "http://benchresources.in/entities/Book", 
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package in.benchresources.entities.book;

ObjectFactory.java

package in.benchresources.entities.book;

import javax.xml.bind.annotation.XmlRegistry;

/**
 * This object contains factory methods for each
 * Java content interface and Java element interface
 * generated in the in.benchresources.entities.book package.
 * <p>An ObjectFactory allows you to programatically
 * construct new instances of the Java representation
 * for XML content. The Java representation of XML
 * content can consist of schema derived interfaces
 * and classes representing the binding of schema
 * type definitions, element declarations and model
 * groups.  Factory methods for each of these are
 * provided in this class.
 *
 */
@XmlRegistry
public class ObjectFactory {

    /**
     * Create a new ObjectFactory that can be used to create new instances of 
     * schema derived classes for package: in.benchresources.entities.book
     *
     */
    public ObjectFactory() {
    }

    /**
     * Create an instance of {@link BookResponseType }
     *
     */
    public BookResponseType createBookResponseType() {
        return new BookResponseType();
    }

    /**
     * Create an instance of {@link BookRequestType }
     *
     */
    public BookRequestType createBookRequestType() {
        return new BookRequestType();
    }

}

BookService.java

package in.benchresources.services.bookservice;

import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.WebEndpoint;
import javax.xml.ws.WebServiceClient;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.WebServiceFeature;

/**
 * This class was generated by the JAX-WS RI.
 * JAX-WS RI 2.2.8
 * Generated source version: 2.1
 *
 */
@WebServiceClient(name = "BookService", 
targetNamespace = "http://benchresources.in/services/BookService/", 
wsdlLocation = "file:/D:/WORKSPACE/JAX-WS_WORKSPACE/Metro-JAX-WS-Top-Down/src/main/resources/com/jaxws/series/top/down/approach/services/BookService.wsdl")
public class BookService
    extends Service
{

    private final static URL BOOKSERVICE_WSDL_LOCATION;
    private final static WebServiceException BOOKSERVICE_EXCEPTION;
    private final static QName BOOKSERVICE_QNAME = new QName("http://benchresources.in/services/BookService/", "BookService");

    static {
        URL url = null;
        WebServiceException e = null;
        try {
            url = new URL("file:/D:/WORKSPACE/JAX-WS_WORKSPACE/Metro-JAX-WS-Top-Down/src/main/resources/com/jaxws/series/top/down/approach/services/BookService.wsdl");
        } catch (MalformedURLException ex) {
            e = new WebServiceException(ex);
        }
        BOOKSERVICE_WSDL_LOCATION = url;
        BOOKSERVICE_EXCEPTION = e;
    }

    public BookService() {
        super(__getWsdlLocation(), BOOKSERVICE_QNAME);
    }

    public BookService(URL wsdlLocation, QName serviceName) {
        super(wsdlLocation, serviceName);
    }

    /**
     *
     * @return
     *     returns IBookService
     */
    @WebEndpoint(name = "BookServicePort")
    public IBookService getBookServicePort() {
        return super.getPort(new QName("http://benchresources.in/services/BookService/", x
        "BookServicePort"), IBookService.class);
    }

    /**
     *
     * @param features
     *     A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy.  
     * Supported features not in the <code>features</code> parameter will have their default values.
     * @return
     *     returns IBookService
     */
    @WebEndpoint(name = "BookServicePort")
    public IBookService getBookServicePort(WebServiceFeature... features) {
        return super.getPort(new QName("http://benchresources.in/services/BookService/", 
        "BookServicePort"), IBookService.class, features);
    }

    private static URL __getWsdlLocation() {
        if (BOOKSERVICE_EXCEPTION!= null) {
            throw BOOKSERVICE_EXCEPTION;
        }
        return BOOKSERVICE_WSDL_LOCATION;
    }
}

9. Directory Structure

Before moving on, let us understand the directory/package structure once you create project and/plus after generating java artifacts in Eclipse IDE

Maven has to follow certain directory structure

  • src/test/java –> test related files, mostly JUnit test cases
  • src/main/java –> create java source files under this folder
  • generated/java/source –> generated java source files are placed here
  • src/main/resources –> all configuration files placed here
  • src/test/resources –> all test related configuration files placed here
  • Maven Dependencies or Referenced Libraries –> includes jars in the classpath
  • WEB-INF under webapp –> stores web.xml & other configuration files related to web application

10. Project Structure (Package Explorer view in Eclipse)

3_Metro-JAX-WS-Top-Down_project_structure_In_Eclipse

11. Jar Libraries Used in the Project (Maven Dependencies)

4_Metro-JAX-WS-Top-Down_jars_in_classpath

12. Web application

For any web application, entry point is web.xml which describes how the incoming http requests are served / processed. Further, it describes about the global-context and local-context param (i.e.; <context-param> & <init-param>) for loading files particular to project requirements & contains respective listener

With this introduction, we will understand how we configured web.xml & sun-jaxws.xml for Metro JAX-WS SOAP based Web Service

web.xml (the entry point –> under WEB-INF)

This web.xml file describes,

  • Like any JEE web framework register com.sun.xml.ws.transport.http.servlet.WSServlet with servlet container
  • http requests with URL pattern “/services/*” will be sent to the registered servlet called “metro-jaxws-servlet” i.e.; (com.sun.xml.ws.transport.http.servlet.WSServlet)
  • configure web service listener “com.sun.xml.ws.transport.http.servlet.WSServletContextListener
  • configure session timeout in secs using <session-config> tag
  • <welcome-file-list> files under this tag is the start-up page

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
	http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	version="3.0">

	<display-name>Metro-JAX-WS-Top-Down</display-name>

	<!-- listener for metro jax-ws -->
	<listener>
		<listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
	</listener>

	<!-- metro jax-ws servlet -->
	<servlet>
		<servlet-name>metro-jaxws-servlet</servlet-name>
		<servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>metro-jaxws-servlet</servlet-name>
		<url-pattern>/services/*</url-pattern>
	</servlet-mapping>

	<!-- session timeout -->
	<session-config>
		<session-timeout>60</session-timeout>
	</session-config>

	<!-- welcome file -->
	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
	</welcome-file-list>

</web-app>

sun-jaxws.xml (under WEB-INF)

This file basically defines endpoint url-pattern stating/mentioning qualified package name of the implementation (java class)

sun-jaxws.xml

<?xml version="1.0" encoding="UTF-8"?>
<endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime"
	version="2.0">
	<endpoint name="IBookService"
		implementation="com.jaxws.series.top.down.approach.service.BookServiceImpl"
		url-pattern="/services/BookService" />
</endpoints>

Let’s see coding in action

URL Pattern

Http url for any common web application is http://<server>:<port>/<root-context>/<from_here_application_specific_path>

In our example, we are going to deploy the war into Tomcat 8.0 server so our server and port are localhost and 8080 respectively. Context root is the project name i.e.; Metro-JAX-WS-Top-Down. Initial path for this application is http://localhost:8080/Metro-JAX-WS-Top-Down

We have configured “/services/*” as url-pattern for the “metro-jaxws-servlet” servlet in web.xml and our business implementation class implements the portType interface generated from WSDL file which is annotated with @WebService annotation at class-level

Book Service Implementation (business logic)

This service provider class implements portType interface generated from WSDL file. Also, class annotated with @WebService annotation at class-level and this is very important

Always, keep a practice of defining most of the attributes of @WebService annotation if not all while developing top-down approach. Defining means providing values of the following attributes

  • serviceName (this is very important, as it defines/controls endpoint URL)
  • endpointInterface (this is mandatory)
  • targetNamespace (same as in the WSDL file)
  • portName (port value under <service> element)
  • name (optional)
  • wsdlLocation (optional)

BookServiceImpl.java

package com.jaxws.series.top.down.approach.service;

import in.benchresources.entities.book.BookRequestType;
import in.benchresources.entities.book.BookResponseType;
import in.benchresources.services.bookservice.IBookService;

import javax.jws.WebService;

@WebService(serviceName="BookService", 
endpointInterface="in.benchresources.services.bookservice.IBookService",
targetNamespace="http://benchresources.in/services/BookService/", 
portName="BookServicePort", name="BookServiceImpl")
public class BookServiceImpl implements IBookService {

	// http://localhost:8080/Metro-JAX-WS-Top-Down/services/BookService?wsdl - Apache Tomcat 7.x
	// http://localhost:7001/Metro-JAX-WS-Top-Down/services/BookService?wsdl - Oracle Weblogic 12c 

	@Override
	public BookResponseType getBookByISDNRequestNumber(BookRequestType parameters) {

		// create object of responseType and set values & return
		BookResponseType bookResponseType = new BookResponseType();
		bookResponseType.setBookISBN(parameters.getIsbnNumber());
		bookResponseType.setBookName("Microbiology Study");
		bookResponseType.setAuthor("T. Devasena");
		bookResponseType.setCategory("Microbiology");
		return bookResponseType;
	}
}

That’s all with coding part, now let us move on to deployment and testing

 

Deployment: We can either deploy on it Apache Tomcat server or Oracle weblogic application server. Steps for deployment on both these servers are detailed below

Server 1: Apache Tomcat-8.0.15 Deployment

  • Run maven command to build the war: mvn clean install (use command prompt or integrated maven in eclipse IDE)
  • Copy(ctrl+c) the war file from the target folder
  • Paste(ctrl+v) it into apache tomcat (webapps folder)
  • Start the tomcat server (Tomcat_Home\bin\startup.bat)

Server 2: Oracle Weblogic server 12.1.1.0 Deployment

  • Change the scope of jax-ws in pom.xml
<jaxws.scope>provided</jaxws.scope><!-- provided(weblogic)/compile(tomcat)-->
  • Run maven command to build the war: mvn clean install (use command prompt or integrated maven in eclipse IDE)
  • Once you see “BUILD SUCCESS” after running maven command, keep the war file ready to be deployed
  • Start weblogic 12c application server and hit the URL http://localhost:7001/console in any of the latest web browser and enter username/password you configured while setting up weblogic 12c server
  • Go to Deployments –> click install button –> browse through the location where you have kept your war file –> say Next –> say Next –> Finish

For Oracle WebLogic 12c Installation see here

Test the service !!

 

Testing

 There are many ways to do testing

  • SOAP UI Client
  • Java Client using JDK’s in-built classes like HttpURLConnection
  • Java Client using SOAP API
  • Eclipse’s Web Services Explorer
  • Write your own client for example, Java client using httpcomponents from Apache

We will cover first 2 ways of testing above JAX-WS deployed service

1. SOAP UI Client

Load the endpoint URL in SOAP UI Client, which will pre-populate the request XML based on the operation deployed/exposed using WSDL

For example, http://localhost:8080/Metro-JAX-WS-Top-Down/services/BookService?wsdl

Request XML

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
	xmlns:book="http://benchresources.in/entities/Book">
	<soapenv:Header />
	<soapenv:Body>
		<book:BookRequestType>
			<book:isbnNumber>ISBN-2134</book:isbnNumber>
		</book:BookRequestType>
	</soapenv:Body>
</soapenv:Envelope>

Response XML

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
	<S:Body>
		<BookResponseType xmlns="http://benchresources.in/entities/Book">
			<bookISBN>ISBN-2134</bookISBN>
			<bookName>Microbiology Study</bookName>
			<author>T. Devasena</author>
			<category>Microbiology</category>
		</BookResponseType>
	</S:Body>
</S:Envelope>
5_Metro-JAX-WS-Top-Down_Soap_ui_testing

2. Java client

For this java client to work/execute, we don’t need to add any extra jars or any new dependency in pom.xml as these classes comes shipped along with JDK. Observe, import statements closely for this client

Note: Request XML pattern formed taking help from pre-populated request XML from SOAP UI client as explained above

TestBookService.java

package test.jaxws.series.top.down.approach.service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;

public class TestBookService {

	/**
	 * wsimport - JAX-WS top-down web service approach
	 * main() method to test/start soap web service
	 * @param args
	 * @throws IOException
	 */
	public static void main(String[] args) throws IOException {

		String httpRequestURL = "http://localhost:8080/Metro-JAX-WS-Top-Down/services/BookService?wsdl";
		String soapRequestParam = 	"<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:book=\"http://benchresources.in/entities/Book\">"
				+						"<soapenv:Header/>"
				+						"<soapenv:Body>"
				+							"<book:BookRequestType>"
				+								"<book:isbnNumber>ISBN-3245</book:isbnNumber>"
				+							"</book:BookRequestType>"
				+						"</soapenv:Body>"
				+					"</soapenv:Envelope>";
		String responseString = testBookService(httpRequestURL, soapRequestParam);
		System.out.println("Response String : " + responseString);
	}

	/**
	 * This method uses HttpURLConnection to invoke exposed SOAP web service and returns the response string to the calling client
	 *
	 * @param httpRequestURL
	 * @param requestXmlParam
	 * @return responseXML
	 * @throws IOException
	 */
	public static String testBookService(String httpRequestURL, String requestXmlParam) throws IOException {

		// local variables
		URL url = null;
		HttpURLConnection httpURLConnection = null;
		OutputStreamWriter outputStreamWriter = null;
		String responseMessageFromServer = null;
		String responseXML = null; 

		try {
			// set basic request parameters
			url = new URL(httpRequestURL);
			httpURLConnection = (HttpURLConnection) url.openConnection();
			httpURLConnection.setDoOutput(true);
			httpURLConnection.setRequestMethod("POST");
			//			httpURLConnection.setRequestProperty("SOAPAction", "");
			httpURLConnection.setRequestProperty("Content-Type", "text/xml");
			httpURLConnection.setRequestProperty("Accept", "text/xml");

			// write request XML to the HTTP request
			outputStreamWriter = new OutputStreamWriter(httpURLConnection.getOutputStream());
			outputStreamWriter.write(requestXmlParam);
			outputStreamWriter.flush();

			System.out.println("Response code: " + httpURLConnection.getResponseCode());
			if (httpURLConnection.getResponseCode() == 200) {

				responseMessageFromServer = httpURLConnection.getResponseMessage();
				System.out.println("ResponseMessageFromServer: " + responseMessageFromServer);
				responseXML = getResponseXML(httpURLConnection);
			}
		}
		catch (IOException ioex) {
			ioex.printStackTrace();
			throw ioex;
		}
		finally{
			// finally close all operations
			outputStreamWriter.close();
			httpURLConnection.disconnect();
		}
		return responseXML;
	}

	/**
	 * This method is used to get response XML from the HTTP POST request
	 *
	 * @param httpURLConnection
	 * @return stringBuffer.toString()
	 * @throws IOException
	 */
	private static String getResponseXML(HttpURLConnection httpURLConnection) throws IOException {

		// local variables
		StringBuffer stringBuffer = new StringBuffer();
		BufferedReader bufferedReader = null;
		InputStreamReader inputStreamReader = null;
		String readSingleLine = null;

		try{
			// read the response stream AND buffer the result into a StringBuffer
			inputStreamReader = new InputStreamReader(httpURLConnection.getInputStream());
			bufferedReader = new BufferedReader(inputStreamReader);

			// reading the XML response content line BY line
			while ((readSingleLine = bufferedReader.readLine()) != null) {
				stringBuffer.append(readSingleLine);
			}
		}
		catch (IOException ioex) {
			ioex.printStackTrace();
			throw ioex;
		}
		finally{
			// finally close all operations
			bufferedReader.close();
			httpURLConnection.disconnect();
		}
		return stringBuffer.toString();
	}
}

Output:

Response code: 200
ResponseMessageFromServer: OK
Response String : 
<?xml version='1.0' encoding='UTF-8'?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
	<S:Body>
		<BookResponseType xmlns="http://benchresources.in/entities/Book">
			<bookISBN>ISBN-3245</bookISBN>
			<bookName>Microbiology Study</bookName>
			<author>T. Devasena</author>
			<category>Microbiology</category>
		</BookResponseType>
	</S:Body>
</S:Envelope>

Conclusion:

  • Thus, we have implemented & understood SOAP based Web Service implementation using top-down approach

In the next article, we will explore and understand how much it is easy to implement SOAP based Web Service implementation using bottom-up approach

Download project

Metro-JAX-WS-Top-Down (16kB)

Related Articles:

Happy Coding !!
Happy Learning !!

Metro JAX-WS: SOAP based Web Service using Bottom-Up approach
Apache Tomcat Server - Enabling SSL/HTTPS configuration for Security