View Javadoc
1   /*
2    * Copyright 2013-2015 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.admin.web;
18  
19  import java.util.ArrayList;
20  import java.util.Collection;
21  
22  import org.springframework.batch.admin.domain.StepExecutionHistory;
23  import org.springframework.batch.admin.domain.StepExecutionInfo;
24  import org.springframework.batch.admin.domain.StepExecutionInfoResource;
25  import org.springframework.batch.admin.domain.StepExecutionProgressInfo;
26  import org.springframework.batch.admin.domain.StepExecutionProgressInfoResource;
27  import org.springframework.batch.admin.service.NoSuchStepExecutionException;
28  import org.springframework.batch.core.StepExecution;
29  import org.springframework.batch.core.launch.NoSuchJobExecutionException;
30  import org.springframework.hateoas.ExposesResourceFor;
31  import org.springframework.http.HttpStatus;
32  import org.springframework.web.bind.annotation.PathVariable;
33  import org.springframework.web.bind.annotation.RequestMapping;
34  import org.springframework.web.bind.annotation.RequestMethod;
35  import org.springframework.web.bind.annotation.ResponseStatus;
36  import org.springframework.web.bind.annotation.RestController;
37  
38  /**
39   * Controller for returning Batch {@link org.springframework.batch.core.StepExecution}s.
40   *
41   * @author Gunnar Hillert
42   * @author Dave Syer
43   * @author Ilayaperumal Gopinathan
44   * @since 2.0
45   */
46  @RestController
47  @RequestMapping("/batch/executions/{jobExecutionId}/steps")
48  @ExposesResourceFor(StepExecutionInfoResource.class)
49  public class BatchStepExecutionsController extends AbstractBatchJobsController {
50  
51  	/**
52  	 * List all step executions.
53  	 *
54  	 * @param jobExecutionId Id of the {@link org.springframework.batch.core.JobExecution}, must not be null
55  	 * @return Collection of {@link StepExecutionInfoResource} for the given jobExecutionId
56  	 * @throws org.springframework.batch.core.launch.NoSuchJobExecutionException Thrown if the respective {@link org.springframework.batch.core.JobExecution} does not exist
57  	 */
58  	@RequestMapping(value = { "" }, method = RequestMethod.GET, produces = "application/json")
59  	@ResponseStatus(HttpStatus.OK)
60  	public Collection<StepExecutionInfoResource> list(@PathVariable("jobExecutionId") long jobExecutionId) throws NoSuchJobExecutionException {
61  
62  		final Collection<StepExecution> stepExecutions;
63  
64  		try {
65  			stepExecutions = jobService.getStepExecutions(jobExecutionId);
66  		}
67  		catch (NoSuchJobExecutionException e) {
68  			throw new NoSuchJobExecutionException(String.format("Could not find jobExecution with id %s", String.valueOf(jobExecutionId)));
69  		}
70  
71  		final Collection<StepExecutionInfoResource> result = new ArrayList<StepExecutionInfoResource>();
72  
73  		for (StepExecution stepExecution : stepExecutions) {
74  			// Band-Aid to prevent Hateos crash - see XD-1206
75  			if (stepExecution.getId() != null) {
76  				result.add(stepExecutionInfoResourceAssembler.toResource(new StepExecutionInfo(stepExecution, timeZone)));
77  			}
78  		}
79  
80  		return result;
81  	}
82  
83  	/**
84  	 * Inspect the StepExecution with the provided Step Execution Id
85  	 *
86  	 * @param jobExecutionId Id of the {@link org.springframework.batch.core.JobExecution}, must not be null
87  	 * @param stepExecutionId Id of the {@link org.springframework.batch.core.StepExecution}, must not be null
88  	 * @return {@link StepExecutionInfoResource} that has the details on the given {@link org.springframework.batch.core.StepExecution}.
89  	 * @throws NoSuchJobExecutionException Thrown if the respective {@link org.springframework.batch.core.JobExecution} does not exist
90  	 * @throws org.springframework.batch.admin.service.NoSuchStepExecutionException Thrown if the respective {@link org.springframework.batch.core.StepExecution} does not exist
91  	 */
92  	@RequestMapping(value = "/{stepExecutionId}", method = RequestMethod.GET)
93  	@ResponseStatus(HttpStatus.OK)
94  	public StepExecutionInfoResource details(@PathVariable long jobExecutionId,
95  			@PathVariable long stepExecutionId) throws NoSuchStepExecutionException, NoSuchJobExecutionException {
96  		try {
97  			StepExecution stepExecution = jobService.getStepExecution(jobExecutionId, stepExecutionId);
98  			return this.stepExecutionInfoResourceAssembler.toResource(new StepExecutionInfo(stepExecution,
99  					this.timeZone));
100 		}
101 		catch (org.springframework.batch.admin.service.NoSuchStepExecutionException e) {
102 			throw new NoSuchStepExecutionException(String.format("Could not find step execution with id %s", String.valueOf(stepExecutionId)));
103 		}
104 		catch (org.springframework.batch.core.launch.NoSuchJobExecutionException e) {
105 			throw new NoSuchJobExecutionException(String.format("Could not find jobExecution with id %s", String.valueOf(jobExecutionId)));
106 		}
107 	}
108 
109 	/**
110 	 * Get the step execution progress for the given jobExecutions step.
111 	 *
112 	 * @param jobExecutionId Id of the {@link org.springframework.batch.core.JobExecution}, must not be null
113 	 * @param stepExecutionId Id of the {@link org.springframework.batch.core.StepExecution}, must not be null
114 	 * @return {@link StepExecutionInfoResource} that has the progress info on the given {@link org.springframework.batch.core.StepExecution}.
115 	 * @throws NoSuchJobExecutionException Thrown if the respective {@link org.springframework.batch.core.JobExecution} does not exist
116 	 * @throws NoSuchStepExecutionException Thrown if the respective {@link org.springframework.batch.core.StepExecution} does not exist
117 	 */
118 	@RequestMapping(value = "/{stepExecutionId}/progress", method = RequestMethod.GET)
119 	@ResponseStatus(HttpStatus.OK)
120 	public StepExecutionProgressInfoResource progress(@PathVariable long jobExecutionId,
121 			@PathVariable long stepExecutionId) throws NoSuchStepExecutionException, NoSuchJobExecutionException {
122 		try {
123 			StepExecution stepExecution = jobService.getStepExecution(jobExecutionId, stepExecutionId);
124 			String stepName = stepExecution.getStepName();
125 			if (stepName.contains(":partition")) {
126 				// assume we want to compare all partitions
127 				stepName = stepName.replaceAll("(:partition).*", "$1*");
128 			}
129 			String jobName = stepExecution.getJobExecution().getJobInstance().getJobName();
130 			StepExecutionHistory stepExecutionHistory = computeHistory(jobName, stepName);
131 			return progressInfoResourceAssembler.toResource(new StepExecutionProgressInfo(stepExecution,
132 					stepExecutionHistory, timeZone));
133 		}
134 		catch (org.springframework.batch.admin.service.NoSuchStepExecutionException e) {
135 			throw new NoSuchStepExecutionException(String.format("Could not find step execution with id %s", String.valueOf(stepExecutionId)));
136 		}
137 		catch (org.springframework.batch.core.launch.NoSuchJobExecutionException e) {
138 			throw new NoSuchJobExecutionException(String.format("Could not find jobExecution with id %s", String.valueOf(jobExecutionId)));
139 		}
140 	}
141 
142 	/**
143 	 * Compute step execution history for the given jobs step.
144 	 * 
145 	 * @param jobName the name of the job
146 	 * @param stepName the name of the step
147 	 * @return the step execution history for the given step
148 	 */
149 	private StepExecutionHistory computeHistory(String jobName, String stepName) {
150 		int total = jobService.countStepExecutionsForStep(jobName, stepName);
151 		StepExecutionHistory stepExecutionHistory = new StepExecutionHistory(stepName);
152 		for (int i = 0; i < total; i += 1000) {
153 			for (StepExecution stepExecution : jobService.listStepExecutionsForStep(jobName, stepName, i, 1000)) {
154 				stepExecutionHistory.append(stepExecution);
155 			}
156 		}
157 		return stepExecutionHistory;
158 	}
159 }