4/01/2010

EJB 3.1 Timer Simple Example

This is a simple webapp that polls a web site to check if a product is available. It uses a stateless session bean and calendar-based timer.

package test;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URL;
import java.util.logging.Logger;

import javax.ejb.Schedule;
import javax.ejb.Stateless;

@Stateless
public class InventoryCheckBean {
private static final String PRODUCT_URL = "http://www.amazon.com/dp/B002BSA298/";
private static final String IN_STOCK = "In Stock";

@SuppressWarnings("unused")
@Schedule(dayOfWeek = "0-5", hour = "0/2", minute = "0/20", timezone = "America/Los_Angeles")
private void checkInventory() {
BufferedReader br = null;
try {
String line = null;
URL url = new URI(PRODUCT_URL).toURL();
br = new BufferedReader(new InputStreamReader(url.openStream()));
while ((line = br.readLine()) != null) {
if(line.indexOf(IN_STOCK) >= 0) {
//email notify
Logger.getLogger("").info(line);
break;
}
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if(br != null) {
try {
br.close();
} catch (IOException e) { //ignore
}
}
}
}
}
After compiling, simply package test/InventoryCheckBean.class into a WAR file under WEB-INF/classes. No other files are needed.
/tmp > jar tf $owd/inventory.war
META-INF/
META-INF/MANIFEST.MF
WEB-INF/
WEB-INF/classes/
WEB-INF/classes/test/
WEB-INF/classes/test/InventoryCheckBean.class
Deploy this war to any application server that is Java EE 6 compliant. The timer is activated upon successful deployment, and starts to check the specified site at the specified intervals. This is so-called automatic timer.

In the server log file, you will notice these logs:
[#|2010-04-01T10:50:01.644-0400|INFO|glassfishv3.0||_ThreadID=26;_ThreadName=Thread-1;|<span class="availGreen">In Stock.</span><br/ > Ships from and sold by <b>Amazon.com</b>. Gift-wrap available.|#]
Note:
(1) This WAR file contains only an EJB bean class.

(2) There is no business method in this EJB; only 1 private timer method, which is only invoked by the container after deployment. So @SuppressWarnings is used to mute any warnings that this method is never used.

(3) No client action is needed. Right after deployment, the timer is activated and starts the processing specified in the timer method.

(4) timezone is optionals and defaults to that of the hosting machine.

(5) This timer goes off every 20 minutes of every other hour starting from 0 o'clock from Sunday to Friday, and the time is based on America/Los_Angeles timezone.

Update on 3/4/2011, I deployed the same inventory.war to JBoss AS 6.0, by copying it to $JBOSS_HOME/server/default/deploy, it also worked. No need to change anything.

14 comments:

Miles said...

Wouldn't dayOfWeek = "0-5" produce a Sunday through Friday, not Monday through Friday? Standard cron ranges are from 0-6 starting on Sunday, not 0-7. Off by one error?

javahowto said...

Yes, you are right. "0-5" means Sun - Fri. Corrected in the post. Thanks.

Anonymous said...

Hello,
I am using WebSphere 7 to deploy this timer and it is not starting the timer automatically.
Do you have any idea why?
Is it just supported to Glassfish?

javahowto said...

This example is portable and should work in any appserver that is JavaEE 6 compatible. At least the target appserver should support EJB 3.1 and JavaEE 6 Web Profile. It's possible your appserer does not support it yet.

Tommy said...

It wouldn't work on WebSphere 7 since it isn't Java EE 6 compatible. As of today, Glassfish is the only compatible AS.

Anonymous said...

Is it possible to inject a "JMS" resouce in a timer? I'm not able to although the same annotations do work in a SLSB implementing a WS.

javahowto said...

You inject resources including jms resources into any Java EE components (certain standard types of classes in Java EE programming model). There is no such component as timer. EJB timers all run in EJB beans. Of course you can inject any supported resources into ejb bean class.

Anonymous said...

I am using Studio Edition Version 11.1.1.6.0 of Jdev .. . Could you let me know if schedule EJB is supported by my JDEV, as curresntly scheduling is not working

javahowto said...

You need to deploy your application to an application server that implements Java EE 6 or later, like GlassFish 3.x, 4, or JBoss AS 7.x or JBoss EAP 6.x. Not sure about JDev (JDeveloper?) but it sounds like an IDE. If so make sure there is an application server integrated to the IDE.

Anonymous said...

Thanks for your response.
Yes your are right its Jdeveloper.
And later on I found that IDE integrated to JDEV version : 11.1.1.6.0 uses weblogic 10.3 version.
Though I have weblogic server 10.3.6 ...but I am not sure how can I check my oracle weblogic server(10.3.6) supports JavaEE 6 or not.

javahowto said...

WebLogic Server 11g Release 1 (10.3.6) is Java EE 5 compatible.

http://docs.oracle.com/cd/E23943_01/web.1111/e14529/compatibility.htm

So EJB schedule timer service is not available in your version of wls.

Anonymous said...

Hi, I am getting below exception, please advice me.

com.ibm.ws.extensionhelper.exception.UnableToInitializeException: javax.naming.NoInitialContextException: We could not find a provider for the InitialContextFactory org.jnp.interfaces.NamingContextFactory

Marcelo said...
This comment has been removed by the author.
Marcelo said...

Setting up a scheduler (EJB Timer) in WebSphere 8 (>WebSphere 7) is straight forward:
http://www.devops-insight.com/2014/10/how-to-use-websphere-ejb-timer.html