I planned to develop a simple JAX-WS 2.0 web services (Top Down one) with JAXB data binding with JPA as persistence layer with EclipseLink. Develop a stateless session Bean using annotation and Unit testing both JAX-WS webservice and EJB 3.0.
But when I started implementing I noticed the following observation:
My past webservice development experience with Weblogic 8.1 is JAX RPC (default technology provided by Weblogic 8.1) with XML Bean as bindings. When a webservice is created using weblogic workshop a jws file is generated along with a EJB / EJB control underneath the jws file so handling the transactions was never that hard but with Oracle Fusion 11g the weblogic workshop is no more supported and either Jdeveloper or eclipse are the tools to develop the webservice.
At this juncture, a webservice can be developed and deployed in web container using (JSR 109 deployment model) or JAX-WS webservices using stateless session bean EJB 3.0 (using POJO / POJI).
If you choose to develop webservice confirming to JSR 109 (deployment as war file) handling the JTA transaction will slightly tricky what I mean is one cannot take the advantage of EJB container (out of box). You end up having some configuration based implementation (in my view use spring transaction ……) or end up using User transaction. ( begin transaction , commit or rollback from resource , resource can be a datasource, JPA entity manager).
If you choose to develop and expose ejb as web service all the advantages provided by EJB container can be used.
But in this exercise I choose implement JAX-WS webservice using WDSL confirming to JSR 109 (as a war file) and take advantage of EJB container JTA transaction by calling EJB in webservice using annotation and EJB acts a data service with JPA annotations with JTA transaction.
During this exercise I have end up developing 3 varieties of implementation
1) Developed a JAX-WS and JPA with User Transactions.
2) Developed a JAX-WS and JPA with Container Manager Transactions.
3) A simple stateless session bean with JPA with annotations and DI (of course Container Managed Transactions).
I used following tools to develop the implementation Weblogic 10.3.3 (Oracle Fusion Middleware 11gR1PS2) , Oepe tools eclipse (JPA plugin, WSDL tool etc), Altova XML SPY, SOAP UI 3.6.1, Oracle database 10g…..
Let’s take deeper dive into my implementation one by one
- JAX-WS and JPA with User Transactions:
- Take to top-down approach to develop the webservice defining the contract first WSDL.
- Define xml schema for JAXB binding.
- Import the xml schemas into web service definition.
- Generate the JPA entitles from table.
- Do database operations using JPA EntityManager.
1. Defining the WSDL:
· Created a Weblogic Webservices project using the eclipse.
· Created a wsdl folder under webContent folder.
· Created a wsdl file with following options (Target Namespace, prefix for name space, Protocol as SOAP and Soap Binding options).
· Added service (Namespace, prefix for name space).
· Added a port (Name, binding,address,protocol).
· Defined the binding (port type, protocol)
· Defined the port type with operations (input & output with parameters).
· Generated implementation class using eclipse WSDL to Webservice tool.
package com.westsideauto.sales.baseprices;
import javax.jws.WebService;
import javax.xml.ws.BindingType;
import com.westsideauto.sales.baseprices.v1.add.AddBasePricesRequest;
import com.westsideauto.sales.baseprices.v1.add.AddBasePricesResponse;
import com.westsideauto.sales.baseprices.v1.del.DeleteBasePricesRequest;
import com.westsideauto.sales.baseprices.v1.del.DeleteBasePricesResponse;
import com.westsideauto.sales.baseprices.v1.find.FindBasePricesRequest;
import com.westsideauto.sales.baseprices.v1.find.FindBasePricesResponse;
import com.westsideauto.sales.baseprices.v1.upd.UpdateBasePricesRequest;
import com.westsideauto.sales.baseprices.v1.upd.UpdateBasePricesResponse;
import com.westsideauto.sales.service.baseprices.AddBasePricesV1;
/**
* This class was generated by the JAX-WS RI. Oracle JAX-WS 2.1.5 Generated
* source version: 2.1
*
*/
@WebService(portName = "BasePricesServiceSoap", serviceName = "BasePricesService", targetNamespace = "baseprices.sales.westsideauto.com", wsdlLocation = "/wsdls/BasePricesServices.wsdl", endpointInterface = "com.westsideauto.sales.baseprices.BasePricesServiceSoap")
@BindingType("http://schemas.xmlsoap.org/wsdl/soap/http")
public class BasePricesService_BasePricesServiceSoapImpl implements
BasePricesServiceSoap {
public BasePricesService_BasePricesServiceSoapImpl() {
}
/**
*
* @param addBasePricesRequest
* @return returns
* com.westsideauto.sales.baseprices.v1.add.AddBasePricesResponse
*/
public AddBasePricesResponse addBasePrices(
AddBasePricesRequest addBasePricesRequest) {
try {
return AddBasePricesV1.Factory.newInstance().addBasePrices(addBasePricesRequest);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
2. Define xml schemas
· Created a Java project for XML schemas.
· Defined the schemas for common, Error and service (Standard way).
3. Import the xml schemas into WSDL
Imported the above schemas into WSDL using
4. Created a JPA project using eclipse.
· Generated entities using eclipse JPA tools – “Generate entities from table” option.
· Selected appropriated schema and tables.(with proper definition of DB constraints….tool has generated the ORM mapping , associations and other annotations..)
package com.westsideauto.sales.entity;
import java.io.Serializable;
import javax.persistence.*;
/**
* The primary key class for the BASEPRICES database table.
*
*/
@Embeddable
public class BasePricePK implements Serializable {
//default serial version id, required for serializable classes.
private static final long serialVersionUID = 1L;
@Column(unique=true, nullable=false, length=50)
private String make;
@Column(unique=true, nullable=false, length=50)
private String model;
public BasePricePK() {
}
public BasePricePK(String make, String model) {
this.make=make;
this.model=model;
}
public String getMake() {
return this.make;
}
public void setMake(String make) {
this.make = make;
}
public String getModel() {
return this.model;
}
public void setModel(String model) {
this.model = model;
}
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof BasePricePK)) {
return false;
}
BasePricePK castOther = (BasePricePK)other;
return
this.make.equals(castOther.make)
&& this.model.equals(castOther.model);
}
public int hashCode() {
final int prime = 31;
int hash = 17;
hash = hash * prime + this.make.hashCode();
hash = hash * prime + this.model.hashCode();
return hash;
}
}
package com.westsideauto.sales.entity;
import java.io.Serializable;
import javax.persistence.*;
import java.math.BigDecimal;
/**
* The persistent class for the BASEPRICES database table.
*
*/
@Entity
@Table(name="BASEPRICES")
public class BasePrice implements Serializable {
private static final long serialVersionUID = 1L;
@EmbeddedId
private BasePricePK id;
@Column(nullable=false, precision=22)
private BigDecimal price;
public BasePrice() {
}
public BasePricePK getId() {
return this.id;
}
public void setId(BasePricePK id) {
this.id = id;
}
public BigDecimal getPrice() {
return this.price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
}
5. Created a Java project to have (JSE) to have services and DAO.
· Implemented an Interface to implementation approach.
package com.westsideauto.sales.service.baseprices; import com.westsideauto.sales.baseprices.v1.add.AddBasePricesRequest; import com.westsideauto.sales.baseprices.v1.add.AddBasePricesResponse; import com.westsideauto.sales.exception.WestSideAutoException; import com.westsideauto.sales.service.baseprices.impl.AddBasePricesServicesImpl; /** * @author advaita * */ public interface AddBasePricesV1 { public static class Factory { public static AddBasePricesV1 newInstance() { AddBasePricesV1 addBasePricesV1 = (AddBasePricesV1) (new AddBasePricesServicesImpl()); return addBasePricesV1; } } public AddBasePricesResponse addBasePrices(AddBasePricesRequest addBasePricesRequest) throws Exception; }
/**
*
*/
package com.westsideauto.sales.service.baseprices.impl;
import org.apache.log4j.Logger;
import com.westsideauto.sales.baseprices.v1.add.AddBasePricesRequest;
import com.westsideauto.sales.baseprices.v1.add.AddBasePricesResponse;
import com.westsideauto.sales.dao.impl.AddBasePricesDAOImpl;
import com.westsideauto.sales.exception.WestSideAutoException;
import com.westsideauto.sales.mapper.AddBasePricesMapper;
import com.westsideauto.sales.service.baseprices.AddBasePricesV1;
import com.westsideauto.sales.vo.BasePricesVO;
/**
* @author advaita
*
*/
public class AddBasePricesServicesImpl implements AddBasePricesV1 {
private Logger logger = Logger.getLogger(this.getClass());
@Override
public AddBasePricesResponse addBasePrices(AddBasePricesRequest addBasePricesRequest) throws Exception {
logger.debug("addBasePrices in AddBasePricesServicesImpl");
AddBasePricesResponse addBasePricesResponse=null;
String version=addBasePricesRequest.getVersion();
try {
BasePricesVO basepricesVO = AddBasePricesMapper.mapRequest(addBasePricesRequest);
String result = new AddBasePricesDAOImpl().saveBasePrices(basepricesVO);
addBasePricesResponse = AddBasePricesMapper.mapResponse(addBasePricesRequest);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw e;
}
return addBasePricesResponse;
}
}
package com.westsideauto.sales.dao.impl;
import java.math.BigDecimal;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import com.westsideauto.sales.dao.BaseWestSideAutoDAO;
import com.westsideauto.sales.entity.BasePrice;
import com.westsideauto.sales.entity.BasePricePK;
import com.westsideauto.sales.exception.WestSideAutoException;
import com.westsideauto.sales.vo.BasePricesVO;
public class AddBasePricesDAOImpl extends BaseWestSideAutoDAO {
/**
*
* @param basePrices
* @return
* @throws WestSideAutoException
*/
public String saveBasePrices(BasePricesVO basePrices)throws WestSideAutoException {
EntityManagerFactory emf = getEntityManagerFactory();
EntityManager em = emf.createEntityManager();
try {
em.getTransaction().begin();
BasePricePK pk = new BasePricePK(basePrices.getMake(),basePrices.getModel());
BasePrice basePrice = new BasePrice();
basePrice.setId(pk);
basePrice.setPrice(new BigDecimal(basePrices.getPrice()));
em.persist(basePrice);
em.getTransaction().commit();
//em.flush();
} catch(Exception ex) {
ex.printStackTrace();
throw new WestSideAutoException("Exception Occured in saveBasePrices", ex.getCause());
} finally {
em.close();
emf.close();
}
return "Success";
}
}
- Developed a JAX-WS and JPA with Container Manager Transactions (This section needs to be updated ..............Later)
- Simple stateless session bean with JPA with annotations and DI (of course Container Managed Transactions) :
§ Create a EJB project
§ Create a Bussiness Interface
§ Have Local and Remote interface extend the Business Interface.
§ Create a Stateless session Bean with all required annotations
}
package com.wsauto.ejb.session.baseprice;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import com.wsauto.entity.BasePrice;
/**
* Session Bean implementation class BasePriceSBean
*/
@Stateless(mappedName = "ejb.session.BasePriceSBean")
@TransactionManagement(value=TransactionManagementType.CONTAINER)
@TransactionAttribute(value=TransactionAttributeType.REQUIRED)
public class BasePriceSBean implements BasePriceSBeanRemote, BasePriceSBeanLocal {
/**
* Default constructor.
*/
public BasePriceSBean() {
// TODO Auto-generated constructor stub
}
@PersistenceContext(unitName = "WSAuto_JPA")
private EntityManager em;
public void add(final BasePrice c) {
em.persist(c);
}
Observation made during this implementation:
- With prior experience with extreme programming (Xdoclets) , It was easy to implement the annotation.
- I'm big fan of EJB and ORM tools / Technologies as I worked with Toplink (even before oracle acquired (webgain toplink), Hibernate (1,2,3x version) along with EJB 1x , 2.0,2.1 and now 3.o. For last few years drifted to Spring implementation as it made a big bang impression with DI / IOC & AOP other common templates (JDBC, JMS etc) techniques attracted me. With new JEE all these techniques introduced in ejb world and EJB development made easy with annotations. EJB3.0 and JPA ROCKS !!
References : (TBD)
- Thanks for Suresh Yenigalla for helping
Good work Rajesh. Sharing is caring. All the best.
ReplyDeleteBhat
Nice article, very informative
ReplyDeleteThalaivar blog always rocks!
ReplyDelete