NullPointerException using Quartz rescheduler function [duplicate] - java

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 6 years ago.
I am new to Quartz API and currently using quartz version 2.2.x to create a scheduler class object in java to support my school project but encountered null pointer exception with scheduler.rescheduleJob(trigger.getKey(), cronTrigger); at rescheduleCron function. I am trying to setup a function to accept cron expression to reschedule quartz jobs and have no idea what I am doing wrong. Please help me to rectify this error.
public class quartzScheduler {
public JobDetail job;
public Trigger trigger;
public Scheduler scheduler;
public void quartzScheduler() throws SchedulerException,InterruptedException
{
job = JobBuilder.newJob(quartzJob.class)
.withIdentity("quartzJob", "group1").build();
trigger = TriggerBuilder
.newTrigger()
.withIdentity("quartzTrigger", "group1")
.startAt(futureDate(1, IntervalUnit.HOUR))
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInHours(1).repeatForever())
.build();
scheduler.start();
scheduler.scheduleJob(job, trigger);
}
public void rescheduleCron(String cronExpression) throws SchedulerException
{
Trigger cronTrigger = TriggerBuilder
.newTrigger()
.withIdentity("quartzTrigger", "group1")
.withSchedule(cronSchedule(cronExpression))
.build();
scheduler.rescheduleJob(trigger.getKey(), cronTrigger);
}
public static void main(String[] args)
{
quartzScheduler sch= new quartzScheduler();
try {
sch.rescheduleCron("0 0 * * * ?");
} catch (SchedulerException ex) {
Logger.getLogger(quartzScheduler.class.getName()).log(Level.SEVERE, null, ex);
}
}

In rescheduleCron(), your trigger has not been initialized. It is set to null and when you try to call .getKey() on it, you're getting a NullPointerException.
I see what you're doing... I think you're trying to use quartzScheduler() as a constructor which is why you're expecting the trigger to be initialized. Very small change to fix this: remove the return value from that function. Java constructors do not have return values.
It should look like this:
public class QuartzScheduler {
public JobDetail job;
public Trigger trigger;
public Scheduler scheduler;
public QuartzScheduler() throws SchedulerException, InterruptedException {
job = JobBuilder.newJob(quartzJob.class)
.withIdentity("quartzJob", "group1").build();
trigger = TriggerBuilder
.newTrigger()
.withIdentity("quartzTrigger", "group1")
.startAt(futureDate(1, IntervalUnit.HOUR))
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInHours(1).repeatForever())
.build();
scheduler = new Scheduler(); //maybe do something else here.
scheduler.start();
scheduler.scheduleJob(job, trigger);
}
public void rescheduleCron(String cronExpression) throws SchedulerException {
Trigger cronTrigger = TriggerBuilder
.newTrigger()
.withIdentity("quartzTrigger", "group1")
.withSchedule(cronSchedule(cronExpression))
.build();
scheduler.rescheduleJob(trigger.getKey(), cronTrigger);
}
}
public static void main(String[] args) {
QuartzScheduler sch= new QuartzScheduler();
try {
sch.rescheduleCron("0 0 * * * ?");
} catch (SchedulerException ex) {
Logger.getLogger(quartzScheduler.class.getName()).log(Level.SEVERE, null, ex);
}
}
What I've changed:
Capitalized your class name (by convention)
Removed the return values and the exceptions from the constructor
moved the main() call to outside of the class. The main() call uses the class, it is not part of it

Related

Avoid Quartz creating new instance every time

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;
}
}

How to assign different threads to different methods of other class not using main main thread

Lets say I have a main class Start.java
public class Start{
//Here I want to integrate the programs for which i will be needing threads
}
and I also have two more classes which contains two different methods.
public class ReadUpdateDb {
public void updateDb(Statement stmt)
}
public class DbToXls {
public void dbtoXLS(Statement stmt)
}
Here is my problem: I dont how to assign two different threads to the methods updateDb() and dbtoXLS().
Also, I want to run updateDb after every two hours and dbtoXLS once in a day.
As mentioned, ScheduledExecutorService will do the job. I also suggest to name threads using Guava's ThreadFactoryBuilder for example, it will be much easier to debug in the future.
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
public class Start {
private static final Integer POOL_SIZE = 2;
private final ScheduledExecutorService schedExecutor = Executors
.newScheduledThreadPool(POOL_SIZE,
new ThreadFactoryBuilder().setNameFormat("Schedule-Updater-%d")
.setDaemon(true).build());
public void go() {
Statement stmt = null; // construct your statement here
ReadUpdateDb readUpdateDb = new ReadUpdateDb();
schedExecutor.scheduleAtFixedRate(() -> readUpdateDb.updateDb(stmt),
0, 2, TimeUnit.HOURS);
DbToXls dbToXls = new DbToXls();
schedExecutor.scheduleAtFixedRate(() -> dbToXls.dbtoXLS(stmt),
0, 1, TimeUnit.DAYS);
schedExecutor.shutdown();
}
}
Hope it helps!
You can use ScheduledExecutorService or open source implementation like quartz.
ScheduledExecutorService example for running in every 15 min.
private final ScheduledExecutorService scheduler = Executors
.newScheduledThreadPool(1);
public void startScheduleTask() {
final ScheduledFuture<?> taskHandle = scheduler.scheduleAtFixedRate(
new Runnable() {
public void run() {
try {
updateDb();
}catch(Exception ex) {
ex.printStackTrace(); //or loggger would be better
}
}
}, 0, 15, TimeUnit.MINUTES);
}
QUARTZ Example
public class SimpleTriggerExample {
public static void main(String[] args) throws Exception {
// Quartz 1.6.3
// JobDetail job = new JobDetail();
// job.setName("dummyJobName");
// job.setJobClass(HelloJob.class);
JobDetail job = JobBuilder.newJob(HelloJob.class)
.withIdentity("dummyJobName", "group1").build();
//Quartz 1.6.3
// SimpleTrigger trigger = new SimpleTrigger();
// trigger.setStartTime(new Date(System.currentTimeMillis() + 1000));
// trigger.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
// trigger.setRepeatInterval(30000);
// Trigger the job to run on the next round minute
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("dummyTriggerName", "group1")
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(5).repeatForever())
.build();
//job2
JobDetail job1 = JobBuilder.newJob(HelloJob2.class)
.withIdentity("dummyJobName1", "group1").build();
Trigger trigger1 = TriggerBuilder
.newTrigger()
.withIdentity("dummyTriggerName1", "group1")
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(5).repeatForever())
.build();
// schedule it
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
scheduler.scheduleJob(job, trigger);
//scheduler.scheduleJob(job1, trigger1);
}
}

Java pass Object to Quartzjob ( Quartz 2 )

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");

Injected values in Quartz Job are null in play framework 2.5

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();
}
}

Veto execution if job is already executing

I want to skip a job execution if another instance of the same job is already executing (if the same "JobDetail" is running). I know the annotation "#DisallowConcurrentExecution" avoid concurrent execution of the same job. But the downside is that when the job (a job that executes is a longer time then the periodicity of the trigger) finishes the job will be instantly re-executed. I want the job to be executed in the next schedule fire time.
Example
Job Implementation
public class LongJob implements Job {
#Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
try {
System.out.println("Executed: " + LocalDateTime.now().toString());
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Scheduling
JobDetail job2 = JobBuilder.newJob(LongJob.class)
.withIdentity("job2")
.build();
Trigger trigger2 = TriggerBuilder.newTrigger()
.forJob(job2)
.startNow()
.withIdentity("job2-trigger")
.withSchedule(
CronScheduleBuilder.cronSchedule("0/3 * * ? * *")
.withMisfireHandlingInstructionIgnoreMisfires())
.build();
scheduler.scheduleJob(job2, trigger2);
Expected output
Executed: 2016-02-18T10:11:15
Executed: 2016-02-18T10:11:21
Executed: 2016-02-18T10:11:27
Executed: 2016-02-18T10:11:33
Output using #DisallowConcurrentExecution
Executed: 2016-02-18T10:11:15
Executed: 2016-02-18T10:11:20
Executed: 2016-02-18T10:11:25
Executed: 2016-02-18T10:11:30
My Solution
I made a solution using Trigger Listeners, But I was wondering if there is a simpler one. In this approach I would have use a Listener Instance for each group of Trigger that fires the same job (I can solve my "bigger" problem using different trigger for different, avoiding the use of the same trigger for different jobs).
class CustomTriggerListener extends TriggerListenerSupport {
private JobExecutionContext lastJobExecutionContext;
#Override
public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) {
boolean vetoExecution = false;
if (lastJobExecutionContext == null) {
lastJobExecutionContext = context;
} else {
boolean lastJobIsDone = lastJobExecutionContext.getJobRunTime() >= 0;
if (lastJobIsDone) {
lastJobExecutionContext = context;
} else {
vetoExecution = true;
}
}
return vetoExecution;
}
#Override
public String getName() {
return "CustomTriggerListener";
}
}

Categories