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.
Related
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 have the following code:
import redis.clients.jedis.JedisPubSub;
import javax.sql.DataSource;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MsgSubscriber extends JedisPubSub {
private final PersistenceService service;
private final ExecutorService pool;
public MsgSubscriber(DataSource dataSource) {
pool = Executors.newFixedThreadPool(4);
service = new PersistenceServiceImpl(dataSource);
}
public void onMessage(String channel, String message) {
pool.execute(new Handler(message, service));
}
}
It is subscribed to a Redis channel, which is receiving hundreds of messages a second.
I am processing each of these messages as they come along and saving them to a data store, the handler looks like this:
public class Handler implements Runnable {
private String msg;
private PersistenceService service;
public MessageHandler(String msg, PersistenceService service) {
this.msg = msg;
this.service = service;
}
#Override
public void run() {
service.save(msg);
}
}
Things seem to be working ok, messages are being written to the database, but I have been running Java VisualVM and am seeing graphs like the following:
I'm concerned because the threads seem to be sitting in this "Parked" state and not running - although with some logging statements I am seeing that the code is being run. I guess my question is firstly, is there a problem with my code, and secondly, why is Visual VM showing me the threads don't seem to be doing anything?
hundreds of messages a second
Redis can easily handle 10K messages per second in 1 thread. With 4 threads it should be well under 1% busy, however this might be too low for VisualVM to detect with sampling and instead it says it is Parked all the time.
I need to schedule a task to run in at fixed interval of time. How can I do this with support of long intervals (for example on each 8 hours)?
I'm currently using java.util.Timer.scheduleAtFixedRate. Does java.util.Timer.scheduleAtFixedRate support long time intervals?
Use a ScheduledExecutorService:
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(yourRunnable, 8, 8, TimeUnit.HOURS);
You should take a look to Quartz it's a java framework wich works with EE and SE editions and allows to define jobs to execute an specific time
Try this way ->
Firstly create a class TimeTask that runs your task, it looks like:
public class CustomTask extends TimerTask {
public CustomTask(){
//Constructor
}
public void run() {
try {
// Your task process
} catch (Exception ex) {
System.out.println("error running thread " + ex.getMessage());
}
}
}
Then in main class you instantiate the task and run it periodically started by a precised date:
public void runTask() {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
calendar.set(Calendar.HOUR_OF_DAY, 15);
calendar.set(Calendar.MINUTE, 40);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
Timer time = new Timer(); // Instantiate Timer Object
// Start running the task on Monday at 15:40:00, period is set to 8 hours
// if you want to run the task immediately, set the 2nd parameter to 0
time.schedule(new CustomTask(), calendar.getTime(), TimeUnit.HOURS.toMillis(8));
}
Use Google Guava AbstractScheduledService as given below:
public class ScheduledExecutor extends AbstractScheduledService {
#Override
protected void runOneIteration() throws Exception {
System.out.println("Executing....");
}
#Override
protected Scheduler scheduler() {
return Scheduler.newFixedRateSchedule(0, 3, TimeUnit.SECONDS);
}
#Override
protected void startUp() {
System.out.println("StartUp Activity....");
}
#Override
protected void shutDown() {
System.out.println("Shutdown Activity...");
}
public static void main(String[] args) throws InterruptedException {
ScheduledExecutor se = new ScheduledExecutor();
se.startAsync();
Thread.sleep(15000);
se.stopAsync();
}
}
If you have more services like this, then registering all services in ServiceManager will be good as all services can be started and stopped together. Read here for more on ServiceManager.
If you want to stick with java.util.Timer, you can use it to schedule at large time intervals. You simply pass in the period you are shooting for. Check the documentation here.
Do something every one second
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
//code
}
}, 0, 1000);
These two classes can work together to schedule a periodic task:
Scheduled Task
import java.util.TimerTask;
import java.util.Date;
// Create a class extending TimerTask
public class ScheduledTask extends TimerTask {
Date now;
public void run() {
// Write code here that you want to execute periodically.
now = new Date(); // initialize date
System.out.println("Time is :" + now); // Display current time
}
}
Run Scheduled Task
import java.util.Timer;
public class SchedulerMain {
public static void main(String args[]) throws InterruptedException {
Timer time = new Timer(); // Instantiate Timer Object
ScheduledTask st = new ScheduledTask(); // Instantiate SheduledTask class
time.schedule(st, 0, 1000); // Create task repeating every 1 sec
//for demo only.
for (int i = 0; i <= 5; i++) {
System.out.println("Execution in Main Thread...." + i);
Thread.sleep(2000);
if (i == 5) {
System.out.println("Application Terminates");
System.exit(0);
}
}
}
}
Reference https://www.mkyong.com/java/how-to-run-a-task-periodically-in-java/
If your application is already using Spring framework, you have Scheduling built in
I use Spring Framework's feature. (spring-context jar or maven dependency).
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
#Component
public class ScheduledTaskRunner {
#Autowired
#Qualifier("TempFilesCleanerExecution")
private ScheduledTask tempDataCleanerExecution;
#Scheduled(fixedDelay = TempFilesCleanerExecution.INTERVAL_TO_RUN_TMP_CLEAN_MS /* 1000 */)
public void performCleanTempData() {
tempDataCleanerExecution.execute();
}
}
ScheduledTask is my own interface with my custom method execute, which I call as my scheduled task.
You can also use JobRunr, an easy to use and open-source Java Scheduler.
To schedule a Job every 8 hours using JobRunr, you would use the following code:
BackgroundJob.scheduleRecurrently(Duration.ofHours(8), () -> yourService.methodToRunEvery8Hours());
If you are using Spring Boot, Micronaut or Quarkus, you can also use the #Recurring annotation:
public class YourService {
#Recurring(interval="PT8H")
public void methodToRunEvery8Hours() {
// your business logic
}
}
JobRunr also comes with an embedded dashboard that allows you to follow-up on how your jobs are doing.
Have you tried Spring Scheduler using annotations ?
#Scheduled(cron = "0 0 0/8 ? * * *")
public void scheduledMethodNoReturnValue(){
//body can be another method call which returns some value.
}
you can do this with xml as well.
<task:scheduled-tasks>
<task:scheduled ref = "reference" method = "methodName" cron = "<cron expression here> -or- ${<cron expression from property files>}"
<task:scheduled-tasks>
my servlet contains this as a code how to keep this in scheduler if a user presses accept
if(bt.equals("accept")) {
ScheduledExecutorService scheduler=Executors.newScheduledThreadPool(1);
String lat=request.getParameter("latlocation");
String lng=request.getParameter("lnglocation");
requestingclass.updatelocation(lat,lng);
}
There is a ScheduledFuture class in java.util.concurrent, it may helps you.
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;
In my java web application, I want to schedule a task.
I have searched the web alot and couldn't find a suitable scheduler for my case. In the application I have different types of users. For a specific user type, I want to schedule a task.
By the time a critical action is taken by a user:
I want to send an email to that specific user and after 15 minutes
I want to send another email and after 30 minutes
I want to send another email and shut down the scheduler.
I know when the users take critical actions and how to send email but I don't have much experience about scheduling.
Can anyone help me for the case?
Why don't you use a ScheduledExecutor?
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledExecutorService.html
It has a method schedule which allows you to schedule whatever task you want (you pass a runnable). So basically, for each user you schedule a task of sending an e-mail and scheduling another task.
import static java.util.concurrent.TimeUnit.*;
class Task implements Runnable {
private final User user;
private final int rep;
private final ScheduledExecutorService scheduler;
public Task(User user, int rep, ScheduledExecutorService scheduler) {
this.user = user;
this.rep = rep;
this.scheduler = scheduler;
}
public void run() {
// send an e-mail to user
if (rep > 0)
scheduler.schedule(new Task(user, rep - 1, scheduler), 15, MINUTES);
}
}
class Example {
private final ScheduledExecutorService scheduler =
Executors.newScheduledThreadPool(1);
public void sendEmails() {
// foreach user
scheduler.submit(new Task(user, 3, scheduler));
}
}
You might want to use a scheduled thread pool with more than one thread.
Use Quartz Scheduler to schedule a task
Steps Required -
1) Quartz job
public class HelloJob implements Job {
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("Hello Quartz!");
}
}
2) Creating a trigger - CronTrigger – Run every 30 seconds
CronTrigger trigger = new CronTrigger();
trigger.setName("dummyTriggerName");
trigger.setCronExpression("0/30 * * * * ?");
3) Creating a scheduler
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
scheduler.scheduleJob(job, trigger);
Here's a tutorial on how to use Java Timers:
http://enos.itcollege.ee/~jpoial/docs/tutorial/essential/threads/timer.html
You can create multiple Timer tasks in sequence to fufill your objective.
Example
Code Quote:
import java.util.Timer;
import java.util.TimerTask;
/**
* Simple demo that uses java.util.Timer to schedule a task
* to execute once 5 seconds have passed.
*/
public class Reminder {
Timer timer;
public Reminder(int seconds) {
timer = new Timer();
timer.schedule(new RemindTask(), seconds*1000);
}
class RemindTask extends TimerTask {
public void run() {
System.out.format("Time's up!%n");
timer.cancel(); //Terminate the timer thread
}
}
public static void main(String args[]) {
new Reminder(5);
System.out.format("Task scheduled.%n");
}
}
You can also use JobRunr, an easy to use and open-source Java Scheduler.
To schedule a Job after 15 minutes using JobRunr, you would use the following code:
JobId firstEmailJobId = BackgroundJob.enqueue(() -> yourService.sendFirstEmail());
JobId secondEmailJobId = BackgroundJob.schedule(Instant.now().plus(15, minutes), () -> yourService.sendSecondEmail());
You can then repeat these steps for the other 2 emails. If you want to cancel sending these emails (e.g. when the user took action), you can easily delete these jobs again by means of the JobId (of course only if the job has not executed yet)
JobRunr also comes with automatic retries (e.g. your mailserver or sendgrid is down) and an embedded dashboard that allows you to follow-up on how your jobs are doing.
I would recommend you to take a look at the quartz scheduling API http://quartz-scheduler.org/
I have used it in several projects so far and it is really easy to setup and configure new jobs in. It supports cron based triggers or simpletriggers so you can either calculate the times for the scheduled events in your java code or you can simply pass it a cron string.
Another advantage is that its really easy to configure with spring.