Quartz is creating new instance of the class through the JobBuilder each time
JobBuilder.newJob(MyJob.class)
However, I only want one MyJob instance, and only trigger testFunction from execute function, how can I make it work?
I find through QuartzGuiceLib I can use some annotations to make it happen, through Spring I can change something in configuration file. But how can I implement it by pure Java without any framwork?
Below is the code snapshot:
public class MyJob implements Job {
public MyJob() {
testFunction();
try {
final Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
if (!scheduler.checkExists(JOB_KEY)) {
triggerScheduler(scheduler);
} else {
log.info("Job with key {{}} already exist", JOB_KEY);
}
} catch (SchedulerException e) {
log.error("Fail to start scheduler", e);
}
}
public void testFunction() {
}
private void triggerScheduler(final Scheduler scheduler) throws SchedulerException {
final JobDetail jobDetail = JobBuilder.newJob(MyJob.class)
.withIdentity(JOB_KEY)
.build();
final Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myjob")
.withSchedule(
simpleSchedule()
.withIntervalInSeconds(60)
.repeatForever())
.build();
scheduler.start();
log.info("Scheduling job with key {{}}", jobDetail.getKey());
scheduler.scheduleJob(jobDetail, trigger);
}
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
testFunction();
}
}
It might be easier to keep the job and scheduler in two separate classes as below:
public class MyQuartzScheduler {
public static void main( String[] args ) throws Exception {
JobDetail job = JobBuilder.newJob(MyJob.class)
.withIdentity("dummyJobName", "group1").build();
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("MyJobTrigger", "group1")
.withSchedule(
CronScheduleBuilder.cronSchedule("0 * * * * ?"))
.build();
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
scheduler.scheduleJob(job, trigger);
}
}
And then your Job Class:
public class MyJob implements Job {
public void testFunction() {
System.out.println("Running Test!");
}
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
testFunction();
}
}
This is an adaptation taken from an mkyong tutorial article found at:
https://www.mkyong.com/java/quartz-2-scheduler-tutorial/
For the answer to your question though, Quartz does create a new instance per run:
https://stackoverflow.com/a/10463309/1410671
You could make another static class or Factory that your Job class would call which would use the same instance every call.
public class MyJob implements Job {
public void testFunction() {
MyClassWithStaticCounter.increaseCounter(1);
System.out.println(MyClassWithStaticCounter.getCounter());
}
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
testFunction();
}
}
And your class that has the static stuff:
public class MyClassWithStaticCounter {
private static int counter = 0;
public static void increaseCounter(int i){
counter += i;
}
public static int getCounter(){
return counter;
}
}
Related
Can a Quartz Scheduler execute a Runnable?
For example, I have the following code being running by a spring TaskScheduler:
[...]
#Autowired
#Qualifier(IntegrationConfiguration.TASK_SCHEDULER_INTEGRATION_NAME)
private TaskScheduler taskScheduler;
[...]
ScheduledFuture<?> scheduledFuture = taskScheduler.schedule(new Runnable() {
#Override
public void run() {
try {
execucaoJobService.executa(jobName, execucaoJobDto, jobScheduleId);
} catch (JobExecutionException e) {
LOG.error("Job Execution fails", e);
}
}
}, new CronTrigger(cronExpression));
[...]
I wanna do something like the above code with Quartz, I know there is QuartzJobBean class, but this one
only works with static code, and I need to pass the cronExpression and other params dynamic.
You could define a job that takes a Runnable via the JobDataMap, and run that on execution.
The job would look like this:
public final class RunnableJob implements Job {
public static final String RUNNABLE_KEY = "RUNNABLE_KEY";
public RunnableJob() {
// Explicit constructor is required by Quartz.
}
#Override
public void execute(JobExecutionContext jobExecutionContext) {
final var runnable = (Runnable) jobExecutionContext.getJobDetail().getJobDataMap().get(RUNNABLE_KEY);
runnable.run();
}
}
Where you schedule your job it would look something like this:
final var cronTrigger = TriggerBuilder.newTrigger()
.withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
.build();
final var jobDetail = JobBuilder.newJob(RunnableJob.class)
.setJobData(new JobDataMap(Map.of(RunnableJob.RUNNABLE_KEY,
(Runnable) () -> {
// Do whatever you want to do
})))
.build();
scheduler.scheduleJob(jobDetail, cronTrigger);
I found this code: QuartzScheduledExecutorService.java that helps me with this problem. maybe it can help someone else in the future.
I am writing a java/spring library to include in other projects that are using quartz.
I need it to log some information about the task/calling class everytime a job is executed.
For example, if a quartz job looks like this:
#Bean
public JobDetail jobADetail() {
return JobBuilder.newJob(QuartzTaskA.class)
.withIdentity("sampleJobA")
.storeDurably().build();
}
#Bean
public Trigger jobATrigger(JobDetail jobADetail) {
return TriggerBuilder.newTrigger()
.forJob(jobADetail)
.withIdentity("sampleTriggerA")
.withSchedule(CronScheduleBuilder.cronSchedule("0/10 * * ? * * *"))
.build();
}
public class QuartzTaskA implements Job {
#Override
public void execute(JobExecutionContext jobExecutionContext) {
log.info("QuartzA - the time is now {}", dateFormat.format(new Date()));
}
}
I want it to log something like:
Job [QuartzTaskA] with details [sampleJobA] and trigger [sampleTriggerA] is starting
QuartzA - the time is now 12:07:39
I customize the SchedulerFactoryBean with a custom TaskExecutor that does a log before the task.run().
This works and I am able print the additional first line, but I can't figure out how to get the details/context to pass into the log.
#Configuration
public class SchedulerFactoryCustomizer implements SchedulerFactoryBeanCustomizer {
private static final Logger log = LogManager.getLogger(SchedulerFactoryCustomizer.class);
#Override
public void customize(SchedulerFactoryBean schedulerFactoryBean) {
Executor executor = SchedulerFactoryBean.getConfigTimeTaskExecutor();
schedulerFactoryBean.setTaskExecutor(new CustomExecutor(executor);
}
private static class CustomExecutor implements Executor {
final Executor executor;
private CustomExecutor(Executor executor) {
this.executor = executor;
}
#Override
public void execute(Runnable task) {
// This line here. How can I get the details/context to pass in?
//log.info("Job {} with details {} and trigger {} is starting");
task.run();
}
}
}
how can I get the details/context to pass into the log?
You can implement a JobListener/TriggerListener
public class LoggingTriggerListener implements TriggerListener {
#Override
public String getName() {
return null;
}
#Override
public void triggerFired(final Trigger trigger, final JobExecutionContext context) {
}
#Override
public boolean vetoJobExecution(final Trigger trigger, final JobExecutionContext context) {
return false;
}
#Override
public void triggerMisfired(final Trigger trigger) {
}
#Override
public void triggerComplete(final Trigger trigger, final JobExecutionContext context, final Trigger.CompletedExecutionInstruction triggerInstructionCode) {
}
}
It injects jobExecutionContext also.
I use Quartz 2 to create a Interval in Java.
Now i want to pass the Object obj1 from the Updater to the UpdateJob.
How can i make this ?
Interval.java/Updater :
public class Interval {
public static void Updater( Object obj1 ) throws SchedulerException {
JobDetail job = newJob(UpdateJob.class).withIdentity("UpdateJob", "Group1").build();
Trigger trigger = newTrigger().withIdentity("UpdateTrigger", "Group1")
.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5).repeatForever()).build();
Scheduler sched = new StdSchedulerFactory().getScheduler();
sched.scheduleJob(job, trigger);
sched.start();
}
}
UpdateJob.java :
public class UpdateJob implements Job {
public void execute(JobExecutionContext context)
throws JobExecutionException {
//obj1 jobs
}
}
You can use datamap
job.getJobDataMap().put("key",obj1);
and then get it from job:
JobDataMap data = _context.getJobDetail().getJobDataMap();
Object o = data.get("key");
Here I have a sample using Quartz scheduling
public class SampleJob implements Job {
#Inject
private MyClass sample;
#Override
public void execute( JobExecutionContext jobExecutionContext ) throws JobExecutionException {
sample.runSampleWithDBConnection();
}
}
public class SampleScheduling {
private String cronExpression = ;
public void run() throws SchedulerException {
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
JobDetail job = newJob(SampleJob.class).withIdentity("job1", "group1").build();
CronTrigger trigger = newTrigger().withIdentity("trigger1", "group1")
.withSchedule(cronSchedule("0 5 * * * ? *"))
.build();
Date nextRuntime = scheduler.scheduleJob(job, trigger);
scheduler.start();
}
}
In the above sample when the Quartz triggers the Job Its getting null for the injected MyClass. where MyClass is simple java class with a method
public class MyClass {
#Inject
#NamedDatabase("default")
private Database defaultDb;
public void runSampleWithDBConnection() {
defaultDb.getConnection();
}
}
I'm currently working on an Java-Application, which checks every second the temperature of my computer. For the timing I made an Timer class which works with Quartz and for the checking of the temperature I made a class called SysKeeper. My problem is, that I want, that the SysKeeper is notified, when the Timer is triggered, but my Observer is not working, because the Syskeeper is not added as Observer.
Here you see my Syskeeper class:
public class SysKeeper implements Observer {
private double temp;
public void start() {
Log.info("SysKeeper starting");
Main.timer.addObserver(this);
}
private void checkTemp() {
String buffer = CmdExecutor.execute("sudo vcgencmd measure_temp");
String[] splitBuffer = buffer.split("=");
String[] splitBuffer1 = splitBuffer[1].split("\'");
temp = Double.parseDouble(splitBuffer1[0]);
if (temp > 70.0) {
//Main.not.sendMessage("Reached crit Temp: " + temp);
}
Log.info(temp + "");
}
public void kill() {
}
#Override
public void update(Observable o, Object arg) {
System.out.println("HI");
this.checkTemp();
}
}
And this is my Timer class:
public class Timer extends Observable implements Job {
public void start() {
try {
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("timer", "timer")
.withSchedule(
CronScheduleBuilder.cronSchedule("0/1 * * * * ?"))
.build();
JobDetail job = JobBuilder.newJob(Timer.class)
.withIdentity("timer", "timer").build();
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
scheduler.scheduleJob(job, trigger);
} catch (SchedulerException ex) {
Logger.getLogger(Timer.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public void execute(JobExecutionContext jec) throws JobExecutionException {
this.setChanged();
this.notifyObservers();
System.out.println("" + countObservers());//always 0
}
public void kill() {
}
}
Here is also my Main class:
public class Main {
public static final String spliterNetwork = ";";
public static final String spliterParameter = "#";
public static Timer timer;
public static Server ser;
public static SysKeeper kep;
public static GPIO gpio;
public static Log log;
public static void main(String[] args) throws UnknownHostException {
Main.init(args);
Main.start();
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
#Override
public void run() {
Main.stop();
}
}));
}
public static void init(String[] args) {
timer = new Timer();
log = new Log();
ser = new Server();
kep = new SysKeeper();
gpio = new GPIO();
}
public static void start() throws UnknownHostException {
Log.info("Welcome to iServer # " + InetAddress.getLocalHost());
timer.start();
log.start();
ser.start();
kep.start();
gpio.start();
}
public static void stop() {
Log.info("Programm shuts down");
timer.kill();
log.kill();
ser.kill();
kep.kill();
gpio.kill();
timer = null;
log = null;
ser = null;
kep = null;
gpio = null;
Log.info("Good bye");
}
}
I'm not familiar wih Quartz, but it would seem that you have two distinct instances of Timer:
The first Timer that is stored in Main.timer, created in timer = new Timer(), and having an observer added in Main.timer.addObserver(this); (in SysKeeper). This instance is never executed, that is, it never has its execute() method called.
The second Timer, that is created by the first Timer in the line JobDetail job = JobBuilder.newJob(Timer.class)... this Timer is the one that is being executed (scheduler.scheduleJob(job, trigger);) but it hasn't any Observer attached.