EMMA Coverage Report (generated Fri Jan 30 13:20:29 EST 2009)
[all classes][org.springframework.batch.core.repository.dao]

COVERAGE SUMMARY FOR SOURCE FILE [JdbcJobExecutionDao.java]

nameclass, %method, %block, %line, %
JdbcJobExecutionDao.java100% (2/2)94%  (15/16)98%  (531/543)96%  (68.8/72)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class JdbcJobExecutionDao100% (1/1)93%  (13/14)97%  (463/475)95%  (55.8/59)
setLobHandler (LobHandler): void 0%   (0/1)0%   (0/4)0%   (0/2)
<static initializer> 100% (1/1)91%  (10/11)90%  (0.9/1)
getLastJobExecution (JobInstance): JobExecution 100% (1/1)93%  (41/44)83%  (5/6)
saveJobExecution (JobExecution): void 100% (1/1)98%  (123/125)100% (6/6)
updateJobExecution (JobExecution): void 100% (1/1)99%  (169/171)100% (13/13)
JdbcJobExecutionDao (): void 100% (1/1)100% (16/16)100% (5/5)
afterPropertiesSet (): void 100% (1/1)100% (24/24)100% (7/7)
findExecutionContext (JobExecution): ExecutionContext 100% (1/1)100% (5/5)100% (1/1)
findJobExecutions (JobInstance): List 100% (1/1)100% (26/26)100% (3/3)
getJobExecutionCount (JobInstance): int 100% (1/1)100% (21/21)100% (4/4)
saveOrUpdateExecutionContext (JobExecution): void 100% (1/1)100% (5/5)100% (2/2)
setExitMessageLength (int): void 100% (1/1)100% (4/4)100% (2/2)
setJobExecutionIncrementer (DataFieldMaxValueIncrementer): void 100% (1/1)100% (4/4)100% (2/2)
validateJobExecution (JobExecution): void 100% (1/1)100% (15/15)100% (5/5)
     
class JdbcJobExecutionDao$JobExecutionRowMapper100% (1/1)100% (2/2)100% (68/68)100% (13/13)
JdbcJobExecutionDao$JobExecutionRowMapper (JdbcJobExecutionDao, JobInstance):... 100% (1/1)100% (9/9)100% (4/4)
mapRow (ResultSet, int): Object 100% (1/1)100% (59/59)100% (9/9)

1package org.springframework.batch.core.repository.dao;
2 
3import java.sql.ResultSet;
4import java.sql.SQLException;
5import java.sql.Types;
6import java.util.List;
7 
8import org.apache.commons.logging.Log;
9import org.apache.commons.logging.LogFactory;
10import org.springframework.batch.core.BatchStatus;
11import org.springframework.batch.core.JobExecution;
12import org.springframework.batch.core.JobInstance;
13import org.springframework.batch.item.ExecutionContext;
14import org.springframework.batch.repeat.ExitStatus;
15import org.springframework.beans.factory.InitializingBean;
16import org.springframework.jdbc.core.RowMapper;
17import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;
18import org.springframework.jdbc.support.lob.DefaultLobHandler;
19import org.springframework.jdbc.support.lob.LobHandler;
20import org.springframework.util.Assert;
21 
22/**
23 * Jdbc implementation of {@link JobExecutionDao}. Uses sequences (via Spring's
24 * {@link DataFieldMaxValueIncrementer} abstraction) to create all primary keys
25 * before inserting a new row. Objects are checked to ensure all mandatory
26 * fields to be stored are not null. If any are found to be null, an
27 * IllegalArgumentException will be thrown. This could be left to JdbcTemplate,
28 * however, the exception will be fairly vague, and fails to highlight which
29 * field caused the exception.
30 * 
31 * @author Lucas Ward
32 * @author Dave Syer
33 * @author Robert Kasanicky
34 */
35public class JdbcJobExecutionDao extends AbstractJdbcBatchMetadataDao implements JobExecutionDao, InitializingBean {
36 
37        private static final Log logger = LogFactory.getLog(JdbcJobExecutionDao.class);
38 
39        private static final String GET_JOB_EXECUTION_COUNT = "SELECT count(JOB_EXECUTION_ID) from %PREFIX%JOB_EXECUTION "
40                        + "where JOB_INSTANCE_ID = ?";
41 
42        private static final String SAVE_JOB_EXECUTION = "INSERT into %PREFIX%JOB_EXECUTION(JOB_EXECUTION_ID, JOB_INSTANCE_ID, START_TIME, "
43                        + "END_TIME, STATUS, CONTINUABLE, EXIT_CODE, EXIT_MESSAGE, VERSION, CREATE_TIME) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
44 
45        private static final String CHECK_JOB_EXECUTION_EXISTS = "SELECT COUNT(*) FROM %PREFIX%JOB_EXECUTION WHERE JOB_EXECUTION_ID = ?";
46 
47        private static final String UPDATE_JOB_EXECUTION = "UPDATE %PREFIX%JOB_EXECUTION set START_TIME = ?, END_TIME = ?, "
48                        + " STATUS = ?, CONTINUABLE = ?, EXIT_CODE = ?, EXIT_MESSAGE = ?, VERSION = ?, CREATE_TIME = ? where JOB_EXECUTION_ID = ?";
49 
50        private static final String FIND_JOB_EXECUTIONS = "SELECT JOB_EXECUTION_ID, START_TIME, END_TIME, STATUS, CONTINUABLE, EXIT_CODE, EXIT_MESSAGE, CREATE_TIME from %PREFIX%JOB_EXECUTION"
51                        + " where JOB_INSTANCE_ID = ?";
52 
53        private static final String GET_LAST_EXECUTION = "SELECT JOB_EXECUTION_ID, START_TIME, END_TIME, STATUS, CONTINUABLE, EXIT_CODE, EXIT_MESSAGE, CREATE_TIME from %PREFIX%JOB_EXECUTION"
54                        + " where JOB_INSTANCE_ID = ? and CREATE_TIME = (SELECT max(CREATE_TIME) from %PREFIX%JOB_EXECUTION where JOB_INSTANCE_ID = ?)";
55 
56        private int exitMessageLength = DEFAULT_EXIT_MESSAGE_LENGTH;
57 
58        private DataFieldMaxValueIncrementer jobExecutionIncrementer;
59 
60        private LobHandler lobHandler = new DefaultLobHandler();
61 
62        private JdbcExecutionContextDao ecDao = new JdbcExecutionContextDao();
63 
64        /**
65         * Public setter for the exit message length in database. Do not set this if
66         * you haven't modified the schema.
67         * @param exitMessageLength the exitMessageLength to set
68         */
69        public void setExitMessageLength(int exitMessageLength) {
70                this.exitMessageLength = exitMessageLength;
71        }
72 
73        public List findJobExecutions(final JobInstance job) {
74 
75                Assert.notNull(job, "Job cannot be null.");
76                Assert.notNull(job.getId(), "Job Id cannot be null.");
77 
78                return getJdbcTemplate().query(getQuery(FIND_JOB_EXECUTIONS), new Object[] { job.getId() },
79                                new JobExecutionRowMapper(job));
80        }
81 
82        /**
83         * @see JobExecutionDao#getJobExecutionCount(JobInstance)
84         * @throws IllegalArgumentException if jobId is null.
85         */
86        public int getJobExecutionCount(JobInstance jobInstance) {
87                Long jobId = jobInstance.getId();
88                Assert.notNull(jobId, "JobId cannot be null");
89 
90                Object[] parameters = new Object[] { jobId };
91 
92                return getJdbcTemplate().queryForInt(getQuery(GET_JOB_EXECUTION_COUNT), parameters);
93        }
94 
95        /**
96         * 
97         * SQL implementation using Sequences via the Spring incrementer
98         * abstraction. Once a new id has been obtained, the JobExecution is saved
99         * via a SQL INSERT statement.
100         * 
101         * @see JobExecutionDao#saveJobExecution(JobExecution)
102         * @throws IllegalArgumentException if jobExecution is null, as well as any
103         * of it's fields to be persisted.
104         */
105        public void saveJobExecution(JobExecution jobExecution) {
106 
107                validateJobExecution(jobExecution);
108 
109                jobExecution.incrementVersion();
110 
111                jobExecution.setId(new Long(jobExecutionIncrementer.nextLongValue()));
112                Object[] parameters = new Object[] { jobExecution.getId(), jobExecution.getJobId(),
113                                jobExecution.getStartTime(), jobExecution.getEndTime(), jobExecution.getStatus().toString(),
114                                jobExecution.getExitStatus().isContinuable() ? "Y" : "N", jobExecution.getExitStatus().getExitCode(),
115                                jobExecution.getExitStatus().getExitDescription(), jobExecution.getVersion(),
116                                jobExecution.getCreateTime() };
117                getJdbcTemplate().update(
118                                getQuery(SAVE_JOB_EXECUTION),
119                                parameters,
120                                new int[] { Types.INTEGER, Types.INTEGER, Types.TIMESTAMP, Types.TIMESTAMP, Types.VARCHAR, Types.CHAR,
121                                                Types.VARCHAR, Types.VARCHAR, Types.INTEGER, Types.TIMESTAMP });
122        }
123 
124        /**
125         * Validate JobExecution. At a minimum, JobId, StartTime, EndTime, and
126         * Status cannot be null.
127         * 
128         * @param jobExecution
129         * @throws IllegalArgumentException
130         */
131        private void validateJobExecution(JobExecution jobExecution) {
132 
133                Assert.notNull(jobExecution);
134                Assert.notNull(jobExecution.getJobId(), "JobExecution Job-Id cannot be null.");
135                Assert.notNull(jobExecution.getStatus(), "JobExecution status cannot be null.");
136                Assert.notNull(jobExecution.getCreateTime(), "JobExecution create time cannot be null");
137        }
138 
139        /**
140         * Update given JobExecution using a SQL UPDATE statement. The JobExecution
141         * is first checked to ensure all fields are not null, and that it has an
142         * ID. The database is then queried to ensure that the ID exists, which
143         * ensures that it is valid.
144         * 
145         * @see JobExecutionDao#updateJobExecution(JobExecution)
146         */
147        public void updateJobExecution(JobExecution jobExecution) {
148 
149                validateJobExecution(jobExecution);
150 
151                jobExecution.incrementVersion();
152 
153                String exitDescription = jobExecution.getExitStatus().getExitDescription();
154                if (exitDescription != null && exitDescription.length() > exitMessageLength) {
155                        exitDescription = exitDescription.substring(0, exitMessageLength);
156                        logger.debug("Truncating long message before update of JobExecution: " + jobExecution);
157                }
158                Object[] parameters = new Object[] { jobExecution.getStartTime(), jobExecution.getEndTime(),
159                                jobExecution.getStatus().toString(), jobExecution.getExitStatus().isContinuable() ? "Y" : "N",
160                                jobExecution.getExitStatus().getExitCode(), exitDescription, jobExecution.getVersion(),
161                                jobExecution.getCreateTime(), jobExecution.getId() };
162 
163                if (jobExecution.getId() == null) {
164                        throw new IllegalArgumentException("JobExecution ID cannot be null.  JobExecution must be saved "
165                                        + "before it can be updated.");
166                }
167 
168                // Check if given JobExecution's Id already exists, if none is found it
169                // is invalid and
170                // an exception should be thrown.
171                if (getJdbcTemplate().queryForInt(getQuery(CHECK_JOB_EXECUTION_EXISTS), new Object[] { jobExecution.getId() }) != 1) {
172                        throw new NoSuchObjectException("Invalid JobExecution, ID " + jobExecution.getId() + " not found.");
173                }
174 
175                getJdbcTemplate().update(
176                                getQuery(UPDATE_JOB_EXECUTION),
177                                parameters,
178                                new int[] { Types.TIMESTAMP, Types.TIMESTAMP, Types.VARCHAR, Types.CHAR, Types.VARCHAR, Types.VARCHAR,
179                                                Types.INTEGER, Types.TIMESTAMP, Types.INTEGER });
180        }
181 
182        /**
183         * Setter for {@link DataFieldMaxValueIncrementer} to be used when
184         * generating primary keys for {@link JobExecution} instances.
185         * 
186         * @param jobExecutionIncrementer the {@link DataFieldMaxValueIncrementer}
187         */
188        public void setJobExecutionIncrementer(DataFieldMaxValueIncrementer jobExecutionIncrementer) {
189                this.jobExecutionIncrementer = jobExecutionIncrementer;
190        }
191 
192        public void afterPropertiesSet() throws Exception {
193                super.afterPropertiesSet();
194                Assert.notNull(jobExecutionIncrementer);
195                ecDao.setJdbcTemplate(getJdbcTemplate());
196                ecDao.setLobHandler(lobHandler);
197                ecDao.setTablePrefix(getTablePrefix());
198                ecDao.afterPropertiesSet();
199        }
200 
201        /**
202         * Re-usable mapper for {@link JobExecution} instances.
203         * 
204         * @author Dave Syer
205         * 
206         */
207        private class JobExecutionRowMapper implements RowMapper {
208 
209                private JobInstance job;
210 
211                public JobExecutionRowMapper(JobInstance job) {
212                        super();
213                        this.job = job;
214                }
215 
216                public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
217                        JobExecution jobExecution = new JobExecution(job);
218                        jobExecution.setId(new Long(rs.getLong(1)));
219                        jobExecution.setStartTime(rs.getTimestamp(2));
220                        jobExecution.setEndTime(rs.getTimestamp(3));
221                        jobExecution.setStatus(BatchStatus.getStatus(rs.getString(4)));
222                        jobExecution.setExitStatus(new ExitStatus("Y".equals(rs.getString(5)), rs.getString(6), rs.getString(7)));
223                        jobExecution.setCreateTime(rs.getDate(8));
224                        jobExecution.setExecutionContext(findExecutionContext(jobExecution));
225                        return jobExecution;
226                }
227 
228        }
229 
230        public JobExecution getLastJobExecution(JobInstance jobInstance) {
231 
232                Long id = jobInstance.getId();
233 
234                List executions = getJdbcTemplate().query(getQuery(GET_LAST_EXECUTION), new Object[] { id, id },
235                                new JobExecutionRowMapper(jobInstance));
236 
237                Assert.state(executions.size() <= 1, "There must be at most one latest job execution");
238 
239                if (executions.isEmpty()) {
240                        return null;
241                }
242                else {
243                        return (JobExecution) executions.get(0);
244                }
245        }
246 
247        public ExecutionContext findExecutionContext(JobExecution jobExecution) {
248                return ecDao.getExecutionContext(jobExecution);
249        }
250 
251        public void saveOrUpdateExecutionContext(JobExecution jobExecution) {
252                ecDao.saveOrUpdateExecutionContext(jobExecution);
253        }
254 
255        public void setLobHandler(LobHandler lobHandler) {
256                this.lobHandler = lobHandler;
257        }
258 
259}

[all classes][org.springframework.batch.core.repository.dao]
EMMA 2.0.5312 (C) Vladimir Roubtsov