MiddlewareGuru

A data service with Eclipselink JPA, JAXB and JAX-WS

Data services deal only with entities – store entities into a database, retrieve them and handle everything about entities while doing so. For example, making sure that relationship between entities are maintained in the database and validations specific to each entity are applied.


Developing data services is surprisingly easy if you have your JPA entities develop and ready for reuse. As you’d see in this example, it takes as little as 10 minutes to a take JPA entities and expose them over a  web service. Below is a entity model for a fictitious healthcare service. Let’s implement a data service for part of this model, Facility and the related Address in a data service.

image



The steps to create a data service are:

  • Prepare the entity classes and annotate with JPA annotations
  • Select a JPA implementation and database
  • Define the service interface
  • Implement the service interface
  • Deploy to a JAX-WS/J-EE container and test – We used CXF on Tomcat

Prepare the entity classes and annotate with JPA annotations

We’ll have two entities in our service, Facility and Address. Because these are entities that will also be exposed as XML over web services, we’ll also add JAXB annotations to the classes. The relationship between Facility and address is one-to-one, with Facility holding a reference to address. Our Facility entity looks like this:

package com.wisealign.training.data;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "Facility")
@Entity
public class Facility {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int ID;
	@Column(name = "Name")
	private String FacilityName;
	@Column(name = "Type")
	private String FacilityType;

	@OneToOne
	@JoinColumn(name = "AddressID")
	private Address address;

	@XmlElement(name = "ID", required = true)
	public int getID() {
		return ID;
	}

	public void setID(int id) {
		ID = id;
	}

	@XmlElement(name = "FacilityName", required = true)
	public String getFacilityName() {
		return FacilityName;
	}

	public void setFacilityName(String facilityname) {
		FacilityName = facilityname;
	}

	@XmlElement(name = "FacilityType", required = true)
	public String getFacilityType() {
		return FacilityType;
	}

	public void setFacilityType(String facilitytype) {
		FacilityType = facilitytype;
	}

	@XmlElement(name = "Address", required = true)
	public Address getAddress() {
		return address;
	}

	public void setAddress(Address address) {
		this.address = address;
	}

}


Note the JAXB and JPA annotations. Facility is related to address through @OneToOne annotation, which also specifies the column. @Id and @GeneratedValue specify the primary key and the method to assign value for it. Address entity is much simpler, but still have JAXB and JPA annotations.

package com.wisealign.training.data;

import javax.persistence.Cacheable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "Address")
@Entity
public class Address {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int ID;

	private String Street;

	private String City;

	private String State;

	private String Zip;

	public Address() {
		System.out.println("Address being initiated");
	}

	@XmlElement(name = "ID", required = true)
	public int getID() {
		return ID;
	}

	public void setID(int id) {
		ID = id;
	}

	@XmlElement(name = "Street", required = true)
	public String getStreet() {
		return Street;
	}

	public void setStreet(String street) {
		Street = street;
	}

	@XmlElement(name = "City", required = true)
	public String getCity() {
		return City;
	}

	public void setCity(String city) {
		City = city;
	}

	@XmlElement(name = "State", required = true)
	public String getState() {
		return State;
	}

	public void setState(String state) {
		State = state;
	}

	@XmlElement(name = "Zip", required = true)
	public String getZip() {
		return Zip;
	}

	public void setZip(String zip) {
		Zip = zip;
	}

}

Select a JPA implementation and database


There many JPA implementation out there, several of them are open-source. Hibernate, OpenJPA, EclipseLink, to name a few. We chose EclipseLink for our sample project. Download EclipseLink binaries from the download site.


We ran this project with Oracle 11 XE and MySQL. The difference between the databases is applicable only to the persistence.xml file, in the properties section. Below are the snippets that differ between Oracle and MySQL. This underscores the power of JPA, in how it decouples specifics of a database from implementation of the entity.


Oracle properties:

<property name="javax.persistence.jdbc.driver" value="oracle.jdbc.driver.OracleDriver" />
<property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@soabpm-vm:1521:XE" />
<property name="javax.persistence.jdbc.user" value="HealthCareDB" />
<property name="javax.persistence.jdbc.password" value="welcome1" />
<property name="eclipselink.ddl-generation" value="create-tables" />


Entity manager will create a database schema the first time application is run. Comment out “create-tables” after running the application first time.

Define the service interface


Our goal is to expose operations to add a Facility and it’s associated address, get a facility and to get an address. These goals are achieved by the simple interface below:

package com.wisealign.training.services.data;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
import javax.jws.soap.SOAPBinding.Use;

import com.wisealign.training.data.Address;
import com.wisealign.training.data.Facility;

@WebService
@SOAPBinding(style = Style.DOCUMENT, use=Use.LITERAL) //optional
public interface IHealthCareDataService
{

	@WebMethod(operationName="getFacility")
	public Facility getFacility(@WebParam(name="id") int id);

	@WebMethod(operationName="getAddress")
	public Address getAddress(@WebParam(name="id") int id);

	@WebMethod(operationName="addFacility")
	public int addFacility(@WebParam(name="facility") Facility facility);

}


We’ll be using code-first approach to implement the data service. To learn more about developing JAX-WS services using this approach, check my previous article on this subject.

Implement the service interface


Implementation is rather simple, thanks to the Entity classes we created before. Remember that in most cases, the entity classes are developed in a reusable fashion, so it is likely that such classes available for use readily. That underscores the powerful capabilities brought by these technologies together. Here is the service implementation:

package com.wisealign.training.services.data;

import javax.jws.WebService;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import com.wisealign.training.data.Address;
import com.wisealign.training.data.Facility;
import com.wisealign.training.data.HealthCareDataUtil;

@WebService(endpointInterface="com.wisealign.training.services.data.IHealthCareDataService", serviceName="HealthCareDataService")
public class HealthCareDataService implements
		IHealthCareDataService {

	private EntityManager em;

	public HealthCareDataService()
	{
	    EntityManagerFactory emf = Persistence.createEntityManagerFactory("HealthCareService");
	    em = emf.createEntityManager();
	}
	@Override
	public int addFacility(Facility facility) {
	    em.getTransaction().begin();

	    em.persist(facility.getAddress());
	    em.persist(facility);

	    em.getTransaction().commit();
	    return facility.getID();
	}

	@Override
	public Address getAddress(int id) {
    	System.out.println("Address being gotten");
		return em.find(Address.class, id);
	}

	@Override
	public Facility getFacility(int id) {
		return em.find(Facility.class, id);
	}

}

Deploy to a JAX-WS/J-EE container and test – We used CXF on Tomcat

It’s time to package and deploy the project. Refer to this post on exporting and running a project using Eclipse and Tomcat. You might add the relevant .jar files, EclipseLink, JPA 1.0 and JDBC libraries in this case, to Tomcat’s class path than adding them to the web application.  Note that the project with JPA entities are in their own project, which is added as a dependency to the web application project. These libraries are required to run the application under Tomcat.

ojdbc6.jar or mysql-connector-java-5.1.25

javax.persistence_1.0.0.jar

eclipselink.jar

HealthCareData.jar

Here is a sample createFacility request observed during tests.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:data="http://data.services.training.wisealign.com/">
   <soapenv:Header/>
   <soapenv:Body>
      <data:addFacility>
         <facility>
            <Address>
               <City>First street</City>
               <ID>0</ID>
               <State>My state</State>
               <Street>New street</Street>
               <Zip>55555</Zip>
            </Address>
            <FacilityName>MyTown-East</FacilityName>
            <FacilityType>Pediatrics</FacilityType>
            <ID>0</ID>
         </facility>
      </data:addFacility>
   </soapenv:Body>
</soapenv:Envelope>


createFacility response:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <ns2:addFacilityResponse xmlns:ns2="http://data.services.training.wisealign.com/">
         <return>210</return>
      </ns2:addFacilityResponse>
   </soap:Body>
</soap:Envelope>

Note:SOAPUi adds a namespace prefix ‘data’ for the address element. Remove the element in order for the calls to succeed.


An export of the project is provided below.

References:

Project archive file for eclipse import: HealthCareJPADataServices




Your email address will not be published. Required fields are marked *

*


seven × 1 =