Archive

Posts Tagged ‘JMS’

Spring + JTA + JPA + JMS

April 8th, 2010 13 comments

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: , , ,

Distributed JMS Queue on WebLogic 10

June 5th, 2008 11 comments

Several months ago, I had to setup a JMS queue on a WebLogic 10 server.  Bea has nice documentation for JMS at http://edocs.bea.com/wls/docs100/messaging.html. Here is a condensed version for setting up JMS Distributed Queues.

Disclaimer: These are instructions for the minimal JMS setup and do not include optimizations/tuning for production environment. 

The first step in setting up a Distributed Queue is to create a JMS server for managing the Queue. Here are the steps for creating a JMS server.

  1. Under Domain Structure, go to Services -> Messaging -> JMS Servers and hit New
  2. Enter a name for the JMS server (e.g., “Blog JMS Server”)  JMS Server Info

     

  3. Hit “Create a new Store” (if you are not planning to persist messages, you don’t need a store).  File Store Info

     

  4. Select “File Store” as the type, and in the subsequent screen, provide a name and directory location for the store. Hit Finish
  5. Hit “Next” and select the target WebLogic server. Hit “Finish” to complete the JMS server creation. Make sure you “Activate” the changes.

The next step is to create a JMS Module. A JMS Module is a way for packaging JMS resources such as Queues and topics. Here are the steps to create a JMS module:

  1. Under Messaging, select JMS Module and hit “New”.
  2. Enter a name (e.g., Blog JMS System Module) and the rest of the fields on the page can be left empty.  File Store Info
  3. Hit “Next”, and select the WebLogic server you would like to target (ideally, this would be the same server that is hosting the JMS server you created above).
  4. On the next screen hit Finish and “Activate” changes.

Now that the entire infrastructure is in place, it’s time to create a Distributed Queue. WebLogic’s new “Distributed Queue” eliminates the need to create physical queues and mapping them to a Distributed Queue (a great improvement from WL 8.x). Here are the steps:

  1. Select the JMS Module you just created and hit “New” on the next page.
  2. Select Distributed Queue option and continue on to the next page.
  3. Provide a name (e.g., Blog JMS Queue) and a JNDI name (e.g., jndi.blogQueue).  Queue Info
  4. On the next page, select “Advance Targeting” and hit “Create a New Subdeployment”. A Subdeployment is a convenient way for grouping and targeting JMS module resources.
  5. Provide a name (e.g., Blog Subdeployment) for the Subdeployment and hit “Ok”. SubDeployment Info
  6. Select the JMS server you created above as the target and hit “Finish”.

For clients to connect and use JMS resources, a JMS Connection Factory is needed. Here are the steps for creating a Connection factory:

  1. Select the JMS Module created above and hit “New” on the next page.
  2. Select “Connection Factory on the next screen and move on to the next page.
  3. Give the Connection factory a name (e.g., Blog Connection Factory) and JNDI name (e.g., jndi.blogfactory). Hit “Next”. Factory Info
  4. Select “Advance Targeting” and on the next page, select the Subdeployment you created above (Blog Subdeployment). Wait for the page to refresh itself and hit Finish
Categories: Configuration Tags: ,