EJB3 Timer Service Example

21 November 2012 By Nithya Vasudevan 13,314 views 2 Comments
14 Flares Twitter 2 Facebook 2 Google+ 10 14 Flares ×

Environment Used

  • JDK 6 (Java SE 6)
  • EJB 3.x Stateless Session Bean
  • Eclipse Indigo IDE for Java EE Developers
  • JBoss Tools – for Eclipse Indigo
  • JBoss Application Server (AS) 7.1.0 Final

Setting up development environment:
Read this page for installing and setting up the environment for developing and deploying EJB 3.x on JBoss application server.

Project Description

  • This EJB3 Timer tutorial explains how to create EJB3 timer service in stateless session bean.
  • Client invokes a method which creates a timer and when timer expires the container invokes the timeout method.
  • This example is deployed in JBoss application server.
  • For testing this example we create a remote Java Application Client (main()) which is created in the same project as session bean.

Project Folder Structure

The figure below shows the final directory structure of this example.

Bean Business Interface

Create business interface “TimerRemote” in package “com.theopentutorials.ejb3.business” and copy the following code.

package com.theopentutorials.ejb3.business;
import javax.ejb.Remote;

@Remote
public interface TimerRemote {
	public String checkTimerStatus();
	public void startTimer();
}

Bean Implementation Class

Create the bean implementation class “TimerBean” in package “com.theopentutorials.ejb3.businesslogic” and copy the following code.

package com.theopentutorials.ejb3.businesslogic;

import java.util.Collection;
import java.util.Iterator;
import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerService;
import com.theopentutorials.ejb3.business.TimerRemote;

@Stateless
public class TimerBean implements TimerRemote {

	@Resource
	TimerService service;

	@Override
	public void startTimer() {
		Timer timer = service.createTimer(1000, 24 * 60 * 60 * 1000, null);
		System.out.println("Timers set");
	}

	@Timeout
	public void handleTimeout(Timer timer) {
		System.out.println("Handle timeout event here...");
	}

	@Override
	public String checkTimerStatus() {
		Timer timer = null;
		Collection<Timer> timers = service.getTimers();
		Iterator<Timer> iterator = timers.iterator();
		while (iterator.hasNext()) {
			timer = iterator.next();
			return ("Timer will expire after " + 
					timer.getTimeRemaining() + " milliseconds.");
		}
		return ("No timer found");
	}
}

Here, the timer expires every 24 hours.

Java Application Client

Client Utility class (JNDILookupClass) for JBoss AS 7.1

Create client utility class “JNDILookupClass” in package “com.theopentutorials.ejb3.clientutility” and copy the following code.

package com.theopentutorials.ejb3.clientutility;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class JNDILookupClass {

	private static Context initialContext;
	private static final String PKG_INTERFACES = "org.jboss.ejb.client.naming";

	public static Context getInitialContext() throws NamingException {
		if (initialContext == null) {
			Properties properties = new Properties();
			properties.put(Context.URL_PKG_PREFIXES, PKG_INTERFACES);

			initialContext = new InitialContext(properties);
		}
		return initialContext;
	}
}

Client

Create client class “EJBApplicationClient” in package “com.theopentutorials.ejb3.client” and copy the following code.

package com.theopentutorials.ejb3.client;

import javax.naming.Context;
import javax.naming.NamingException;
import com.theopentutorials.ejb3.business.TimerRemote;
import com.theopentutorials.ejb3.businesslogic.TimerBean;
import com.theopentutorials.ejb3.clientutility.JNDILookupClass;

public class EJBApplicationClient {
	public static void main(String[] args) {
		// 1. Creating bean instance through lookup
		TimerRemote bean = doLookup();
		
		// 5. Call bean methods
		//starts the timer
		bean.startTimer();
		System.out.println(bean.checkTimerStatus());
	}

	private static TimerRemote doLookup() {
		Context context = null;
		TimerRemote bean = null;
		try {
			// 2. Obtaining Context
			context = JNDILookupClass.getInitialContext();
			// 3. Generate JNDI Lookup name
			String lookupName = getLookupName();
			// 4. Lookup and cast
			bean = (TimerRemote) context.lookup(lookupName);

		} catch (NamingException e) {
			e.printStackTrace();
		}
		return bean;
	}

	private static String getLookupName() {
		/*
		 * The app name is the EAR name of the deployed EJB without .ear suffix.
		 * Since we haven't deployed the application as a .ear, the app name for
		 * us will be an empty string
		 */
		String appName = "";

		// The module name is the JAR name of the deployed EJB without the .jar
		// suffix.
		String moduleName = "EJB3TimerService";

		/*
		 * AS7 allows each deployment to have an (optional) distinct name. This
		 * can be an empty string if distinct name is not specified.
		 */
		String distinctName = "";

		// The EJB bean implementation class name
		String beanName = TimerBean.class.getSimpleName();

		// Fully qualified remote interface name
		final String interfaceName = TimerRemote.class.getName();

		// Create a look up string name
		String name = "ejb:" + appName + "/" + moduleName + "/" + distinctName
				+ "/" + beanName + "!" + interfaceName;

		return name;
	}
}

We use JBoss AS 7.1 and EJB3.1 look up naming convention.

If the application server uses EJB3 look up naming convention, (JBoss AS 5 or 6) then the following lookup name should be used.
“TimerBean/remote”

JBoss console output

[stdout] Timers set
[stdout] Handle timeout event here…

For a step by step tutorial on creating and deploying EJB project in
JBoss AS 7 -> refer this page.
JBoss AS 6 -> refer this page.
JBoss AS 5 -> refer this page.

Tags: , , , ,

  • haris

    I got following exception after the time out, please advice where the problem is ?

    19:21:50,481 INFO [org.jboss.as] (MSC service thread 1-2) JBAS015874: JBoss AS 7.1.0.Final “Thunder” started in 8277ms – Started 220 of 294 services (72 services are passive or on-demand)
    19:21:50,543 INFO [org.jboss.as.server] (DeploymentScanner-threads – 2) JBAS018559: Deployed “HelloWorldSessionBean.jar”
    19:22:16,260 INFO [stdout] (EJB default – 1) Timers set

    19:22:26,323 ERROR [org.jboss.as.ejb3] (EJB default – 2) JBAS014120: Error invoking timeout for timer: [id=d06a7692-72fd-4469-a171-20d6f25e3d19 timedObjectId=HelloWorldSessionBean.HelloWorldSessionBean.TimerBean auto-timer?:false persistent?:true timerService=org.jboss.as.ejb3.timerservice.TimerServiceImpl@76e15aed initialExpiration=Mon Sep 30 19:22:26 SGT 2013 intervalDuration(in milli sec)=86400000 nextExpiration=Tue Oct 01 19:22:26 SGT 2013 timerState=IN_TIMEOUT: java.lang.RuntimeException: JBAS014481: Cannot invoke timeout method because method null is not a timeout method
    at org.jboss.as.ejb3.timerservice.TimedObjectInvokerImpl.callTimeout(TimedObjectInvokerImpl.java:81) [jboss-as-ejb3-7.1.0.Final.jar:7.1.0.Final]
    at org.jboss.as.ejb3.timerservice.TimedObjectInvokerImpl.callTimeout(TimedObjectInvokerImpl.java:111) [jboss-as-ejb3-7.1.0.Final.jar:7.1.0.Final]
    at org.jboss.as.ejb3.timerservice.task.TimerTask.callTimeout(TimerTask.java:157) [jboss-as-ejb3-7.1.0.Final.jar:7.1.0.Final]
    at org.jboss.as.ejb3.timerservice.task.TimerTask.run(TimerTask.java:132) [jboss-as-ejb3-7.1.0.Final.jar:7.1.0.Final]
    at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) [rt.jar:1.7.0_25]
    at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source) [rt.jar:1.7.0_25]
    at java.util.concurrent.FutureTask.run(Unknown Source) [rt.jar:1.7.0_25]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [rt.jar:1.7.0_25]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [rt.jar:1.7.0_25]
    at java.lang.Thread.run(Unknown Source) [rt.jar:1.7.0_25]
    at org.jboss.threads.JBossThread.run(JBossThread.java:122) [jboss-threads-2.0.0.GA.jar:2.0.0.GA]

    19:22:26,338 INFO [org.jboss.as.ejb3] (EJB default – 2) JBAS014121: Timer: [id=d06a7692-72fd-4469-a171-20d6f25e3d19 timedObjectId=HelloWorldSessionBean.HelloWorldSessionBean.TimerBean auto-timer?:false persistent?:true timerService=org.jboss.as.ejb3.timerservice.TimerServiceImpl@76e15aed initialExpiration=Mon Sep 30 19:22:26 SGT 2013 intervalDuration(in milli sec)=86400000 nextExpiration=Tue Oct 01 19:22:26 SGT 2013 timerState=IN_TIMEOUT will be retried
    19:22:26,338 INFO [org.jboss.as.ejb3] (EJB default – 2) JBAS014123: Retrying timeout for timer: [id=d06a7692-72fd-4469-a171-20d6f25e3d19 timedObjectId=HelloWorldSessionBean.HelloWorldSessionBean.TimerBean auto-timer?:false persistent?:true timerService=org.jboss.as.ejb3.timerservice.TimerServiceImpl@76e15aed initialExpiration=Mon Sep 30 19:22:26 SGT 2013 intervalDuration(in milli sec)=86400000 nextExpiration=Tue Oct 01 19:22:26 SGT 2013 timerState=IN_TIMEOUT
    19:22:26,402 ERROR [org.jboss.as.ejb3] (EJB default – 2) JBAS014122: Error during retyring timeout for timer: [id=d06a7692-72fd-4469-a171-20d6f25e3d19 timedObjectId=HelloWorldSessionBean.HelloWorldSessionBean.TimerBean auto-timer?:false persistent?:true timerService=org.jboss.as.ejb3.timerservice.TimerServiceImpl@76e15aed initialExpiration=Mon Sep 30 19:22:26 SGT 2013 intervalDuration(in milli sec)=86400000 nextExpiration=Tue Oct 01 19:22:26 SGT 2013 timerState=RETRY_TIMEOUT: java.lang.RuntimeException: JBAS014481: Cannot invoke timeout method because method null is not a timeout method
    at org.jboss.as.ejb3.timerservice.TimedObjectInvokerImpl.callTimeout(TimedObjectInvokerImpl.java:81) [jboss-as-ejb3-7.1.0.Final.jar:7.1.0.Final]
    at org.jboss.as.ejb3.timerservice.TimedObjectInvokerImpl.callTimeout(TimedObjectInvokerImpl.java:111) [jboss-as-ejb3-7.1.0.Final.jar:7.1.0.Final]
    at org.jboss.as.ejb3.timerservice.task.TimerTask.callTimeout(TimerTask.java:157) [jboss-as-ejb3-7.1.0.Final.jar:7.1.0.Final]
    at org.jboss.as.ejb3.timerservice.task.TimerTask.run(TimerTask.java:132) [jboss-as-ejb3-7.1.0.Final.jar:7.1.0.Final]
    at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) [rt.jar:1.7.0_25]
    at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source) [rt.jar:1.7.0_25]
    at java.util.concurrent.FutureTask.run(Unknown Source) [rt.jar:1.7.0_25]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [rt.jar:1.7.0_25]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [rt.jar:1.7.0_25]
    at java.lang.Thread.run(Unknown Source) [rt.jar:1.7.0_25]
    at org.jboss.threads.JBossThread.run(JBossThread.java:122) [jboss-threads-2.0.0.GA.jar:2.0.0.GA]

  • haris

    Hi All,

    I found the issue.
    problem was I missed to add @Timeout method

    Thanks.