5 minutes with – EjbTimer

Have you ever had to scheduled some activities on web application? In this articles I’d like to show you how get this aim using JavaEE technology with a little example. I will  describe the use of programmatic and not programmatic timer in the same workflow process.

I’ve already written something about this issue on one of my previous post (https://techannotation.wordpress.com/2012/07/17/spring-execution-scheduled-task) using Spring tecnology. Now, I’m using JavaEE 6 and Glassfish 3.1.2. In the following example you can see a persistent and not persistent timer. For practical reason I kept the default derby database installed on Glassfish.

In my example I created a order process with the following workflow:

EjbTimer

Briefly, a random order is generated in the first step (every 20 seconds). Every minute the order is processed by “Process Order” step. This process generates a timer per order in list. The order is shipped after three minutes next the insert date.

Easy, doesn’t it?

Let’s see some code. The first are the timers declarations. I used an ejb-jar file instead of using annotations. That’s because I think is more flexible changing the schedulated time in Xml than recompile the jar.

<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar version="3.1" xmlns="<a href="http://java.sun.com/xml/ns/javaee">http://java.sun.com/xml/ns/javaee</a>"
 xmlns:xsi="<a href="http://www.w3.org/2001/XMLSchema-instance">http://www.w3.org/2001/XMLSchema-instance</a>"
 xsi:schemaLocation="<a href="http://java.sun.com/xml/ns/javaee">http://java.sun.com/xml/ns/javaee</a> <a href="http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd">http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd</a>">
 <display-name>OrderEjbTimer</display-name></pre>
 <enterprise-beans>
  <session>
   <ejb-name>TimerOrderPush</ejb-name>
   <ejb-class>it.orderejbtimer.bean.OrderTimer</ejb-class>
   <session-type>Stateless</session-type>
   <timer>
    <schedule>
     <second>*/20</second>
     <minute>*</minute>
     <hour>*</hour>
     <month>*</month>
     <year>*</year>
    </schedule>
    <timeout-method>
     <method-name>pushOrder</method-name>
     <method-params>
      <method-param>javax.ejb.Timer</method-param>
     </method-params>
    </timeout-method>
    <persistent>false</persistent>
   </timer>
   <timer>
    <schedule>
     <second>10</second>
     <minute>*/1</minute>
     <hour>*</hour>
     <month>*</month>
     <year>*</year>
    </schedule>
    <timeout-method>
     <method-name>processOrder</method-name>
     <method-params>
      <method-param>javax.ejb.Timer</method-param>
     </method-params>
    </timeout-method>
    <persistent>false</persistent>
   </timer>
  </session>
  <session>
   <ejb-name>OrderWareHouse</ejb-name>
   <local-bean />
   <ejb-class>it.orderejbtimer.bean.OrderWareHouse</ejb-class>
   <session-type>Singleton</session-type>
  </session>
 </enterprise-beans>

</ejb-jar>

In this file I’ve declared two Ejb. The first is the Ejb which implements the workflow steps while the second is the list of the orders stored.

Take a look at timer definition. In this node I’ve declared the schedule time, the method with the params that will be called when the trigger start and whether the timer is persistent or not. More references are available at the oracle reference page http://docs.oracle.com/javaee/6/tutorial/doc/bnboy.html.

You can use a @Timeout annotation into the code to get the same result. The code.

package it.orderejbtimer.bean;

import java.util.Calendar;
import java.util.Date;
import java.util.Random;

import javax.annotation.Resource;
import javax.ejb.EJB;

import javax.ejb.Singleton;

import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerConfig;
import javax.ejb.TimerService;

import java.util.logging.Logger;

@Singleton
public class OrderTimer {

 @EJB()
 protected OrderWareHouse orderWareHouse;

 @Resource
 protected TimerService timerService;

 private Logger logger = Logger.getLogger("OrderProcess");

 public void pushOrder(Timer timer) {
  orderWareHouse.getWareHouse().add(getRandomOrder());
 }
 public void processOrder(Timer timer) {
  for (Order order : orderWareHouse.getWareHouse()) {
   if (order.isProcessed() == false) {
    timerService.createSingleActionTimer(order.getShippingTime(),
      new TimerConfig(order, true));
    logger.info("Process order: " + order.getCode());
    order.setProcessed(true);
   }
  }
 }

 protected Order getRandomOrder() {
  Random random = new Random();
  Calendar cal = Calendar.getInstance();
  cal.setTime(new Date());
  cal.add(Calendar.MINUTE, 3);

  Order order = new Order();
  order.setCode("AZ" + random.nextInt(100));
  order.setPrice(random.nextInt(100) / 10);
  order.setQuantity(random.nextInt(10));
  order.setShippingTime(cal.getTime());

  logger.info("Inserted Order code: " + order.getCode() + " Shipping at "
    + order.getShippingTime());

  return order;
 }

 @Timeout
 public void shipOrder(Timer timer) {
  Order order = (Order) timer.getInfo();
  logger.info("Shipping order: " + order.getCode());
 }
}

Take a look at @Timeout annotation. The method with that annotation will be called when the trigger created inside the processOrder method starts. The method receives a serializable object Order and starts at order shipping time.

package it.orderejbtimer.bean;

import java.io.Serializable;
import java.util.Date;

public class Order implements Serializable{
 private static final long serialVersionUID = 1L;
 private String code;
 private float price;
 private int quantity;
 private Date shippingTime;
 private boolean isProcessed = false;
 
 public String getCode() {
  return code;
 }
 public void setCode(String code) {
  this.code = code;
 }
 public float getPrice() {
  return price;
 }
 public void setPrice(float price) {
  this.price = price;
 }
 public int getQuantity() {
  return quantity;
 }
 public void setQuantity(int quantity) {
  this.quantity = quantity;
 }
 public Date getShippingTime() {
  return shippingTime;
 }
 public void setShippingTime(Date shippingTime) {
  this.shippingTime = shippingTime;
 }
 public boolean isProcessed() {
  return isProcessed;
 }
 public void setProcessed(boolean isProcessed) {
  this.isProcessed = isProcessed;
 }

}

The OrderWareHouse class is injected as Ejb.

package it.orderejbtimer.bean;

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

public class OrderWareHouse{
 private List<Order> wareHouse = new ArrayList<Order>();

 public List<Order> getWareHouse() {
  return wareHouse;
 }
}

Now it’s time to deploy the EAR package on Glassfish server. After having done that, take a look at Glassfish administration console. Under the tree menu Resources->JDBC->JDBC Connection Pools you can see “__TimerPool” where is declared the connection string ${com.sun.aas.instanceRoot}/lib/databases/ejbtimer.

That’s the database where the timer are persisted. The table is the following

CREATE TABLE EJB__TIMER__TBL (
TIMERID VARCHAR(255) NOT NULL,
APPLICATIONID BIGINT,
BLOB BLOB(2147483647),
CONTAINERID BIGINT,
CREATIONTIMERAW BIGINT,
INITIALEXPIRATIONRAW BIGINT,
INTERVALDURATION BIGINT,
LASTEXPIRATIONRAW BIGINT,
OWNERID VARCHAR(255),
PKHASHCODE INTEGER,
SCHEDULE VARCHAR(255),
STATE INTEGER<br /> );

In the columns CREATIONTIMERAW and INITIALEXPIRATIONRAW you can see the creation date and when the trigger, in my example only once time, will be started. I used the this function under mySql to get the timestamp.

SELECT FROM_UNIXTIME([CREATIONTIMERAW]/1000);

All right. That’s all, after running the application you’ll see the console with the processes running

[#|2013-02-12T10:23:20.013+0100|INFO|glassfish3.1.2|OrderProcess|_ThreadID=120;_ThreadName=Thread-2;|Inserted Order code: AZ59 Shipping at Tue Feb 12 10:26:20 CET 2013|#]

[#|2013-02-12T10:24:10.010+0100|INFO|glassfish3.1.2|OrderProcess|_ThreadID=123;_ThreadName=Thread-2;|Process order: AZ59|#]

[#|2013-02-12T10:26:20.017+0100|INFO|glassfish3.1.2|OrderProcess|_ThreadID=118;_ThreadName=Thread-2;|Shipping order: AZ59|#]

I hope you can enjoy and give you some solution for your next project.

Advertisements

2 thoughts on “5 minutes with – EjbTimer

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