/* * Copyright 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 de.codecentric.batch.web; import java.io.IOException; import java.util.HashSet; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.explore.JobExplorer; import org.springframework.batch.core.launch.JobOperator; import org.springframework.batch.core.launch.NoSuchJobExecutionException; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ExceptionHandler; 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 de.codecentric.batch.monitoring.RunningExecutionTracker; /** * Controller for delivering monitoring information, like * <ul> * <li> which jobs are deployed?</li> * <li> which jobs are currently running on this machine?</li> * <li> detailed information on any running or finished job.</li> * </ul> * <p>The base url can be set via property batch.web.monitoring.base, its default is /batch/monitoring. * * There are four endpoints available: * * <ol> * <li>Retrieving the names of deployed jobs<br> * {base_url}/jobs / GET<br> * On success, it returns a JSON array of String containing the names of the deployed jobs.</li> * * <li>Retrieving the ids of JobExecutions running on this server<br> * {base_url}/jobs/runningexecutions / GET<br> * On success, it returns a JSON array containing the ids of the JobExecutions running on this server.</li> * * <li>Retrieving the ids of JobExecutions running on this server for a certain job name<br> * {base_url}/jobs/runningexecutions/{jobName} / GET<br> * On success, it returns a JSON array containing the ids of the JobExecutions running on this server * belonging to the specified job.</li> * * <li>Retrieving the JobExecution<br> * {base_url}/jobs/executions/{executionId} / GET<br> * On success, it returns a JSON representation of the JobExecution specified by the id. This representation * contains everything you need to know about that job, from job name and BatchStatus to the number of * processed items and time used and so on.<br> * If the JobExecution cannot be found, a HTTP response code 404 is returned.</li> * </ol> * * * @author Tobias Flohre * */ @RestController @RequestMapping("${batch.web.monitoring.base:/batch/monitoring}") public class JobMonitoringController { private static final Logger LOG = LoggerFactory.getLogger(JobMonitoringController.class); private JobOperator jobOperator; private JobExplorer jobExplorer; private RunningExecutionTracker runningExecutionTracker; public JobMonitoringController(JobOperator jobOperator, JobExplorer jobExplorer, RunningExecutionTracker runningExecutionTracker) { super(); this.jobOperator = jobOperator; this.jobExplorer = jobExplorer; this.runningExecutionTracker = runningExecutionTracker; } @RequestMapping(value="/jobs", method = RequestMethod.GET) public Set<String> findRegisteredJobs() throws IOException { Set<String> registeredJobs = new HashSet<>(jobOperator.getJobNames()); // Add JSR-352 jobs ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); Resource[] xmlConfigurations = resourcePatternResolver.getResources("classpath*:/META-INF/batch-jobs/*.xml"); for (Resource resource : xmlConfigurations) { registeredJobs.add(resource.getFilename().substring(0, resource.getFilename().length()-4)); } return registeredJobs; } @RequestMapping(value = "/jobs/runningexecutions", method = RequestMethod.GET) public Set<Long> findAllRunningExecutions() { return runningExecutionTracker.getAllRunningExecutionIds(); } @RequestMapping(value = "/jobs/runningexecutions/{jobName}", method = RequestMethod.GET) public Set<Long> findRunningExecutionsForJobName(@PathVariable String jobName) { return runningExecutionTracker.getRunningExecutionIdsForJobName(jobName); } @RequestMapping(value = "/jobs/executions/{executionId}", method = RequestMethod.GET) public JobExecution findExecution(@PathVariable long executionId) throws NoSuchJobExecutionException { JobExecution jobExecution = jobExplorer.getJobExecution(executionId); if (jobExecution == null){ throw new NoSuchJobExecutionException("JobExecution with id "+executionId+" not found."); } return jobExecution; } @ResponseStatus(HttpStatus.NOT_FOUND) @ExceptionHandler(NoSuchJobExecutionException.class) public String handleNotFound(Exception ex) { LOG.warn("JobExecution not found.",ex); return ex.getMessage(); } }