I am using SpringBoot 1.4.5 and quartz for scheduling with a DataSource configured in Tomcat's context.xml which is injected as a bean via JndiDataSource for connecting to a Oracle 10g DB.
Here are the relevant dependencies, including the Oracle driver, I am using the dependency management provided by SpringBoot:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>oracle-ojdbc7</artifactId>
<version>12.1.0-2</version>
</dependency>
This is the DataSource configured in Tomcat in context.xml (the placeholder properties are defined in catalina.properties) :
<Resource name="${tomcat.dbpool.ups.quartz.resourcename}" auth="Container"
type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver"
url="${tomcat.dbpool.ups.quartz.connectionurl}"
username="${tomcat.dbpool.ups.quartz.username}"
password="${tomcat.dbpool.ups.quartz.password}"
maxTotal="${tomcat.dbpool.ups.quartz.maxTotal}"
maxIdle="${tomcat.dbpool.ups.quartz.maxIdle}"
minIdle="${tomcat.dbpool.ups.quartz.minIdle}"
maxWaitMillis="${tomcat.dbpool.ups.quartz.maxWaitMillis}"
validationQueryTimeout="${tomcat.dbpool.ups.quartz.validationQueryTimeout}"
testWhileIdle="true"
removeAbandonedOnMaintenance="true"
timeBetweenEvictionRunsMillis="${tomcat.dbpool.ups.quartz.timeBetweenEvictionRunsMillis}"
minEvictableIdleTimeMillis="${tomcat.dbpool.ups.quartz.minEvictableIdleTimeMillis}"
/>
The datasource bean configuration and quartz necessary beans:
@Bean
public JobFactory jobFactory(final ApplicationContext applicationContext) {
final AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
jobFactory.setApplicationContext(applicationContext);
return jobFactory;
}
@Bean
public SchedulerFactoryBean schedulerFactoryBean(@Qualifier("quartzDataSource") final DataSource quartzDS,
final JobFactory jobFactory,
@Qualifier("loansAppTrigger") final Trigger jobTrigger) throws IOException {
final SchedulerFactoryBean factory = new SchedulerFactoryBean();
// this allows to update triggers in DB when updating settings in config file:
factory.setOverwriteExistingJobs(true);
factory.setDataSource(quartzDS);
factory.setJobFactory(jobFactory);
factory.setQuartzProperties(quartzProperties());
factory.setTriggers(jobTrigger);
return factory;
}
@Bean(name = "quartzDataSource")
@Profile("!local")
public DataSource jndiDataSource() {
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
DataSource dataSource = dataSourceLookup.getDataSource("java:comp/env/jdbc/QUARTZ");
return dataSource;
}
@Bean
public Properties quartzProperties() throws IOException {
final PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
}
@Bean
public JobDetailFactoryBean checkUnconfirmedApplicationsJobDetail() {
return createJobDetail(CheckUnconfirmedApplicationsJob.class);
}
@Bean(name = "loansAppTrigger")
public SimpleTriggerFactoryBean unconfirmedLoansApplicationsTrigger(
@Qualifier("checkUnconfirmedApplicationsJobDetail") final JobDetail jobDetail,
@Value("${ups.loan.check.pending.apps.frequency}") final long frequency) {
return createTrigger(jobDetail, frequency);
}
private static JobDetailFactoryBean createJobDetail(final Class jobClass) {
final JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
factoryBean.setJobClass(jobClass);
// job has to be durable to be stored in DB:
factoryBean.setDurability(true);
return factoryBean;
}
private static SimpleTriggerFactoryBean createTrigger(final JobDetail jobDetail, final long pollFrequencyMs) {
final SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
factoryBean.setJobDetail(jobDetail);
factoryBean.setStartDelay(0L);
factoryBean.setRepeatInterval(pollFrequencyMs);
factoryBean.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
// in case of misfire, ignore all missed triggers and continue :
factoryBean.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT);
return factoryBean;
}
And the following properties in quartz.properties file:
org.quartz.scheduler.instanceName=scheduler
org.quartz.scheduler.instanceId=AUTO
org.quartz.threadPool.threadCount=5
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
org.quartz.jobStore.tablePrefix=QRTZ_
org.quartz.jobStore.useProperties=true
org.quartz.jobStore.misfireThreshold=60000
org.quartz.jobStore.isClustered=true
org.quartz.jobStore.clusterCheckinInterval=20000
When I deploy this on Tomcat 8 I get the following error :
org.quartz.JobPersistenceException: Couldn't store job: Driver's Blob representation is of an usupported type: oracle.sql.BLOB
In Tomcat's lib folder I have the oracle-ojdbc7-12.1.0-2.jar driver.
Can you please check if you have any duplicate oracle-ojdbc JAR files present? The JAR should be in only one location: either in WEB-INF/lib or under tomcat/lib