I need to create an interval Timer that is set to run once a week automatically. I don't want it to start based on user input, but I want it to be created when the application is deployed to the server. Every example that I have seen has another class starting the timer. I don't want to use a message driven bean to create the timer because the audit should just query a database for a given time period and is not based off of actions which send messages.
I have included an example of a Timer. In the example below, the timer should fire every 10 minutes. As a test I want the timer to fire every 10 minutes so I can test the timer.
#Stateless
public class TimerTest implements
TimerTestLocal, TimerTestRemote{
#Resource
private TimerService timerService;
private Logger log = Logger.getLogger(TimerTest.class);
private long interval = 1000 * 60 * 10;
private static String TIMER_NAME = "AuditTimer";
public void scheduleTimer() throws NamingException {
// TODO Auto-generated method stub
Calendar cal = Calendar.getInstance();
//cal.set(Calendar.HOUR_OF_DAY, 23);//run at 11pm
//cal.set(Calendar.MINUTE, 00);
//cal.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY);
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy hh:mm");
log.debug("schedule for: " + sdf.format(cal.getTime()));
timerService.createTimer(cal.getTime(), interval, TIMER_NAME);
}
public void cancelTimer() {
for(Object obj : timerService.getTimers())
{
Timer timer = (Timer)obj;
if(timer.getInfo().equals(TIMER_NAME))
timer.cancel();
}
}
#Timeout
public void timerEvent(Timer timer) {
log.debug("timer fired");
}
}
So is there any way that I can start this timer when the application is deployed? I don't think it's a good idea to put the creation of the Timer in a #PostConstruct method because of class loaders on in the server.
If your project can use jee6 / ejb3.1 there is a much better solution to this problem.
http://docs.oracle.com/javaee/6/tutorial/doc/bnboy.html
#javax.ejb.Schedule(minute="*/10", hour="*")
public void automaticTimeout() {
logger.info("Automatic timeout occured");
}
By using the new #Schedule annotation you have extensive control about when and how often a timeout method will be called. The big upside: you no longer have to start the timer "from outside".
Oracle writes:
Automatic timers are created by the EJB container when an enterprise
bean that contains methods annotated with the #Schedule or #Schedules
annotations is deployed. An enterprise bean can have multiple
automatic timeout methods, unlike a programmatic timer, which allows
only one method annotated with the #Timeout annotation in the
enterprise bean class.
The way that I've done timers in the past is to create a context listener in the web.xml to configure the timer.
That way you can ensure that it is started with the container, and shut down cleanly when the app is taken down.
I don't know whether using the contextListener to start the timer can work. From this article, how to use EJb 3 timer in a weblogic 10 cluster, it looks like you may run into some problems in weblogic 10.3.2.
Related
I have ear application consisting of war - a servlet and ejb.
I needed the ejb solely for the #javax.ejb.Schedule . Which should have ran every minute and all it would do is fire a CDI event that is going to be intercepted by war app.
It turns out this doesn't work, as, evidently, CDI events only connect when classes share the same class loader. EJB and WAR being different packages - different class loaders.
So i came up with this pattern (in it's most basic form):
#javax.enterprise.context.ApplicationScoped
public class TimerMockUp {
#Resource(mappedName="java:jboss/ee/concurrency/executor/cacheService") Executor ex;
#Inject Event<SomeEvent> evt;
#PostConstruct
private void initTimer(){
ex.execute(()->{
try{
while(true){
evt.fire(new SomeEvent());
Thread.sleep(4000);
}
} catch (Exception ex){
}
});
}
What is your take on this? Do you think this would be reliable in the long turn? What other options are there to achieve the same thing?
Not sure what your requirement is for having injected events, but the standard way for running an incremental timer would be to use an EJB timer with the #Schedule annotation.
For example:
#Singleton
#Startup
public class TimerBean {
#Schedule(hour = "*", minute = "*", second = "*/5", persistent = false)
public void doEvery5Sec() {
// do something...
}
}
I am following the Using the Timer Service tutorial to build a simple scheduled execution. Trying the automatic approach and using WildFly 8.1.0 Final for it.
Session Bean
#Singleton
#Startup
public class HelloJob {
private static final Logger logger = Logger.getLogger(HelloJob.class);
public HelloJob() {
logger.error(">>> Hello Job Created.");
}
#Schedule(second="*")
public void sayHello() {
logger.error(">>> Server Hello!");
}
}
On deploy the class is properly instantiated printing the >>> Hello Job Created. message, but the method sayHello() is never called.
According to the tutorial the #Schedule(second="*") means that it should execute every second.
Setting an attribute to an asterisk symbol (*) represents all
allowable values for the attribute.
Also only stateful session beans are not allowed for timers, and I am using a singleton, which is also used in the example.
The timer service of the enterprise bean container enables you to
schedule timed notifications for all types of enterprise beans except
for stateful session beans.
Use #Schedule(second="*", minute="*", hour="*").
the default values for hour and minute are "0" which can be quite irritating and effectively forces you to set these.
I currently have an EJB that has an # schedule that runs every 5 minutes, but I only run after the ejb initialized.
the question is whether you can make the timer starts running after deployment and do not wait until there is an invocation to the EJB for starting.
Here is my code:
#Remote(ServiceRemote.class)
#Stateless(mappedName = "ejb/ServiceEJBSL")
public class ServiceBean implements ServiceRemote {
#Schedule(second="*", minute="*/5", hour="*", dayOfWeek="0-6")
public void autmaticTimer() throws Exception, RemoteException{
System.out.println("do something");
}
}
I did this in glasfish server but it seems doesnt work the same way.
Thanks in advance.
You'll need GlassFish v3.+ because this feature was added in EJB 3.1
Automatic timers are created by the EJB container when an enterprise
bean that contains methods annotated with the #Schedule or
#Schedules annotations is deployed.
#Schedule(minute="*/5", hour="*")
public void automaticTimer() throws Exception, RemoteException{
System.out.println("do something");
}
Addition
Try to add
#Schedule(minute="*/5", hour="*", persistent=false)
Because persistent timers are not re-created if already existing when keepstate is set to true.
See
Automatic Timers
This question already has answers here:
How to run a background task in a servlet based web application?
(5 answers)
Closed 7 years ago.
I am using JSP/Servlet on Apache Tomcat. I have to run a method every 10 minutes. How can I achieve this?
As you're on Tomcat, which is just a barebones servletcontainer, you can't use EJB's #Schedule for this which is recommended by Java EE specification. Your best bet is then the ScheduledExecutorService from Java 1.5's java.util.concurrent package. You can trigger this with help of a ServletContextListener like follows:
#WebListener
public class BackgroundJobManager implements ServletContextListener {
private ScheduledExecutorService scheduler;
#Override
public void contextInitialized(ServletContextEvent event) {
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new SomeTask(), 0, 10, TimeUnit.MINUTES);
}
#Override
public void contextDestroyed(ServletContextEvent event) {
scheduler.shutdownNow();
}
}
where the SomeTask class look like this:
public class SomeTask implements Runnable {
#Override
public void run() {
// Do your job here.
}
}
If you were actually using a real Java EE container with EJB support and all on em (like Glassfish, JBoss AS, TomEE, etc), then you could use a #Singleton EJB with a #Schedule method. This way the container will worry itself about pooling and destroying threads. All you need is then the following EJB:
#Singleton
public class SomeTask {
#Schedule(hour="*", minute="*/10", second="0", persistent=false)
public void run() {
// Do your job here.
}
}
Note that this way you can continue transparently using container managed transactions the usual way (#PersistenceContext and so on), which isn't possible with ScheduledExecutorService — you'd have to manually obtain the entity manager and manually start/commit/end transaction, but you would by default already not have another option on a barebones servletcontainer like Tomcat anyway.
Note that you should never use a Timer in a supposedly "lifetime long" running Java EE web application. It has the following major problems which makes it unsuitable for use in Java EE (quoted from Java Concurrency in Practice):
Timer is sensitive to changes in the system clock, ScheduledExecutorService isn't.
Timer has only one execution thread, so long-running task can delay other tasks. ScheduledExecutorService can be configured with any number of threads.
Any runtime exceptions thrown in a TimerTask kill that one thread, thus making Timer dead, i.e. scheduled tasks will not run anymore (until you restart the server). ScheduledThreadExecutor not only catches runtime exceptions, but it lets you handle them if you want. Task which threw exception will be canceled, but other tasks will continue to run.
Read on ScheduledExecutorService it has to be initiated by a ServletContextListener
public class MyContext implements ServletContextListener
{
private ScheduledExecutorService sched;
#Override
public void contextInitialized(ServletContextEvent event)
{
sched = Executors.newSingleThreadScheduledExecutor();
sched.scheduleAtFixedRate(new MyTask(), 0, 10, TimeUnit.MINUTES);
}
#Override
public void contextDestroyed(ServletContextEvent event)
{
sched.shutdownNow();
}
}
Also, you may try using the Java Timer from a ServletContextListener but it's not recommended in a Java EE container since it takes away control of the Thread resources from the container. (the first option with ScheduledExecutorService is the way to go).
Timer timer = new Timer("MyTimer");
MyTask t = new MyTask();
//Second Parameter is the specified the Starting Time for your timer in
//MilliSeconds or Date
//Third Parameter is the specified the Period between consecutive
//calling for the method.
timer.schedule(t, 0, 1000*60*10);
And MyTask that implements TimerTask is a class that implements the Runnable interface so you have to override the run method with your code:
class MyTask extends TimerTask
{
public void run()
{
// your code here
}
}
I'm doing my graduation project, and have run into a dilemma here.
I need to make an application that generates PDFs and emails them to people on a schedule defined by data in the database.
I'm working for a company with this project, and we already have a GlassFish application server that we use. It would be best if the entire solution is delivered in one package, as it is now.
Client with webstart
Web Application etc. is all in one package
My new service needs to run on a separate thread, generate reports and send them out on emails. From what I can read on the web, running your own threads in an application server as GlassFish is highly discouraged, so it sounds like I need to make my own separate application.
Can this really be? What are your comments, and what are the best practices for this?
#Schedule
If you are using Ejb 3.1 (glassfish 3.x), you may use the #Schedule annotation to have the container invoke a method in a specified interval or at a given calendar time. Allowing you to avoid handling threads in your own code
Read about ejb 3.1 timer
#Stateless
public class LabbBean {
#EJB
WorkerEjb workerEjb;
#Schedule(second="*/5", minute="*",hour="*", persistent=false)
public void myMethod() {
for (all jobs found in db){
workerEjb.workerMethod(job);
}
}
}
#Stateless
public class WorkerEjb {
#Asynchronous
public void workerMethod(job) {
//Send emails
}
}
If you wanted to do the work in separate threads, the #Schedule annotated method could call a worker-ejb with the worker-method annotated as #Asynchronous
#Timeout
I just realised you wanted the schedule to be initiated from the database. An option the would be to initiate a bunch of timers programmatically using a #Singleton ejb with #Startup annotation. The timeout annotated method would be called in separate threads if some timers run out at the same time.
#Singleton
#Startup
public class LabbBean {
#Resource
protected TimerService timerService;
#PostConstruct
public void init() {
//Init your timers from the data in the database here
for (all your timers) {
TimerConfig config = new TimerConfig();
config.setInfo("timer1");
config.setPersistent(false);
ScheduleExpression schedule = new ScheduleExpression();
schedule.dayOfMonth(10);
schedule.minute(2);
timerService.createCalendarTimer(schedule, config);
}
}
//method called when timeout occurs
#Timeout
public void timeoutHandler(Timer timer) {
String name = timer.getInfo().toString();
System.out.println("Timer name=" + name);
}
}