Hi this is my Cron Scheduler
public class CronListener implements ServletContextListener {
Scheduler scheduler = null;
#Override
public void contextInitialized(ServletContextEvent servletContext) {
System.out.println("Context Initialized");
try {
// Setup the Job class and the Job group
JobDetail job = newJob(CronJob.class).withIdentity("CronQuartzJob",
"Webapp").build();
// This is what I've tried as well
/*
* JobDataMap jdm = new JobDataMap(); jdm.put("targetDAO",
* targetDAO);
*/
// Create a Trigger that fires every X minutes.
Trigger trigger = newTrigger()
.withIdentity("CronQuartzJob", "Sauver")
.withSchedule(
CronScheduleBuilder.cronSchedule
("0 0/1 * 1/1 * ? *")).build();
// Setup the Job and Trigger with Scheduler & schedule jobs
scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
scheduler.scheduleJob(job, trigger);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
#Override
public void contextDestroyed(ServletContextEvent servletContext) {
System.out.println("Context Destroyed");
try {
scheduler.shutdown();
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
And here's the Cron Job itself
public class CronJob implements org.quartz.Job {
static Logger log = Logger.getLogger(CronJob.class.getName());
#Autowired
TargetDAO targetDAO;
#Override
public void execute(JobExecutionContext context)
throws JobExecutionException {
try {
targetDAO.getAllTargets();
} catch (Exception e1) {
e1.printStackTrace();
}
log.info("webapp-rest cron job started");
try {
Utils.getProcessed();
} catch (Exception e) {
e.printStackTrace();
}
}
What I'm trying to do is getting a DAO class to call some data into it and call a function through it, every few hours.
But when I call data through the DAO, it always returns empty.
What I've found is that I must map the DAO somehow, I've seen in xml-based cron jobs, but I am unable to map it in this one.
This not exactly an answer, but a workaround,
What I did was made a new class
#EnableScheduling
#Component
public class SpringCronJob {
private static Logger log = Logger.getLogger(SpringCronJob.class.getName());
#Autowired
TargetDAO targetDAO;
#Scheduled(fixedRate = 15000)
public void getPostedTargets() {
try {
log.info(targetDAO.getAllTargets());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
It doesn't need anything else, no scheduler, you just need to add it to your component scan
This is what lead me to it
http://howtodoinjava.com/spring/spring-core/4-ways-to-schedule-tasks-in-spring-3-scheduled-example/
Related
When the user calls the api /bet/{id}/start, the Schedule will immediately be created with name = id, group = Exchanges, every 3rd second on the minute it will automatically call the excute function to process, for example here I will call the findById(id) function of the repository to retrieve and process the data, but the result I get is java.lang.NullPointerException: null
BetController.java
#RestController
#RequestMapping("/api")
#Transactional
public class BetController extends AbstractController {
private MainScheduler mainScheduler;
#RequestMapping(value = "/bet/{id}/start", method = RequestMethod.POST)
public String addAndStartScheduleWithBetId(#PathVariable("id") Long id) {
mainScheduler.addAndStartScheduler(""+id);
return "";
}
}
MainScheduler.java
#Service
public class MainScheduler {
private Scheduler scheduler;
public MainScheduler(Scheduler scheduler) {
this.scheduler = scheduler;
}
public Scheduler addAndStartScheduler(String betId) {
try {
Trigger trigger = TriggerBuilder.newTrigger().withIdentity(betId,"Exchanges").withSchedule(CronScheduleBuilder.cronSchedule("3 * * ? * * *")).build();
JobDetail jobDetail = JobBuilder.newJob(ScheduleJob.class).withIdentity(betId, "Exchanges") .build();
scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
scheduler.scheduleJob(jobDetail, trigger);
System.out.println(jobDetail.getKey() + ","+ trigger.getKey() + " will run at: " + new Date());
} catch(Exception ex) {
System.out.println(ex);
}
return scheduler;
}
public boolean deleteJobDetail(String name) {
boolean flag = false;
try {
flag = scheduler.deleteJob(jobKey(name, "Exchanges"));
} catch (SchedulerException e) {
e.printStackTrace();
}
return flag;
}
}
BetRepository.java
public interface BetRepository extends CrudRepository<Bet, Long> {
Page<Bet> findAll(Pageable pageable);
Optional<Bet> findById(Long id) ;
}
ScheduleJob.java
public class ScheduleJob implements Job{
#Autowired
private BetRepository betRepository;
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// TODO Auto-generated method stub
System.out.println("key+group trigger: " + context.getTrigger().getKey());
Long id = Long.parseLong(context.getJobDetail().getKey().getName());
System.out.println("Bet repositorys: " + betRepository.findById(id));
}
}
13-07-2021 03:33:03.015 [35m[DefaultQuartzScheduler_Worker-3][0;39m
[1;31mERROR[0;39m
org.quartz.core.ErrorLogger.schedulerError - Job (Exchanges.5 threw an exception.
org.quartz.SchedulerException: Job threw an unhandled exception.
at org.quartz.core.JobRunShell.run(JobRunShell.java:213)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)
Caused by: java.lang.NullPointerException: null
at com.bot.auto.utils.ScheduleJob.execute(ScheduleJob.java:21)
at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
... 1 common frames omitted
Modify your MainScheduler so that you get the autowired BetRepository and put it in the scheduler context before starting the schedular and get it in the Job.
#Service
public class MainScheduler {
private Scheduler scheduler;
#Autowired
private BetRepository betRepository;
public MainScheduler(Scheduler scheduler) {
this.scheduler = scheduler;
}
public Scheduler addAndStartScheduler(String betId) {
try {
Trigger trigger = TriggerBuilder.newTrigger().withIdentity(betId,"Exchanges").withSchedule(CronScheduleBuilder.cronSchedule("3 * * ? * * *")).build();
JobDetail jobDetail = JobBuilder.newJob(ScheduleJob.class).withIdentity(betId, "Exchanges") .build();
scheduler = StdSchedulerFactory.getDefaultScheduler();
schduler.getContext().put("betRepo",betRepository);
scheduler.start();
scheduler.scheduleJob(jobDetail, trigger);
System.out.println(jobDetail.getKey() + ","+ trigger.getKey() + " will run at: " + new Date());
} catch(Exception ex) {
System.out.println(ex);
}
return scheduler;
}
< -----other methods as is---->
}
Change your Job class as below
public class ScheduleJob implements Job{
private BetRepository betRepository;
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// TODO Auto-generated method stub
betRepository= context.get("betRepo"); or context.getScheduler().getContext().get("betRepo");
System.out.println("key+group trigger: " + context.getTrigger().getKey());
Long id = Long.parseLong(context.getJobDetail().getKey().getName());
System.out.println("Bet repositorys: " + betRepository.findById(id));
}
}
I have implement jms with spring boot, I am using #JmsListener to listen the topic
#Component
public class AMQListner {
BlockingQueue<MessageBO> queue = new ArrayBlockingQueue<>(1024);
#JmsListener(destination = "${spring.activemq.topic}")
public void Consume(TextMessage message) {
try {
String json = message.getText();
MessageBO bo = ObjectMapperConfig.getInstance().readValue(json, MessageBO.class);
queue.add(bo);
} catch (JMSException e) {
e.printStackTrace();
} catch (JsonParseException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Now I want a listener that listen that blocking-queue, if it has value , then process. can we achieve this using annotation in spring boot ?
First of all, the proper way is to create a handler bean instead of having a member with the message queue in the receiver class.
public interface MessageHandler extends Consumer<MessageBO> {
public default void handle(MessageBO msg) { accept(msg); }
}
#Component
public class AMQListener {
#Resource("multiplexer")
MessageHandler handler;
#JmsListener(destination = "${spring.activemq.topic}")
public void Consume(TextMessage message) {
try {
String json = message.getText();
MessageBO bo = ObjectMapperConfig.getInstance().readValue(json, MessageBO.class);
handler.handle(bo);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Then, you would have the queue in the handler bean
#Component("multiplexer")
public class MessageMultiplexer implements MessageHandler {
#Autowired
MessageHandler actualConsumer;
ExecutorService executor = Executors.newFixedThreadPool(4);
public void accept(MessageBO msg) {
executor.submit(msg -> actualConsumer.handle(msg));
}
}
The Executor is pretty much the queue in this case.
Caveat: you do not have your 1024 limit in this way. You can do that by using the ThreadPoolExecutor constructor and pass it a limited queue.
We are running one schedule using Quartz and getting the updated data from table in the executeinternal method, but how to access that java object from main method.
Here is the code:
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
JobDetail jobDetail = new JobDetail("SlaTime", "SlaTimeGroup",
SlaUptimeImpl.class);
CronTrigger cronTrigger = new CronTrigger("SlaTrigger", "SlaGroup",
"0/10 * 0-23 ? * *");
scheduler.scheduleJob(jobDetail, cronTrigger);
scheduler.start();
} catch (SchedulerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Here we are executing the query in this SlaUptimeImpl class but not able to get the return data here because am executing the query in ExecuteInternal Method which have return type as void.
anyone help me in this issue.
Thanks in advance,
Mahesh
You can provide a data map to your job, thanks to JobBuilder#usingDataMap(). I think you could put an "observer" into this map, retrieve the observer at job execution, and notify it about the result.
While scheduling your job:
JobDataMap map = new JobDataMap();
map.put("myObserver", new MyObserver());
JobDetail jobDetail = JobBuilder.newJob(SlaUptimeImpl.class).withIdentity("SlaTime", "SlaTimeGroup").usingJobData(map).build();
And in your job:
public void execute(final JobExecutionContext context) throws JobExecutionException {
...
((MyObserver) context.getJobDetail().getJobDataMap().get("myObserver")).notify(result);
}
we wanted to watch a file periodically for changes, we are using jboss 7 . Following is my code snippet. I initialized the watcher in the postconstruct method of singleton bean and scheduled a method to poll watch events. I could observe the changes when i modify the file very first time, however the subsequent modifications to the file are not recieved . Can anyone please let me know what could be the issue
#Startup
#ConcurrencyManagement(ConcurrencyManagementType.BEAN)
#Interceptors(NonThrowingPostConstructInterceptor.class)
#Singleton
#Service
#LocalBinding(jndiBinding=IHeartBeatProducerService.JNDI_LOCAL_BINDING)
public class HeartBeatProducerService extends EMSingletonService implements IHeartBeatProducerService{
#EJB(mappedName=IMessageService.JNDI_LOCAL_BINDING)
public IMessageService messageService;
#EJB(mappedName=ICommandExecutionService.JNDI_LOCAL_BINDING)
public ICommandExecutionService commandService;
private final static String LAST_OPERATION_COMPLETED="Last Operation Completed";
private final static String STATUS="Status";
private WatchService watcher;
private Path dir;
private String concServer;
public static final String TOPIC="foo";
private IMLogger logger = new IMLogger("foo");
private String content=null;
#PostConstruct
#Override
public void init() {
// TODO Auto-generated method stub
super.init();
try {
watcher = FileSystems.getDefault().newWatchService();
dir=Paths.get("/shared/foo");
dir.register(watcher, StandardWatchEventKinds.ENTRY_MODIFY);
logger.entering(0, IHeartBeatProducerService.class.getSimpleName(), "Initializing Heart Beat", new String[]{"Entered"});
} catch (IOException e) {
e.printStackTrace();
}
}
#Schedule(second="*/10", minute = "*", hour="*")
private void checkStatus()
{
logger.entering(0, IHeartBeatProducerService.class.getSimpleName(), "Checking Status", new String[]{"Entered"});
final String[] command={"pidof","server"};
commandService.run(command, null, false);
concServer=(commandService.getExitCode()==0)?"UP":"DOWN";
if(concServer.equals("UP"))
{
watch();
}
else
{
content="foo:Failed";
}
produce();
}
public void watch()
{
logger.entering(0, IHeartBeatProducerService.class.getSimpleName(), "Entering watch()", new String[]{"Entered"});
WatchKey key = null;
try
{
key = watcher.take();
}
catch (InterruptedException e)
{
logger.error(HeartBeatProducerService.class.getSimpleName(),"Interupted Exception " + e.getMessage());
}
for ( WatchEvent<?> event: key.pollEvents())
{
WatchEvent.Kind kind = event.kind();
logger.info(HeartBeatProducerService.class.getSimpleName(),"Watch Event :" + kind.name());
if(kind.name().equals("OVERFLOW"))
{
continue;
}
if(kind.name().equals("ENTRY_MODIFY"))
{
Path concLog = (Path) event.context();
logger.info(HeartBeatProducerService.class.getSimpleName(),"Modified File Name:" + concLog.getFileName());
if(concLog.endsWith("current_status.txt"))
{
logger.info(HeartBeatProducerService.class.getSimpleName(), "Reading Status");
readStatus();
}
}
}
boolean valid = key.reset();
if ( !valid)
{
logger.error(HeartBeatProducerService.class.getSimpleName(),"Key Unregistered");
}
}
private void parse(String output)
{
// parse file contents
}
private void readStatus() {
//read status and parse()
}
private void produce()
{
try {
messageService.publish(TOPIC, content, PublishType.ASync);
} catch (MessageException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
There is already a link explaining the same with #Asynchronous tag (EJB 3.1 and NIO2: Monitoring the file system) . however I need to know what could be wrong in this approach.
Your watch method needs to run in an infinite loop. What's happening now is that after
try {
key = watcher.take();
}
you process the event and then the watch() method is finished. Try the effect of
for(;;) {
before the above lines, ending the for block after the validity check. Did you see the example at The Java Tutorials?
I'd like to use quartz for a project, but it seems to be missing some functionality. What I need is very simple, to fire another job after one finishes execution. This ideally would be done with a stored trigger, but quartz only considers time-based triggers, and no other kind. I'm looking for some kind of a job dependency system for quartz.
In reality there should be lots of triggers, such as other jobs finishing, files being modified, database tables being updated, etc.
Here's a job that waits for 5 seconds:
public class JobA implements Job, JobListener {
public static final String LISTENER_NAME = "JobA";
public void execute(JobExecutionContext arg0) throws JobExecutionException {
System.out.println("Job A, Waiting for 5 seconds");
try {
Thread.sleep(5L * 1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Done waiting");
}
public String getName() {
return LISTENER_NAME;
}
public void jobExecutionVetoed(JobExecutionContext context) {
//TODO
}
public void jobToBeExecuted(JobExecutionContext context) {
String jobName = context.getJobDetail().getKey().toString();
System.out.println("Job : " + jobName + " is going to start...");
}
public void jobWasExecuted(JobExecutionContext context,
JobExecutionException jobException) {
// System.out.println("jobWasExecuted");
String jobName = context.getJobDetail().getKey().toString();
System.out.println("Job : " + jobName + " is finished...");
if (!jobException.getMessage().equals("")) {
System.out.println("Exception thrown by: " + jobName
+ " Exception: " + jobException.getMessage());
}
JobKey jobKey = new JobKey("JobA", "group1");
try {
context.getScheduler().triggerJob(jobKey);
} catch (SchedulerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The context.getScheduler().triggerJob(jobKey) line simply doesn't work. I've tried adding full jobs, recursive jobs, and can't seem to get anything to work. How can I get another job to fire while using this listener?