Wednesday, February 24, 2010

JAX-WS RESTful web services

Publishing a Restful web service with JAX-WS starts by implementing the javax.xml.ws.Provider<T> interface. Implementations are required to support Provider<Source> and Provider<SOAPMessage>. The ServiceMode annotation can be used to control whether the Provider instance will receive entire protocol messages or just message payloads.

Here we are going to look at an example which accepts search consumer request and results the particular consumer details.

So our service will look like
public class ConsumerSearchService implements Provider<Source>{
}

The next step is to declare a @Resource annotation that will be used by the JAX-WS runtime to inject a WebServiceContext into our ConsumerSearchService instance.

public class ConsumerSearchService implements Provider<Source>{
@javax.annotation.Resource(type=Object.class)
protected static WebServiceContext wsContext;
}

Here we use JAXB for marshall and unmarshall the xml request and response objects.
So the next step is to create JAXBContext in the constructor of our service class.


public class ConsumerSearchService implements Provider<Source>{
@javax.annotation.Resource(type=Object.class)
protected static WebServiceContext wsContext;
private JAXBContext jc;
public ConsumerSearchService () {
    try {
       jc = JAXBContext.newInstance("consumer.rest");
    } catch(JAXBException je) {
       System.out.println("Exception " + je);
       throw new WebServiceException("Cannot create JAXBContext", je);
    }
    }
}

The next step is to implement Source Provider<Source>.invoke (Source source)

public Source invoke(Source source) {
try{
    MessageContext mc = wsContext.getMessageContext();
    String path = (String)mc.get(MessageContext.PATH_INFO);
    String method = (String)mc.get(MessageContext.HTTP_REQUEST_METHOD);
    System.out.println("Got HTTP "+method+" request for "+path);
    if (method.equals("POST"))
        return handlePost(source, mc);
    throw new WebServiceException("Unsupported method:" +method);
} catch(JAXBException je) {
   throw new WebServiceException(je);
}
}

If you look at API documentation of MessageContext it says, javax.xml.ws.handler.MessageContext interface provides methods to manage a property set. MessageContext properties enable handlers in a handler chain to share processing related state.

From MessageContext.HTTP_REQUEST_METHOD we get HTTP method and we can handle all other methods(GET, PUT, DELETE) similarly as POST method handled above.

Next we will look at the implementation of handlePost (source, mc) method.
/**
* Handles HTTP POST.
*/
private Source handlePost (Source source, MessageContext mc)
throws JAXBException {
mc.put(MessageContext.HTTP_RESPONSE_CODE, 201);
Unmarshaller u = jc.createUnmarshaller();
ConsumerReq request = (ConsumerReq) u.unmarshal(source);
ConsumerRes response = searchConsumer(request);
return new JAXBSource(jc, response);
}

Deployment
We are going to look at deploying same service in two different environments. One is IBM specific where you can deploy the war file in Web sphere without any sun specific configurations. The other one if sun specific.

1. IBM Specific

@javax.xml.ws.WebServiceProvider(
serviceName="ConsumerSearchService",
portName="ConsumerSearchServicePort",
targetNamespace=http://consumer.details.com/v1)

By placing the above annotation statement on top of the web service class is enough to deploy the web service in web sphere.

2. Sun Specific

To deploy our endpoint on a servler container we need to make configuration changes in two files. One is in web.xml and other is to create or modify sun-jaxws.xml.

The following entries in web.xml for above example.
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee">
<listener>
<listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener
</listener>
<servlet>
<servlet-name>ConsumerSearch</servlet-name>
<servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ConsumerSearch</servlet-name>
<url-pattern>/ConsumerSearchService/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>60</session-timeout>
</session-config>
</web-app>

Next we add a sun-jaxws.xml deployment descriptor to the WAR file. The following is an example.
<?xml version="1.0" encoding="UTF-8"?>
<endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime" version="2.0">
<endpoint name="ConsumerSearchService"
implementation="ConsumerSearchService"
binding="http://www.w3.org/2004/08/wsdl/http"
url-pattern='/ConsumerSearchService/*'/>
</endpoints>

Tuesday, February 23, 2010

Hibernate update and dynamic-update

Introduction:

When we start working on hibernate we always get confused with some properties and their behavior. This write up explains the difference between two such properties that are used for table update.

update="false" and dynamic-update="true"

There are two scenarios with respect to hibernate update functionality.
1. One scenario is that we never want to update some fields. We just need to retain the value that was created originally. In such cases we have to set update="false" in hibernate mapping file as mentioned below.

<property name=”xxx” column=”xxx” update=”false”>

Practical usage of this could be, for example consider the following entity

public class User{
Integer userId;
String firstName;
String lastName;
Date createDate;
String createdBy;
Date updateDate;
String updatedBy;
}

The "createDate" and "createdBy" fields should be set only for the first time when it is created. Any further updates to that row should not modify "createDate" and "createdBy" fields.

So the configuration for this is set update=”false” in user.hbm.xml file.

<property name="createDate" column="createDate" update="false">
<property name="createdBy" column="createdBy" update="false">

2. Second scenario is that when we call session.update() method it generates SQL update statement for all the fields of that entity. If we would like to have only the fields that we modify then we need to set dynamic-update="true" in hibernate mapping files.

For example:
Consider the values of a user table’s row
{
1,
"Joe",
"Tee",
16/10/2009,
"John",
17/10/2009,
"John"
}
And we are updating only the user name

User user = userDAO.get(1);
user.setFirstName("Bee");
userDAO.update(user);
And the update statement generated usually is

UPDATE USER SET first_name='Bee', last_name='Tee', update_date='17/10/2009', updated_by='John' WHERE user_id=1;

Though we modified only one field, all fields are getting populated in the update statement. Here USER table is small and the performance impact may be less, but if we consider production tables with huge number of columns this will have the biggest performance impact.

To improve the performance, the requirement here is that update statement should contain only the fields that are updated.

To do that we need to set

<class name="User" table="USER" dynamic-update="true">

Once the property is set the update statement that gets generated is

UPDATE user set first_name='Bee' WHERE user_id=1;

Hibernate Interceptors

Introduction

This article mainly talks about hibernate interceptor and its uses. This also includes different types of hibernate interceptors and available APIs.

Sometimes we may require performing some operations before or after performing core functional logic. In such case an interceptor can be used to intercept the existing functionality to provide new features or add-ons to the application. Interceptors provide callback APIs which can be called on specific event or action.

Hibernate Interceptors

The Interceptor interface provides callbacks from the session to the application, allowing the application to inspect and/or manipulate properties of a persistent object before it is saved, updated, deleted or loaded. One possible use for this is to track auditing information. For example, Interceptor can be used to set audit trail properties such as created by, created on, updated by and updated on automatically.

Types of Hibernate Interceptors

1. Application scope interceptors
2. Session scope interceptors

1. Application Scope Interceptors
An application may contain more than one database session. If the interceptor is configured in the application scope level, then it is applicable to persistent objects in all the sessions of that application. The following code configures application scope interceptor.

Configuration configuration = new Configuration();
configuration.setInterceptor(new AppScopeInterceptor());
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session1 = sessionFactory.openSession();
Session session2 = sessionFactory.openSession();

Hibernate Configuration class provides an API to set application scope interceptors. In the above example the interceptor is applicable to both “session1” and “session2”.

2. Session Scope Interceptors
Each session can have different interceptors configured to them. In that case the interceptor is applicable to persistent objects of that particular session.

Configuration configuration = new Configuration();
SessionFactory sessionFactory = configuration.buildSessionFactory();
FirstInterceptor firstInterceptor = new FirstInterceptor ();
Session session1 = sessionFactory.openSession(firstInterceptor);
SecondInterceptor secondInterceptor = new SecondInterceptor ();
Session session2 = sessionFactory.openSession(secondInterceptor);

In the above example two different interceptors (firstInterceptor, secondInterceptor) are configured to two different sessions (session1, session2). In that case “firstInterceptor” is applicable only for “session1” and the “secondInterceptor” for “session2”.

Interceptor API
1. Interceptor – interface
2. EmptyInterceptor - contains empty method implementation of interceptor interface.

We can either implement interceptor directly or extend EmptyInterceptor. It’s always better to extend EmptyInterceptor and override only methods that are required.

This interface allows application to provide greater customization to persist the objects. It even allows the code to modify the state of the persistent object. It has more than 15 different methods and so the designers of Hibernate provide the concrete EmptyInterceptor class which implements the Interceptor interface to provide default/empty method implementations. Applications can use EmptyInterceptor class instead of depending on the Interceptor interface.

Examples

1. Set audit trail properties

For example almost in every application the database tables might have some kind of audit trail fields. Ideally these fields need to be set based on who created/updated and when. There fields may present in almost all table at times. Using Hibernate Interceptor this can be set without touching the existing application code. So this helps the developer from setting these fields each and every time manually and places this code in a common place apart from application code.

For Example we have a base class which contains only the audit trail information.

Public class BaseEntity implements Serializable {
String createdBy
Date createdOn
String updatedBy
Date updatedOn
}

And we have PersonEntity extending BaseEntity.
Public Class PersonEntity extends BaseEntity {
String fname;
String lname;
String fullName;
}

To implement the interceptor, we need to implement the Interceptor interface or extend the EmptyIntercepter. Let’s extend EmptyInterceptor so we need to implement only the methods we actually need.

Public class AuditTrailInterceptor extends EmptyInterceptor {
public boolean onFlushDirty(
Object entity, Serializable id, Object[] currentState,
Object[] previousState, String[] propertyNames, Type[] types) {
setValue(currentState, propertyNames, "updatedBy", UserUtils.getCurrentUsername());
setValue(currentState, propertyNames, "updatedOn", new Date());
return true;
}


public boolean onSave(
Object entity, Serializable id, Object[] state,
String[] propertyNames, Type[] types) {
setValue(state, propertyNames, "createdBy", UserUtils.getCurrentUsername());
setValue(state, propertyNames, "createdOn", new Date());
return true;
}


private void setValue(
Object[] currentState, String[] propertyNames,
String propertyToSet, Object value) {
def index = propertyNames.toList().indexOf(propertyToSet)
if (index >= 0) {
currentState[index] = value
}
}
}

Here we implemented onFlushDirty() and onSave() methods because these are called for SQL updates and inserts, respectively. For example when a new PersonEntity is created onSave method is called and here we need to set “createdBy” and “createdOn” fields. Same way when an existing PersonEntity is modified onFlushDirty method is called and here we need to set “updatedBy” and “updatedOn”.

There are two ways to modify / view values of persistent objects. Notice that each method takes parameters of “state” array and “propertyNames” array. State array contains values of a persistent object where as propertyNames array contains properties of a persistent object.

For example “propertyNames” array of a PersonEntity might look like this
{
“createBy”,
“createdOn”,
“updatedBy”,
“updatedOn”,
“fname”,
“lname”,
“fullName”
}
And “state” array might look like this after creating and updating the same
{
“Tom”,
07-10-2009 14:27:00,
“Jerry”,
17-10-2009 14:30:00,
“xxxx”,
“yyyy”,
“xxxx yyyy”
}

One way of modifying the persistent objects are to traverse through these arrays and edit the appropriate value as we have done in “setValue” utility method.

The other way of accessing and modifying the persistent objects are through entity parameter. As specified below:-
public boolean onSave(
Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
if (entity instanceof BaseEntity){
BaseEntity baseEntity = (BaseEntity)entity;
baseEntity.setCreatedBy(UserUtils.getCurrentUsername());
baseEntity.setCreatedOn(new Date());
}
return super.onSave(entity, id, state, propertyNames, types);
}

2. Set Derived properties
Any property is derived from existing properties can also be set through interceptors. For example in the above PersonEntity the fullName can be derived from fname and lname properties. Instead of setting this value in the application logic we can move it to interceptor.

public boolean onSave(
Object entity, Serializable id, Object[] state, String[] propertyNames,
Type[] types){
if (entity instanceof PersonEntity){
PersonEntity personEntity = (PersonEntity)entity;
String fullName = personEntity.getFName() + " " +
personEntity.getLName();
personEntity.setFullName(fullName);
}
return super.onSave(entity, id, state, propertyNames, types);
}

3. Maintain log information
Log information can also be recorded on save or update.
public class LoggerInterceptor extends EmptyInterceptor{
public boolean onSave(
Object entity, Serializable id, Object[] state, String[] propertyNames,
Type[] types){
System.out.println("Inserting the persistent Object " +
entity.getClass() + " with Id " + id);
return super.onSave(entity, id, state, propertyNames, types);
}
}
Same method can be used to monitor what values are getting saved. This helps the developer to debug the values that are passed to database.

Summary
This article is just an introduction to Hibernate Interceptors and includes few examples which reduces the redundant code and provides modularity from the core application logic.