1

I'm trying to implement a system in server that will do some updates on database on a ragular basis.

Here: Spawning threads in a JSF managed bean for scheduled tasks using a timer and in some other similar questions, I saw that BalusC strongly recommended to use Stateless Beans, if not possible SchedulerExecuterService rather than Timer.

Here is my situation. I need a JSF page in which I can configure the schedule interval. i.e. I can change its rule from run once in every 5 min to run once in 10 min

First, I tried to use @Schedule annotation and it was great. However, I couldn't find a way to change interval with that. First question, is it possible to change it dynamically like I told above?

I am currently using SchedulerExecutorService which is called from @PostConstruct of a Stateless Bean. Second question, is the Timer BalusC strongly recommended not to use is the TimerService of EJB?

Third Question, I liked the properties of timerService which is: using scheduleExpression and timerConfig. Are there any similar things for ScheduledExecutorService?

Additional Question: Am I on right track? Can the thing that I am trying to pull be done in a better way?

Community
  • 1
  • 1
xtrapolate
  • 33
  • 1
  • 5

1 Answers1

1

I think @Schedule is used only for fixed cron-like timers, where the EJB container deploys a timer at EJB startup. You obviously need more dynamic scheduling connected with a JSF page.

If you are running on a full Java EE 6 profile, why not use the TimerService with a Stateless Session EJB like this:

@Stateless
public class JobSchedulerBean {
    @Resource
    private TimerService timerService;

    // @PostConstruct
    public void initTimer() {
        // set initial timer
        ScheduleExpression sch = new ScheduleExpression();
        // set cron expression into sch
        timerService.createCalendarTimer(sch, new TimerConfig("myTimer", false));
    }

    public void rescheduleTimer(int interval) {
        // get timer from timer service
        for (Timer timer : timerService.getTimers()) {
            if (timer != null && timer.getInfo().equals("myTimer")) {
                timer.cancel();
            }
        }
        // schedule new timer, like in initTimer() method
    }

    @Timeout
    public void timeout(Timer timer) {
        // do the job
    }
}

EDIT:

@ManagedBean(eager=true)
@ApplicationScoped
public class JobRunner {
    private ScheduledExecutorService scheduler;
    private static final int POOL_SIZE = 1;

    ScheduledFuture<?> runHandle;

    @PostConstruct
    public void init() {
        scheduler = Executors.newScheduledThreadPool(POOL_SIZE);
        // set initial expiry to 5 minutes after 5 minutes delay
        runHandle = scheduler.scheduleAtFixedRate(new MyJob(), 5, 5, TimeUnit.MINUTES);
    }

    @PreDestroy
    public void destroy() {
        scheduler.shutdownNow();
    }

    public void reschedule(int newDelay) {
        // cancel old timer, but do not interrupt it
        runHandle.cancel(false);
        runHandle = scheduler.scheduleAtFixedRate(new MyJob(), newDelay, newDelay, TimeUnit.MINUTES);
    }
}

public class MyJob implements Runnable {
    public void run() { 
        // do the job
    }
}
Magic Wand
  • 1,572
  • 10
  • 9
  • In a lot of posts similar to which I shared the link above, I saw people suggest ***SchedulerExecutorService*** that is why I'm asking. Second and third questions – xtrapolate Jul 17 '14 at 06:34
  • @xtrapolate Didn't work with ScheduledExecutorService, but I see that it offers similar feature through ScheduledFuture objects: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledExecutorService.html – Magic Wand Jul 17 '14 at 11:52
  • Thanks. What is ***eager=true*** for? – xtrapolate Jul 17 '14 at 13:36
  • It means that this stateless bean is eagerly loaded, meaning is is instantiated at startup. Opposite to eager=false, when bean is instantiated on first use. – Magic Wand Jul 17 '14 at 14:54
  • so it does the same thing as @Startup annotation. – xtrapolate Jul 17 '14 at 14:55
  • Annotation Startup is used for EJBs (http://docs.oracle.com/javaee/6/tutorial/doc/girch.html), and annotation ManagedBean is from JSF managed beans (http://docs.oracle.com/javaee/6/api/javax/ejb/Startup.html). But yes, they do the same thing. It depends do you want to use EJBs or not. – Magic Wand Jul 17 '14 at 15:03
  • 1
    p.s. note that `@LocalBean` is not needed here. This is only used when you want your bean to expose a no-interface view, but since you don't implement any interfaces you already get such a view by default. – Arjan Tijms Jul 18 '14 at 20:28
  • Removed @LocalBean annotation according to Arjen's comment. – Magic Wand Jul 20 '14 at 11:03
  • Did not add that EJB timers have some additional features not present in Standard Java, such as persistent timers and support for clustered environment in application servers. – Magic Wand Jul 20 '14 at 11:05