I'm honestly missing something here. I have no idea how to make an instance of TimerService object. It is always null. I don't have a constructor because it's an Interface. I can't use the create methods. #Resource doesn't seem to allocate anything to it.
I'm trying to setup a simple programmatic timer that does a task every X minutes. The timeout duration can vary based on configuration which can change throughout runtime. I am using a WebLogic 12 web application.
What I have so far:
import javax.annotation.Resource;
import javax.ejb.Singleton;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerService;
#Singleton
public class TimerBean {
#Resource
protected TimerService timerService;
public TimerBean(){
System.out.println("TimerBean constructor " + timerService);
}
#Timeout
public void timeoutHandler(Timer timer){
String name = timer.getInfo().toString();
System.out.println("Timer ticked. Name=" + name);
}
public void startOrModifyTimer(long initialExpiration, long interval, String name) {
System.out.println("Start or modify " + timerService);
}
}
This outputs:
TimerBean constructor null
& then after the server is running if I call start or modify:
Start or modify null
edit:
I got it to work by making the TimerBean #Singleton & #Startup & replacing constructor with #PostConstruct method.
however while it has an object for TimerService instantiated whenever I try to use its methods it gives me java.lang.IllegalArgumentException: Unknown bean state 0 for which there is no information...
If you're trying to use field injection, you're relying on the framework to come along after the object has already been instantiated and set the field, so it will always be null in the constructor. You can either do whatever logic you need in an #PostConstruct method or, my strong preference, inject the TimerService as a constructor argument instead of directly into the field.
#PostConstruct is never called. #Inject is not either (and Im unsure if I did it right)
I got it to work by making the TimerBean #Singleton & #Startup & replacing constructor with #PostConstruct method.
chrylis is right. From your description it looks like you instantiating TimerBean via constructor.
Result is that you manage life-cycle by yourself and container is not able to take care of this instance and inject anymore.
Inject your TimerBean into the class where you want to use it (Session for example), or use it as you did:
#Singleton
#Startup
public class TimerBean { .. }
Combination of these annotations basically create one instance of TimerBean during app server start sequence.
Btw. Constructor with #PostConstruct is wrong idea and it may behave really unpredictable during run-time (not sure if it is possible, but you creating circular instantiation with this combo).
I ended up using Timer & TimerTask for this. Couldn't figure TimerService out. Oh well. Seems to work fine.
For anyone curious:
long interval = minutes*60*1000;
long delay = interval;
if(prevTask != null){
delay = System.currentTimeMillis() - prevTask.scheduledExecutionTime(); //time left of previous setting
prevTask.cancel();
delay = interval - delay; //difference in time left & new interval
if(delay <=0) //if by new setting should've already ran, so run it ASAP...
delay = 2000;
logger.info(String.format("DB dump was already scheduled before. Set dump delay to %s minutes & setting new schedule to every %s minutes.", delay/60/1000, minutes));
}
TimerTask task = new TimerTask(){
private SimpleDateFormat ft = new SimpleDateFormat("yyyy.MM.dd 'at' HH:mm:ss SSS");
private int minutes;
public TimerTask initialize(int minutes){
this.minutes = minutes;
return this;
}
public void run() {
try {
logger.info(String.format("Doing scheduled %s dump to DB. (Configured to occur every %s minutes.)", ft.format(new Date(this.scheduledExecutionTime())), minutes));
dumpToDB();
} catch (NamingException | SQLException e) {
e.printStackTrace();
}
}
}.initialize(minutes);
timer.schedule(task, delay, interval);
prevTask = task;
Related
I have a stateless bean that insert some data using asynchronous method of other bean ( local injection). This data insertion takes a time , so I do not wait to finish for this operation. After this data insertion, I am calling another method of same bean. When I put a debug point to method, server waits for approximately 90 seconds to reach this point. May be Jboss waits for transaction to complete for asynchronous method. I do not know what is going on. .
#Stateless
public class SimulationNodePersistenceBean implements SimulationNodePersistenceRemote, SimulationNodePersistenceLocal {
#Resource
SessionContext context;
#EJB
private SimulationResultGraphPersitenceBean graphPersistenceBean;
#Asynchronous
#TransactionAttribute(TransactionAttributeType.REQUIRED)
private void addResultGraphsToDatabase(long id, Graph[] graphList) {
ResultGraph paramGraph;
ResultGraphPoint dataPoint;
Graph graph;
for (int i = 0; i < graphList.length; i++) {
graph = graphList[i];
paramGraph = new ResultGraph();
try {
graphPersistenceBean.persistGraph(paramGraph);
} catch (Exception databaseException) {
// TODO add error message to the contingency simulation messages
// list
logger.error("Error saving ResultGraph:" + paramGraph);
}
}
long duration = System.nanoTime() - startTime;
logger.debug("Graphs inserted to DB in (sec) :" + (duration / NANO_SECOND_CONVERSION_FACTOR));
}
// #Asynchronous
public void persistSimulationResults(long contingencySimulationId, Graph[] graphList,
List<AB> reiList) {
if (graphList != null) {
addResultGraphsToDatabase(contingencySimulationId, graphList);
}
if (reiList != null) {
//another method
}
calculateContSimStability(contingencySimulationId);
}
#Override
public void calculateSimIndex(long id) {
}
This is other bean called from main bean
#Stateless
public class SimulationResultGraphPersitenceBean {
#PersistenceContext(unitName = "DBService")
private EntityManager em;
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
#Asynchronous
public void persistGraph(ResultGraph graph) throws SiGuardPersistenceException {
try {
ResultGraphService service = new ResultGraphService(em);
service.create(graph);
em.flush();
} catch (Exception ex) {
throw new PersistenceException("Error persisting graph", ex);
}
}
This is client calls main bean.This works asynchronously.
getSimulationEJB().persistSimulationResults(id, tsaParser.getLstFile().getGraphArray());
After calling this method, I call another method of SimulationNodePersistenceBean.This method waits for some minutes.
getSimulationEJB().calculateSimIndex(contSimId);
I have created a thread dump using jstack. Actually I do not have this problem in Jboss As 6. I migrated my application to Jboss EAP 6. 4. May be I need to make some configuration changes in configuration. But I do not know what should I do.
I checked thread dump. I did not find any thread in BLOCKING state. Should I look for other keywords?
As I already pointed out in the comments, you are mixing the calling of Asynchronous and Synchronous methods. In your example, you are calling the addResultGraphsToDatabase method (Which is a Asynch method) from persistSimulationResults method (which is a synch method - since you have commented out the asynchronous annotation on top of it). Therefore, right now the addResultGraphsToDatabase method is behaving like a Synchronous method despite the Asynchronous annotation.
I am not sure if you took a look at the link that I posted in the comments but you need to call the Asynch method using the SessionContext. Something like this:
At the class level:
#Inject
SessionContext ctx;
The, within the persistSimulationResults method:
ctx.addResultGraphsToDatabase
For a more detailed example, please take a look at the link I have posted in the comments.
I am creating an EJB TimerService mock. Is there a way to manually trigger the call to a method with the #Timeout annotation?
You can create new timer with preferred duration. When you need to call timeout call bellow code segment with duration. Then Framework should call timeout method within given duration from now.
context.getTimerService().createTimer(duration, "Hello World!");
Full code
import javax.annotation.Resource;
import javax.ejb.SessionContext;
import javax.ejb.Timer;
import javax.ejb.Stateless;
import javax.ejb.Timeout;
#Stateless
public class TimerSessionBean implements TimerSessionBeanRemote {
#Resource
private SessionContext context;
public void createTimer(long duration) {
context.getTimerService().createTimer(duration, "Hello World!");
}
#Timeout
public void timeOutHandler(Timer timer){
System.out.println("timeoutHandler : " + timer.getInfo());
timer.cancel();
}
}
Now let's take into account that
The method is not public.
If you would like to test only the logic contained in method annotated with #Timeout, there are few solutions.
I would recommend the last one, because it would also improve the overall design (see this answer).
Make that method protected or package-private. This one is the simplest way to make that logic testable.
Use reflection or PowerMock to invoke private method.
Here is a simple example, assuming that we want to invoke instance.timeOutHandlerMethod with Timer instance timer.
Whitebox.invokeMethod(instance, "timeOutHandlerMethod", timer);
See doc page for more details.
Extract logic to separate class and test it instead.
Here we extract logic from this.timeOutHandler to Delegate.execute:
#Timeout
private void timeOutHandler(Timer timer) {
// some complicated logic
timer.cancel();
}
to this:
private Delegate delegate;
#Timeout
private void timeOutHandler(Timer timer) {
delegate.execute(timer);
}
With Delegate declared as:
class Delegate {
public void execute(Timer timer) {
// some complicated logic
timer.cancel();
}
}
Now we can write a test for Delegate class.
I need to run a daily job which will run once a day and get some data from a different database. The task is developed as an EJB. I tried the #Schedule with EJB, and it is working fine. But the issue is if there is a change in the schedule, the code has to be changed and the app to be redeployed. Is there a way to avoid this? May be by using configuration files etc. I am using JSF 2.2, glassfish3.4.2 in CentOS.
You can do this by creating your timer programmatically something like this
....
private static final String TIMER_NAME = "SOME_TIMER_NAME";
....
#Resource
TimerService timerService;
....
public void createTimer(String days, String hours, String minutes) {
removeTimer();
ScheduleExpression scheduleExpression = new ScheduleExpression();
if (days != null) {
scheduleExpression.dayOfMonth(datys);
}
if (hours != null) {
scheduleExpression.hour(hours);
}
if (minutes != null) {
scheduleExpression.minute(minutes);
}
TimerConfig timerConfig = new TimerConfig();
timerConfig.setInfo(TIMER_NAME);
Timer timer = timerService.createCalendarTimer(scheduleExpression, timerConfig);
}
private void removeTimer() {
for (Timer timer : timerService.getTimers()) {
if (TIMER_NAME.equals(timer.getInfo())) {
timer.cancel();
}
}
}
#Timeout
public void retrieveData() {
// retrieve data from DBs
}
now calling the createTimer method like this
createTimer("*", "3", null);
retrieveData() method will be executed at 3:00 AM each day. If you want to change the schedule you should call the method with appropriate values. You may tune it to meet your requirements like add input validation, define parameters differently etc. You may want to look at ScheduleExpression to find what is best for you. My code just shows an idea.
Did you consider using cron job?
here are some examples:
Cron examples
How would you suggest to implement the following in JavaEE:
I need to have a background process in the app server (I was thinking a stateful session beans) that constantly monitors "something" and if some conditions apply it does operations with the database.
Most importantly it has to manipulated remotely by various clients.
So, basically, I need a process that will run constantly, keep its state and be open for method invocations by a number of remote clients.
Since I'm new to JavaEE I'm a bit confused which approach/"technology" to use. An help would be appreciated.
You can use a combination of a stateless session or singleton bean with an EJB timer an timer service. The bean would the interface used by the remote clients to control the background process. The timer service would periodically call back a method on the bean to verify the condition. The timers are automatically persisted by the EJB container, so they will do their job when your bean clients are disconnected.
Here is a sketch:
#Singleton
...
public TimerMangerbean implements TimerManager {
#Resource
private TimerService timerService;
public void startMonitoring() {
//start in 5 sec and timeout every 10 minutes
Timer timer = timerService.createTimer(5000, 60000, "MyTimer");
}
public void stopMonitoring() {
Collection<Timer> timers = timerService.getTimers();
for(Timer timer : timers) {
//look for your timer
if("MyTimer".equals(timer.getInfo())) {
timer.cancel();break;
}
}
}
//called every 10 minutes
#Timeout
public void onTimeout() {
//verify the condition and do your processing
}
}
See also: Using the timer service on Oracle JavaEE tutorial
What about Quartz? See the links
http://rwatsh.blogspot.com/2007/03/using-quartz-scheduler-in-java-ee-web.html
http://lanbuithe.blogspot.com/2011/07/using-quartz-scheduler-in-java-ee-web.html
http://www.mkyong.com/tutorials/quartz-scheduler-tutorial/
As you stated yourself, you have two requirements: 1) periodically perform some background job, and 2) respond to client requests.
For 1), you can use the TimerService or spawn a thread with a ServletContextListener. The second is not fully conform, but works. If you use timers, you can either create a periodic timer (as pointed out by #dcernahoschi), or a unique timer that reschedules itself:
#Timeout
public void onTimeout() {
//do something
// create a new timer
}
If your periodic timer fires each 10 sec and you have processing that last form more than 10 seconds, you might have a problem. Having a timer that reschedules itself works better if the processing time is not fixed.
For 2) you can go with statelesss or staefull EJB, that's precisely their purpose.
Java EE is the solution. You will need to follow thoses steps:
build a Java EE application, a jar containing a EJB:
1.1 you will need a IDE : Eclipse Juno is my favorit,
1.2 Many tuto exists on the web. Search for EJB3 and you will find,
have an application server to run your EJB. JBoss is a good choice, Glassfish is an another good choice. With JBoss and the JBoss Tools plugin for Eclipse installed, you will be able to build and run rapidly an basic application.
EDIT : a complete Timer EJB class (with automatic reload if needed)
package clouderial.saas.commons.utils;
import java.util.Map;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import javax.ejb.ScheduleExpression;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerConfig;
import javax.ejb.TimerService;
import javax.inject.Inject;
import jmcnet.libcommun.exception.ExceptionTechnique;
import jmcnet.libcommun.utilit.mail.MailException;
import org.apache.commons.configuration.event.ConfigurationEvent;
import org.apache.commons.configuration.event.ConfigurationListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import clouderial.saas.commons.email.EmailSender;
import clouderial.saas.commons.jpamongo.JPAMongoBasePersistenceContextAccessor;
/**
* A base class for a periodic process
* #author jmc
*
*/
public abstract class PeriodicProcessBase extends JPAMongoBasePersistenceContextAccessor implements ConfigurationListener {
private static Logger log = LoggerFactory.getLogger(PeriodicProcessBase.class);
#Resource
private TimerService timerService;
#Inject
protected GlobalConfiguration _config;
#Inject
protected EmailSender _emailSender;
private Timer _timer=null;
private String _processName=null;
private Logger _log = null;
protected void initTimer(String processName, Logger log) {
if (processName != null) _processName = processName;
if (log != null) _log = log;
String second = _config.getString("timer."+_processName+".second","0");
String minute = _config.getString("timer."+_processName+".minute","0");
String hour = _config.getString("timer."+_processName+".hours","4");
String dayOfWeek = _config.getString("timer."+_processName+".dayOfWeek","*");
ScheduleExpression scheduleExp =
new ScheduleExpression().second(second).minute(minute).hour(hour).dayOfWeek(dayOfWeek);
cancelTimer();
if (timerService != null) {
_timer = timerService.createCalendarTimer(scheduleExp, new TimerConfig(_processName, false));
_log.info("{} : timer programmed for '{}'h, '{}'m, '{}'s for days '{}'.", _processName, hour, minute, second, dayOfWeek);
}
else _log.error("{} : no timer programmed because timerService is not initialized. (Normal during tests)", _processName);
// Listen to change
_config.addModificationListener(this); // on timer modification, configurationChanged is called
}
#PreDestroy
private void cancelTimer() {
if (_log != null) _log.info("Stopping timer for '{}'", _processName);
if (_timer != null) _timer.cancel();
_timer = null;
}
#Override
public void configurationChanged(ConfigurationEvent event) {
if (_log != null) _log.info("Configuration have change. Reloading config for ProcessBilling.");
_config.removeModificationListener(this);
initTimer(null, null);
}
#Timeout
private void run(Timer timer) {
runProcess(timer);
}
/**
* The entry point for runner the process. Must be overriden by super class
* #param timer
*/
protected abstract void runProcess(Timer timer); // do the job here
}
I hope this helps.
I want to write a back-ground job (EJB 3.1), which executes every minute. For this I use the following annotation:
#Schedule(minute = "*/1", hour = "*")
which is working fine.
However, sometimes the job may take more than one minute. In this case, the timer is still fired, causing threading-issues.
Is it somehow possible, to terminate the scheduler if the current execution is not completed?
If only 1 timer may ever be active at the same time, there are a couple of solutions.
First of all the #Timer should probably be present on an #Singleton. In a Singleton methods are by default write-locked, so the container will automatically be locked-out when trying to invoke the timer method while there's still activity in it.
The following is basically enough:
#Singleton
public class TimerBean {
#Schedule(second= "*/5", minute = "*", hour = "*", persistent = false)
public void atSchedule() throws InterruptedException {
System.out.println("Called");
Thread.sleep(10000);
}
}
atSchedule is write-locked by default and there can only ever be one thread active in it, including calls initiated by the container.
Upon being locked-out, the container may retry the timer though, so to prevent this you'd use a read lock instead and delegate to a second bean (the second bean is needed because EJB 3.1 does not allow upgrading a read lock to a write lock).
The timer bean:
#Singleton
public class TimerBean {
#EJB
private WorkerBean workerBean;
#Lock(READ)
#Schedule(second = "*/5", minute = "*", hour = "*", persistent = false)
public void atSchedule() {
try {
workerBean.doTimerWork();
} catch (Exception e) {
System.out.println("Timer still busy");
}
}
}
The worker bean:
#Singleton
public class WorkerBean {
#AccessTimeout(0)
public void doTimerWork() throws InterruptedException {
System.out.println("Timer work started");
Thread.sleep(12000);
System.out.println("Timer work done");
}
}
This will likely still print a noisy exception in the log, so a more verbose but more silently solution is to use an explicit boolean:
The timer bean:
#Singleton
public class TimerBean {
#EJB
private WorkerBean workerBean;
#Lock(READ)
#Schedule(second = "*/5", minute = "*", hour = "*", persistent = false)
public void atSchedule() {
workerBean.doTimerWork();
}
}
The worker bean:
#Singleton
public class WorkerBean {
private AtomicBoolean busy = new AtomicBoolean(false);
#Lock(READ)
public void doTimerWork() throws InterruptedException {
if (!busy.compareAndSet(false, true)) {
return;
}
try {
System.out.println("Timer work started");
Thread.sleep(12000);
System.out.println("Timer work done");
} finally {
busy.set(false);
}
}
}
There are some more variations possible, e.g. you could delegate the busy check to an interceptor, or inject a singleton that only contains the boolean into the timer bean, and check that boolean there, etc.
I ran into the same problem but solved it slightly differently.
#Singleton
public class DoStuffTask {
#Resource
private TimerService timerSvc;
#Timeout
public void doStuff(Timer t) {
try {
doActualStuff(t);
} catch (Exception e) {
LOG.warn("Error running task", e);
}
scheduleStuff();
}
private void doActualStuff(Timer t) {
LOG.info("Doing Stuff " + t.getInfo());
}
#PostConstruct
public void initialise() {
scheduleStuff();
}
private void scheduleStuff() {
timerSvc.createSingleActionTimer(1000l, new TimerConfig());
}
public void stop() {
for(Timer timer : timerSvc.getTimers()) {
timer.cancel();
}
}
}
This works by setting up a task to execute in the future (in this case, in one second). At the end of the task, it schedules the task again.
EDIT: Updated to refactor the "stuff" into another method so that we can guard for exceptions so that the rescheduling of the timer always happens
Since Java EE 7 it is possible to use an "EE-aware" ManagedScheduledExecutorService, i.e. in WildFly:
In for example a #Singleton #Startup #LocalBean, inject the default "managed-scheduled-executor-service" configured in standalone.xml:
#Resource
private ManagedScheduledExecutorService scheduledExecutorService;
Schedule some task in #PostConstruct to be executed i.e. every second with fixed delay:
scheduledExecutorService.scheduleWithFixedDelay(this::someMethod, 1, 1, TimeUnit.SECONDS);
scheduleWithFixedDelay:
Creates and executes a periodic action that becomes enabled first
after the given initial delay, and subsequently with the given delay
between the termination of one execution and the commencement of the
next.[...]
Do not shutdown the scheduler in i.e. #PreDestroy:
Managed Scheduled Executor Service instances are managed by the
application server, thus Java EE applications are forbidden to invoke
any lifecycle related method.
well I had a similar problem. There was a job that was supposed to run every 30 minutes and sometimes the job was taking more than 30 minutes to complete in this case another instance of job was starting while previous one was not yet finished.
I solved it by having a static boolean variable which my job would set to true whenever it started run and then set it back to false whenever it finished. Since its a static variable all instances will see the same copy at all times. You could even synchronize the block when u set and unset the static variable.
class myjob{
private static boolean isRunning=false;
public executeJob(){
if (isRunning)
return;
isRunning=true;
//execute job
isRunning=false;
}
}