OPEN - issue BATCH-90: StepExecution and StepExecutionContext are parallel domains, and StepExecution is by comparison anaemic

http://opensource.atlassian.com/projects/spring/browse/BATCH-90

Add ExitStatus to *Execution entities
This commit is contained in:
dsyer
2007-09-30 21:16:44 +00:00
parent 484961f5ab
commit 9d44d8f455
28 changed files with 541 additions and 489 deletions

View File

@@ -93,7 +93,7 @@ public class DefaultJobExecutor implements JobExecutor {
}
finally {
jobExecution.setEndTime(new Timestamp(System.currentTimeMillis()));
jobExecution.setExitCode(status.getExitCode());
jobExecution.setExitStatus(status);
jobRepository.saveOrUpdate(jobExecution);
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.execution.repository.dao;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.HibernateException;
import org.springframework.batch.repeat.ExitStatus;
/**
* User type object to help Hibernate persist (@link {@link ExitStatus})
* objects. The continuable flag is mapped to a String with value Y/N.
*
* @author Dave Syer
*
*/
public class ExitStatusUserType extends ImmutableValueUserType {
/**
* Convert a result set to an {@link ExitStatus}.
*
* @see org.springframework.batch.execution.repository.dao.ImmutableValueUserType#nullSafeGet(java.sql.ResultSet, java.lang.String[], java.lang.Object)
*/
public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
throws HibernateException, SQLException {
boolean continuable = "Y".equals(rs.getString(names[0]));
String code = rs.getString(names[1]);
String message = rs.getString(names[2]);
return new ExitStatus(continuable, code, message);
}
/**
* Convert the value (as an {@link ExitStatus}) to the columns in the
* prepared statement.
*
* @see org.springframework.batch.execution.repository.dao.ImmutableValueUserType#nullSafeSet(java.sql.PreparedStatement,
* java.lang.Object, int)
*/
public void nullSafeSet(PreparedStatement st, Object value, int index)
throws HibernateException, SQLException {
ExitStatus status = (ExitStatus) value;
st.setString(index, status.isContinuable() ? "Y" : "N");
st.setString(index + 1, status.getExitCode());
st.setString(index + 2, status.getExitDescription());
}
public Class returnedClass() {
return ExitStatus.class;
}
public int[] sqlTypes() {
return new int[] { Types.CHAR, Types.VARCHAR, Types.VARCHAR };
}
}

View File

@@ -0,0 +1,62 @@
package org.springframework.batch.execution.repository.dao;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;
/**
* A base class for user types that map immutable values (objects that cannot be
* changed after construction and may be safely shared).
*
* @author Ben Hale
* @author Dave Syer
*/
public abstract class ImmutableValueUserType implements UserType {
public Object assemble(Serializable cached, Object owner)
throws HibernateException {
return cached;
}
public Object deepCopy(Object value) throws HibernateException {
return value;
}
public Serializable disassemble(Object value) throws HibernateException {
return (Serializable) value;
}
public boolean equals(Object x, Object y) throws HibernateException {
return x.equals(y);
}
public int hashCode(Object x) throws HibernateException {
return x.hashCode();
}
public boolean isMutable() {
return false;
}
public Object replace(Object original, Object target, Object owner)
throws HibernateException {
return original;
}
// subclasses must implement the following methods
public abstract Class returnedClass();
public abstract int[] sqlTypes();
public abstract Object nullSafeGet(ResultSet rs, String[] names,
Object owner) throws HibernateException, SQLException;
public abstract void nullSafeSet(PreparedStatement st, Object value,
int index) throws HibernateException, SQLException;
}

View File

@@ -26,6 +26,7 @@ import org.springframework.batch.core.domain.JobInstance;
import org.springframework.batch.core.repository.NoSuchBatchDomainObjectException;
import org.springframework.batch.core.runtime.JobIdentifier;
import org.springframework.batch.execution.runtime.ScheduledJobIdentifier;
import org.springframework.batch.repeat.ExitStatus;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
@@ -69,10 +70,10 @@ public class SqlJobDao implements JobDao, InitializingBean {
// Job Execution SqlStatements
private static final String UPDATE_JOB_EXECUTION = "UPDATE %PREFIX%JOB_EXECUTION set START_TIME = ?, END_TIME = ?, "
+ " STATUS = ?, EXIT_CODE = ? where ID = ?";
+ " STATUS = ?, CONTINUABLE = ?, EXIT_CODE = ?, EXIT_MESSAGE = ? where ID = ?";
private static final String SAVE_JOB_EXECUTION = "INSERT into %PREFIX%JOB_EXECUTION(ID, JOB_ID, START_TIME, "
+ "END_TIME, STATUS, EXIT_CODE) values (?, ?, ?, ?, ?, ?)";
+ "END_TIME, STATUS, CONTINUABLE, EXIT_CODE, EXIT_MESSAGE) values (?, ?, ?, ?, ?, ?, ?, ?)";
private static final String CHECK_JOB_EXECUTION_EXISTS = "SELECT COUNT(*) FROM %PREFIX%JOB_EXECUTION WHERE ID=?";
@@ -187,7 +188,9 @@ public class SqlJobDao implements JobDao, InitializingBean {
Object[] parameters = new Object[] { jobExecution.getId(),
jobExecution.getJobId(), jobExecution.getStartTime(),
jobExecution.getEndTime(), jobExecution.getStatus().toString(),
jobExecution.getExitCode() };
jobExecution.getExitStatus().isContinuable() ? "Y" : "N",
jobExecution.getExitStatus().getExitCode(),
jobExecution.getExitStatus().getExitDescription() };
jdbcTemplate.update(getSaveJobExecutionQuery(), parameters);
}
@@ -205,7 +208,10 @@ public class SqlJobDao implements JobDao, InitializingBean {
Object[] parameters = new Object[] { jobExecution.getStartTime(),
jobExecution.getEndTime(), jobExecution.getStatus().toString(),
jobExecution.getExitCode(), jobExecution.getId() };
jobExecution.getExitStatus().isContinuable() ? "Y" : "N",
jobExecution.getExitStatus().getExitCode(),
jobExecution.getExitStatus().getExitDescription(),
jobExecution.getId() };
if (jobExecution.getId() == null) {
throw new IllegalArgumentException(
@@ -246,7 +252,8 @@ public class SqlJobDao implements JobDao, InitializingBean {
Assert.notNull(job, "Job cannot be null.");
Assert.notNull(job.getId(), "Job Id cannot be null.");
return jdbcTemplate.query(getQuery(JobExecutionRowMapper.FIND_JOB_EXECUTIONS),
return jdbcTemplate.query(
getQuery(JobExecutionRowMapper.FIND_JOB_EXECUTIONS),
new Object[] { job.getId() }, new JobExecutionRowMapper(job));
}
@@ -366,16 +373,17 @@ public class SqlJobDao implements JobDao, InitializingBean {
/**
* Re-usable mapper for {@link JobExecution} instances.
*
* @author Dave Syer
*
*
*/
public static class JobExecutionRowMapper implements RowMapper {
public static final String FIND_JOB_EXECUTIONS = "SELECT ID, START_TIME, END_TIME, STATUS from %PREFIX%JOB_EXECUTION"
+ " where JOB_ID = ?";
public static final String GET_JOB_EXECUTION = "SELECT ID, START_TIME, END_TIME, STATUS from %PREFIX%JOB_EXECUTION"
+ " where ID = ?";
public static final String FIND_JOB_EXECUTIONS = "SELECT ID, START_TIME, END_TIME, STATUS, CONTINUABLE, EXIT_CODE, EXIT_MESSAGE from %PREFIX%JOB_EXECUTION"
+ " where JOB_ID = ?";
public static final String GET_JOB_EXECUTION = "SELECT ID, START_TIME, END_TIME, STATUS, CONTINUABLE, EXIT_CODE, EXIT_MESSAGE from %PREFIX%JOB_EXECUTION"
+ " where ID = ?";
private JobInstance job;
@@ -390,6 +398,8 @@ public class SqlJobDao implements JobDao, InitializingBean {
jobExecution.setStartTime(rs.getTimestamp(2));
jobExecution.setEndTime(rs.getTimestamp(3));
jobExecution.setStatus(BatchStatus.getStatus(rs.getString(4)));
jobExecution.setExitStatus(new ExitStatus("Y".equals(rs
.getString(5)), rs.getString(6), rs.getString(7)));
return jobExecution;
}

View File

@@ -28,6 +28,7 @@ import org.springframework.batch.core.domain.StepExecution;
import org.springframework.batch.core.domain.StepInstance;
import org.springframework.batch.core.repository.NoSuchBatchDomainObjectException;
import org.springframework.batch.execution.repository.dao.SqlJobDao.JobExecutionRowMapper;
import org.springframework.batch.repeat.ExitStatus;
import org.springframework.batch.restart.GenericRestartData;
import org.springframework.batch.restart.RestartData;
import org.springframework.batch.support.PropertiesConverter;
@@ -69,18 +70,18 @@ public class SqlStepDao implements StepDao, InitializingBean {
// StepExecution statements
private static final String SAVE_STEP_EXECUTION = "INSERT into %PREFIX%STEP_EXECUTION(ID, VERSION, STEP_ID, JOB_EXECUTION_ID, START_TIME, "
+ "END_TIME, STATUS, COMMIT_COUNT, TASK_COUNT, TASK_STATISTICS, EXIT_CODE, EXIT_MESSAGE) "
+ "values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+ "END_TIME, STATUS, COMMIT_COUNT, TASK_COUNT, TASK_STATISTICS, CONTINUABLE, EXIT_CODE, EXIT_MESSAGE) "
+ "values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
private static final String UPDATE_STEP_EXECUTION = "UPDATE %PREFIX%STEP_EXECUTION set START_TIME = ?, END_TIME = ?, "
+ "STATUS = ?, COMMIT_COUNT = ?, TASK_COUNT = ?, TASK_STATISTICS = ?, EXIT_CODE = ?, "
+ "STATUS = ?, COMMIT_COUNT = ?, TASK_COUNT = ?, TASK_STATISTICS = ?, CONTINUABLE = ? , EXIT_CODE = ?, "
+ "EXIT_MESSAGE = ? where ID = ?";
private static final String GET_STEP_EXECUTION_COUNT = "SELECT count(ID) from %PREFIX%STEP_EXECUTION where "
+ "STEP_ID = ?";
private static final String FIND_STEP_EXECUTIONS = "SELECT ID, JOB_EXECUTION_ID, START_TIME, END_TIME, STATUS, COMMIT_COUNT,"
+ " TASK_COUNT, TASK_STATISTICS, EXIT_CODE, EXIT_MESSAGE from %PREFIX%STEP_EXECUTION where STEP_ID = ?";
+ " TASK_COUNT, TASK_STATISTICS, CONTINUABLE, EXIT_CODE, EXIT_MESSAGE from %PREFIX%STEP_EXECUTION where STEP_ID = ?";
private JdbcOperations jdbcTemplate;
@@ -108,7 +109,8 @@ public class SqlStepDao implements StepDao, InitializingBean {
* Injection setter for job dao. Used to save {@link JobExecution}
* instances.
*
* @param jobDao a {@link JobDao}
* @param jobDao
* a {@link JobDao}
*/
public void setJobDao(JobDao jobDao) {
this.jobDao = jobDao;
@@ -270,8 +272,10 @@ public class SqlStepDao implements StepDao, InitializingBean {
stepExecution.getCommitCount(),
stepExecution.getTaskCount(),
PropertiesConverter.propertiesToString(stepExecution
.getStatistics()), stepExecution.getExitCode(),
stepExecution.getExitDescription() };
.getStatistics()),
stepExecution.getExitStatus().isContinuable() ? "Y" : "N",
stepExecution.getExitStatus().getExitCode(),
stepExecution.getExitStatus().getExitDescription() };
jdbcTemplate.update(getQuery(SAVE_STEP_EXECUTION), parameters);
}
@@ -309,8 +313,11 @@ public class SqlStepDao implements StepDao, InitializingBean {
stepExecution.getCommitCount(),
stepExecution.getTaskCount(),
PropertiesConverter.propertiesToString(stepExecution
.getStatistics()), stepExecution.getExitCode(),
stepExecution.getExitDescription(), stepExecution.getId() };
.getStatistics()),
stepExecution.getExitStatus().isContinuable() ? "Y" : "N",
stepExecution.getExitStatus().getExitCode(),
stepExecution.getExitStatus().getExitDescription(),
stepExecution.getId() };
jdbcTemplate.update(getQuery(UPDATE_STEP_EXECUTION), parameters);
}
@@ -355,8 +362,8 @@ public class SqlStepDao implements StepDao, InitializingBean {
stepExecution.setTaskCount(rs.getInt(7));
stepExecution.setStatistics(PropertiesConverter
.stringToProperties(rs.getString(8)));
stepExecution.setExitCode(rs.getString(9));
stepExecution.setExitDescription(rs.getString(10));
stepExecution.setExitStatus(new ExitStatus("Y".equals(rs
.getString(9)), rs.getString(10), rs.getString(11)));
return stepExecution;
}
};

View File

@@ -266,8 +266,7 @@ public class SimpleStepExecutor implements StepExecutor {
}
finally {
stepExecution.setExitCode(status.getExitCode());
stepExecution.setExitDescription(status.getExitDescription());
stepExecution.setExitStatus(status);
stepExecution.setEndTime(new Timestamp(System.currentTimeMillis()));
try {
jobRepository.saveOrUpdate(stepExecution);