Metro JAX-WS: SOAP based Web Service using Top-Down approach + Integrating with Spring & Hibernate ORM framework

In previous article, we have integrated spring framework with SOAP web service. We will extend the same article to integrate with hibernate ORM framework for database operation

We will use MySql database for this demo example

Technology Used

  • Java 1.7
  • Eclipse Luna IDE
  • jaxws-rt-2.2.8
  • webservices-rt-2.3
  • Spring-4.1.0.RELEASE
  • Hibernate-4.2.15.Final
  • MySql-Connector-java-5.1.32
  • Apache Maven 3.2.1
  • Apache Tomcat-8.0.15
  • Oracle Weblogic server 12c

Mavenize or download required jars

Add jaxws-rt, webservices-rt, spring-webmvc, hibernate & mysql-connector-java dependencies to pom.xml

<!-- properties -->
<properties>
	<sun.jaxws.version>2.2.8</sun.jaxws.version>
	<metro.jaxws.version>2.3</metro.jaxws.version>
	<jaxws.spring.version>1.9</jaxws.spring.version>
	<spring.version>4.1.0.RELEASE</spring.version>
	<hibernate.version>4.2.15.Final</hibernate.version>
	<mysql.version>5.1.32</mysql.version>
	<jaxws.scope>compile</jaxws.scope> <!-- provided(weblogic) / compile(tomcat) -->
	<spring.scope>compile</spring.scope>
	<hibernate.scope>compile</hibernate.scope>
	<compileSource>1.7</compileSource>
	<maven.compiler.target>1.7</maven.compiler.target>
	<maven.compiler.source>1.7</maven.compiler.source>
	<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>

	<!-- Spring Framework-4.x -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-webmvc</artifactId>
		<version>${spring.version}</version>
		<scope>${spring.scope}</scope>
	</dependency>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-orm</artifactId>
		<version>${spring.version}</version>
		<scope>${spring.scope}</scope>
	</dependency>

	<!-- Hibernate Core-4.2.x -->
	<dependency>
		<groupId>org.hibernate</groupId>
		<artifactId>hibernate-core</artifactId>
		<version>${hibernate.version}</version>
		<scope>${hibernate.scope}</scope>
	</dependency>
	<dependency>
		<groupId>org.hibernate</groupId>
		<artifactId>hibernate-ehcache</artifactId>
		<version>${hibernate.version}</version>
		<scope>${hibernate.scope}</scope>
	</dependency>

	<!-- MySql-Connector-5.1.32 -->
	<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
		<version>${mysql.version}</version>
		<scope>compile</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

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-Spring-Hibernate_web_service_resources

Let us understand above steps in more detail

Write/design well-formed XML Schema

music.xsd (src/main/resources/com/jaxws/series/td/spring/hibernate/entities)

Below XSD contains two elements with name “MusicListRequestType” and “MusicListResponseType” with a “BusinessFaultType” element in case of any exception

  • MusicListRequestType contains single string called composerName
  • MusicListResponseType contains simple type string called composer and complex type which references to MovieListType (which again references to MovieType)
  • BusinessFaultType for exception wraps three sub-elements namely errorCode, errorMessage and errorDescription
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
	targetNamespace="http://benchresources.in/entities/music" xmlns:tns="http://benchresources.in/entities/music"
	elementFormDefault="qualified">

	<!-- Music List Request Type -->
	<xsd:element name="MusicListRequestType">
		<xsd:complexType>
			<xsd:sequence>
				<xsd:element name="composerName" type="xsd:string" />
			</xsd:sequence>
		</xsd:complexType>
	</xsd:element>

	<!-- Music List Response Type -->
	<xsd:element name="MusicListResponseType">
		<xsd:complexType>
			<xsd:sequence>
				<xsd:element name="composer" type="xsd:string" />
				<xsd:element ref="tns:MovieListType" />
			</xsd:sequence>
		</xsd:complexType>
	</xsd:element>

	<!-- List of Movies -->
	<xsd:element name="MovieListType">
		<xsd:complexType>
			<xsd:sequence>
				<xsd:element ref="tns:MovieType" maxOccurs="unbounded" />
			</xsd:sequence>
		</xsd:complexType>
	</xsd:element>

	<!-- Movie Type -->
	<xsd:element name="MovieType">
		<xsd:complexType>
			<xsd:sequence>
				<xsd:element name="movieName" type="xsd:string" />
				<xsd:element name="year" type="xsd:string" />
				<xsd:element name="director" type="xsd:string" />
				<xsd:element name="comments" type="xsd:string" />
			</xsd:sequence>
		</xsd:complexType>
	</xsd:element>

	<!-- Business Exception Type -->
	<xsd:element name="BusinessFaultType">
		<xsd:complexType>
			<xsd:sequence>
				<xsd:element name="errorCode" type="xsd:int" />
				<xsd:element name="errorMessage" type="xsd:string" />
				<xsd:element name="errorDescription" type="xsd:string" />
			</xsd:sequence>
		</xsd:complexType>
	</xsd:element>

</xsd:schema>

Write/design well-formed WSDL

MusicService.wsdl (src/main/resources/com/jaxws/series/td/spring/hibernate/services)

This is the contract document for Music Service exposing one operation called “getMovieDetailByComposer” whose input argument is “MusicListRequestType” and return type is “MusicListResponseType” and fault is “BusinessFaultType

Note: In case of any exception while invoking this exposed service, business exception will be returned stating the reason instead of actual response type

<?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/MusicService/"
	xmlns:tns="http://benchresources.in/services/MusicService/"
	xmlns:muzix="http://benchresources.in/entities/music" name="MusicService">

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

	<wsdl:message name="MusicListRequest">
		<wsdl:part element="muzix:MusicListRequestType" name="parameters" />
	</wsdl:message>
	<wsdl:message name="MusicListResponse">
		<wsdl:part element="muzix:MusicListResponseType" name="parameters" />
	</wsdl:message>
	<wsdl:message name="BusinessException">
		<wsdl:part element="muzix:BusinessFaultType" name="parameters" />
	</wsdl:message>

	<wsdl:portType name="IMusicService">
		<wsdl:operation name="getAllMovieDetailByComposer">
			<wsdl:input message="tns:MusicListRequest" />
			<wsdl:output message="tns:MusicListResponse" />
			<wsdl:fault name="businessException" message="tns:BusinessException" />
		</wsdl:operation>
	</wsdl:portType>

	<wsdl:binding name="MusicServiceSOAPBinding" type="tns:IMusicService">
		<soap:binding style="document"
			transport="http://schemas.xmlsoap.org/soap/http" />
		<wsdl:operation name="getAllMovieDetailByComposer">
			<soap:operation soapAction="" />
			<wsdl:input>
				<soap:body use="literal" />
			</wsdl:input>
			<wsdl:output>
				<soap:body use="literal" />
			</wsdl:output>
			<wsdl:fault name="businessException">
				<soap:fault name="businessException" use="literal" />
			</wsdl:fault>
		</wsdl:operation>
	</wsdl:binding>

	<wsdl:service name="MusicService">
		<wsdl:port name="MusicServicePort" binding="tns:MusicServiceSOAPBinding">
			<soap:address
				location="http://localhost:8080/Metro-JAX-WS-Top-Down-Spring-Hibernate/services/MusicService" />
		</wsdl:port>
	</wsdl:service>
</wsdl:definitions>

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

<!-- 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\td\spring\hibernate\services\MusicService.wsdl
			</wsdlFile>
		</wsdlFiles>
		<sourceDestDir>${basedir}\generated\java\source</sourceDestDir>
		<verbose>true</verbose>
		<target>2.1</target>
	</configuration>
</plugin>

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-Spring-Hibernate_generated_java_artifacts

  • IMusicService.java
  • MusicListRequestType.java
  • MusicListResponseType.java
  • MovieListType
  • MovieType
  • BusinessFaultType.java
  • BusinessException.java
  • MusicService.java
  • ObjectFactory.java
  • package-info.jav

We will look at one file IMusicService.java, for other files you can download this eclipse project provided in the last section “Download Project”

This interface which is implemented by our endpoint business implementation class

IMusicService.java

package in.benchresources.services.musicservice;

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.music.MusicListRequestType;
import in.benchresources.entities.music.MusicListResponseType;
import in.benchresources.entities.music.ObjectFactory;

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

    /**
     *
     * @param parameters
     * @return
     *     returns in.benchresources.entities.music.MusicListResponseType
     * @throws BusinessException
     */
    @WebMethod(action = "http://benchresources.in/services/MusicService/getAllMovieDetailByComposer")
    @WebResult(name = "MusicListResponseType", targetNamespace = "http://benchresources.in/entities/music", partName = "parameters")
    public MusicListResponseType getAllMovieDetailByComposer(
        @WebParam(name = "MusicListRequestType", targetNamespace = "http://benchresources.in/entities/music", partName = "parameters")
        MusicListRequestType parameters)
        throws BusinessException
    ;

}

 

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

Project Structure (Package Explorer view in Eclipse)

3_Metro-JAX-WS-Top-Down-Spring-Hibernate_Project_Structure_In_Eclipse

Jar Libraries Used in the Project (Maven Dependencies)

4_Metro-JAX-WS-Top-Down-Spring-Hibernate_Jars_In_classpath

 

Database scripts

Database: Creating table and inserting few records for this example

Create Table command

CREATE TABLE `MUSIC` (
  `MUSIC_ID` INT(6) NOT NULL AUTO_INCREMENT,
  `MOVIE_NAME` VARCHAR(50) NOT NULL,
  `MOVIE_DIRECTOR` VARCHAR(50) NOT NULL,
  `YEAR_OF_RELEASE` VARCHAR(50) NOT NULL,
  `COMMENTS` VARCHAR(50),
  PRIMARY KEY (`MUSIC_ID`)
);

Insert command (examples)

INSERT INTO `music`(`MOVIE_NAME`, `MOVIE_DIRECTOR`, `YEAR_OF_RELEASE`, `COMMENTS`) VALUES ('Alaipayuthey','Mani Ratnam','2000','Romantic drama');
INSERT INTO `music`(`MOVIE_NAME`, `MOVIE_DIRECTOR`, `YEAR_OF_RELEASE`, `COMMENTS`) VALUES ('Slumdog Millionaire','Danny Boyle','2009','British drama film');
INSERT INTO `music`(`MOVIE_NAME`, `MOVIE_DIRECTOR`, `YEAR_OF_RELEASE`, `COMMENTS`) VALUES ('Rockstar','Imtiaz Ali','2011','Feature film');
INSERT INTO `music`(`MOVIE_NAME`, `MOVIE_DIRECTOR`, `YEAR_OF_RELEASE`, `COMMENTS`) VALUES ('I','S Shankar','2014','Romantic thriller');

Select * from music;

6_Metro-JAX-WS-Top-Down-Spring-Hibernate_Database_select

 

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-Spring-Hibernate</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="IMusicService"
		implementation="com.jaxws.series.td.spring.hibernate.service.MusicServiceImpl"
		url-pattern="/services/MusicService" />
</endpoints>

 

Spring Application Context file

This Spring Application Context file describes,

  • <context:annotation-config /> to activate annotation on the registered beans with application context
  • <context:component-scan base-package=”” /> tag scans all classes & sub-classes under the value of base-package attribute and register them with the Spring container
  • bean with id=”transactionManager” to inform spring to take care of the database transaction. All methods annotated with @Transactional
  • <tx:annotation-driven /> to turn ON transaction annotation on all DAO methods
  • bean with id=”sessionFactory” defines hibernate properties to let it take care of database operations using hibernate’s rich API
  • bean with id=”dataSource” defines values for driverClassName, url, username and password for MySql database
  • Note: injection series between transactionManager, sessionFactory and dataSource

spring-jax-ws.xml  (src/main/resources/com/jaxws/series/td/spring/hibernate/config)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

	<!-- to activate annotations in beans already registered in the ApplicationContext -->
	<context:annotation-config />

	<!-- scans packages to find and register beans within the application context -->
	<context:component-scan base-package="com.jaxws.series.td.spring.hibernate" />

	<!-- turn on spring transaction annotation -->
	<tx:annotation-driven transaction-manager="transactionManager" />

	<!-- Transaction Manager -->
	<bean id="transactionManager"
		class="org.springframework.orm.hibernate4.HibernateTransactionManager">
		<property name="sessionFactory" ref="sessionFactory" />
	</bean>

	<!-- Session Factory -->
	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="annotatedClasses">
			<list>
				<value>com.jaxws.series.td.spring.hibernate.model.Music</value>
			</list>
		</property>
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
				<prop key="hibernate.hbm2ddl.auto">update</prop>
				<prop key="hibernate.show_sql">true</prop>
			</props>
		</property>
	</bean>

	<!-- dataSource configuration -->
	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="com.mysql.jdbc.Driver" />
		<property name="url" value="jdbc:mysql://localhost:3306/benchresources" />
		<property name="username" value="root" />
		<property name="password" value="" />
	</bean>

</beans>

 

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-Spring-Hibernate. Initial path for this application is http://localhost:8080/Metro-JAX-WS-Top-Down-Spring-Hibernate

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

 

Model Class (POJO with Annotation)

Model class Music with five primitive attributes with their getter/setter

Also Hibernate POJO class is annotated describing the mapping between java property and database columns

@Entity:  represents an object that can be persisted in the database –> for this, class should have no-arg constructor
@Table: describes which table in the database to map with this class properties
@Id: defines this is unique which means it represents primary key in the database table
@GeneratedValue: this will be taken care by hibernate to define generator sequence
@Column: tells to map this particular property to table column in the database
For example, “musicId” property used to map “MUSIC_ID” column in the “MUSIC” table in the database
@Column(name= “MUSIC_ID”)
private int musicId;

Note: we can add attributes to the @Column annotation like name, length, nullable and unique

Music.java

package com.jaxws.series.td.spring.hibernate.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "MUSIC")
public class Music {

	// member variables
	@Id
	@GeneratedValue
	@Column(name = "MUSIC_ID")
	private int musicId;

	@Column(name= "MOVIE_NAME")
	private String movieName;

	@Column(name= "MOVIE_DIRECTOR")
	private String director;

	@Column(name= "YEAR_OF_RELEASE")
	private String yearOfRelease;

	@Column(name= "COMMENTS")
	private String comments;

	// getters & setters
	public int getMusicId() {
		return musicId;
	}

	public void setMusicId(int musicId) {
		this.musicId = musicId;
	}

	public String getMovieName() {
		return movieName;
	}

	public void setMovieName(String movieName) {
		this.movieName = movieName;
	}

	public String getDirector() {
		return director;
	}

	public void setDirector(String director) {
		this.director = director;
	}

	public String getYearOfRelease() {
		return yearOfRelease;
	}

	public void setYearOfRelease(String yearOfRelease) {
		this.yearOfRelease = yearOfRelease;
	}

	public String getComments() {
		return comments;
	}

	public void setComments(String comments) {
		this.comments = comments;
	}
}

 

Music 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

Exposed method loads the spring application context file from the classpath and uses getBean() variants to load required bean and invokes successive layers (using spring auto-wiring annotation)

MusicServiceImpl.java

package com.jaxws.series.td.spring.hibernate.service;

import in.benchresources.entities.music.BusinessFaultType;
import in.benchresources.entities.music.MovieListType;
import in.benchresources.entities.music.MovieType;
import in.benchresources.entities.music.MusicListRequestType;
import in.benchresources.entities.music.MusicListResponseType;
import in.benchresources.services.musicservice.BusinessException;
import in.benchresources.services.musicservice.IMusicService;

import java.util.List;

import javax.jws.WebService;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Service;

import com.jaxws.series.td.spring.hibernate.dao.MusicDAO;
import com.jaxws.series.td.spring.hibernate.model.Music;

@Service("musicService")
@WebService(serviceName="MusicService", endpointInterface="in.benchresources.services.musicservice.IMusicService",
targetNamespace="http://benchresources.in/services/MusicService/", portName="MusicServicePort", name="MusicServiceImpl")
public class MusicServiceImpl implements IMusicService {

	private MusicDAO musicDAO;

	@SuppressWarnings("resource")
	@Override
	public MusicListResponseType getAllMovieDetailByComposer(MusicListRequestType parameters) throws BusinessException {

		// local variables
		ApplicationContext applicationContext = null;
		List<Music> lstMusic = null;
		MovieType movieType = null;
		MovieListType movieListType = null;
		MusicListResponseType musicListResponseType = null;
		BusinessFaultType businessFaultType = null;

		// loading spring context XML from resource classpath
		applicationContext = new ClassPathXmlApplicationContext("com/jaxws/series/td/spring/hibernate/config/spring-hibernate-jax-ws.xml");
		musicDAO = applicationContext.getBean(MusicDAO.class);

		try{
			if(null != parameters && !parameters.getComposerName().equalsIgnoreCase("")){

				// invoke dao to get values
				lstMusic = musicDAO.getAllMoviesByComposer(parameters.getComposerName());

				// create musicListType to set return/response values
				musicListResponseType = new MusicListResponseType();
				musicListResponseType.setComposer(parameters.getComposerName());

				// create movieListType and add movie type retrieved from DAO layer
				movieListType = new MovieListType();

				// iterate through lstMusic and set values in the movieType
				for(Music music : lstMusic){

					// set values retrieved from DAO class
					movieType = new MovieType();
					movieType.setMovieName(music.getMovieName());
					movieType.setDirector(music.getDirector());
					movieType.setYear(music.getYearOfRelease());
					movieType.setComments(music.getComments());
					movieListType.getMovieType().add(movieType); // add movieType to the movieListType
				}

				// finally set movieListType in the response object i.e. musicListResponseType
				musicListResponseType.setMovieListType(movieListType);
			}
		}
		catch(Exception ex){
			// dummy setting for business exception, we can set more meaningful error depending on the business requirements
			businessFaultType = new BusinessFaultType();
			businessFaultType.setErrorCode(16359);
			businessFaultType.setErrorMessage("Error in invoking Music Service " + ex.getMessage());
			businessFaultType.setErrorDescription(ex.getStackTrace().toString());
		}
		finally{
			// close resources, if any
			((AbstractApplicationContext)applicationContext).registerShutdownHook();
		}
		return musicListResponseType;
	}
}

 

DAO layer

This DAO layer takes care of the database interaction i.e.; uses Hibernate’s rich API to interact with MySql database using MySqlDialect

MusicDAO.java

package com.jaxws.series.td.spring.hibernate.dao;

import java.util.List;

import com.jaxws.series.td.spring.hibernate.model.Music;

public interface MusicDAO {

	public List<Music> getAllMoviesByComposer(String composerName);
}

MusicDAOImpl.java

package com.jaxws.series.td.spring.hibernate.dao;

import java.util.List;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.jaxws.series.td.spring.hibernate.model.Music;

@Repository("musicDAO")
public class MusicDAOImpl implements MusicDAO {

	public static final String MUSIC_COMPOSER = "AR Rahman";

	@Autowired
	private SessionFactory sessionFactory;

	@SuppressWarnings("unchecked")
	@Override
	@Transactional(value="transactionManager")
	public List<Music> getAllMoviesByComposer(String composerName) {

		// local variables
		List<Music> lstMusic = null;

		if(null != composerName && composerName.equalsIgnoreCase(MUSIC_COMPOSER)){

			// get all books info from database
			lstMusic = sessionFactory.getCurrentSession().createCriteria(Music.class).list();
		}
		return lstMusic;
	}
}

 

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 steps 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-Spring-Hibernate/services/MusicService?wsdl

Request XML

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
	xmlns:mus="http://benchresources.in/entities/music">
	<soapenv:Header />
	<soapenv:Body>
		<mus:MusicListRequestType>
			<mus:composerName>AR Rahman</mus:composerName>
		</mus:MusicListRequestType>
	</soapenv:Body>
</soapenv:Envelope>

Response XML

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
	<S:Body>
		<MusicListResponseType xmlns="http://benchresources.in/entities/music">
			<composer>AR Rahman</composer>
			<MovieListType>
				<MovieType>
					<movieName>Alaipayuthey</movieName>
					<year>2000</year>
					<director>Mani Ratnam</director>
					<comments>Romantic drama</comments>
				</MovieType>
				<MovieType>
					<movieName>Slumdog Millionaire</movieName>
					<year>2009</year>
					<director>Danny Boyle</director>
					<comments>British drama film</comments>
				</MovieType>
				<MovieType>
					<movieName>Rockstar</movieName>
					<year>2011</year>
					<director>Imtiaz Ali</director>
					<comments>Feature film</comments>
				</MovieType>
				<MovieType>
					<movieName>I</movieName>
					<year>2014</year>
					<director>S Shankar</director>
					<comments>Romantic thriller</comments>
				</MovieType>
			</MovieListType>
		</MusicListResponseType>
	</S:Body>
</S:Envelope>

5_Metro-JAX-WS-Top-Down-Spring-Hibernate_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

TestMusicService.java

package test.jaxws.series.td.spring.hibernate.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 TestMusicService {

	/**
	 * 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-Spring-Hibernate/services/MusicService?wsdl";
		String soapRequestParam = 	"<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:mus=\"http://benchresources.in/entities/music\">"
				+						"<soapenv:Header/>"
				+						"<soapenv:Body>"
				+							"<mus:MusicListRequestType>"
				+								"<mus:composerName>AR Rahman</mus:composerName>"
				+							"</mus:MusicListRequestType>"
				+						"</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 in console

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>
		<MusicListResponseType xmlns="http://benchresources.in/entities/music">
			<composer>AR Rahman</composer>
			<MovieListType>
				<MovieType>
					<movieName>Alaipayuthey</movieName>
					<year>2000</year>
					<director>Mani Ratnam</director>
					<comments>Romantic drama</comments>
				</MovieType>
				<MovieType>
					<movieName>Slumdog Millionaire</movieName>
					<year>2009</year>
					<director>Danny Boyle</director>
					<comments>British drama film</comments>
				</MovieType>
				<MovieType>
					<movieName>Rockstar</movieName>
					<year>2011</year>
					<director>Imtiaz Ali</director>
					<comments>Feature film</comments>
				</MovieType>
				<MovieType>
					<movieName>I</movieName>
					<year>2014</year>
					<director>S Shankar</director>
					<comments>Romantic thriller</comments>
				</MovieType>
			</MovieListType>
		</MusicListResponseType>
	</S:Body>
</S:Envelope>

 

Conclusion: Thus, we have implemented & understood SOAP based Web Service implementation using top-down approach integrating with Spring and Hibernate ORM framework

In the next article, we will understand how we can integrate UsernameToken security headers in Metro JAX-WS

Download project

Metro-JAX-WS-Top-Down-Spring-Hibernate (19kB)

 

Happy Coding !!
Happy Learning !!