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