com.vip.saturn.job.console.controller.gui.JobOverviewController Maven / Gradle / Ivy
/**
* Copyright 1999-2015 dangdang.com.
*
* 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 com.vip.saturn.job.console.controller.gui;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.vip.saturn.job.console.aop.annotation.Audit;
import com.vip.saturn.job.console.aop.annotation.AuditParam;
import com.vip.saturn.job.console.controller.SuccessResponseEntity;
import com.vip.saturn.job.console.domain.*;
import com.vip.saturn.job.console.exception.SaturnJobConsoleException;
import com.vip.saturn.job.console.mybatis.entity.JobConfig4DB;
import com.vip.saturn.job.console.service.AlarmStatisticsService;
import com.vip.saturn.job.console.service.JobService;
import com.vip.saturn.job.console.utils.*;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Pageable;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.*;
import static com.vip.saturn.job.console.exception.SaturnJobConsoleException.ERROR_CODE_BAD_REQUEST;
/**
* Job overview related operations.
*/
@RequestMapping("/console/namespaces/{namespace:.+}/jobs")
public class JobOverviewController extends AbstractGUIController {
private static final Logger log = LoggerFactory.getLogger(JobOverviewController.class);
private static final String QUERY_CONDITION_STATUS = "status";
private static final String QUERY_CONDITION_GROUP = "groups";
@Resource
private JobService jobService;
@Resource
private AlarmStatisticsService alarmStatisticsService;
/**
* 按条件分页获取域下所有作业的细节信息
* @param namespace 域名
* @return 作业细节
*/
@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
@GetMapping
public SuccessResponseEntity getJobsWithCondition(final HttpServletRequest request, @PathVariable String namespace,
@RequestParam Map condition, @RequestParam(required = false, defaultValue = "1") int page,
@RequestParam(required = false, defaultValue = "25") int size) throws SaturnJobConsoleException {
if (condition.containsKey(QUERY_CONDITION_STATUS)) {
String statusStr = checkAndGetParametersValueAsString(condition, QUERY_CONDITION_STATUS, false);
JobStatus jobStatus = JobStatus.getJobStatus(statusStr);
return new SuccessResponseEntity(getJobOverviewByStatusAndPage(namespace, jobStatus, condition, page, size));
}
return new SuccessResponseEntity(getJobOverviewByPage(namespace, condition, page, size));
}
/**
* 获取域下的总作业数、启用作业数和异常作业数
* @param namespace 域名
* @return 总作业数、启用作业数和异常作业数总数
*/
@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
@GetMapping(value = "/counts")
public SuccessResponseEntity countJobsStatus(final HttpServletRequest request, @PathVariable String namespace)
throws SaturnJobConsoleException {
return new SuccessResponseEntity(countJobOverviewVo(namespace));
}
/**
* 获取域下所有作业的名字
* @param namespace 域名
* @return 全域作业名字
*/
@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
@GetMapping(value = "/names")
public SuccessResponseEntity getJobNames(@PathVariable String namespace) throws SaturnJobConsoleException {
return new SuccessResponseEntity(jobService.getJobNames(namespace));
}
@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
@GetMapping(value = "/sharding/status")
public SuccessResponseEntity getJobsShardingStatus(@PathVariable String namespace,
@RequestParam(required = false) List jobNames) throws SaturnJobConsoleException {
Map jobShardingMap = new HashMap<>();
if (!CollectionUtils.isEmpty(jobNames)) {
for (String jobName : jobNames) {
JobStatus jobStatus = jobService.getJobStatus(namespace, jobName);
boolean isAllocated = !JobStatus.STOPPED.equals(jobStatus) && jobService
.isJobShardingAllocatedExecutor(namespace, jobName);
if (isAllocated) {
jobShardingMap.put(jobName, "已分配");
} else {
jobShardingMap.put(jobName, "未分配");
}
}
}
return new SuccessResponseEntity(jobShardingMap);
}
private JobOverviewVo getJobOverviewByPage(String namespace, Map condition, int page, int size)
throws SaturnJobConsoleException {
JobOverviewVo jobOverviewVo = new JobOverviewVo();
try {
preHandleCondition(condition);
List unSystemJobs = jobService.getUnSystemJobsWithCondition(namespace, condition, page, size);
if (unSystemJobs == null || unSystemJobs.isEmpty()) {
jobOverviewVo.setJobs(Lists.newArrayList());
jobOverviewVo.setTotalNumber(0);
return jobOverviewVo;
}
List jobOverviewList = updateJobOverviewDetail(namespace, unSystemJobs, null);
jobOverviewVo.setJobs(jobOverviewList);
jobOverviewVo.setTotalNumber(jobService.countUnSystemJobsWithCondition(namespace, condition));
} catch (SaturnJobConsoleException e) {
throw e;
} catch (Exception e) {
throw new SaturnJobConsoleException(e);
}
return jobOverviewVo;
}
private JobOverviewVo getJobOverviewByStatusAndPage(String namespace, JobStatus jobStatus,
Map condition, int page, int size) throws SaturnJobConsoleException {
JobOverviewVo jobOverviewVo = new JobOverviewVo();
try {
preHandleStatusAndCondition(condition, jobStatus);
List unSystemJobs = jobService.getUnSystemJobsWithCondition(namespace, condition, page, size);
if (unSystemJobs == null || unSystemJobs.isEmpty()) {
jobOverviewVo.setJobs(Lists.newArrayList());
jobOverviewVo.setTotalNumber(0);
return jobOverviewVo;
}
Pageable pageable = PageableUtil.generatePageble(page, size);
// 当 jobStatus 为null时,底层取数据已经做了分页,此处无需再次分页
List targetJobs = jobStatus == null ? unSystemJobs : getJobSubListByPage(unSystemJobs, pageable);
List jobOverviewList = updateJobOverviewDetail(namespace, targetJobs, jobStatus);
jobOverviewVo.setJobs(jobOverviewList);
jobOverviewVo.setTotalNumber(jobService.countUnSystemJobsWithCondition(namespace, condition));
} catch (SaturnJobConsoleException e) {
throw e;
} catch (Exception e) {
throw new SaturnJobConsoleException(e);
}
return jobOverviewVo;
}
private void preHandleCondition(Map condition) {
if (condition.containsKey(QUERY_CONDITION_GROUP) && SaturnConstants.NO_GROUPS_LABEL
.equals(condition.get(QUERY_CONDITION_GROUP))) {
condition.put(QUERY_CONDITION_GROUP, "");
}
}
private void preHandleStatusAndCondition(Map condition, JobStatus jobStatus) {
condition.put("jobStatus", jobStatus);
if (JobStatus.STOPPED.equals(jobStatus) || JobStatus.STOPPING.equals(jobStatus)) {
condition.put("isEnabled", SaturnConstants.JOB_IS_DISABLE);
} else {
condition.put("isEnabled", SaturnConstants.JOB_IS_ENABLE);
}
}
private void updateAbnormalJobSizeInOverview(String namespace, JobOverviewVo jobOverviewVo) {
try {
List abnormalJobList = alarmStatisticsService.getAbnormalJobListByNamespace(namespace);
jobOverviewVo.setAbnormalNumber(abnormalJobList.size());
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
private List updateJobOverviewDetail(String namespace, List unSystemJobs,
JobStatus jobStatus) {
List result = Lists.newArrayList();
for (JobConfig4DB jobConfig : unSystemJobs) {
try {
jobConfig.setDefaultValues();
JobOverviewJobVo jobOverviewJobVo = new JobOverviewJobVo();
SaturnBeanUtils.copyProperties(jobConfig, jobOverviewJobVo);
updateJobTypesInOverview(jobConfig, jobOverviewJobVo);
if (jobStatus == null) {
jobOverviewJobVo.setStatus(jobService.getJobStatus(namespace, jobConfig));
} else {
jobOverviewJobVo.setStatus(jobStatus);
}
result.add(jobOverviewJobVo);
} catch (Exception e) {
log.error("list job " + jobConfig.getJobName() + " error", e);
}
}
return result;
}
private void updateJobTypesInOverview(JobConfig jobConfig, JobOverviewJobVo jobOverviewJobVo) {
JobType jobType = JobType.getJobType(jobConfig.getJobType());
if (JobType.UNKNOWN_JOB == jobType) {
if (jobOverviewJobVo.getJobClass() != null
&& jobOverviewJobVo.getJobClass().indexOf("SaturnScriptJob") != -1) {
jobOverviewJobVo.setJobType(JobType.SHELL_JOB.name());
} else {
jobOverviewJobVo.setJobType(JobType.JAVA_JOB.name());
}
}
}
protected List getJobSubListByPage(List unSystemJobs, Pageable pageable) {
int totalCount = unSystemJobs.size();
int offset = pageable.getOffset();
int end = offset + pageable.getPageSize();
int fromIndex = totalCount >= offset ? offset : -1;
int toIndex = totalCount >= end ? end : totalCount;
if (fromIndex == -1 || fromIndex > toIndex) {
return Lists.newArrayList();
}
return unSystemJobs.subList(fromIndex, toIndex);
}
private JobOverviewVo countJobOverviewVo(String namespace) throws SaturnJobConsoleException {
JobOverviewVo jobOverviewVo = new JobOverviewVo();
jobOverviewVo.setTotalNumber(
jobService.countUnSystemJobsWithCondition(namespace, Maps.newHashMap()));
jobOverviewVo.setEnabledNumber(jobService.countEnabledUnSystemJobs(namespace));
// 获取该域下的异常作业数量,捕获所有异常,打日志,不抛到前台
updateAbnormalJobSizeInOverview(namespace, jobOverviewVo);
return jobOverviewVo;
}
@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
@GetMapping(value = "/groups")
public SuccessResponseEntity getGroups(final HttpServletRequest request, @PathVariable String namespace)
throws SaturnJobConsoleException {
return new SuccessResponseEntity(jobService.getGroups(namespace));
}
@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
@Audit
@PostMapping(value = "/{jobName}/enable")
public SuccessResponseEntity enableJob(final HttpServletRequest request,
@AuditParam("namespace") @PathVariable String namespace,
@AuditParam("jobName") @PathVariable String jobName) throws SaturnJobConsoleException {
assertIsPermitted(PermissionKeys.jobEnable, namespace);
jobService.enableJob(namespace, jobName, getCurrentLoginUserName());
return new SuccessResponseEntity();
}
@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
@Audit
@PostMapping(value = "/enable")
public SuccessResponseEntity batchEnableJob(final HttpServletRequest request,
@AuditParam("namespace") @PathVariable String namespace,
@AuditParam("jobNames") @RequestParam List jobNames) throws SaturnJobConsoleException {
assertIsPermitted(PermissionKeys.jobBatchEnable, namespace);
String userName = getCurrentLoginUserName();
for (String jobName : jobNames) {
jobService.enableJob(namespace, jobName, userName);
}
return new SuccessResponseEntity();
}
@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
@Audit
@PostMapping(value = "/{jobName}/disable")
public SuccessResponseEntity disableJob(final HttpServletRequest request,
@AuditParam("namespace") @PathVariable String namespace,
@AuditParam("jobName") @PathVariable String jobName) throws SaturnJobConsoleException {
assertIsPermitted(PermissionKeys.jobDisable, namespace);
jobService.disableJob(namespace, jobName, getCurrentLoginUserName());
return new SuccessResponseEntity();
}
@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
@Audit
@PostMapping(value = "/disable")
public SuccessResponseEntity batchDisableJob(final HttpServletRequest request,
@AuditParam("namespace") @PathVariable String namespace,
@AuditParam("jobNames") @RequestParam List jobNames) throws SaturnJobConsoleException {
assertIsPermitted(PermissionKeys.jobBatchDisable, namespace);
String userName = getCurrentLoginUserName();
for (String jobName : jobNames) {
jobService.disableJob(namespace, jobName, userName);
}
return new SuccessResponseEntity();
}
@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
@Audit
@DeleteMapping(value = "/{jobName}")
public SuccessResponseEntity removeJob(final HttpServletRequest request,
@AuditParam("namespace") @PathVariable String namespace,
@AuditParam("jobName") @PathVariable String jobName) throws SaturnJobConsoleException {
assertIsPermitted(PermissionKeys.jobRemove, namespace);
jobService.removeJob(namespace, jobName);
return new SuccessResponseEntity();
}
@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
@Audit
@DeleteMapping
public SuccessResponseEntity batchRemoveJob(final HttpServletRequest request,
@AuditParam("namespace") @PathVariable String namespace,
@AuditParam("jobNames") @RequestParam List jobNames) throws SaturnJobConsoleException {
assertIsPermitted(PermissionKeys.jobBatchRemove, namespace);
List successJobNames = new ArrayList<>();
List failJobNames = new ArrayList<>();
for (String jobName : jobNames) {
try {
jobService.removeJob(namespace, jobName);
successJobNames.add(jobName);
} catch (Exception e) {
failJobNames.add(jobName);
log.info("remove job failed, cause of {}", e);
}
}
if (!failJobNames.isEmpty()) {
StringBuilder message = new StringBuilder();
message.append("删除成功的作业:").append(successJobNames).append(",").append("删除失败的作业:").append(failJobNames);
throw new SaturnJobConsoleException(message.toString());
}
return new SuccessResponseEntity();
}
/**
* 批量设置作业的优先Executor
*/
@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
@Audit
@PostMapping(value = "/preferExecutors")
public SuccessResponseEntity batchSetPreferExecutors(final HttpServletRequest request,
@AuditParam("namespace") @PathVariable String namespace,
@AuditParam("jobNames") @RequestParam List jobNames,
@AuditParam("preferList") @RequestParam String preferList) throws SaturnJobConsoleException {
assertIsPermitted(PermissionKeys.jobBatchSetPreferExecutors, namespace);
String userName = getCurrentLoginUserName();
for (String jobName : jobNames) {
jobService.setPreferList(namespace, jobName, preferList, userName);
}
return new SuccessResponseEntity();
}
@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
@GetMapping(value = "/candidateDownStream")
public SuccessResponseEntity getCandidateDownStream(final HttpServletRequest request,
@PathVariable String namespace) throws SaturnJobConsoleException {
return new SuccessResponseEntity(jobService.getCandidateDownStream(namespace));
}
@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
@GetMapping(value = "/candidateUpStream")
public SuccessResponseEntity getCandidateUpStream(final HttpServletRequest request, @PathVariable String namespace)
throws SaturnJobConsoleException {
return new SuccessResponseEntity(jobService.getCandidateUpStream(namespace));
}
@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
@Audit
@PostMapping(value = "/jobs")
public SuccessResponseEntity createJob(final HttpServletRequest request,
@AuditParam("namespace") @PathVariable String namespace, JobConfig jobConfig)
throws SaturnJobConsoleException {
assertIsPermitted(PermissionKeys.jobAdd, namespace);
jobService.addJob(namespace, jobConfig, getCurrentLoginUserName());
return new SuccessResponseEntity();
}
@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
@Audit
@PostMapping(value = "/{jobNameCopied}/copy")
public SuccessResponseEntity copyJob(final HttpServletRequest request,
@AuditParam("namespace") @PathVariable String namespace,
@AuditParam("jobNameCopied") @PathVariable String jobNameCopied, JobConfig jobConfig)
throws SaturnJobConsoleException {
assertIsPermitted(PermissionKeys.jobCopy, namespace);
jobService.copyJob(namespace, jobConfig, jobNameCopied, getCurrentLoginUserName());
return new SuccessResponseEntity();
}
@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
@Audit
@PostMapping(value = "/import")
public SuccessResponseEntity importJobs(final HttpServletRequest request,
@AuditParam("namespace") @PathVariable String namespace, @RequestParam("file") MultipartFile file)
throws SaturnJobConsoleException {
assertIsPermitted(PermissionKeys.jobImport, namespace);
if (file.isEmpty()) {
throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, "请上传一个有内容的文件");
}
String originalFilename = file.getOriginalFilename();
if (originalFilename == null || !originalFilename.endsWith(".xls")) {
throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, "仅支持.xls文件导入");
}
AuditInfoContext.put("originalFilename", originalFilename);
return new SuccessResponseEntity(jobService.importJobs(namespace, file, getCurrentLoginUserName()));
}
// 导出全部的作业
@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
@Audit
@GetMapping(value = "/export")
public void exportJobs(final HttpServletRequest request, @AuditParam("namespace") @PathVariable String namespace,
final HttpServletResponse response) throws SaturnJobConsoleException {
File exportJobFile = jobService.exportJobs(namespace);
String currentTime = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
String exportFileName = namespace + "_allJobs_" + currentTime + ".xls";
SaturnConsoleUtils.exportFile(response, exportJobFile, exportFileName, true);
}
// 导出选定的作业
@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
@Audit
@GetMapping(value = "/exportSelected")
public void exportSelectedJobs(final HttpServletRequest request, @AuditParam("namespace") @PathVariable String namespace,
@RequestParam(required = false) List jobList, final HttpServletResponse response) throws SaturnJobConsoleException {
// assertIsPermitted(PermissionKeys.jobExport, namespace);
File exportJobFile = jobService.exportSelectedJobs(namespace, jobList);
String currentTime = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
String exportFileName = namespace + "_" + currentTime + ".xls";
SaturnConsoleUtils.exportFile(response, exportJobFile, exportFileName, true);
}
@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
@GetMapping(value = "/arrangeLayout")
public SuccessResponseEntity getArrangeLayout(final HttpServletRequest request, @PathVariable String namespace)
throws SaturnJobConsoleException {
return new SuccessResponseEntity(jobService.getArrangeLayout(namespace));
}
/**
* 获取该作业可选择的优先Executor
*/
@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
@GetMapping(value = "/{jobName}/executors")
public SuccessResponseEntity getExecutors(final HttpServletRequest request, @PathVariable String namespace,
@PathVariable String jobName) throws SaturnJobConsoleException {
return new SuccessResponseEntity(jobService.getCandidateExecutors(namespace, jobName));
}
/**
* 批量设置作业的分组
*/
@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
@Audit
@PostMapping(value = "/batchSetGroups")
public SuccessResponseEntity batchSetGroups(final HttpServletRequest request,
@AuditParam("namespace") @PathVariable String namespace,
@AuditParam("jobNames") @RequestParam List jobNames,
@AuditParam("oldGroupNames") @RequestParam List oldGroupNames,
@AuditParam("newGroupNames") @RequestParam List newGroupNames) throws SaturnJobConsoleException {
assertIsPermitted(PermissionKeys.jobBatchSetPreferExecutors, namespace);
String userName = getCurrentLoginUserName();
jobService.batchSetGroups(namespace, jobNames, oldGroupNames, newGroupNames, userName);
return new SuccessResponseEntity();
}
@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
@Audit
@PostMapping("/batchRunAtOnce")
public SuccessResponseEntity batchRunAtOnce(@AuditParam("namespace") @PathVariable String namespace,
@AuditParam("jobNames") @RequestParam List jobNames) throws SaturnJobConsoleException {
assertIsPermitted(PermissionKeys.jobBatchRunAtOnce, namespace);
if (!CollectionUtils.isEmpty(jobNames)) {
for (String jobName : jobNames) {
jobService.runAtOnce(namespace, jobName);
}
}
return new SuccessResponseEntity();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy