View Javadoc
1   /*
2    * Copyright 2009-2014 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.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   * Controller for step executions.
49   * 
50   * @author Dave Syer
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  	 * @param timeZone the timeZone to set
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 				// assume we want to compare all partitions
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 }