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.JdbcOperations; |
41 | import org.springframework.jdbc.core.JdbcTemplate; |
42 | import org.springframework.jdbc.core.simple.ParameterizedRowMapper; |
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 | @Override |
62 | public JobParameters getNext(JobParameters parameters) { |
63 | return new JobParameters(Collections.singletonMap("count", new JobParameter(count++))); |
64 | } |
65 | |
66 | }; |
67 | |
68 | private JdbcOperations jdbcTemplate; |
69 | |
70 | /** |
71 | * @see InitializingBean#afterPropertiesSet() |
72 | */ |
73 | @Override |
74 | public void afterPropertiesSet() throws Exception { |
75 | Assert.notNull(jobRepository, "JobRepository must be set"); |
76 | Assert.notNull(jdbcTemplate, "DataSource must be set"); |
77 | } |
78 | |
79 | /** |
80 | * Default constructor. |
81 | */ |
82 | public JobRepositoryTestUtils() { |
83 | } |
84 | |
85 | /** |
86 | * Create a {@link JobRepositoryTestUtils} with all its mandatory |
87 | * properties. |
88 | * |
89 | * @param jobRepository a {@link JobRepository} backed by a database |
90 | * @param dataSource a {@link DataSource} |
91 | */ |
92 | public JobRepositoryTestUtils(JobRepository jobRepository, DataSource dataSource) { |
93 | super(); |
94 | this.jobRepository = jobRepository; |
95 | setDataSource(dataSource); |
96 | } |
97 | |
98 | public final void setDataSource(DataSource dataSource) { |
99 | jdbcTemplate = new JdbcTemplate(dataSource); |
100 | } |
101 | |
102 | /** |
103 | * @param jobParametersIncrementer the jobParametersIncrementer to set |
104 | */ |
105 | public void setJobParametersIncrementer(JobParametersIncrementer jobParametersIncrementer) { |
106 | this.jobParametersIncrementer = jobParametersIncrementer; |
107 | } |
108 | |
109 | /** |
110 | * @param jobRepository the jobRepository to set |
111 | */ |
112 | public void setJobRepository(JobRepository jobRepository) { |
113 | this.jobRepository = jobRepository; |
114 | } |
115 | |
116 | /** |
117 | * Use the {@link JobRepository} to create some {@link JobExecution} |
118 | * instances each with the given job name and each having step executions |
119 | * with the given step names. |
120 | * |
121 | * @param jobName the name of the job |
122 | * @param stepNames the names of the step executions |
123 | * @param count the required number of instances of {@link JobExecution} to |
124 | * create |
125 | * @return a collection of {@link JobExecution} |
126 | * @throws Exception if there is a problem in the {@link JobRepository} |
127 | */ |
128 | public List<JobExecution> createJobExecutions(String jobName, String[] stepNames, int count) |
129 | throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException { |
130 | List<JobExecution> list = new ArrayList<JobExecution>(); |
131 | JobParameters jobParameters = new JobParameters(); |
132 | for (int i = 0; i < count; i++) { |
133 | JobExecution jobExecution = jobRepository.createJobExecution(jobName, jobParametersIncrementer |
134 | .getNext(jobParameters)); |
135 | list.add(jobExecution); |
136 | for (String stepName : stepNames) { |
137 | jobRepository.add(jobExecution.createStepExecution(stepName)); |
138 | } |
139 | } |
140 | return list; |
141 | } |
142 | |
143 | /** |
144 | * Use the {@link JobRepository} to create some {@link JobExecution} |
145 | * instances each with a single step execution. |
146 | * |
147 | * @param count the required number of instances of {@link JobExecution} to |
148 | * create |
149 | * @return a collection of {@link JobExecution} |
150 | * @throws Exception if there is a problem in the {@link JobRepository} |
151 | */ |
152 | public List<JobExecution> createJobExecutions(int count) throws JobExecutionAlreadyRunningException, |
153 | JobRestartException, JobInstanceAlreadyCompleteException { |
154 | return createJobExecutions("job", new String[] { "step" }, count); |
155 | } |
156 | |
157 | /** |
158 | * Remove the {@link JobExecution} instances, and all associated |
159 | * {@link JobInstance} and {@link StepExecution} instances from the standard |
160 | * RDBMS locations used by Spring Batch. |
161 | * |
162 | * @param list a list of {@link JobExecution} |
163 | * @throws DataAccessException if there is a problem |
164 | */ |
165 | public void removeJobExecutions(Collection<JobExecution> list) throws DataAccessException { |
166 | for (JobExecution jobExecution : list) { |
167 | List<Long> stepExecutionIds = jdbcTemplate.query( |
168 | getQuery("select STEP_EXECUTION_ID from %PREFIX%STEP_EXECUTION where JOB_EXECUTION_ID=?"), |
169 | new ParameterizedRowMapper<Long>() { |
170 | @Override |
171 | public Long mapRow(ResultSet rs, int rowNum) throws SQLException { |
172 | return rs.getLong(1); |
173 | } |
174 | }, jobExecution.getId()); |
175 | for (Long stepExecutionId : stepExecutionIds) { |
176 | jdbcTemplate.update(getQuery("delete from %PREFIX%STEP_EXECUTION_CONTEXT where STEP_EXECUTION_ID=?"), |
177 | stepExecutionId); |
178 | jdbcTemplate.update(getQuery("delete from %PREFIX%STEP_EXECUTION where STEP_EXECUTION_ID=?"), |
179 | stepExecutionId); |
180 | } |
181 | jdbcTemplate.update(getQuery("delete from %PREFIX%JOB_EXECUTION_CONTEXT where JOB_EXECUTION_ID=?"), |
182 | jobExecution.getId()); |
183 | jdbcTemplate.update(getQuery("delete from %PREFIX%JOB_EXECUTION_PARAMS where JOB_EXECUTION_ID=?"), jobExecution |
184 | .getId()); |
185 | jdbcTemplate.update(getQuery("delete from %PREFIX%JOB_EXECUTION where JOB_EXECUTION_ID=?"), jobExecution |
186 | .getId()); |
187 | } |
188 | for (JobExecution jobExecution : list) { |
189 | jdbcTemplate.update(getQuery("delete from %PREFIX%JOB_INSTANCE where JOB_INSTANCE_ID=?"), jobExecution |
190 | .getJobId()); |
191 | } |
192 | } |
193 | |
194 | /** |
195 | * Remove all the {@link JobExecution} instances, and all associated |
196 | * {@link JobInstance} and {@link StepExecution} instances from the standard |
197 | * RDBMS locations used by Spring Batch. |
198 | * |
199 | * @throws DataAccessException if there is a problem |
200 | */ |
201 | public void removeJobExecutions() throws DataAccessException { |
202 | jdbcTemplate.update(getQuery("delete from %PREFIX%STEP_EXECUTION_CONTEXT")); |
203 | jdbcTemplate.update(getQuery("delete from %PREFIX%STEP_EXECUTION")); |
204 | jdbcTemplate.update(getQuery("delete from %PREFIX%JOB_EXECUTION_CONTEXT")); |
205 | jdbcTemplate.update(getQuery("delete from %PREFIX%JOB_EXECUTION_PARAMS")); |
206 | jdbcTemplate.update(getQuery("delete from %PREFIX%JOB_EXECUTION")); |
207 | jdbcTemplate.update(getQuery("delete from %PREFIX%JOB_INSTANCE")); |
208 | |
209 | } |
210 | |
211 | } |