Home > JMS, JPA, JTA, Spring > Spring + JTA + JPA + JMS

Spring + JTA + JPA + JMS

I recently worked on a Spring application that used Hibernate as JPA provider and JTA for transaction demarcation. In this post I will create a simple Order Processing Message Driven Bean that showcases this integration. I will be using an Oracle database and deploy the application on a WebLogic 10.3 server.

To keep things manageable, the Message Driven Bean is designed to consume messages from a Queue. When a new message gets added to the Queue, the Application Server delivers it to the MDB. The MDB then uses a Spring Managed Service/Repository to persist a new “Order” JPA Entity in the database. The application is configured such that this entire process runs in a container managed transaction. I will be using the Blog Queue I created in a previous post.

Step 1: The first step is to create an Order Entity and the corresponding database table to store the newly created orders.

 
package com.inflinx.blog.orderprocessing.domain;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="ORDER_TABLE", schema="BLOGDEMO")
public class Order 
{
	@Id
	@Column(name="ORDER_ID")
	private Long id;
	
	@Column(name="NAME")
	private String name;
	
	@Column(name="CREATED_DATE")
	private Date createdDate;

	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Date getCreatedDate() {
		return createdDate;
	}
	public void setCreatedDate(Date createdDate) {
		this.createdDate = createdDate;
	}
}

I have created the ORDER_TABLE in an Oracle database under the BLOGDEMO schema:

Order Table

Order Table

Step 2: In the WebLogic console, create a XA datasource to the database with the JNDI name jdbc.blgods.

XA Blog Data Source

XA Blog Data Source

The XA datasource is necessary for Hibernate to participate in a JTA global transaction. WebLogic also provides an option to emulate XA with the Emulate Two-Phase Commit.

Step 3: The next step is to create an OrderRepository that deals with persistence logic such as creating a new Order.

package com.inflinx.blog.orderprocessing.repository;

import com.inflinx.blog.orderprocessing.domain.Order;

public interface OrderRepository 
{
	public void createOrder(Order order);
}
package com.inflinx.blog.orderprocessing.repository;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.springframework.stereotype.Repository;

import com.inflinx.blog.orderprocessing.domain.Order;

@Repository("orderRepository")
public class OrderRepositoryImpl implements OrderRepository 
{
	// Spring injected EntityManager
	@PersistenceContext
    private EntityManager entityManager;
	
	@Override
	public void createOrder(Order order) 
	{
		 entityManager.persist(order);
	}
}

Step 4: Following the principles of layered architecture, the next step is to create an OrderService and its implementation.

package com.inflinx.blog.orderprocessing.service;

import com.inflinx.blog.orderprocessing.domain.Order;

public interface OrderService {
	public void createOrder(Order order);
}
package com.inflinx.blog.orderprocessing.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.inflinx.blog.orderprocessing.domain.Order;
import com.inflinx.blog.orderprocessing.repository.OrderRepository;

@Service("orderService")
@Transactional
public class OrderServiceImpl implements OrderService {

	@Autowired
	@Qualifier("orderRepository")
	private OrderRepository orderRepository;
	
	@Override
	public void createOrder(Order order) {
		// Simply delegate the call to repository layer
		orderRepository.createOrder(order);
	}
}

As you can see, the implementation is annotated with @Transactional to make the service call transactional.

Step 5: The next step is to create a persistence.xml file without any JPA provider information.

 

	
		
			com.inflinx.blog.orderprocessing.domain.Order
		

		

Step 6: The next step is to create a Spring configuration application-context.xml file to hold bean and transaction definition. In addition, the file also holds the JPA provider information.


       
	     
    
     
    
    
    
	
	
	
	
    
	    
    
    			
    				
    					
    					
    				
    			
    			
    				
    					hibernate.transaction.factory_class=org.hibernate.transaction.JTATransactionFactory
					hibernate.transaction.manager_lookup_class=org.hibernate.transaction.WeblogicTransactionManagerLookup
					hibernate.current_session_context_class=jta
					hibernate.transaction.flush_before_completion=true						
					hibernate.connection.release_mode=auto
    				
    			
    			
    	
             

Step 7: With the above configuration in place, the next step is to create a Message Driven Bean that processes incoming messages. The MDB is annotated to use container managed transactions:

 
package com.inflinx.blog.mdb;

import java.util.Date;

import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.interceptor.Interceptors;
import javax.jms.Message;
import javax.jms.MessageListener;

import org.apache.commons.lang.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor;

import com.inflinx.blog.orderprocessing.domain.Order;
import com.inflinx.blog.orderprocessing.service.OrderService;


@MessageDriven(
		mappedName = "jndi.blogQueue",
		name="orderProcessor",
		activationConfig = { @ActivationConfigProperty(
				propertyName = "destinationType", propertyValue = "javax.jms.Queue"
		)}
)
@Interceptors(SpringBeanAutowiringInterceptor.class)
@TransactionManagement(TransactionManagementType.CONTAINER)
public class OrderProcessor implements MessageListener
{
	@Autowired
	@Qualifier("orderService")
	private OrderService orderService;
	
    @Override
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
	public void onMessage(Message message) 
	{
    	// Create a new Order
    	Order order = new Order();
    	order.setId(System.currentTimeMillis());
    	order.setName(RandomStringUtils.randomAlphabetic(5));
    	order.setCreatedDate(new Date());
    	
    	// Save the order
    	orderService.createOrder(order);
	}
	
}

Step 8: The SpringBeanAutowiringInterceptor by default looks for a beanRefContext.xml file to create a spring context. So the final step in the process is to create a beanRefContext.xml with a reference to the application-context.xml.




			 
		
							
				application-context.xml
			
		 		
	
	 

Now when a new message gets added to the Queue, the onMessage method will run inside a transaction and will create a new Order. Here is a new Order record in the database:

Order Table Populated

Order Table Populated

Categories: JMS, JPA, JTA, Spring Tags: , , ,
  1. April 13th, 2010 at 02:59 | #1

    Nice Post. It’s a clear example of how to mix different technologies in a single project.

  2. John Jacobs
    April 26th, 2010 at 12:20 | #2

    Great post. I was wondering what app server you’re using and are you deploying and EAR or WAR?

  3. April 26th, 2010 at 13:58 | #3

    @John Jacobs
    I tested this on WebLogic 10.3.0 server. I have deployed the application as an EAR file.

  4. Dan
    May 24th, 2010 at 20:25 | #4

    Thanks for your post. For your deployment, are the spring jars in the war file under /WEB-INF/lib or in the ear file under /APP-INF/lib?

  5. May 25th, 2010 at 08:33 | #5

    @Dan
    I have the jar files under APP-INF/lib directory.

  6. Tez
    September 5th, 2010 at 08:24 | #6

    I have a question. In the beginning you said “JTA for transaction demarcation” is used and I do not find the core JTA in the code. You have used EJBs transaction demarcation. Can you be a little clear on this.

  7. Amin
    October 13th, 2010 at 02:17 | #7

    Has anyone tried out the example, there are so many errors in the context files. Its would help for thoses still learning to have working examples.

  8. October 13th, 2010 at 08:54 | #8

    @Amin
    The SyntaxHighlighter tool I am using is messing up the configuration files. Download the bookstore.zip file with the source code and give it a try.

  9. Amin
    October 13th, 2010 at 09:12 | #9

    Hi Balaji,

    Where can I find the bookstore.zip or did you mean the orderprocessing.zip?

  10. October 13th, 2010 at 09:38 | #10

    My bad. Its the orderprocessing.zip file. Give it a try and if you run into any problems let me know.

  11. Amin
    October 13th, 2010 at 10:59 | #11

    Balaji,

    I have a similar senario to your example where I persist records to the database, calling the service classes from a Stateless EJB. I have copied your application-context.xml and persitence.xml and modified with my specific values.

    Testing the code it did not saving any records to the database, its seems not commit the transaction, and there were no inidcation of any errors.

    I managed to get it to work by calling flush() “entityManager.flush();” in the dao. In your example is does it auto commit when you run it?

  12. October 13th, 2010 at 12:32 | #12

    @Amin
    You are right. Looks like the transaction is not being committed in your case. Notice that in my Message Driven Bean, I am using container managed transaction and JPA will simply run under that transaction. As soon as the transaction commits, the record gets inserted in the database. I have this configuration running for a long time.

    The only thing I can think of to check is to make sure that your EJB method is being invoked inside a transaction (existing or new)? Can you make sure that you have properly annotated your class and method with TransactionManagement and TransactionAttribute.

    Hope this helps.

  13. Hitesh tara
    May 28th, 2013 at 14:27 | #13

    Hi very good example but I can you tell if I could achieve the same process by not using ejb with tomcat only as app server

  1. April 16th, 2010 at 20:03 | #1
  2. April 19th, 2010 at 13:28 | #2