According to Quratz documentation2.x Here
If you add setter methods to your job class that correspond to the names of keys in the JobDataMap (such as a setJobSays(String val) method for the data in the example above), then Quartz’s default JobFactory implementation will automatically call those setters when the job is instantiated, thus preventing the need to explicitly get the values out of the map within your execute method.
Now in my case the setters are not automatically called although my all values are primitives. Also in execute method i am able to get values from jobDataMap.
i am using Quartz 2.2.1 and here is my sample code.what should i do ? thanks in advance.
Here is my Job class.
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.PersistJobDataAfterExecution;
#PersistJobDataAfterExecution
#DisallowConcurrentExecution
public class Db2Db implements Job {
public static final String SOURCE_HOST = "sourceHost";
public static final String DESTINATION_HOST = "destinationHost";
protected String sourceHost;
protected String destinationHost;
public Db2Db() {
System.out.println("created object of job");
}
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
//sourceHost is still null
system.out.println(sourceHost);
}
public void setSourceHost(String sourceHost) {
this.sourceHost = sourceHost;
}
public void setDestinationHost(String destinationHost) {
this.destinationHost= destinationHost;
}
}
and Here is my main method
public class JobDriver {
public static void main(String[] args) throws SchedulerException {
/*Starting quartz server remotely*/
QuartzServer server = QuartzServer.getInstance();
server.start();
JobDetail job = newJob(Db2Db.class)
.usingJobData(SOURCE_HOST, "132.168.0.12")
.usingJobData(DESTINATION_HOST, "localhost")
.withIdentity("DailyRead91", "group1")
.build();
Trigger trigger = newTrigger().withIdentity("DailyTrigger91", "group1").startNow()
.withSchedule(simpleSchedule().withIntervalInSeconds(10).repeatForever()).build();
//Quartz Server Properties
Properties prop = new Properties();
prop.put("org.quartz.scheduler.rmi.proxy", "true");
prop.put("org.quartz.scheduler.rmi.registryHost", "localhost");
prop.put("org.quartz.scheduler.rmi.registryPort", "1099");
prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
prop.put("org.quartz.threadPool.threadCount", "10");
Scheduler scheduler = new StdSchedulerFactory(prop).getScheduler();
scheduler.scheduleJob(job, trigger);
}
}
Related
I want to create a daily background job to be executed by AEM.
I read an aem document and apache sling official site, and I thought I need two classes.
a service class that register the job to JobManager.
a consumer class that do the job.
So I tried these code, but my job was not executed.
service class
import org.apache.sling.event.jobs.JobManager;
import org.apache.sling.event.jobs.JobBuilder.ScheduleBuilder;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#Component
public class MyJobService {
private static final Logger logger = LoggerFactory.getLogger(MyJobService.class);
#Reference
private JobManager jobManager;
public static final String JOB_TOPIC = "my/sample/jobtopic";
public void startScheduledJob() {
ScheduleBuilder scheduleBuilder = jobManager.createJob(JOB_TOPIC).schedule();
scheduleBuilder.hourly(9, 0); // execute daily at AM9:00
if (scheduleBuilder.add() == null) {
logger.error("myjobservice error");
}
}
}
job consumer class
import org.apache.sling.event.jobs.Job;
import org.apache.sling.event.jobs.consumer.JobConsumer;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#Component(
immediate = true,
service = JobConsumer.class,
property = {
JobConsumer.PROPERTY_TOPICS + "=my/sample/jobtopic"
}
)
public class MyJobConsumer implements JobConsumer {
private static final Logger logger = LoggerFactory.getLogger(MyJobConsumer.class);
#Override
public JobResult process(Job job) {
String topic = job.getTopic();
logger.info("this message is from myjobconsumer. topic is " + topic);
return JobResult.OK;
}
}
Do I need another class or some configurations? Does My code have something wrong?
If you annotate a method with #Activate it will be called when the component starts.
#Activate
public void startScheduledJob()
I guess you want your job to run on startup.
Another option would be to let MyJobService be a servlet and call it from outside.
I'm creating a simple cron job that run a task in a specific time (for example 3AM) with Play Framework 2.6.x.
But now I'm stucking in a simple schedule task:
I created an Actor:
package actors;
import akka.actor.UntypedActor;
import org.slf4j.LoggerFactory;
public class DoSomethingActor extends UntypedActor {
private static final org.slf4j.Logger log = LoggerFactory.getLogger(DoSomethingActor.class);
#Override
public void onReceive(final Object message) throws Throwable {
log.info("Write your crone task or simply call your method here that perform your task " + message);
}
}
Then I created a Schedule class that call Actor each time I've set:
package tasks;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Cancellable;
import scala.concurrent.duration.Duration;
#Singleton
public class DoSomethingScheduler {
#Inject
public DoSomethingScheduler(final ActorSystem system,
#Named("do-something-actor") final ActorRef doSomethingActor) {
final Cancellable scheduler;
final int timeDelayFromAppStart = 0;
final int timeGapInSeconds = 1; //Here you provide the time delay for every run
system.scheduler().schedule(
Duration.create(timeDelayFromAppStart, TimeUnit.MILLISECONDS), //Initial delay when system start
Duration.create(timeGapInSeconds, TimeUnit.SECONDS), //Frequency delay for next run
doSomethingActor,
"message for onreceive method of doSomethingActor",
system.dispatcher(),
null);
}
}
Finally, I bind these class in a Module class:
package modules;
import actors.DoSomethingActor;
import com.google.inject.AbstractModule;
import play.libs.akka.AkkaGuiceSupport;
import tasks.DoSomethingScheduler;
public class SchedulerModule extends AbstractModule implements AkkaGuiceSupport{
#Override
protected void configure() {
this.bindActor(DoSomethingActor.class, "do-something-actor");
this.bind(DoSomethingScheduler.class).asEagerSingleton();
}
}
After these things, I run the application but it doesn't work as I expected. I expected it shows a logging every 1 SECOND but there is nothing happen.
Could you please help me to fix it?
Thank you so much!
The solution is in dev mode, I have to send a HTTP request to the application to load the module. In production mode, they will be loaded immediately.
I am using Micronaut as framework for developing an AWS Java Lambda.
Micronaut supports #Value for reading, well, "values".
#io.micronaut.context.annotation.Factory
public class SomeFactory {
public SomeFactory(
#io.micronaut.context.annotation.Value("${NameOfValue}")
final String value) {
...
}
...
}
When testing, I want to set "NameOfValue" to a specific value, how can I do that?
#io.micronaut.test.annotation.MicronautTest
class SomeLambdaIT {
#org.junit.jupiter.api.Test
void aTest() {
// When this test runs, "NameOfValue" shall be set to a specific value
}
}
When testing, I want to set "NameOfValue" to a specific value, how can
I do that?
You have a number of options.
One option is to define src/test/resources/application-test.yml and define the config setting there. That file will only be loaded in the test environment and any settings defined in that file will supersede values defined in src/main/resources/application.yml.
Another option that might make sense if you only want the special setting in play for this particular test is you can do something like this...
import io.micronaut.test.annotation.MicronautTest;
import org.junit.jupiter.api.Test;
#MicronautTest(propertySources = "classpath:some-special-test-props.properties")
public class SomeTest {
#Test
void someTest() {
// ...
}
}
Then define src/test/resources/some-special-test-props.properties and assign the value there.
Yet another option is to mark your test with #Property:
import io.micronaut.context.annotation.Property;
import io.micronaut.test.annotation.MicronautTest;
import org.junit.jupiter.api.Test;
#MicronautTest
#Property(name="some.config.value", value = "My Test Value")
public class SomeTest {
#Test
void someTest() {
// ...
}
}
I hope that helps.
EDIT
A comment below includes "I did give it a try, but the #Property solution nor the some-special-test-props.properties works in my case.". I have created a sample app demonstrating each of these techniques. See the project at https://github.com/jeffbrown/markusschultevalue.
https://github.com/jeffbrown/markusschultevalue/blob/8131e96492356180e2c7fade09603bd41f8c8829/src/main/java/markusschultevalue/SomeWidget.java
package markusschultevalue;
public class SomeWidget {
private final String name;
public SomeWidget(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
https://github.com/jeffbrown/markusschultevalue/blob/master/src/main/java/markusschultevalue/SomeFactory.java
package markusschultevalue;
import io.micronaut.context.annotation.Bean;
import io.micronaut.context.annotation.Factory;
import io.micronaut.context.annotation.Value;
#Factory
public class SomeFactory {
private final String name;
// there are better ways to do this but
// this is consistent with the code in the
// question being asked...
public SomeFactory(#Value("${some.config.value}") String name) {
this.name = name;
}
#Bean
public SomeWidget createWidget() {
return new SomeWidget(name);
}
}
https://github.com/jeffbrown/markusschultevalue/blob/8131e96492356180e2c7fade09603bd41f8c8829/src/test/java/markusschultevalue/PropertyAnnotationTest.java
package markusschultevalue;
import io.micronaut.context.annotation.Property;
import io.micronaut.test.annotation.MicronautTest;
import org.junit.jupiter.api.Test;
import javax.inject.Inject;
import static org.junit.jupiter.api.Assertions.assertEquals;
#MicronautTest
#Property(name="some.config.value", value="Some Widget Name")
public class PropertyAnnotationTest {
#Inject
SomeWidget someWidget;
#Test
void testWidget() {
assertEquals("Some Widget Name", someWidget.getName());
}
}
https://github.com/jeffbrown/markusschultevalue/blob/8131e96492356180e2c7fade09603bd41f8c8829/src/test/java/markusschultevalue/ConfigFileTest.java
package markusschultevalue;
import io.micronaut.test.annotation.MicronautTest;
import org.junit.jupiter.api.Test;
import javax.inject.Inject;
import static org.junit.jupiter.api.Assertions.assertEquals;
// This will load the config value
// from src/test/resources/some-widget-test-config.yml
#MicronautTest(propertySources = "classpath:some-widget-test-config.yml")
public class ConfigFileTest {
#Inject
SomeWidget someWidget;
#Test
void testWidget() {
assertEquals("Some Other Widget Name", someWidget.getName());
}
}
https://github.com/jeffbrown/markusschultevalue/blob/8131e96492356180e2c7fade09603bd41f8c8829/src/test/resources/some-widget-test-config.yml
some:
config:
value: Some Other Widget Name
Note that in your example you are referencing a config variable with "${NameOfValue}". If that is actually the name of your config variable, note that in code you need to reference that in valid kebab-case which would be "${name-of-value}".
I hope that helps.
I have an ItemProcessor which has a #BeforeStep method to access the ExecutionContext:
public class MegaProcessor implements ItemProcessor<String, String> {
private ExecutionContext context;
#BeforeStep
void getExecutionContext(final StepExecution stepExecution) {
this.context = stepExecution.getExecutionContext();
}
#Override
public String process(final String string) throws Exception {
// ...
}
}
The unit test for this class:
#ContextConfiguration(classes = MegaProcessor.class)
#TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, StepScopeTestExecutionListener.class })
#RunWith(SpringRunner.class)
public class MegaProcessorTest {
#Autowired
private MegaProcessor sut;
public StepExecution getStepExecution() {
StepExecution execution = MetaDataInstanceFactory.createStepExecution();
execution.getExecutionContext().put("data", "yeah");
return execution;
}
#Test
public void MegaProcessor() throws Exception {
assertNotNull(sut.process("pew pew"));
}
}
When I debug the test run, context is null and the #BeforeStep method is never called. Why is that and how to achieve that?
Why is that
If you want to use the StepScopeTestExecutionListener, the tested component should be step-scoped (See Javadoc). It's not the case in your example. But this is not the real issue. The real issue is that the method annotated with #BeforeStep will be called before the step in which your processor is registered is executed. In your test case, there is no step running so the method is never called.
how to achieve that?
Since it is a unit test, you can assume the step execution will be passed to your item processor by Spring Batch before running the step and mock/stub it in your unit test. This is how I would unit test the component:
import org.junit.Before;
import org.junit.Test;
import org.springframework.batch.core.StepExecution;
import static org.junit.Assert.assertNotNull;
public class MegaProcessorTest {
private MegaProcessor sut;
#Before
public void setUp() {
StepExecution execution = MetaDataInstanceFactory.createStepExecution();
execution.getExecutionContext().put("data", "yeah");
sut = new MegaProcessor();
sut.getExecutionContext(execution); // I would rename getExecutionContext to setExecutionContext
}
#Test
public void MegaProcessor() throws Exception {
assertNotNull(sut.process("pew pew"));
}
}
The StepScopeTestExecutionListener is handy when you have step-scoped components that use late-binding to get values from the step execution context. For example:
#Bean
#StepScope
public ItemReader<String> itemReader(#Value("#{stepExecutionContext['items']}") String[] items) {
return new ListItemReader<>(Arrays.asList(items));
}
A unit test of this reader would be something like:
import java.util.Arrays;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
#ContextConfiguration(classes = StepScopeExecutionListenerSampleTest.MyApplicationContext.class)
#TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, StepScopeTestExecutionListener.class })
#RunWith(SpringRunner.class)
public class StepScopeExecutionListenerSampleTest {
#Autowired
private ItemReader<String> sut;
public StepExecution getStepExecution() {
StepExecution execution = MetaDataInstanceFactory.createStepExecution();
execution.getExecutionContext().put("items", new String[] {"foo", "bar"});
return execution;
}
#Test
public void testItemReader() throws Exception {
Assert.assertEquals("foo", sut.read());
Assert.assertEquals("bar", sut.read());
Assert.assertNull(sut.read());
}
#Configuration
static class MyApplicationContext {
#Bean
#StepScope
public ItemReader<String> itemReader(#Value("#{stepExecutionContext['items']}") String[] items) {
return new ListItemReader<>(Arrays.asList(items));
}
/*
* Either declare the step scope like the following or annotate the class
* with `#EnableBatchProcessing` and the step scope will be added automatically
*/
#Bean
public static org.springframework.batch.core.scope.StepScope stepScope() {
org.springframework.batch.core.scope.StepScope stepScope = new org.springframework.batch.core.scope.StepScope();
stepScope.setAutoProxy(false);
return stepScope;
}
}
}
Hope this helps.
package org.quartz;
import org.quartz.Scheduler;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Trigger;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.SchedulerException;
import org.quartz.impl.StdSchedulerFactory;
import static org.quartz.JobBuilder.*;
import static org.quartz.TriggerBuilder.*;
import static org.quartz.SimpleScheduleBuilder.*;
import static org.quartz.CronScheduleBuilder.*;
import static org.quartz.CalendarIntervalScheduleBuilder.*;
import static org.quartz.DateBuilder.*;
class myJob implements Job {
public void execute(JobExecutionContext context)
throws JobExecutionException
{
System.out.println("Hello! HelloJob is executing.");
}
}
public class schedule{
public static void main(String args[]) throws Exception{
System.out.println("Java working");
try {
// Grab the Scheduler instance from the Factory
JobKey jobKeyA = new JobKey("myJob", "group1");
JobDetail jobA = JobBuilder.newJob(myJob.class)
.withIdentity(jobKeyA).build();
// Trigger the job to run now, and then every 40 seconds
Trigger trigger1 = TriggerBuilder
.newTrigger()
.withIdentity("dummyTriggerName1", "group1")
.withSchedule(
CronScheduleBuilder.cronSchedule("0/5 * * * * ?"))
.build();
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
// and start it off
scheduler.start();
// Tell quartz to schedule the job using our trigger
scheduler.scheduleJob(jobA, trigger1);
} catch (SchedulerException se) {
se.printStackTrace();
}
}
}
And I am getting an error of instantiating job and then obviously All triggers of Job set to ERROR state.
What is the reason?
and please help it is very important.
provide me the answer.
Error
[ERROR] 28 Dec 03:03:30.008 PM
DefaultQuartzScheduler_QuartzSchedulerThread
[org.quartz.core.ErrorLogger]
An error occured instantiating job to be executed. job= 'group1.myJob'
org.quartz.SchedulerException: Problem instantiating class
'org.quartz.myJob' [See nested exception:
java.lang.IllegalAccessException: Class
org.quartz.simpl.SimpleJobFactory can not access a member of class
org.quartz.myJob with modifiers ""]
at org.quartz.simpl.SimpleJobFactory.newJob(SimpleJobFactory.java:58)
at org.quartz.simpl.PropertySettingJobFactory.newJob(PropertySettingJobFactory.java:69)
at org.quartz.core.JobRunShell.initialize(JobRunShell.java:127)
at org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java:375)
Caused by: java.lang.IllegalAccessException: Class
org.quartz.simpl.SimpleJobFactory can not access a member of class
org.quartz.myJob with modifiers ""
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
at java.lang.Class.newInstance(Class.java:436)
at org.quartz.simpl.SimpleJobFactory.newJob(SimpleJobFactory.java:56)
... 3 more [INFO] 28 Dec 03:03:30.013 PM
DefaultQuartzScheduler_QuartzSchedulerThread
[org.quartz.simpl.RAMJobStore]
All triggers of Job group1.myJob set to ERROR state.
Your job class has to be public. Otherwise, the JobBuilder can not read it.
public class myJob implements Job {
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("Hello! HelloJob is executing.");
}
}
Class should be public class
Default constructor should be public
Improvement on top of the solution above. The class can be marked with static keyword to improve the efficiency. The job will be created each time when the scheduled slot occured.
public static class MyJob implements Job {
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("My job is called");
}
}