1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.springframework.batch.admin.web;
17
18 import java.io.IOException;
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.Date;
22 import java.util.HashMap;
23 import java.util.Map;
24 import java.util.TimeZone;
25
26 import com.fasterxml.jackson.databind.ObjectMapper;
27
28 import org.springframework.batch.admin.domain.JobExecutionInfo;
29 import org.springframework.batch.admin.domain.StepExecutionHistory;
30 import org.springframework.batch.admin.domain.StepExecutionInfo;
31 import org.springframework.batch.admin.domain.StepExecutionProgress;
32 import org.springframework.batch.admin.service.JobService;
33 import org.springframework.batch.admin.service.NoSuchStepExecutionException;
34 import org.springframework.batch.core.JobExecution;
35 import org.springframework.batch.core.StepExecution;
36 import org.springframework.batch.core.launch.NoSuchJobExecutionException;
37 import org.springframework.beans.factory.annotation.Autowired;
38 import org.springframework.beans.factory.annotation.Qualifier;
39 import org.springframework.stereotype.Controller;
40 import org.springframework.ui.Model;
41 import org.springframework.validation.Errors;
42 import org.springframework.web.bind.annotation.ModelAttribute;
43 import org.springframework.web.bind.annotation.PathVariable;
44 import org.springframework.web.bind.annotation.RequestMapping;
45 import org.springframework.web.bind.annotation.RequestMethod;
46
47
48
49
50
51
52
53 @Controller
54 public class StepExecutionController {
55 private JobService jobService;
56 private ObjectMapper objectMapper;
57 private TimeZone timeZone = TimeZone.getDefault();
58
59
60
61
62 @Autowired(required=false)
63 @Qualifier("userTimeZone")
64 public void setTimeZone(TimeZone timeZone) {
65 this.timeZone = timeZone;
66 }
67
68 @Autowired
69 public void setObjectMapper(ObjectMapper objectMapper) {
70 this.objectMapper = objectMapper;
71 }
72
73 @Autowired
74 public StepExecutionController(JobService jobService) {
75 super();
76 this.jobService = jobService;
77 }
78
79 @RequestMapping(value = "/jobs/executions/{jobExecutionId}/steps", method = RequestMethod.GET)
80 public String list(Model model, @PathVariable Long jobExecutionId, @ModelAttribute("date") Date date, Errors errors) {
81
82 Collection<StepExecutionInfo> result = new ArrayList<StepExecutionInfo>();
83 try {
84 for (StepExecution stepExecution : jobService.getStepExecutions(jobExecutionId)) {
85 result.add(new StepExecutionInfo(stepExecution, timeZone));
86 }
87 JobExecution jobExecution = jobService.getJobExecution(jobExecutionId);
88 model.addAttribute(new JobExecutionInfo(jobExecution, timeZone));
89 }
90 catch (NoSuchJobExecutionException e) {
91 errors.reject("no.such.job.execution", new Object[] { jobExecutionId }, "There is no such job execution ("
92 + jobExecutionId + ")");
93 }
94 model.addAttribute("stepExecutions", result);
95
96 return "jobs/executions/steps";
97
98 }
99
100 @RequestMapping(value = "/jobs/executions/{jobExecutionId}/steps/{stepExecutionId}", method = RequestMethod.GET)
101 public String detail(Model model, @PathVariable Long jobExecutionId, @PathVariable Long stepExecutionId,
102 @ModelAttribute("date") Date date, Errors errors) {
103
104 try {
105 StepExecution stepExecution = jobService.getStepExecution(jobExecutionId, stepExecutionId);
106 model.addAttribute(new StepExecutionInfo(stepExecution, timeZone));
107 }
108 catch (NoSuchStepExecutionException e) {
109 errors.reject("no.such.step.execution", new Object[] { stepExecutionId }, "There is no such step execution ("
110 + stepExecutionId + ")");
111 }
112 catch (NoSuchJobExecutionException e) {
113 errors.reject("no.such.job.execution", new Object[] { jobExecutionId }, "There is no such job execution ("
114 + jobExecutionId + ")");
115 }
116
117 return "jobs/executions/step";
118
119 }
120
121 @RequestMapping(value = "/jobs/executions/{jobExecutionId}/steps/{stepExecutionId}/progress", method = RequestMethod.GET)
122 public String history(Model model, @PathVariable Long jobExecutionId, @PathVariable Long stepExecutionId,
123 @ModelAttribute("date") Date date, Errors errors) {
124
125 try {
126 StepExecution stepExecution = jobService.getStepExecution(jobExecutionId, stepExecutionId);
127 model.addAttribute(new StepExecutionInfo(stepExecution, timeZone));
128 String stepName = stepExecution.getStepName();
129 if (stepName.contains(":partition")) {
130
131 stepName = stepName.replaceAll("(:partition).*", "$1*");
132 }
133 String jobName = stepExecution.getJobExecution().getJobInstance().getJobName();
134 StepExecutionHistory stepExecutionHistory = computeHistory(jobName, stepName);
135 model.addAttribute(stepExecutionHistory);
136 model.addAttribute(new StepExecutionProgress(stepExecution, stepExecutionHistory));
137 }
138 catch (NoSuchStepExecutionException e) {
139 errors.reject("no.such.step.execution", new Object[] { stepExecutionId }, "There is no such step execution ("
140 + stepExecutionId + ")");
141 }
142 catch (NoSuchJobExecutionException e) {
143 errors.reject("no.such.job.execution", new Object[] { jobExecutionId }, "There is no such job execution ("
144 + jobExecutionId + ")");
145 }
146
147 return "jobs/executions/step/progress";
148
149 }
150
151 private StepExecutionHistory computeHistory(String jobName, String stepName) {
152 int total = jobService.countStepExecutionsForStep(jobName, stepName);
153 StepExecutionHistory stepExecutionHistory = new StepExecutionHistory(stepName);
154 for (int i = 0; i < total; i += 1000) {
155 for (StepExecution stepExecution : jobService.listStepExecutionsForStep(jobName, stepName, i, 1000)) {
156 stepExecutionHistory.append(stepExecution);
157 }
158 }
159 return stepExecutionHistory;
160 }
161
162 @RequestMapping(value = "/jobs/executions/{jobExecutionId}/steps/{stepExecutionId}/execution-context", method = RequestMethod.GET)
163 public String getStepExecutionContext(Model model, @PathVariable Long jobExecutionId, @PathVariable Long stepExecutionId,
164 @ModelAttribute("date") Date date, Errors errors) {
165 try {
166 StepExecution stepExecution = jobService.getStepExecution(jobExecutionId, stepExecutionId);
167 Map<String, Object> executionMap = new HashMap<String, Object>();
168
169 for (Map.Entry<String, Object> entry : stepExecution.getExecutionContext().entrySet()) {
170 executionMap.put(entry.getKey(), entry.getValue());
171 }
172
173 model.addAttribute("stepExecutionContext", objectMapper.writeValueAsString(executionMap));
174 model.addAttribute("stepExecutionId", stepExecutionId);
175 model.addAttribute("stepName", stepExecution.getStepName());
176 model.addAttribute("jobExecutionId", jobExecutionId);
177 }
178 catch (NoSuchJobExecutionException e) {
179 errors.reject("no.such.job.execution", new Object[] { jobExecutionId }, "There is no such job execution ("
180 + jobExecutionId + ")");
181 }
182 catch (NoSuchStepExecutionException e) {
183 errors.reject("no.such.step.execution", new Object[] { stepExecutionId }, "There is no such step execution ("
184 + stepExecutionId + ")");
185 }
186 catch (IOException e) {
187 errors.reject("serialization.error", new Object[] { jobExecutionId }, "Error serializing execution context for step execution ("
188 + stepExecutionId + ")");
189 }
190
191 return "jobs/executions/step/execution-context";
192 }
193 }