BATCH-84:Added BATCH_JOB_INSTANCE_PROPERTIES table and removed schedule date from the BATCH_JOB table. Also updated JdbcJobDao to store a serialization of the JobInstanceProperties (renamed from JobParameters) in the JOB_KEY column, for unique identification.

This commit is contained in:
lucasward
2008-01-11 06:04:58 +00:00
parent af3af0a82f
commit ce9814f573
13 changed files with 247 additions and 70 deletions

View File

@@ -130,7 +130,7 @@ public class SimpleJobRepository implements JobRepository {
*
*/
public JobExecution findOrCreateJob(JobConfiguration jobConfiguration,
JobIdentifier runtimeInformation)
JobIdentifier jobIdentifier)
throws JobExecutionAlreadyRunningException {
List jobs = new ArrayList();
@@ -148,7 +148,7 @@ public class SimpleJobRepository implements JobRepository {
* thread or process will block until this transaction has finished.
*/
jobs = jobDao.findJobs(runtimeInformation);
jobs = jobDao.findJobs(jobIdentifier);
}
if (jobs.size() == 1) {
@@ -172,7 +172,7 @@ public class SimpleJobRepository implements JobRepository {
}
} else if (jobs.size() == 0) {
// no job found, create one
job = createJob(jobConfiguration, runtimeInformation);
job = createJob(jobConfiguration, jobIdentifier);
} else {
// More than one job found, throw exception
throw new BatchRestartException(

View File

@@ -18,8 +18,15 @@ package org.springframework.batch.execution.repository.dao;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -27,19 +34,23 @@ import org.springframework.batch.core.domain.BatchStatus;
import org.springframework.batch.core.domain.JobExecution;
import org.springframework.batch.core.domain.JobIdentifier;
import org.springframework.batch.core.domain.JobInstance;
import org.springframework.batch.core.domain.JobInstanceProperties;
import org.springframework.batch.core.domain.JobInstancePropertiesBuilder;
import org.springframework.batch.core.repository.NoSuchBatchDomainObjectException;
import org.springframework.batch.execution.runtime.DefaultJobIdentifier;
import org.springframework.batch.execution.runtime.ScheduledJobIdentifier;
import org.springframework.batch.repeat.ExitStatus;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* SQL implementation of {@link JobDao}. Uses sequences (via Spring's
* Jdbc implementation of {@link JobDao}. Uses sequences (via Spring's
* {@link DataFieldMaxValueIncrementer} abstraction) to create all primary keys
* before inserting a new row. Objects are checked to ensure all mandatory
* fields to be stored are not null. If any are found to be null, an
@@ -55,18 +66,20 @@ public class JdbcJobDao implements JobDao, InitializingBean {
private static final String CHECK_JOB_EXECUTION_EXISTS = "SELECT COUNT(*) FROM %PREFIX%JOB_EXECUTION WHERE ID=?";
// Job SQL statements
private static final String CREATE_JOB = "INSERT into %PREFIX%JOB(ID, JOB_NAME, JOB_KEY, SCHEDULE_DATE)"
+ " values (?, ?, ?, ?)";
/**
private static final String CREATE_JOB = "INSERT into %PREFIX%JOB(ID, JOB_NAME, JOB_KEY)"
+ " values (?, ?, ?)";
private static final String CREATE_JOB_PARAMETERS = "INSERT into %PREFIX%JOB_INSTANCE_PROPERTIES(JOB_ID, KEY, TYPE_CD, " +
"STRING_VAL, DATE_VAL, LONG_VAL) values (?, ?, ?, ?, ?, ?)";
/**
* Default value for the table prefix property.
*/
public static final String DEFAULT_TABLE_PREFIX = "BATCH_";
private static final int EXIT_MESSAGE_LENGTH = 250;
private static final String FIND_JOBS = "SELECT ID, STATUS from %PREFIX%JOB where JOB_NAME = ? and "
+ "JOB_KEY = ? and SCHEDULE_DATE = ?";
private static final String FIND_JOBS = "SELECT ID, STATUS from %PREFIX%JOB where JOB_NAME = ? and JOB_KEY = ?";
private static final String GET_JOB_EXECUTION_COUNT = "SELECT count(ID) from %PREFIX%JOB_EXECUTION "
+ "where JOB_ID = ?";
@@ -119,17 +132,28 @@ public class JdbcJobDao implements JobDao, InitializingBean {
validateJobIdentifier(jobIdentifier);
ScheduledJobIdentifier defaultJobId = getScheduledJobIdentifier(jobIdentifier);
Long jobId = new Long(jobIncrementer.nextLongValue());
Object[] parameters = new Object[] { jobId, defaultJobId.getName(),
defaultJobId.getJobKey(), defaultJobId.getScheduleDate() };
Object[] parameters = new Object[] { jobId, jobIdentifier.getName(), createJobKey(jobIdentifier.getRuntimeParameters()) };
jdbcTemplate.update(getCreateJobQuery(), parameters, new int[] {
Types.INTEGER, Types.VARCHAR, Types.VARCHAR, Types.DATE});
Types.INTEGER, Types.VARCHAR, Types.VARCHAR});
insertJobParameters(jobId, jobIdentifier.getRuntimeParameters());
JobInstance job = new JobInstance(jobIdentifier, jobId);
return job;
}
private String createJobKey(JobInstanceProperties jobInstanceProperties){
Map props = jobInstanceProperties.getParameters();
StringBuilder stringBuilder = new StringBuilder();
for(Iterator it = props.entrySet().iterator();it.hasNext();){
Entry entry = (Entry)it.next();
stringBuilder.append(entry.toString() + ";");
}
return stringBuilder.toString();
}
public List findJobExecutions(final JobInstance job) {
@@ -153,10 +177,8 @@ public class JdbcJobDao implements JobDao, InitializingBean {
validateJobIdentifier(jobIdentifier);
ScheduledJobIdentifier defaultJobId = getScheduledJobIdentifier(jobIdentifier);
Object[] parameters = new Object[] { defaultJobId.getName(),
defaultJobId.getJobKey(), defaultJobId.getScheduleDate() };
Object[] parameters = new Object[] { jobIdentifier.getName(),
createJobKey(jobIdentifier.getRuntimeParameters()) };
RowMapper rowMapper = new RowMapper() {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
@@ -183,6 +205,10 @@ public class JdbcJobDao implements JobDao, InitializingBean {
private String getFindJobsQuery() {
return getQuery(FIND_JOBS);
}
private String getCreateJobParamsQuery(){
return getQuery(CREATE_JOB_PARAMETERS);
}
/**
* @see JobDao#getJobExecutionCount(JobInstance)
@@ -211,26 +237,6 @@ public class JdbcJobDao implements JobDao, InitializingBean {
return getQuery(SAVE_JOB_EXECUTION);
}
/**
* Convert a {@link JobIdentifier} to a {@link ScheduledJobIdentifier} by
* supplying additional fields with null values, as necessary.
*
* @param jobIdentifier
* a {@link JobIdentifier}
* @return a {@link ScheduledJobIdentifier} with the same name
*/
private ScheduledJobIdentifier getScheduledJobIdentifier(
JobIdentifier jobIdentifier) {
if (jobIdentifier instanceof ScheduledJobIdentifier) {
return (ScheduledJobIdentifier) jobIdentifier;
}
if (jobIdentifier instanceof DefaultJobIdentifier) {
return new ScheduledJobIdentifier(jobIdentifier.getName(),
((DefaultJobIdentifier) jobIdentifier).getJobKey());
}
return new ScheduledJobIdentifier(jobIdentifier.getName());
}
private String getUpdateJobExecutionQuery() {
return getQuery(UPDATE_JOB_EXECUTION);
}
@@ -238,6 +244,61 @@ public class JdbcJobDao implements JobDao, InitializingBean {
private String getUpdateJobQuery() {
return getQuery(UPDATE_JOB);
}
/*
* Convenience method that inserts all parameters from the provided JobParameters.
*
*/
private void insertJobParameters(Long jobId, JobInstanceProperties jobParameters){
Map parameters = jobParameters.getStringParameters();
if(!parameters.isEmpty()){
for(Iterator it = parameters.entrySet().iterator(); it.hasNext();){
Entry entry = (Entry)it.next();
insertParameter(jobId, ParameterType.STRING, entry.getKey().toString(), entry.getValue());
}
}
parameters = jobParameters.getLongParameters();
if(!parameters.isEmpty()){
for(Iterator it = parameters.entrySet().iterator(); it.hasNext();){
Entry entry = (Entry)it.next();
insertParameter(jobId, ParameterType.LONG, entry.getKey().toString(), entry.getValue());
}
}
parameters = jobParameters.getDateParameters();
if(!parameters.isEmpty()){
for(Iterator it = parameters.entrySet().iterator(); it.hasNext();){
Entry entry = (Entry)it.next();
insertParameter(jobId, ParameterType.DATE, entry.getKey().toString(), entry.getValue());
}
}
}
/*
* Convenience method that inserts an individual records into the JobParameters table.
*/
private void insertParameter(Long jobId, ParameterType type, String key, Object value){
Object[] args = new Object[0];
int[] argTypes = new int[]{Types.INTEGER, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.TIMESTAMP, Types.INTEGER};
if(type == ParameterType.STRING){
args = new Object[]{jobId, key, type, value, new Timestamp(System.currentTimeMillis()), new Long(0)};
}
else if(type == ParameterType.LONG){
args = new Object[]{jobId, key, type, "", new Timestamp(System.currentTimeMillis()), value};
}
else if(type == ParameterType.DATE){
args = new Object[]{jobId, key, type, "", value, new Long(0)};
}
jdbcTemplate.update(getCreateJobParamsQuery(), args, argTypes);
}
/**
*
@@ -399,15 +460,7 @@ public class JdbcJobDao implements JobDao, InitializingBean {
Assert.notNull(jobIdentifier, "JobIdentifier cannot be null.");
Assert.notNull(jobIdentifier.getName(),
"JobIdentifier name cannot be null.");
if (jobIdentifier instanceof ScheduledJobIdentifier) {
ScheduledJobIdentifier identifier = (ScheduledJobIdentifier) jobIdentifier;
Assert.notNull(identifier.getJobKey(),
"JobIdentifier JobKey cannot be null.");
Assert.notNull(identifier.getScheduleDate(),
"JobIdentifier ScheduleDate cannot be null.");
}
Assert.notNull(jobIdentifier.getRuntimeParameters(), "JobIdentifier runtime parameters must not be null.");
}
/**
@@ -443,5 +496,80 @@ public class JdbcJobDao implements JobDao, InitializingBean {
}
}
/*
* Private inner class for mapping values from the JOB_PARAMETERS table into the java
* JobParameters class.
*/
private static class JobParameterCallbackHandler implements RowCallbackHandler{
private JobInstancePropertiesBuilder parametersBuilder;
public JobParameterCallbackHandler() {
parametersBuilder = new JobInstancePropertiesBuilder();
}
public void processRow(ResultSet rs) throws SQLException {
ParameterType parameterType = ParameterType.getType(rs.getString("TYPE_CD"));
String key = rs.getString("KEY");
if(parameterType == ParameterType.STRING){
parametersBuilder.addString(key, rs.getString("STRING_VAL"));
}
else if(parameterType == ParameterType.LONG){
parametersBuilder.addLong(key, new Long(rs.getLong("LONG_VAL")));
}
else if(parameterType == ParameterType.DATE){
//I debated about just passing the Timestamp in, however, I didn't want there to be any equality
//issues when comparing a java.util.Date to a timestamp.
Timestamp ts = rs.getTimestamp("DATE_VAL");
parametersBuilder.addDate(key, new Date(ts.getTime()));
}
else{
//invalid type code, error out.
throw new DataRetrievalFailureException("Invalid JobParameter type");
}
}
public JobInstanceProperties getJobParmeters(){
return parametersBuilder.toJobParameters();
}
}
private static class ParameterType {
private final String type;
private ParameterType(String type) {
this.type = type;
}
public String toString(){
return type;
}
public static final ParameterType STRING = new ParameterType("STRING");
public static final ParameterType DATE = new ParameterType("DATE");
public static final ParameterType LONG = new ParameterType("LONG");
private static final ParameterType[] VALUES = {STRING, DATE, LONG};
public static ParameterType getType(String typeAsString){
for(int i = 0; i < VALUES.length; i++){
if(VALUES[i].toString().equals(typeAsString)){
return (ParameterType)VALUES[i];
}
}
return null;
}
}
}

View File

@@ -51,11 +51,11 @@ public class MapJobDao implements JobDao {
return job;
}
public List findJobs(JobIdentifier jobRuntimeInformation) {
public List findJobs(JobIdentifier jobIdentifier) {
List list = new ArrayList();
for (Iterator iter = jobsById.values().iterator(); iter.hasNext();) {
JobInstance job = (JobInstance) iter.next();
if (job.getName().equals(jobRuntimeInformation.getName())) {
if (job.getName().equals(jobIdentifier.getName())) {
list.add(job);
}
}

View File

@@ -16,8 +16,8 @@
package org.springframework.batch.execution.runtime;
import org.springframework.batch.core.domain.JobIdentifier;
import org.springframework.batch.core.domain.JobRuntimeParameters;
import org.springframework.batch.core.domain.JobRuntimeParametersBuilder;
import org.springframework.batch.core.domain.JobInstanceProperties;
import org.springframework.batch.core.domain.JobInstancePropertiesBuilder;
import org.springframework.batch.core.runtime.SimpleJobIdentifier;
/**
@@ -48,10 +48,10 @@ public class DefaultJobIdentifier extends SimpleJobIdentifier implements
* @param name the name for the job
*/
public DefaultJobIdentifier(String name, String key) {
this(name, new JobRuntimeParametersBuilder().addString(JOB_KEY, key).toJobRuntimeParameters());
this(name, new JobInstancePropertiesBuilder().addString(JOB_KEY, key).toJobParameters());
}
public DefaultJobIdentifier(String name, JobRuntimeParameters parameters){
public DefaultJobIdentifier(String name, JobInstanceProperties parameters){
super(name, parameters);
}

View File

@@ -19,7 +19,7 @@ package org.springframework.batch.execution.runtime;
import java.util.Date;
import org.springframework.batch.core.domain.JobIdentifier;
import org.springframework.batch.core.domain.JobRuntimeParametersBuilder;
import org.springframework.batch.core.domain.JobInstancePropertiesBuilder;
public class ScheduledJobIdentifier extends DefaultJobIdentifier implements JobIdentifier {
@@ -42,12 +42,12 @@ public class ScheduledJobIdentifier extends DefaultJobIdentifier implements JobI
}
public ScheduledJobIdentifier(String name, Date scheduleDate){
super(name, new JobRuntimeParametersBuilder().addDate(SCHEDULE_DATE, scheduleDate).toJobRuntimeParameters());
super(name, new JobInstancePropertiesBuilder().addDate(SCHEDULE_DATE, scheduleDate).toJobParameters());
}
public ScheduledJobIdentifier(String name, String jobKey, Date scheduleDate){
super(name, new JobRuntimeParametersBuilder().addString(ScheduledJobIdentifier.JOB_KEY, jobKey).
addDate(SCHEDULE_DATE, scheduleDate).toJobRuntimeParameters());
super(name, new JobInstancePropertiesBuilder().addString(ScheduledJobIdentifier.JOB_KEY, jobKey).
addDate(SCHEDULE_DATE, scheduleDate).toJobParameters());
}
public Date getScheduleDate() {

View File

@@ -15,7 +15,6 @@ CREATE TABLE BATCH_JOB (
VERSION BIGINT,
JOB_NAME VARCHAR(100) NOT NULL ,
JOB_KEY VARCHAR(250) ,
SCHEDULE_DATE DATE ,
STATUS VARCHAR(10) );
CREATE TABLE BATCH_JOB_EXECUTION (
@@ -28,6 +27,14 @@ CREATE TABLE BATCH_JOB_EXECUTION (
CONTINUABLE CHAR(1),
EXIT_CODE VARCHAR(20),
EXIT_MESSAGE VARCHAR(250));
CREATE TABLE BATCH_JOB_INSTANCE_PROPERTIES (
JOB_ID BIGINT NOT NULL ,
TYPE_CD VARCHAR(6) NOT NULL ,
KEY VARCHAR(100) NOT NULL ,
STRING_VAL VARCHAR(250) ,
DATE_VAL TIMESTAMP ,
LONG_VAL VARCHAR(10) );
CREATE TABLE BATCH_STEP (
ID BIGINT PRIMARY KEY ,

View File

@@ -15,7 +15,6 @@ CREATE TABLE BATCH_JOB (
VERSION BIGINT,
JOB_NAME VARCHAR(100) NOT NULL ,
JOB_KEY VARCHAR(250) ,
SCHEDULE_DATE DATE ,
STATUS VARCHAR(10) );
CREATE TABLE BATCH_JOB_EXECUTION (
@@ -28,6 +27,14 @@ CREATE TABLE BATCH_JOB_EXECUTION (
CONTINUABLE CHAR(1),
EXIT_CODE VARCHAR(20),
EXIT_MESSAGE VARCHAR(250));
CREATE TABLE BATCH_JOB_INSTANCE_PROPERTIES (
JOB_ID BIGINT NOT NULL ,
TYPE_CD VARCHAR(6) NOT NULL ,
KEY VARCHAR(100) NOT NULL ,
STRING_VAL VARCHAR(250) ,
DATE_VAL TIMESTAMP ,
LONG_VAL VARCHAR(10) );
CREATE TABLE BATCH_STEP (
ID BIGINT PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,

View File

@@ -15,7 +15,6 @@ CREATE TABLE BATCH_JOB (
VERSION BIGINT,
JOB_NAME VARCHAR(100) NOT NULL ,
JOB_KEY VARCHAR(250) ,
SCHEDULE_DATE DATE ,
STATUS VARCHAR(10) );
CREATE TABLE BATCH_JOB_EXECUTION (
@@ -28,6 +27,14 @@ CREATE TABLE BATCH_JOB_EXECUTION (
CONTINUABLE CHAR(1),
EXIT_CODE VARCHAR(20),
EXIT_MESSAGE VARCHAR(250));
CREATE TABLE BATCH_JOB_INSTANCE_PROPERTIES (
JOB_ID BIGINT NOT NULL ,
TYPE_CD VARCHAR(6) NOT NULL ,
KEY VARCHAR(100) NOT NULL ,
STRING_VAL VARCHAR(250) ,
DATE_VAL TIMESTAMP ,
LONG_VAL VARCHAR(10) );
CREATE TABLE BATCH_STEP (
ID BIGINT IDENTITY PRIMARY KEY ,

View File

@@ -15,7 +15,6 @@ CREATE TABLE BATCH_JOB (
VERSION NUMBER(38),
JOB_NAME VARCHAR(100) NOT NULL ,
JOB_KEY VARCHAR(250) ,
SCHEDULE_DATE DATE ,
STATUS VARCHAR(10) );
CREATE TABLE BATCH_JOB_EXECUTION (
@@ -28,6 +27,14 @@ CREATE TABLE BATCH_JOB_EXECUTION (
CONTINUABLE CHAR(1),
EXIT_CODE VARCHAR(20),
EXIT_MESSAGE VARCHAR(250));
CREATE TABLE BATCH_JOB_INSTANCE_PROPERTIES (
JOB_ID BIGINT NOT NULL ,
TYPE_CD VARCHAR(6) NOT NULL ,
KEY VARCHAR(100) NOT NULL ,
STRING_VAL VARCHAR(250) ,
DATE_VAL TIMESTAMP ,
LONG_VAL VARCHAR(10) );
CREATE TABLE BATCH_STEP (
ID NUMBER(38) PRIMARY KEY ,

View File

@@ -15,7 +15,6 @@ CREATE TABLE BATCH_JOB (
VERSION BIGINT,
JOB_NAME VARCHAR(100) NOT NULL ,
JOB_KEY VARCHAR(250) ,
SCHEDULE_DATE DATE ,
STATUS VARCHAR(10) );
CREATE TABLE BATCH_JOB_EXECUTION (
@@ -28,6 +27,14 @@ CREATE TABLE BATCH_JOB_EXECUTION (
CONTINUABLE CHAR(1),
EXIT_CODE VARCHAR(20),
EXIT_MESSAGE VARCHAR(250));
CREATE TABLE BATCH_JOB_INSTANCE_PROPERTIES (
JOB_ID BIGINT NOT NULL ,
TYPE_CD VARCHAR(6) NOT NULL ,
KEY VARCHAR(100) NOT NULL ,
STRING_VAL VARCHAR(250) ,
DATE_VAL TIMESTAMP ,
LONG_VAL VARCHAR(10) );
CREATE TABLE BATCH_STEP (
ID BIGINT PRIMARY KEY ,

View File

@@ -4,7 +4,6 @@ CREATE TABLE BATCH_JOB (
VERSION ${BIGINT},
JOB_NAME VARCHAR(100) NOT NULL ,
JOB_KEY VARCHAR(250) ,
SCHEDULE_DATE DATE ,
STATUS VARCHAR(10) );
CREATE TABLE BATCH_JOB_EXECUTION (
@@ -17,6 +16,14 @@ CREATE TABLE BATCH_JOB_EXECUTION (
CONTINUABLE CHAR(1),
EXIT_CODE VARCHAR(20),
EXIT_MESSAGE VARCHAR(250));
CREATE TABLE BATCH_JOB_INSTANCE_PROPERTIES (
JOB_ID BIGINT NOT NULL ,
TYPE_CD VARCHAR(6) NOT NULL ,
KEY VARCHAR(100) NOT NULL ,
STRING_VAL VARCHAR(250) ,
DATE_VAL TIMESTAMP ,
LONG_VAL VARCHAR(10) );
CREATE TABLE BATCH_STEP (
ID ${BIGINT} $!{IDENTITY} PRIMARY KEY $!{GENERATED},

View File

@@ -263,12 +263,12 @@ public abstract class AbstractJobDaoTests extends
// Create job.
job = jobDao.createJob(jobIdentifier);
List jobs = jdbcTemplate.queryForList(
"SELECT * FROM BATCH_JOB where ID=?", new Object[] { job
.getId() });
List jobs = jobDao.findJobs(jobIdentifier);
assertEquals(1, jobs.size());
assertEquals(job.getName(), ((Map) jobs.get(0)).get("JOB_NAME"));
assertEquals(jobIdentifier.getJobKey(), ((Map) jobs.get(0)).get("JOB_KEY"));
assertEquals(job.getName(), ((JobInstance) jobs.get(0)).getName());
assertEquals(jobIdentifier.getJobKey(), ((JobInstance) jobs.get(0)).
getIdentifier().getRuntimeParameters().getString(DefaultJobIdentifier.JOB_KEY));
}

View File

@@ -4,7 +4,6 @@ CREATE TABLE BATCH_JOB (
VERSION BIGINT,
JOB_NAME VARCHAR(100) NOT NULL ,
JOB_KEY VARCHAR(250) ,
SCHEDULE_DATE DATE ,
STATUS VARCHAR(10) );
CREATE TABLE BATCH_JOB_EXECUTION (
@@ -17,6 +16,14 @@ CREATE TABLE BATCH_JOB_EXECUTION (
CONTINUABLE CHAR(1),
EXIT_CODE VARCHAR(20),
EXIT_MESSAGE VARCHAR(250));
CREATE TABLE BATCH_JOB_INSTANCE_PROPERTIES (
JOB_ID BIGINT NOT NULL ,
TYPE_CD VARCHAR(6) NOT NULL ,
KEY VARCHAR(100) NOT NULL ,
STRING_VAL VARCHAR(250) ,
DATE_VAL TIMESTAMP ,
LONG_VAL VARCHAR(10) );
CREATE TABLE BATCH_STEP (
ID BIGINT IDENTITY PRIMARY KEY ,