1 | /* |
2 | * Copyright 2006-2007 the original author or authors. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | package org.springframework.batch.test; |
17 | |
18 | import java.sql.ResultSet; |
19 | import java.sql.SQLException; |
20 | import java.util.ArrayList; |
21 | import java.util.Collection; |
22 | import java.util.Collections; |
23 | import java.util.List; |
24 | |
25 | import javax.sql.DataSource; |
26 | |
27 | import org.springframework.batch.core.JobExecution; |
28 | import org.springframework.batch.core.JobInstance; |
29 | import org.springframework.batch.core.JobParameter; |
30 | import org.springframework.batch.core.JobParameters; |
31 | import org.springframework.batch.core.JobParametersIncrementer; |
32 | import org.springframework.batch.core.StepExecution; |
33 | import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException; |
34 | import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException; |
35 | import org.springframework.batch.core.repository.JobRepository; |
36 | import org.springframework.batch.core.repository.JobRestartException; |
37 | import org.springframework.batch.core.repository.dao.AbstractJdbcBatchMetadataDao; |
38 | import org.springframework.beans.factory.InitializingBean; |
39 | import org.springframework.dao.DataAccessException; |
40 | import org.springframework.jdbc.core.simple.ParameterizedRowMapper; |
41 | import org.springframework.jdbc.core.simple.SimpleJdbcOperations; |
42 | import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; |
43 | import org.springframework.util.Assert; |
44 | |
45 | /** |
46 | * Convenience class for creating and removing {@link JobExecution} instances |
47 | * from a database. Typical usage in test case would be to create instances |
48 | * before a transaction, save the result, and then use it to remove them after |
49 | * the transaction. |
50 | * |
51 | * @author Dave Syer |
52 | */ |
53 | public class JobRepositoryTestUtils extends AbstractJdbcBatchMetadataDao implements InitializingBean { |
54 | |
55 | private JobRepository jobRepository; |
56 | |
57 | private JobParametersIncrementer jobParametersIncrementer = new JobParametersIncrementer() { |
58 | |
59 | Long count = 0L; |
60 | |
61 | public JobParameters getNext(JobParameters parameters) { |
62 | return new JobParameters(Collections.singletonMap("count", new JobParameter(count++))); |
63 | } |
64 | |
65 | }; |
66 | |
67 | private SimpleJdbcOperations jdbcTemplate; |
68 | |
69 | /** |
70 | * @see InitializingBean#afterPropertiesSet() |
71 | */ |
72 | public void afterPropertiesSet() throws Exception { |
73 | Assert.notNull(jobRepository, "JobRepository must be set"); |
74 | Assert.notNull(jdbcTemplate, "DataSource must be set"); |
75 | } |
76 | |
77 | /** |
78 | * Default constructor. |
79 | */ |
80 | public JobRepositoryTestUtils() { |
81 | } |
82 | |
83 | /** |
84 | * Create a {@link JobRepositoryTestUtils} with all its mandatory |
85 | * properties. |
86 | * |
87 | * @param jobRepository a {@link JobRepository} backed by a database |
88 | * @param dataSource a {@link DataSource} |
89 | */ |
90 | public JobRepositoryTestUtils(JobRepository jobRepository, DataSource dataSource) { |
91 | super(); |
92 | this.jobRepository = jobRepository; |
93 | setDataSource(dataSource); |
94 | } |
95 | |
96 | public final void setDataSource(DataSource dataSource) { |
97 | jdbcTemplate = new SimpleJdbcTemplate(dataSource); |
98 | } |
99 | |
100 | /** |
101 | * @param jobParametersIncrementer the jobParametersIncrementer to set |
102 | */ |
103 | public void setJobParametersIncrementer(JobParametersIncrementer jobParametersIncrementer) { |
104 | this.jobParametersIncrementer = jobParametersIncrementer; |
105 | } |
106 | |
107 | /** |
108 | * @param jobRepository the jobRepository to set |
109 | */ |
110 | public void setJobRepository(JobRepository jobRepository) { |
111 | this.jobRepository = jobRepository; |
112 | } |
113 | |
114 | /** |
115 | * Use the {@link JobRepository} to create some {@link JobExecution} |
116 | * instances each with the given job name and each having step executions |
117 | * with the given step names. |
118 | * |
119 | * @param jobName the name of the job |
120 | * @param stepNames the names of the step executions |
121 | * @param count the required number of instances of {@link JobExecution} to |
122 | * create |
123 | * @return a collection of {@link JobExecution} |
124 | * @throws Exception if there is a problem in the {@link JobRepository} |
125 | */ |
126 | public List<JobExecution> createJobExecutions(String jobName, String[] stepNames, int count) |
127 | throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException { |
128 | List<JobExecution> list = new ArrayList<JobExecution>(); |
129 | JobParameters jobParameters = new JobParameters(); |
130 | for (int i = 0; i < count; i++) { |
131 | JobExecution jobExecution = jobRepository.createJobExecution(jobName, jobParametersIncrementer |
132 | .getNext(jobParameters)); |
133 | list.add(jobExecution); |
134 | for (String stepName : stepNames) { |
135 | jobRepository.add(jobExecution.createStepExecution(stepName)); |
136 | } |
137 | } |
138 | return list; |
139 | } |
140 | |
141 | /** |
142 | * Use the {@link JobRepository} to create some {@link JobExecution} |
143 | * instances each with a single step execution. |
144 | * |
145 | * @param count the required number of instances of {@link JobExecution} to |
146 | * create |
147 | * @return a collection of {@link JobExecution} |
148 | * @throws Exception if there is a problem in the {@link JobRepository} |
149 | */ |
150 | public List<JobExecution> createJobExecutions(int count) throws JobExecutionAlreadyRunningException, |
151 | JobRestartException, JobInstanceAlreadyCompleteException { |
152 | return createJobExecutions("job", new String[] { "step" }, count); |
153 | } |
154 | |
155 | /** |
156 | * Remove the {@link JobExecution} instances, and all associated |
157 | * {@link JobInstance} and {@link StepExecution} instances from the standard |
158 | * RDBMS locations used by Spring Batch. |
159 | * |
160 | * @param list a list of {@link JobExecution} |
161 | * @throws DataAccessException if there is a problem |
162 | */ |
163 | public void removeJobExecutions(Collection<JobExecution> list) throws DataAccessException { |
164 | for (JobExecution jobExecution : list) { |
165 | List<Long> stepExecutionIds = jdbcTemplate.query( |
166 | getQuery("select STEP_EXECUTION_ID from %PREFIX%STEP_EXECUTION where JOB_EXECUTION_ID=?"), |
167 | new ParameterizedRowMapper<Long>() { |
168 | public Long mapRow(ResultSet rs, int rowNum) throws SQLException { |
169 | return rs.getLong(1); |
170 | } |
171 | }, jobExecution.getId()); |
172 | for (Long stepExecutionId : stepExecutionIds) { |
173 | jdbcTemplate.update(getQuery("delete from %PREFIX%STEP_EXECUTION_CONTEXT where STEP_EXECUTION_ID=?"), |
174 | stepExecutionId); |
175 | jdbcTemplate.update(getQuery("delete from %PREFIX%STEP_EXECUTION where STEP_EXECUTION_ID=?"), |
176 | stepExecutionId); |
177 | } |
178 | jdbcTemplate.update(getQuery("delete from %PREFIX%JOB_EXECUTION_CONTEXT where JOB_EXECUTION_ID=?"), |
179 | jobExecution.getId()); |
180 | jdbcTemplate.update(getQuery("delete from %PREFIX%JOB_EXECUTION where JOB_EXECUTION_ID=?"), jobExecution |
181 | .getId()); |
182 | } |
183 | for (JobExecution jobExecution : list) { |
184 | jdbcTemplate.update(getQuery("delete from %PREFIX%JOB_PARAMS where JOB_INSTANCE_ID=?"), jobExecution |
185 | .getJobId()); |
186 | jdbcTemplate.update(getQuery("delete from %PREFIX%JOB_INSTANCE where JOB_INSTANCE_ID=?"), jobExecution |
187 | .getJobId()); |
188 | } |
189 | } |
190 | |
191 | /** |
192 | * Remove all the {@link JobExecution} instances, and all associated |
193 | * {@link JobInstance} and {@link StepExecution} instances from the standard |
194 | * RDBMS locations used by Spring Batch. |
195 | * |
196 | * @param list a list of {@link JobExecution} |
197 | * @throws DataAccessException if there is a problem |
198 | */ |
199 | public void removeJobExecutions() throws DataAccessException { |
200 | |
201 | jdbcTemplate.update(getQuery("delete from %PREFIX%STEP_EXECUTION_CONTEXT")); |
202 | jdbcTemplate.update(getQuery("delete from %PREFIX%STEP_EXECUTION")); |
203 | jdbcTemplate.update(getQuery("delete from %PREFIX%JOB_EXECUTION_CONTEXT")); |
204 | jdbcTemplate.update(getQuery("delete from %PREFIX%JOB_EXECUTION")); |
205 | jdbcTemplate.update(getQuery("delete from %PREFIX%JOB_PARAMS")); |
206 | jdbcTemplate.update(getQuery("delete from %PREFIX%JOB_INSTANCE")); |
207 | |
208 | } |
209 | |
210 | } |