Spring Web Services using JAXB part-2

After the part-1 this is the contd part of it, now we are going to write the endpoint implementations and mapping these end points to the request from the web. so lets not waste time just jumping into the implementation part here we go.

Lets write AbstractPersonEndPoint class which will extend AbstractMarshallingPayloadEndpoint of Spring framework. Here we are going to just create PersonService object and define an abstract method invokeInternal of AbstractMarshallingPayloadEndpoint class.

/**
 * 
 */
package com.spark.springws.abstrct.endpoint;

import org.springframework.ws.server.endpoint.AbstractMarshallingPayloadEndpoint;

import com.spark.springws.service.PersonService;

/**
 * @author Sony
 *
 */
public abstract class AbstractPersonEndPoint extends AbstractMarshallingPayloadEndpoint {

	protected PersonService personService;
	
	/**
	 * @param personService the personService to set
	 */
	public void setPersonService(PersonService personService) {
		this.personService = personService;
	}


	/* (non-Javadoc)
	 * @see org.springframework.ws.server.endpoint.AbstractMarshallingPayloadEndpoint#invokeInternal(java.lang.Object)
	 */
	@Override
	protected abstract Object invokeInternal(Object request) throws Exception;

}

Now its time to create concrete endpoint classes which will have exact business logic implementation and will extend AbstractPersonEndPoint. I will show for one of the service and other implementations are left for you.

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

import org.springws.beans.schema.AddPersonRequest;

import com.spark.springws.abstrct.endpoint.AbstractPersonEndPoint;

/**
 * @author Sony
 *
 */
public class AddPersonEndPoint extends AbstractPersonEndPoint {

	/* (non-Javadoc)
	 * @see com.spark.springws.abstrct.endpoint.AbstractPersonEndPoint#invokeInternal(java.lang.Object)
	 */
	@Override
	protected Object invokeInternal(Object request) throws Exception {

		AddPersonRequest addPersonRequest = (AddPersonRequest) request;
		personService.addPerson(addPersonRequest.getPerson());
		return null;
	}

}

now lets take a look at the spring-ws-servlet.xml which we already defined in this part-1 section and modify it a little bit as shown below.

<?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-3.2.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>

	<bean id="validationInterceptor"
		class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
		<property name="xsdSchema" ref="schema"></property>
		<property name="validateRequest" value="true" />
		<property name="validateResponse" value="true" />
	</bean>

	<bean id="loggingInterceptor"
		class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor" />

	<oxm:jaxb2-marshaller id="marshaller"
		contextPath="org.springws.beans.schema" />
	<oxm:jaxb2-marshaller id="unmarshaller"
		contextPath="org.springws.beans.schema" />

	<bean id="addPersonEndpoint" class="com.spark.springws.endpoints.AddPersonEndPoint"
		autowire="byName" />
	<bean id="getAllPersonsEndpoint" class="com.spark.springws.endpoints.GetAllPersonsEndPoint"
		autowire="byName" />
	<bean id="getPersonEndpoint" class="com.spark.springws.endpoints.GetPersonEndPoint"
		autowire="byName" />

	<bean name="endpointMapping"
		class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping">
		<property name="interceptors">
			<list>
				<ref local="loggingInterceptor" />
				<ref local="validationInterceptor" />
			</list>
		</property>
		<property name="mappings">
			<props>
				<prop key="{http://www.example.org/person/schema}AddPersonRequest">addPersonEndpoint</prop>
				<prop key="{http://www.example.org/person/schema}GetAllPersonsRequest">getAllPersonsEndpoint</prop>
				<prop key="{http://www.example.org/person/schema}GetPersonRequest">getPersonEndpoint</prop>
				<prop key="{http://www.example.org/person/schema}UpdatePersonRequest">updatePersonEndpoint</prop> 
					<prop key="{http://www.example.org/person/schema}DeletePersonRequest">deletePersonEndpoint</prop>
			</props>
		</property>
	</bean>

	<bean id="exceptionResolver"
		class="org.springframework.ws.soap.server.endpoint.SoapFaultMappingExceptionResolver">
		<property name="defaultFault" value="SERVER" />
		<property name="exceptionMappings">
			<props>
				<prop key="org.springframework.oxm.ValidationFailureException">CLIENT,Invalid request</prop>
				<prop key="com.spark.springws.custom.exception.PersonException">SERVER</prop>
			</props>
		</property>
	</bean>
</beans>

once this is done just deploy the project and test the request and response from SOAP UI as shown below.
add-request

get-req-res

Happy Spring-Web services 🙂

Advertisements

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 🙂

Web services using JAXB

Hi Guys here is my brief post on how to develop web services using jaxb notation.

The Java Architecture for XML Binding API (JAXB) makes it easy to access XML documents from applications written in the Java programming language. JAXB is an alternative to using a SAX or DOM parser to access the data in an XML document. When you access an XML document with JAXB, first you bind the schema for the XML document into a set of Java classes that represents the schema. Then you unmarshal the XML document. Unmarshalling a document means creating a tree of content objects that represents the content and organization of the document.

You can also use JAXB to build an XML document. To build an XML document with JAXB, you first bind the schema for the XML document you want to build. Then you create a content tree. Lastly, you marshal the content tree into an XML document.

The following diagram, from Java Architecture for XML Binding API, shows the processes both for accessing and for building XML documents from Java applications.


Working with JAXB is easy, just annotate object with JAXB annotation, later use jaxbMarshaller.marshal() or jaxbMarshaller.unmarshal() to do the object / XML conversion.
No extra jaxb libraries are required if you are using JDK1.6 or above, because JAXB is bundled in JDK 1.6.
Note
For JDK < 1.6, download JAXB from here and put “jaxb-api.jar” and “jaxb-impl.jar” on your project classpath.

now lets see how to code with “jaxb”

/**
 * 
 */
package com.spark.jaxb.model;

import java.io.Serializable;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

/**
 * @author Pavan Mantha
 * 
 */
@SuppressWarnings("serial")
@XmlRootElement
public class Customer implements Serializable {

	private int id;
	private String firstName;
	private String lastName;
	private String designation;
	private String phoneNumber;

	/**
	 * @return the id
	 */
	public int getId() {
		return id;
	}

	/**
	 * @param id
	 *            the id to set
	 */
	@XmlAttribute
	public void setId(int id) {
		this.id = id;
	}

	/**
	 * @return the firstName
	 */
	public String getFirstName() {
		return firstName;
	}

	/**
	 * @param firstName
	 *            the firstName to set
	 */
	@XmlElement
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	/**
	 * @return the lastName
	 */
	public String getLastName() {
		return lastName;
	}

	/**
	 * @param lastName
	 *            the lastName to set
	 */
	@XmlElement
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	/**
	 * @return the designation
	 */
	public String getDesignation() {
		return designation;
	}

	/**
	 * @param designation
	 *            the designation to set
	 */
	@XmlElement
	public void setDesignation(String designation) {
		this.designation = designation;
	}

	/**
	 * @return the phoneNumber
	 */
	public String getPhoneNumber() {
		return phoneNumber;
	}

	/**
	 * @param phoneNumber
	 *            the phoneNumber to set
	 */
	@XmlElement
	public void setPhoneNumber(String phoneNumber) {
		this.phoneNumber = phoneNumber;
	}

}

now its time to code jaxb marshaller,

/**
 * 
 */
package com.spark.jaxb.marshaller;

import java.io.File;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

import com.spark.jaxb.model.Customer;

/**
 * @author Pavan Mantha
 * 
 */
public class JaxbMarshaller {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Customer customer = new Customer();
		customer.setId(100);
		customer.setFirstName("Pavan");
		customer.setLastName("Mantha");
		customer.setDesignation("SoftwareEngineer");
		customer.setPhoneNumber("123-4567-890");

		try {

			File file = new File("C:\\customer.xml");
			JAXBContext jaxbContext = JAXBContext.newInstance(Customer.class);
			Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

			// output pretty printed
			jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

			jaxbMarshaller.marshal(customer, file);
			jaxbMarshaller.marshal(customer, System.out);

		} catch (JAXBException e) {
			e.printStackTrace();
		}
	}

}

and unmarshaller as below.

/**
 * 
 */
package com.spark.jaxb.unmarshaller;

import java.io.File;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

import com.spark.jaxb.model.Customer;

/**
 * @author Pavan Mantha
 * 
 */
public class JaxbUnmarshaller {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		try {

			File file = new File("C:\\customer.xml");
			JAXBContext jaxbContext = JAXBContext.newInstance(Customer.class);

			Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
			Customer customer = (Customer) jaxbUnmarshaller.unmarshal(file);
			System.out.println(customer);

		} catch (JAXBException e) {
			e.printStackTrace();
		}
	}

}

Happy Coding 🙂