NullPointerException while deploying Quartz Scheduler with spring on Tomcat - spring

I am trying to use Quartz 2.2.0 with spring 3.2.x, using ServletContextListener for listening FileChangeListener class.Is My importManagerService object is null? Any suggestions? Not getting how to resolve it
Error While deploying
INFO [2013-10-04 15:13:16.009] [localhost-startStop-1]: org.springframework.web.context.ContextLoader - Root WebApplicationContext: initialization started
ERROR [2013-10-04 15:13:16.061] [DefaultQuartzScheduler_Worker-1]: org.quartz.core.JobRunShell - Job g1.t1 threw an unhandled Exception:
java.lang.NullPointerException at
com.demo.portal.web.importExportFile.ScheduleImportFile.execute(ScheduleImportFile.java:40)
at org.quartz.core.JobRunShell.run(JobRunShell.java:207)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:560)
ERROR [2013-10-04 15:13:16.065] [DefaultQuartzScheduler_Worker-1]: org.quartz.core.ErrorLogger - Job (g1.t1 threw an exception.
org.quartz.SchedulerException: Job threw an unhandled exception. [See nested exception: java.lang.NullPointerException]
at org.quartz.core.JobRunShell.run(JobRunShell.java:218)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:560)
Caused by: java.lang.NullPointerException
at com.happiestminds.portal.web.importExportFile.ScheduleImportFile.execute(ScheduleImportFile.java:40)
at org.quartz.core.JobRunShell.run(JobRunShell.java:207)
... 1 more
FileChangeListener
public class FileChangeListener implements ServletContextListener {
private static final Logger logger = Logger.getLogger(FileChangeListener.class);
#Override
public void contextDestroyed(ServletContextEvent arg0) {
System.out.println("Stopping Application successfully");
}
#Override
public void contextInitialized(ServletContextEvent arg0) {
logger.info("Initializing Application successfully..........");
JobDetail job = JobBuilder.newJob(ScheduleImportFile.class).withIdentity("t1", "g1").build();
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "g1").startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(60).repeatForever()).forJob("t1", "g1").build();
SchedulerFactory schFactory = new StdSchedulerFactory();
Scheduler sch;
try {
sch = schFactory.getScheduler();
sch.start();
sch.scheduleJob(job, trigger);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
ScheduleImportFile
**public class ScheduleImportFile implements Job{
#Autowired
ImportManagerService importManagerService;
#Override
public void execute(JobExecutionContext arg0) throws JobExecutionException {
//some logic for reading and parsing files
Line no. 40
Map<String, List<File>> fileToBeProcessMap = importManagerService.getFilesInfo(config);
Config is object of Configuration class
}**
Web.xml
<listener>
<listener-class>com.demo.portal.web.importExportFile.FileChangeListener</listener-class>
</listener>

As you identified, We can not auto wire of Spring beans inside Quartz job as Spring Bean's life cycle is forbidden in side a job class.
But we can get those spring beans through a simple way without loading Spring bean xml again.
Here is it.
public class MyJob Implements Job
{
private MyBean myBean;
#Override
public void execute(JobExecutionContext context) throws JobExecutionException
{
getBeansFromContext(context);
mybean.doSomeThing();
}
private void getBeansFromContext(JobExecutionContext context) throws SchedulerException
{
ApplicationContext applicationContext = (ApplicationContext)context.getScheduler().getContext().get("applicationContext");
this.mybean=applicationContext.getBean(MyBean.class);
}
}
You should have your schedulerFactoryBean configired in your beans.xml.
<beans:bean id="schedulerFactoryBean"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<beans:property name="jobFactory">
<beans:bean class="org.springframework.scheduling.quartz.SpringBeanJobFactory"></beans:bean>
</beans:property>
...
<beans:property name="applicationContextSchedulerContextKey"
value="applicationContext" /> -- Here is the guy!!
Hope this helps you.

Related

cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'MyTastTasklet'

I am developing Spring Boot Batch Example. In this example, I have created BatchJPA core module which has Entities, JPARepository and DB configurations.
This module adding into another Spring Module as dependency and in this module, I am adding code related specific batch jobs (like custom repository etc). I have total 15 batch jobs and I will be creating separate Spring Boot project with BatchJPA dependency.
10-08-2018 14:54:11.853 [main] WARN org.springframework.context.support.ClassPathXmlApplicationContext.refresh - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'MyTestTasklet': Initialization of bean failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'transactionManager' available
10-08-2018 14:54:11.855 [main] INFO org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener.logAutoConfigurationReport -
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
10-08-2018 14:54:11.919 [main] ERROR org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter.report -
***************************
APPLICATION FAILED TO START
***************************
Description:
A component required a bean named 'transactionManager' that could not be found.
Action:
Consider defining a bean named 'transactionManager' in your configuration.
Code below:
#Service
public class MyTaskTasklet implements Tasklet {
#Autowired
private MyCustomerCustomRepository myCustomerCustomRepository;
#Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
List<MyTest> mydata = myCustomerCustomRepository.getElligibleData();
if (!mydata.isEmpty()) {
System.out.println("XXXXXX = " + mydata.size());
}
chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext()
.put("listOfData", mydata);
return RepeatStatus.FINISHED;
}
}
Another file:
#Component
#EnableBatchProcessing
public class MyJobLauncher {
public void executeJob() {
String[] springConfig = { "jobs/ABC.xml"};
ApplicationContext context = new ClassPathXmlApplicationContext(springConfig);
JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher");
Job job = (Job) context.getBean("MyJobId");
try {
JobParameters jobParameters = new JobParametersBuilder().addString("runMode", "DATA")
.addDate("date", new Date()).addLong("time", System.currentTimeMillis()).toJobParameters();
jobLauncher.run(job, jobParameters);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
and another file
MainApplication
#SpringBootApplication
#EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class,HibernateJpaAutoConfiguration.class})
public class MainApplication implements CommandLineRunner {
#Autowired
private MyJobLauncher jobLauncher;
public static void main(String[] args) {
SpringApplication.run(MyJobLauncher.class, args);
}
#Override
public void run(String... args) throws Exception {
jobLauncher.executeJob();
}
}

Unable to schedule Quartz job

I have written a small Spring Boot service using Quartz. I am trying to schedule a job using the code below. However, I am repeatedly getting the following error:
ERROR[my-service] [2017-01-22 17:38:37,328] [] [main] [SpringApplication]: Application startup failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'schedulerFactoryBean' defined in class path resource [com/myservice/configuration/QuartzConfiguration.class]: Invocation of init method failed; nested exception is org.quartz.JobPersistenceException: Couldn't store trigger 'group1.trigger1' for 'group1.job1' job:The job (group1.job1) referenced by the trigger does not exist. [See nested exception: org.quartz.JobPersistenceException: The job (group1.job1) referenced by the trigger does not exist.]
Needless to say, the job never gets scheduled. Here is the relevant code:
#Slf4j
#NoArgsConstructor
public class TimedJob implements Job {
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
log.debug("**********timed job****************");
}
}
#Configuration
public class QuartzConfiguration {
...
#Inject
MyDao myDao;
#Bean
public SchedulerFactoryBean schedulerFactoryBean(ApplicationContext applicationContext) throws SchedulerException {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setAutoStartup(true);
factory.setOverwriteExistingJobs(true);
QuartzJobFactory jobFactory = new QuartzJobFactory();
jobFactory.setApplicationContext(applicationContext);
factory.setJobFactory(jobFactory);
factory.setDataSource(dataSource());
factory.setSchedulerContextAsMap(Collections.singletonMap("my_dao", myDao));
JobDetail jobDetail = JobBuilder.newJob()
.ofType(TimedJob.class)
.storeDurably()
.withDescription("desc")
.withIdentity("job1", "group1")
.build();
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.SECOND, 10);
Trigger trigger = TriggerBuilder
.newTrigger()
.startAt(calendar.getTime())
.withSchedule(
SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1).repeatForever()
)
.forJob(jobDetail)
.withIdentity("trigger1", "group1")
.build();
factory.setTriggers(trigger);
Properties quartzProperties = new Properties();
quartzProperties.setProperty("org.quartz.scheduler.instanceName", instanceName);
quartzProperties.setProperty("org.quartz.scheduler.instanceId", instanceId);
quartzProperties.setProperty("org.quartz.threadPool.threadCount", threadCount);
quartzProperties.setProperty("org.quartz.jobStore.driverDelegateClass", driverDelegateClassName);
factory.setQuartzProperties(quartzProperties);
factory.start();
return factory;
}
This is almost exactly copied from the Quartz tutorials here. What am I doing wrong?
I guess you need setting your jobDetail to your factory instance.
The below URL might help you.
http://www.baeldung.com/spring-quartz-schedule

Passing arguments from BatchJob to Tasklet in Spring Batch

To all Spring enthusiasts, here's a good challenge. Hope someone can crack it!!!
I use Spring to batch the extraction process. I have two classes 'ExtractBatchJob' and 'TaskletImpl'
public class ExtractBatchJob {
/** Logger for current class */
private static Log log = LogFactory.getLog(Extractor.class);
public static void main(String[] args)
throws IOrganizationServiceRetrieveMultipleOrganizationServiceFaultFaultFaultMessage,
IOException {
ApplicationContext context = new ClassPathXmlApplicationContext(
"/META-INF/cxf/batch-context.xml");
SpringBusFactory factory = new SpringBusFactory(context);
Bus bus = factory.createBus();
SpringBusFactory.setDefaultBus(bus);
IOrganizationService service = (IOrganizationService) factory
.getApplicationContext().getBean("service");
JobLauncher jobLauncher = (JobLauncher)context.getBean("jobLauncher");
Job job = (Job) context.getBean("firstBatchJob");
try {
JobExecution execution = jobLauncher.run(job, new JobParameters());
}catch (Exception e){
e.printStackTrace();
}
}
The second class TaskletImpl implements the Spring Tasklet interface.
public class TaskletImpl implements Tasklet {
/** Logger for current class */
private static Log log = LogFactory.getLog(CRMExtractor.class);
/* (non-Javadoc)
* #see org.springframework.batch.core.step.tasklet.Tasklet#execute(org.springframework.batch.core.StepContribution, org.springframework.batch.core.scope.context.ChunkContext)
*/
#Overridepublic RepeatStatus execute(StepContribution arg0, ChunkContext arg1)
throws Exception {
// TODO Auto-generated method stub
log.info("************ CRM Extraction Batch Job is executing!!! *******");
//QUESTION: To Extract Entity from third party
// web service need object reference for
//factory and service from ExtractBatchjob class
List<Entity> orderEntities = getEntities("orderQueryImpl", factory, service);
OrderDao orderDao = (OrderDao) factory.getApplicationContext()
.getBean("orderDao");
orderDao.batchInsert(orderEntities);*/
return RepeatStatus.FINISHED;
}
public static List<Entity> getEntities(String queryImpl, SpringBusFactory factory,
IOrganizationService service)
throws IOrganizationServiceRetrieveMultipleOrganizationServiceFaultFaultFaultMessage,
IOException {
QueryBuilder queryBuilder = (QueryBuilderTemplate) factory
.getApplicationContext().getBean(queryImpl);
QueryExpression queryExpr = queryBuilder.getQuery();
EntityCollection result = service
.retrieveMultiple(queryExpr);
return result.getEntities().getEntities();
}
}
Below is the snippet of the context file
`<import resource="cxf.xml" />
<bean id="firstBatch" class="com.abc.model.TaskletImpl" />
<batch:step id="firstBatchStepOne">
<batch:tasklet ref="firstBatch" />
</batch:step>
<batch:job id="firstBatchJob">
<batch:step id="stepOne" parent="firstBatchStepOne" />
</batch:job>`
My question is quite straightforward, how do I pass the two variables/objects 'service' and 'factory' to the TaskletImpl class from the ExtractBatchJob class.
The cleanest solution is to wire service and factory using Spring injection mechanism.
You have two solution:
Create SpringBusFactory as Spring bean and wire it into tasklet
Define a ContextBean (as singleton) for you job, create SpringBusFactory and set it as property of ContextBean; wire this bean to your tasklet
If you want to use object created outside Spring context (with new I meant) must be injected into Spring context.

Why would Spring autowire fail?

#Service
public class LogProcessorServiceImpl {
#Autowired
private static ApplicationConfigurationService applicationConfigurationService;
public static void processPageRequestsLogs() {
if(applicationConfigurationService==null) {
System.out.println("autowire failed");
}
I have the ApplicationConfigurationService service autowired like this all over the place and it works fine. The package of this class is being scanned so that's not the problem. It might be related to the way this particular method is called. I have a servlet that is loaded after all other servlets and it fires of a timer that executes the method above with 60 second delay. I assume all autowiring should be completed.
public class ProcessSchedulerServlet implements javax.servlet.Servlet {
Timer timer=new Timer();
#Override
public void init(ServletConfig arg0) throws ServletException {
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
LogProcessorServiceImpl.processPageRequestsLogs();
}
}, 60*1000, 120*1000);
}
Here's what happens as soon as I true to use ApplicationConfigurationService:
autowire failed
Exception in thread "Timer-1" java.lang.NullPointerException
at com.siteadmin.services.impl.LogProcessorServiceImpl.processPageRequestsLogs(LogProcessorServiceImpl.java:39)
at com.siteadmin.servlets.ProcessSchedulerServlet$1.run(ProcessSchedulerServlet.java:20)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
=== 2012-11-18 ============================================================
See also: How to go about Spring autowiring?
You can't autowire static fields in Spring, this is discussed here
As alternative, if your LogProcessorServiceresides in the root web application context, you can
autowire it with Spring WebApplicationContextUtils utility class.
public class ProcessSchedulerServlet implements javax.servlet.Servlet {
Timer timer=new Timer();
#Autowired
LogProcessorService logProcessorService;
#Override
public void init(ServletConfig arg0) throws ServletException {
WebApplicationContextUtils.getWebApplicationContext(arg0.getServletContext())
.getAutowireCapableBeanFactory().autowireBean(this);
final LogProcessorService svc = this.logProcessorService;
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
svc.processPageRequestsLogs();
}
}, 60*1000, 120*1000);
In general, you should avoid using Java singletons, where using Spring singletons is enough.
Also, if you declared LogProcessorServiceImpl with a #Service annotation, that implies it to be a Spring singleton, so you should not use static fields there at all.
P.S. this answer is about autowiring, it assumes that the idea with TimerTask is correct, in the real apps consider using the Spring Scheduling API

Why in destroy method is not called automatically in below when object will destroy?

public class Instrumentalist implements Performer, InitializingBean, DisposableBean {
private Instrument instrument;
private String song;
public void setInstrument(Instrument instrument)
{
this.instrument=instrument;
}
public void setSong(String song)
{
this.song=song;
}
public void afterPropertiesSet() throws Exception
{
System.out.println("Before Playing Instrument");
}
public void destroy() throws Exception
{
System.out.println("After Playing Instrument");
}
public void perform() {
// TODO Auto-generated method stub
System.out.println("Playing "+ song + " : ");
instrument.play();
}
}
In above example only i got the out put in which afterPropertiesSet() is called but not destroy method. Below is my config.xml
<bean id="dhiraj" class="Instrumentalist">
<property name="song" value="Sa Re Ga Ma" />
<property name="instrument" ref="piano" />
</bean>
<bean id="piano" class="Piano" />
and i called from my main method as below -
ApplicationContext context = new ClassPathXmlApplicationContext("Spring-config.xml");
Performer performer1=(Performer)context.getBean("dhiraj");
performer1.perform();
Try this:
AbstractApplicationContext context = new ClassPathXmlApplicationContext("Spring-config.xml");
//...
context.close(); //!!!
You have to close the context manually, otherwise Spring does not know that the bean is no longer needed and should be destroyed. Note that you have to use AbstractApplicationContext type as ApplicationContext interface does not define close().
For singleton beans like dhiraj, the destroy() lifecycle method will be called when, and only when, the application context is shut down.
If your code fragment is the entirety of your program, then destroy() will not be called because you're not closing the context properly.
Add context.close() to the end of your fragment, and you'll see destroy() being called.
You need to close Context Object,Then Only destroy method is called.Check for img
ConfigurableApplicationContext Context= new ClassPathXmlApplicationContext("ApplicationContext.xml");
//.............
//.........
Context.close();
**
You can also register shutdown hook this way:
AbstractApplicationContext context = new ClassPathXmlApplicationContext("Spring-config.xml");
context.registerShutdownHook();

Resources