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 | |
17 | package org.springframework.batch.core; |
18 | |
19 | import java.io.IOException; |
20 | import java.io.ObjectInputStream; |
21 | import java.util.ArrayList; |
22 | import java.util.Collection; |
23 | import java.util.Date; |
24 | import java.util.HashSet; |
25 | import java.util.LinkedHashSet; |
26 | import java.util.List; |
27 | import java.util.Set; |
28 | |
29 | import org.springframework.batch.item.ExecutionContext; |
30 | |
31 | /** |
32 | * Batch domain object representing the execution of a job. |
33 | * |
34 | * @author Lucas Ward |
35 | * |
36 | */ |
37 | public class JobExecution extends Entity { |
38 | |
39 | private JobInstance jobInstance; |
40 | |
41 | private volatile Collection<StepExecution> stepExecutions = new LinkedHashSet<StepExecution>(); |
42 | |
43 | private volatile BatchStatus status = BatchStatus.STARTING; |
44 | |
45 | private volatile Date startTime = null; |
46 | |
47 | private volatile Date createTime = new Date(System.currentTimeMillis()); |
48 | |
49 | private volatile Date endTime = null; |
50 | |
51 | private volatile Date lastUpdated = null; |
52 | |
53 | private volatile ExitStatus exitStatus = ExitStatus.UNKNOWN; |
54 | |
55 | private volatile ExecutionContext executionContext = new ExecutionContext(); |
56 | |
57 | private transient volatile List<Throwable> failureExceptions = new ArrayList<Throwable>(); |
58 | |
59 | /** |
60 | * Because a JobExecution isn't valid unless the job is set, this |
61 | * constructor is the only valid one from a modelling point of view. |
62 | * |
63 | * @param job the job of which this execution is a part |
64 | */ |
65 | public JobExecution(JobInstance job, Long id) { |
66 | super(id); |
67 | this.jobInstance = job; |
68 | } |
69 | |
70 | /** |
71 | * Constructor for transient (unsaved) instances. |
72 | * |
73 | * @param job the enclosing {@link JobInstance} |
74 | */ |
75 | public JobExecution(JobInstance job) { |
76 | this(job, null); |
77 | } |
78 | |
79 | public JobExecution(Long id) { |
80 | super(id); |
81 | } |
82 | |
83 | public Date getEndTime() { |
84 | return endTime; |
85 | } |
86 | |
87 | public void setJobInstance(JobInstance jobInstance) { |
88 | this.jobInstance = jobInstance; |
89 | } |
90 | |
91 | public void setEndTime(Date endTime) { |
92 | this.endTime = endTime; |
93 | } |
94 | |
95 | public Date getStartTime() { |
96 | return startTime; |
97 | } |
98 | |
99 | public void setStartTime(Date startTime) { |
100 | this.startTime = startTime; |
101 | } |
102 | |
103 | public BatchStatus getStatus() { |
104 | return status; |
105 | } |
106 | |
107 | /** |
108 | * Set the value of the status field. |
109 | * |
110 | * @param status the status to set |
111 | */ |
112 | public void setStatus(BatchStatus status) { |
113 | this.status = status; |
114 | } |
115 | |
116 | /** |
117 | * Upgrade the status field if the provided value is greater than the |
118 | * existing one. Clients using this method to set the status can be sure |
119 | * that they don't overwrite a failed status with an successful one. |
120 | * |
121 | * @param status the new status value |
122 | */ |
123 | public void upgradeStatus(BatchStatus status) { |
124 | this.status = this.status.upgradeTo(status); |
125 | } |
126 | |
127 | /** |
128 | * Convenience getter for for the id of the enclosing job. Useful for DAO |
129 | * implementations. |
130 | * |
131 | * @return the id of the enclosing job |
132 | */ |
133 | public Long getJobId() { |
134 | if (jobInstance != null) { |
135 | return jobInstance.getId(); |
136 | } |
137 | return null; |
138 | } |
139 | |
140 | /** |
141 | * @param exitStatus |
142 | */ |
143 | public void setExitStatus(ExitStatus exitStatus) { |
144 | this.exitStatus = exitStatus; |
145 | } |
146 | |
147 | /** |
148 | * @return the exitCode |
149 | */ |
150 | public ExitStatus getExitStatus() { |
151 | return exitStatus; |
152 | } |
153 | |
154 | /** |
155 | * @return the Job that is executing. |
156 | */ |
157 | public JobInstance getJobInstance() { |
158 | return jobInstance; |
159 | } |
160 | |
161 | /** |
162 | * Accessor for the step executions. |
163 | * |
164 | * @return the step executions that were registered |
165 | */ |
166 | public Collection<StepExecution> getStepExecutions() { |
167 | return stepExecutions; |
168 | } |
169 | |
170 | /** |
171 | * Register a step execution with the current job execution. |
172 | * @param stepName the name of the step the new execution is associated with |
173 | */ |
174 | public StepExecution createStepExecution(String stepName) { |
175 | StepExecution stepExecution = new StepExecution(stepName, this); |
176 | this.stepExecutions.add(stepExecution); |
177 | return stepExecution; |
178 | } |
179 | |
180 | /** |
181 | * Test if this {@link JobExecution} indicates that it is running. It should |
182 | * be noted that this does not necessarily mean that it has been persisted |
183 | * as such yet. |
184 | * @return true if the end time is null |
185 | */ |
186 | public boolean isRunning() { |
187 | return endTime == null; |
188 | } |
189 | |
190 | /** |
191 | * Test if this {@link JobExecution} indicates that it has been signalled to |
192 | * stop. |
193 | * @return true if the status is {@link BatchStatus#STOPPING} |
194 | */ |
195 | public boolean isStopping() { |
196 | return status == BatchStatus.STOPPING; |
197 | } |
198 | |
199 | /** |
200 | * Signal the {@link JobExecution} to stop. Iterates through the associated |
201 | * {@link StepExecution}s, calling {@link StepExecution#setTerminateOnly()}. |
202 | * |
203 | */ |
204 | public void stop() { |
205 | for (StepExecution stepExecution : stepExecutions) { |
206 | stepExecution.setTerminateOnly(); |
207 | } |
208 | status = BatchStatus.STOPPING; |
209 | } |
210 | |
211 | /** |
212 | * Sets the {@link ExecutionContext} for this execution |
213 | * |
214 | * @param executionContext the context |
215 | */ |
216 | public void setExecutionContext(ExecutionContext executionContext) { |
217 | this.executionContext = executionContext; |
218 | } |
219 | |
220 | /** |
221 | * Returns the {@link ExecutionContext} for this execution. The content is |
222 | * expected to be persisted after each step completion (successful or not). |
223 | * |
224 | * @return the context |
225 | */ |
226 | public ExecutionContext getExecutionContext() { |
227 | return executionContext; |
228 | } |
229 | |
230 | /** |
231 | * @return the time when this execution was created. |
232 | */ |
233 | public Date getCreateTime() { |
234 | return createTime; |
235 | } |
236 | |
237 | /** |
238 | * @param createTime creation time of this execution. |
239 | */ |
240 | public void setCreateTime(Date createTime) { |
241 | this.createTime = createTime; |
242 | } |
243 | |
244 | /** |
245 | * Package private method for re-constituting the step executions from |
246 | * existing instances. |
247 | * @param stepExecution |
248 | */ |
249 | void addStepExecution(StepExecution stepExecution) { |
250 | stepExecutions.add(stepExecution); |
251 | } |
252 | |
253 | /** |
254 | * Get the date representing the last time this JobExecution was updated in |
255 | * the JobRepository. |
256 | * |
257 | * @return Date representing the last time this JobExecution was updated. |
258 | */ |
259 | public Date getLastUpdated() { |
260 | return lastUpdated; |
261 | } |
262 | |
263 | /** |
264 | * Set the last time this JobExecution was updated. |
265 | * |
266 | * @param lastUpdated |
267 | */ |
268 | public void setLastUpdated(Date lastUpdated) { |
269 | this.lastUpdated = lastUpdated; |
270 | } |
271 | |
272 | public List<Throwable> getFailureExceptions() { |
273 | return failureExceptions; |
274 | } |
275 | |
276 | /** |
277 | * Add the provided throwable to the failure exception list. |
278 | * |
279 | * @param t |
280 | */ |
281 | public void addFailureException(Throwable t) { |
282 | this.failureExceptions.add(t); |
283 | } |
284 | |
285 | /** |
286 | * Return all failure causing exceptions for this JobExecution, including |
287 | * step executions. |
288 | * |
289 | * @return List<Throwable> containing all exceptions causing failure for |
290 | * this JobExecution. |
291 | */ |
292 | public List<Throwable> getAllFailureExceptions() { |
293 | |
294 | Set<Throwable> allExceptions = new HashSet<Throwable>(failureExceptions); |
295 | for (StepExecution stepExecution : stepExecutions) { |
296 | allExceptions.addAll(stepExecution.getFailureExceptions()); |
297 | } |
298 | |
299 | return new ArrayList<Throwable>(allExceptions); |
300 | } |
301 | |
302 | /** |
303 | * Deserialise and ensure transient fields are re-instantiated when read |
304 | * back |
305 | */ |
306 | private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { |
307 | stream.defaultReadObject(); |
308 | failureExceptions = new ArrayList<Throwable>(); |
309 | } |
310 | |
311 | /* |
312 | * (non-Javadoc) |
313 | * |
314 | * @see org.springframework.batch.core.domain.Entity#toString() |
315 | */ |
316 | public String toString() { |
317 | return super.toString() |
318 | + String.format(", startTime=%s, endTime=%s, lastUpdated=%s, status=%s, exitStatus=%s, job=[%s]", |
319 | startTime, endTime, lastUpdated, status, exitStatus, jobInstance); |
320 | } |
321 | |
322 | /** |
323 | * Setter for the step executions. For internal use only. |
324 | * @param stepExecutions |
325 | */ |
326 | public void addStepExecutions(List<StepExecution> stepExecutions) { |
327 | if (stepExecutions!=null) { |
328 | this.stepExecutions.addAll(stepExecutions); |
329 | } |
330 | } |
331 | |
332 | } |