RESOLVED - issue BATCH-281: Null fields cause problems in Oracle and Derby

http://jira.springframework.org/browse/BATCH-281
This commit is contained in:
dsyer
2008-01-21 13:44:50 +00:00
parent badcf74c7b
commit 8ab7e1371a
4 changed files with 81 additions and 64 deletions

View File

@@ -20,7 +20,6 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -33,13 +32,10 @@ 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.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;
@@ -142,7 +138,7 @@ public class JdbcJobDao implements JobDao, InitializingBean {
private String createJobKey(JobInstanceProperties jobInstanceProperties){
Map props = jobInstanceProperties.getParameters();
StringBuilder stringBuilder = new StringBuilder();
StringBuilder stringBuilder = new StringBuilder("params:");
for(Iterator it = props.entrySet().iterator();it.hasNext();){
Entry entry = (Entry)it.next();
stringBuilder.append(entry.toString() + ";");
@@ -492,49 +488,7 @@ public class JdbcJobDao implements JobDao, InitializingBean {
}
}
/*
* Private inner class for mapping values from the JOB_PARAMETERS table into the java
* JobParameters class. TODO: is this going to be used? If not can we delete it?
*/
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;

View File

@@ -21,33 +21,57 @@ import java.util.Date;
import org.springframework.batch.core.domain.JobIdentifier;
import org.springframework.batch.core.domain.JobInstancePropertiesBuilder;
/**
* Convenient {@link JobIdentifier} implementation that identifies itself by a
* {@link Date} as well as an optional String key. The time portion of the
* schedule date is significant, and clients are responsible for truncating it
* if it represents a date rather than a timestamp.
*
* @author Dave Syer
*
*/
public class ScheduledJobIdentifier extends DefaultJobIdentifier implements JobIdentifier {
public static final String SCHEDULE_DATE = "schedule.date";
ScheduledJobIdentifier() {
this(null);
}
public ScheduledJobIdentifier(String name) {
super(name);
}
/**
* @param name
* @param key
* Convenience constructor that leaves the schedule date null.
*
* @param name the name of the job
* @param key a unique key for this execution
*/
public ScheduledJobIdentifier(String name, String key) {
super(name, key);
}
public ScheduledJobIdentifier(String name, Date scheduleDate){
/**
* Convenience constructor that leaves the key null.
*
* @param name the name of the job
* @param scheduleDate a timestamp
*/
public ScheduledJobIdentifier(String name, Date scheduleDate) {
super(name, new JobInstancePropertiesBuilder().addDate(SCHEDULE_DATE, scheduleDate).toJobParameters());
}
public ScheduledJobIdentifier(String name, String jobKey, Date scheduleDate){
super(name, new JobInstancePropertiesBuilder().addString(ScheduledJobIdentifier.JOB_KEY, jobKey).
addDate(SCHEDULE_DATE, scheduleDate).toJobParameters());
/**
* Convenience constructor with all properties.
*
* @param name the name of the job
* @param key a unique key for this execution
* @param scheduleDate a timestamp
*/
public ScheduledJobIdentifier(String name, String key, Date scheduleDate) {
super(name, new JobInstancePropertiesBuilder().addString(ScheduledJobIdentifier.JOB_KEY, key).addDate(
SCHEDULE_DATE, scheduleDate).toJobParameters());
}
public Date getScheduleDate() {

View File

@@ -272,6 +272,39 @@ public abstract class AbstractJobDaoTests extends
}
public void testJobWithScheduledJobIdentifier() throws Exception {
Date date = new Date();
ScheduledJobIdentifier jobIdentifier = new ScheduledJobIdentifier("Job1", "testKey", date);
// Create job.
job = jobDao.createJob(jobIdentifier);
List jobs = jobDao.findJobs(jobIdentifier);
assertEquals(1, jobs.size());
assertEquals(job.getName(), ((JobInstance) jobs.get(0)).getName());
assertEquals(jobIdentifier.getJobKey(), ((JobInstance) jobs.get(0)).
getIdentifier().getJobInstanceProperties().getString(DefaultJobIdentifier.JOB_KEY));
}
public void testJobWithScheduledJobIdentifierAndDifferentTime() throws Exception {
Date date = new Date();
ScheduledJobIdentifier jobIdentifier = new ScheduledJobIdentifier("Job1", "testKey", date);
// Create job.
job = jobDao.createJob(jobIdentifier);
Date later = new Date(date.getTime()+3600000);
ScheduledJobIdentifier laterIdentifier = new ScheduledJobIdentifier("Job1", "testKey", later);
List jobs = jobDao.findJobs(laterIdentifier);
// Different timestamp is different identifier...
assertEquals(0, jobs.size());
}
public void testFindJobExecutions(){
List results = jobDao.findJobExecutions(job);

View File

@@ -3,6 +3,7 @@ package org.springframework.batch.execution.repository.dao;
import java.util.List;
import java.util.Map;
import org.springframework.batch.core.runtime.SimpleJobIdentifier;
import org.springframework.batch.repeat.ExitStatus;
public class JdbcJobDaoTests extends AbstractJobDaoTests {
@@ -16,16 +17,21 @@ public class JdbcJobDaoTests extends AbstractJobDaoTests {
public void testUpdateJobExecutionWithLongExitCode() {
assertTrue(LONG_STRING.length() > 250);
jobExecution.setExitStatus(ExitStatus.FINISHED
.addExitDescription(LONG_STRING));
jobExecution.setExitStatus(ExitStatus.FINISHED.addExitDescription(LONG_STRING));
jobDao.update(jobExecution);
List executions = jdbcTemplate.queryForList(
"SELECT * FROM BATCH_JOB_EXECUTION where JOB_ID=?",
List executions = jdbcTemplate.queryForList("SELECT * FROM BATCH_JOB_EXECUTION where JOB_ID=?",
new Object[] { job.getId() });
assertEquals(1, executions.size());
assertEquals(LONG_STRING.substring(0, 250), ((Map) executions.get(0))
.get("EXIT_MESSAGE"));
assertEquals(LONG_STRING.substring(0, 250), ((Map) executions.get(0)).get("EXIT_MESSAGE"));
}
public void testJobInstanceParametersNotNullOrEmptyWithSimpleJobIdentifier() {
job = jobDao.createJob(new SimpleJobIdentifier("foo"));
Map map = jdbcTemplate.queryForMap("SELECT * FROM BATCH_JOB_INSTANCE where ID=?",
new Object[] { job.getId() });
String key = (String) map.get("JOB_KEY");
assertTrue("Key should be non-zero length (otherwise Oracle will treat as null)", key.length()>0);
}
}