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:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 };
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user