/*
* Copyright 2013-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.xd.dirt.rest;
import java.util.ArrayList;
import java.util.Collection;
import org.springframework.batch.admin.history.StepExecutionHistory;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.StepExecution;
import org.springframework.hateoas.ExposesResourceFor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.xd.dirt.job.NoSuchJobExecutionException;
import org.springframework.xd.dirt.job.NoSuchStepExecutionException;
import org.springframework.xd.dirt.job.StepExecutionInfo;
import org.springframework.xd.dirt.job.StepExecutionProgressInfo;
import org.springframework.xd.rest.domain.StepExecutionInfoResource;
import org.springframework.xd.rest.domain.StepExecutionProgressInfoResource;
/**
* Controller for returning Batch {@link StepExecution}s.
*
* @author Gunnar Hillert
* @author Dave Syer
* @author Ilayaperumal Gopinathan
*/
@RestController
@RequestMapping("/jobs/executions/{jobExecutionId}/steps")
@ExposesResourceFor(StepExecutionInfoResource.class)
public class BatchStepExecutionsController extends AbstractBatchJobsController {
/**
* List all step executions.
*
* @param jobExecutionId Id of the {@link JobExecution}, must not be null
* @return Collection of {@link StepExecutionInfoResource} for the given jobExecutionId
* @throws NoSuchJobExecutionException Thrown if the respective {@link JobExecution} does not exist
*/
@RequestMapping(value = { "" }, method = RequestMethod.GET, produces = "application/json")
@ResponseStatus(HttpStatus.OK)
public Collection<StepExecutionInfoResource> list(@PathVariable("jobExecutionId") long jobExecutionId) {
final Collection<StepExecution> stepExecutions;
try {
stepExecutions = jobService.getStepExecutions(jobExecutionId);
}
catch (org.springframework.batch.core.launch.NoSuchJobExecutionException e) {
throw new NoSuchJobExecutionException(jobExecutionId);
}
final Collection<StepExecutionInfoResource> result = new ArrayList<StepExecutionInfoResource>();
for (StepExecution stepExecution : stepExecutions) {
// Band-Aid to prevent Hateos crash - see XD-1206
if (stepExecution.getId() != null) {
result.add(stepExecutionInfoResourceAssembler.toResource(new StepExecutionInfo(stepExecution, timeZone)));
}
}
return result;
}
/**
* Inspect the StepExecution with the provided Step Execution Id
*
* @param jobExecutionId Id of the {@link JobExecution}, must not be null
* @param stepExecutionId Id of the {@link StepExecution}, must not be null
* @return {@link StepExecutionInfoResource} that has the details on the given {@link StepExecution}.
* @throws NoSuchJobExecutionException Thrown if the respective {@link JobExecution} does not exist
* @throws NoSuchStepExecutionException Thrown if the respective {@link StepExecution} does not exist
*/
@RequestMapping(value = "/{stepExecutionId}", method = RequestMethod.GET)
@ResponseStatus(HttpStatus.OK)
public StepExecutionInfoResource details(@PathVariable long jobExecutionId,
@PathVariable long stepExecutionId) {
try {
StepExecution stepExecution = jobService.getStepExecution(jobExecutionId, stepExecutionId);
return this.stepExecutionInfoResourceAssembler.toResource(new StepExecutionInfo(stepExecution,
this.timeZone));
}
catch (org.springframework.batch.admin.service.NoSuchStepExecutionException e) {
throw new NoSuchStepExecutionException(stepExecutionId);
}
catch (org.springframework.batch.core.launch.NoSuchJobExecutionException e) {
throw new NoSuchJobExecutionException(jobExecutionId);
}
}
/**
* Get the step execution progress for the given jobExecutions step.
*
* @param jobExecutionId Id of the {@link JobExecution}, must not be null
* @param stepExecutionId Id of the {@link StepExecution}, must not be null
* @return {@link StepExecutionInfoResource} that has the progress info on the given {@link StepExecution}.
* @throws NoSuchJobExecutionException Thrown if the respective {@link JobExecution} does not exist
* @throws NoSuchStepExecutionException Thrown if the respective {@link StepExecution} does not exist
*/
@RequestMapping(value = "/{stepExecutionId}/progress", method = RequestMethod.GET)
@ResponseStatus(HttpStatus.OK)
public StepExecutionProgressInfoResource progress(@PathVariable long jobExecutionId,
@PathVariable long stepExecutionId) {
try {
StepExecution stepExecution = jobService.getStepExecution(jobExecutionId, stepExecutionId);
String stepName = stepExecution.getStepName();
if (stepName.contains(":partition")) {
// assume we want to compare all partitions
stepName = stepName.replaceAll("(:partition).*", "$1*");
}
String jobName = stepExecution.getJobExecution().getJobInstance().getJobName();
StepExecutionHistory stepExecutionHistory = computeHistory(jobName, stepName);
return progressInfoResourceAssembler.toResource(new StepExecutionProgressInfo(stepExecution,
stepExecutionHistory));
}
catch (org.springframework.batch.admin.service.NoSuchStepExecutionException e) {
throw new NoSuchStepExecutionException(stepExecutionId);
}
catch (org.springframework.batch.core.launch.NoSuchJobExecutionException e) {
throw new NoSuchJobExecutionException(jobExecutionId);
}
}
/**
* Compute step execution history for the given jobs step.
*
* @param jobName the name of the job
* @param stepName the name of the step
* @return the step execution history for the given step
*/
private StepExecutionHistory computeHistory(String jobName, String stepName) {
int total = jobService.countStepExecutionsForStep(jobName, stepName);
StepExecutionHistory stepExecutionHistory = new StepExecutionHistory(stepName);
for (int i = 0; i < total; i += 1000) {
for (StepExecution stepExecution : jobService.listStepExecutionsForStep(jobName, stepName, i, 1000)) {
stepExecutionHistory.append(stepExecution);
}
}
return stepExecutionHistory;
}
}