Spring execution scheduled task

The Spring Framework  allows you to configure “scheduled task” in different ways. In this article I’d like to show you a scheduled task using Quartz Scheduler inside Spring.

That is quite easy to configure and powerful in these situations when you need to have some scheduled activities.

To be fair, I want to draw your attention at this big difference between what is a web server and, on other hand, an Esb (Enterprise Serial Bus).

As you might have seen in this blog,I’m using Mule Esb in my projects where I need to orchestrator activities or complicated business rule and back office operations. I think that a web server should accept web requests and let its thread free for the requests rather than hold them busy for other operation (like scheduled activities).

Maybe that’s only my personal opinion. Anyway I’d like to describe how it works in web application using Spring so you can decide, once you’ve got it, when use it.

Let me describe the example using this use-case.

An user calls a Mvc spring application to insert a new order into the cart. Once you get  2 orders (this parameter will be configurable) a scheduled process starts shipping the order and clear the cart.

The first entity is the Order bean.


package it.springscheduledtask.bean;

public class Order {

 private String orderId;
 private String productCode;
 private int quantity;

 public Order(String orderId, String productCode, int quantity) {
  this.orderId = orderId;
  this.productCode = productCode;
  this.quantity = quantity;
 }

 public String getOrderId() {
  return orderId;
 }

 public void setOrderId(String orderId) {
  this.orderId = orderId;
 }

 public String getProductCode() {
  return productCode;
 }

 public void setProductCode(String productCode) {
  this.productCode = productCode;
 }

 public int getQuantity() {
  return quantity;
 }

 public void setQuantity(int quantity) {
  this.quantity = quantity;
 }

}

The other entity is the Cart bean.


package it.springscheduledtask.bean;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class Cart {

 private List<Order> orders = new ArrayList<Order>();
 private Date shippingDate;

 public List<Order> getOrders() {
  return orders;
 }

 public void add(Order order) {
  orders.add(order);
 }

 public void shipOrder()
 {
  setShippingDate(new Date());
  orders.clear();
 }

 public Date getShippingDate() {
  return shippingDate;
 }

 public void setShippingDate(Date shippingDate) {
  this.shippingDate = shippingDate;
 }
}

Now the controller class used to insert a new order into the cart.


package it.springscheduledtask.controller;

import it.springscheduledtask.bean.Order;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class OrderController {

 @Autowired
 private it.springscheduledtask.bean.Cart orderCart;
 
 @RequestMapping(value="/order/{orderId}/{productCode}/{quantity}")
 public String getOrder(ModelMap model,
       @PathVariable String orderId,
       @PathVariable String productCode,
       @PathVariable int quantity) {
  
  orderCart.add(new Order(orderId, productCode, quantity));
  
  model.addAttribute("detail", orderCart);
  return "order";

 }
}

Now the most important step of this project. I’m speaking about the spring configuration file where I configured the quartz job. I used a database connection for supporting cluster configuration. More information are available on http://quartz-scheduler.org.


<bean id="orderCart" class="it.springscheduledtask.bean.Cart" />

<bean name="orderShipping">
 <property name="jobClass" value="it.springscheduledtask.quartz.OrderShipping" />  
 <property name="jobDataAsMap">
  <map>
   <entry key="cartLength" value="2" />
   <entry key="orderCartToShip" value-ref="orderCart" />
  </map>
 </property>
</bean>

<bean id="cronTrigger">
 <property name="jobDetail" ref="orderShipping" />
 <property name="cronExpression" value="0/10 * * * * ? *" />
</bean>

<bean>
 <property name="triggers">
  <list>
   <ref bean="cronTrigger" />
  </list>
 </property>
 <property name="quartzProperties">
  <value>classpath:quartz.properties</value>
 </property>
</bean>

The job run every 10 seconds and check how many items are in the cart. If the items’ number are more of “cartLenght” parameter the order will be sent.


package it.springscheduledtask.quartz;

import it.springscheduledtask.bean.Cart;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;

public class OrderShipping extends QuartzJobBean {

 private Cart orderCartToShip;

 private int cartLength;

 @Override
 protected void executeInternal(JobExecutionContext job)
   throws JobExecutionException {

  // Check the number of items in cart
  if (orderCartToShip.getOrders().size() > cartLength)
   orderCartToShip.shipOrder();
 }

 public int getCartLength() {
  return cartLength;
 }

 public void setCartLength(int cartLength) {
  this.cartLength = cartLength;
 }

 public Cart getOrderCartToShip() {
  return orderCartToShip;
 }

 public void setOrderCartToShip(Cart orderCartToShip) {
  this.orderCartToShip = orderCartToShip;
 }

}

The quartz.properties file hold the database information to manage cluster information with difference web server. You can find a very good documentation about it using internet search engine.


org.quartz.scheduler.instanceName = MyClusteredScheduler
org.quartz.scheduler.instanceId = AUTO
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 15
org.quartz.threadPool.threadPriority = 5
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.useProperties = false
org.quartz.jobStore.dataSource = myDSRec
org.quartz.jobStore.tablePrefix = CLU_
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 20000
org.quartz.dataSource.myDSRec.driver = org.gjt.mm.mysql.Driver
org.quartz.dataSource.myDSRec.URL = jdbc:mysql://clusterserver:3306/Quartz

org.quartz.dataSource.myDSRec.user = quartz
org.quartz.dataSource.myDSRec.password = quartz
org.quartz.dataSource.myDSRec.maxConnections = 5
org.quartz.dataSource.myDSRec.validationQuery = select 0 from dual

The result will be the screen below. After 3 orders the cart has been emptied and the last order shipping date will be shown at the top of the page.

At official Web site (http://static.springsource.org/spring/docs/3.0.5.RELEASE/reference/scheduling.html) you can find out other different ways to configure Scheduled task using spring. Take a look at it.

Again, probably I’d used a different technology for this type of operation … but it’s only my idea! Make your test and make your choice to use it or not.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s