Spring Web Services using JAXB part-1

Hi all its long time i put pen on my blog, its now time to write some thing about Spring web services implementation. Web services implementation of Spring is the best product and now a days service driven projects are in more demand, spring web services are of two types 1.RESTful Services and SOAP services. Some of the key features of spring web services are as follows

a) XML API support: Incoming XML messages can be handled in standard JAXP APIs such as DOM, SAX, and StAX, but also JDOM, dom4j, XOM, or even marshalling technologies.

b) Flexible XML Marshalling: The Object/XML Mapping module in the Spring Web Services distribution supports JAXB 1 and 2, Castor, XMLBeans, JiBX, and XStream. And because it is a separate module, you can use it in non-Web services code as well.

c) Also, the architecture of Spring-WS resembles that of Spring-MVC.

d) Apache license. You can confidently use Spring-WS in your project.

Before moving into the coding part, the essential jars required by the project as as below.
jars

Now its time for us to define the service contract.
Service Contract

Here’s where we start our contract first approach, the Service contract. The wsdl contract can be happily generated by Spring’s DefaultWsdl11Definition later. so lets start with simple schema as below.

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
	targetNamespace="http://www.example.org/person/schema" xmlns:per="http://www.example.org/person/schema"
	elementFormDefault="qualified">

	<xs:element name="Person">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="FirstName" type="xs:string" />
				<xs:element name="LastName" type="xs:string" />
			</xs:sequence>
			<xs:attribute ref="per:Id" use="required" />
		</xs:complexType>
	</xs:element>

	<xs:attribute name="Id" type="xs:int" />

	<xs:element name="AddPersonRequest">
		<xs:complexType>
			<xs:sequence>
				<xs:element ref="per:Person" />
			</xs:sequence>
		</xs:complexType>
	</xs:element>

	<xs:element name="GetPersonRequest">
		<xs:complexType>
			<xs:attribute ref="per:Id" use="required" />
		</xs:complexType>
	</xs:element>

	<xs:element name="GetPersonResponse">
		<xs:complexType>
			<xs:sequence>
				<xs:element ref="per:Person" />
			</xs:sequence>
		</xs:complexType>
	</xs:element>

	<xs:element name="GetAllPersonsRequest">
		<xs:complexType>
			<xs:sequence />
		</xs:complexType>
	</xs:element>

	<xs:element name="GetAllPersonsResponse">
		<xs:complexType>
			<xs:sequence>
				<xs:element ref="per:Person" maxOccurs="unbounded" />
			</xs:sequence>
		</xs:complexType>
	</xs:element>

	<xs:element name="UpdatePersonRequest">
		<xs:complexType>
			<xs:sequence>
				<xs:element ref="per:Person" />
			</xs:sequence>
		</xs:complexType>
	</xs:element>

	<xs:element name="DeletePersonRequest">
		<xs:complexType>
			<xs:attribute ref="per:Id" use="required" />
		</xs:complexType>
	</xs:element>
</xs:schema>

once our schema is ready now lets write simple ant script to generate the jaxb classes and compile them using jaxb’s xjc command using as follows.

<?xml version="1.0" encoding="UTF-8"?>
<project name="Spring-Ws Project With JaxB,XMLBeans and Jibx Capability"
	default="all" basedir=".">
	
	<property file="./build.properties" />
	
	<property name="javac.source" value="1.6" />
	<property name="javac.target" value="1.6" />
	
	<path id="classpath" description="Classpath to web application">
		<fileset dir="${dir.webapp.lib}" includes="**/*.jar" />
		<pathelement location="bin" />
	</path>
	
	<target name="clean">
        <delete dir="${base.dir}/classes"/>
        <mkdir dir="${base.dir}/classes"></mkdir>
    </target>
    
	<target name="compile">
        <javac srcdir="${dir.src}/org/springws/beans/schema" destdir="${base.dir}/classes"/>
    </target>
	
	<target name="clean-compile" description="java xml binding tool" depends="clean,compile">
		<echo message="compiling JAXB classes from xsd" />
		<exec executable="${jdk.home}/bin/xjc.exe">
			<arg value="-d" />
			<arg value="${dir.src}" />
			<arg value="-p" />
			<arg value="org.springws.beans.schema" />
			<arg value="${xsd.dir}/Person.xsd" />
		</exec>
	</target>
</project>

build.properties

base.dir=.

jdk.home=C\:\\Oracle\\Middleware\\jdk160_24
dir.src=../../src
xsd.dir=${base.dir}/xsd/schemas

dir.webapp.lib=${base.dir}/lib

Now lets design our own custom exception class as follows.
PersonException.java

/**
 * 
 */
package com.spark.springws.custom.exception;

/**
 * @author Sony
 *
 */
public class PersonException extends Exception {

	private static final long serialVersionUID = 1L;

	public PersonException(String message) {
		super(message);
	}
}

now lets start with the service class and its implementation class as follows.
PersonService.java, PersonServiceImpl.java

/**
 * 
 */
package com.spark.springws.service;

import java.util.List;

import org.springws.beans.schema.Person;

import com.spark.springws.custom.exception.PersonException;

/**
 * @author Sony
 * 
 */
public interface PersonService {
	public void addPerson(Person person) throws PersonException;
	public Person getPerson(Integer id) throws PersonException;
	public List<Person> getAllPersons();
	public void updatePerson(Person person) throws PersonException;
	public void deletePerson(Integer id) throws PersonException;
}

/**
 * 
 */
package com.spark.springws.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springws.beans.schema.Person;

import com.spark.springws.custom.exception.PersonException;
import com.spark.springws.service.PersonService;

/**
 * @author Sony
 * 
 */
public class PersonServiceImpl implements PersonService {

	private Map dataSource;

	@Override
	public void addPerson(Person person) throws PersonException {
		if (idExists(person.getId())) {
			throw new PersonException("Cannot add person. Id already exists.");
		}
		dataSource.put(person.getId(), person);
	}

	
	@Override
	public Person getPerson(Integer id) throws PersonException {
		if (!idExists(id)) {
			throw new PersonException("Cannot get person. ID does not exist.");
		}
		return (Person) dataSource.get(id);
	}

	@Override
	public List<Person> getAllPersons() {
		return new ArrayList(dataSource.values());
	}

	@Override
	public void updatePerson(Person person) throws PersonException {
		if (!idExists(person.getId())) {
			throw new PersonException(
					"Cannot update person. ID does not exist.");
		}
		dataSource.put(person.getId(), person);
	}

	@Override
	public void deletePerson(Integer id) throws PersonException {
		if (!idExists(id)) {
			throw new PersonException(
					"Cannot delete person. Id does not exists.");
		}
		dataSource.remove(id);
	}

	public void initialize() {
		dataSource = new HashMap();
		putPerson(1, "Clark", "Kent");
		putPerson(2, "Bruce", "Wayne");
		putPerson(3, "Harold", "Jordan");
	}

	private void putPerson(Integer id, String firstName, String lastName) {
		Person person = new Person();
		person.setId(id);
		person.setFirstName(firstName);
		person.setLastName(lastName);
		dataSource.put(id, person);
	}

	private boolean idExists(Integer id) {
		return dataSource.containsKey(id);
	}

}

Now lets write web.xml file as follows.

<?xml version="1.0" encoding="ISO-8859-1"?> 

<!DOCTYPE web-app PUBLIC 
    "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 
    "http://java.sun.com/dtd/web-app_2_4.dtd">

<web-app>
	<display-name>Person Service</display-name>
	<description>Simple CRUD like Application</description>

	<!-- Defines the Spring-WS MessageDispatcherServlet -->
	<servlet>
		<servlet-name>spring-ws</servlet-name>
		<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
		<init-param>
			<!-- Transform the location attributes in WSDLs -->
			<param-name>transformWsdlLocations</param-name>
			<param-value>true</param-value>
		</init-param>
	</servlet>

	<!-- Map all requests to this servlet -->
	<servlet-mapping>
		<servlet-name>spring-ws</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>
</web-app>

spring-ws-servlet.xml

<?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:oxm="http://www.springframework.org/schema/oxm"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
		http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-1.5.xsd">

	<bean id="personService" class="com.spark.springws.service.impl.PersonServiceImpl"
		init-method="initialize" />
	<bean id="Person"
		class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition">
		<property name="schema" ref="schema" />
		<property name="portTypeName" value="Person" />
		<property name="locationUri" value="/services" />
		<property name="targetNamespace" value="http://www.example.org/person/schema" />
	</bean>
	<bean id="schema" class="org.springframework.xml.xsd.SimpleXsdSchema">
		<property name="xsd" value="/WEB-INF/xsd/schemas/Person.xsd" />
	</bean>
</beans>

my project structure looks as below.
project-struct

once comleted please deploy the project onto server and run this url we should see the contract wsdl in the browser.
http://localhost:8080/Spring-WS-Ant/Person.wsdl

lets see how to define the service-endpoint-implementation,endpoint-mapping,mapping request to beans in the next post
until then keep coding
Happy Java and web services 🙂

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s