123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 |
- /*
- * <<
- * Davinci
- * ==
- * Copyright (C) 2016 - 2019 EDP
- * ==
- * 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 edp.davinci.service.impl;
- import com.alibaba.druid.util.StringUtils;
- import com.alibaba.fastjson.JSONObject;
- import edp.core.common.quartz.ScheduleService;
- import edp.core.enums.MailContentTypeEnum;
- import edp.core.exception.ServerException;
- import edp.core.model.MailAttachment;
- import edp.core.model.MailContent;
- import edp.core.utils.CollectionUtils;
- import edp.core.utils.MailUtils;
- import edp.davinci.core.common.Constants;
- import edp.davinci.core.enums.ActionEnum;
- import edp.davinci.core.enums.CronJobMediaType;
- import edp.davinci.core.enums.FileTypeEnum;
- import edp.davinci.core.enums.LogNameEnum;
- import edp.davinci.dao.*;
- import edp.davinci.dto.cronJobDto.CronJobConfig;
- import edp.davinci.dto.cronJobDto.CronJobContent;
- import edp.davinci.dto.cronJobDto.ExcelContent;
- import edp.davinci.dto.cronJobDto.MsgMailExcel;
- import edp.davinci.dto.dashboardDto.DashboardWithPortal;
- import edp.davinci.dto.projectDto.ProjectDetail;
- import edp.davinci.dto.widgetDto.WidgetWithRelationDashboardId;
- import edp.davinci.dto.widgetDto.WidgetWithVizId;
- import edp.davinci.model.*;
- import edp.davinci.service.ProjectService;
- import edp.davinci.service.excel.ExecutorUtils;
- import edp.davinci.service.excel.MsgWrapper;
- import edp.davinci.service.excel.WidgetContext;
- import edp.davinci.service.excel.WorkBookContext;
- import edp.davinci.service.screenshot.ImageContent;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.beans.BeanUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.stereotype.Service;
- import java.util.*;
- import java.util.concurrent.CopyOnWriteArrayList;
- import java.util.concurrent.Future;
- import java.util.concurrent.TimeUnit;
- import java.util.concurrent.atomic.AtomicInteger;
- import java.util.stream.Collectors;
- import static edp.core.consts.Consts.AT_SYMBOL;
- import static edp.core.consts.Consts.EMPTY;
- @Service("emailScheduleService")
- public class EmailScheduleServiceImpl extends BaseScheduleService implements ScheduleService {
- private static final Logger scheduleLogger = LoggerFactory.getLogger(LogNameEnum.BUSINESS_SCHEDULE.getName());
- @Autowired
- private CronJobMapper cronJobMapper;
- @Autowired
- private MailUtils mailUtils;
- @Autowired
- private UserMapper userMapper;
- @Autowired
- private WidgetMapper widgetMapper;
- @Autowired
- private DashboardMapper dashboardMapper;
- @Autowired
- private MemDashboardWidgetMapper memDashboardWidgetMapper;
- @Autowired
- private DisplayMapper displayMapper;
- @Autowired
- private ProjectService projectService;
- @Value("${source.result-limit:1000000}")
- private int resultLimit;
- @Override
- public void execute(long jobId) throws Exception {
- CronJob cronJob = cronJobMapper.getById(jobId);
- if (null == cronJob || StringUtils.isEmpty(cronJob.getConfig())) {
- scheduleLogger.error("CronJob({}) config is empty", jobId);
- return;
- }
- cronJobMapper.updateExecLog(jobId, "");
- CronJobConfig cronJobConfig = null;
- try {
- cronJobConfig = JSONObject.parseObject(cronJob.getConfig(), CronJobConfig.class);
- } catch (Exception e) {
- scheduleLogger.error("Cronjob({}) parse config({}) error:{}", jobId, cronJob.getConfig(), e.getMessage());
- return;
- }
- if (StringUtils.isEmpty(cronJobConfig.getType())) {
- scheduleLogger.error("Cronjob({}) config type is empty", jobId);
- return;
- }
- scheduleLogger.info("CronJob({}) is start! --------------", jobId);
- List<ExcelContent> excels = null;
- List<ImageContent> images = null;
- User creator = userMapper.getById(cronJob.getCreateBy());
- if (cronJobConfig.getType().equals(CronJobMediaType.IMAGE.getType())) {
- images = generateImages(jobId, cronJobConfig, creator.getId());
- }
- if (cronJobConfig.getType().equals(CronJobMediaType.EXCEL.getType())) {
- excels = generateExcels(jobId, cronJobConfig, creator);
- }
- if (cronJobConfig.getType().equals(CronJobMediaType.IMAGEANDEXCEL.getType())) {
- images = generateImages(jobId, cronJobConfig, creator.getId());
- excels = generateExcels(jobId, cronJobConfig, creator);
- }
- List<MailAttachment> attachmentList = new ArrayList<>();
- if (!CollectionUtils.isEmpty(excels)) {
- excels.forEach(excel -> attachmentList.add(new MailAttachment(excel.getName() + FileTypeEnum.XLSX.getFormat(), excel.getFile())));
- }
- if (!CollectionUtils.isEmpty(images)) {
- images.forEach(image -> {
- String contentId = CronJobMediaType.IMAGE.getType() +
- Constants.UNDERLINE +
- UUID.randomUUID().toString().replaceAll(Constants.MINUS, EMPTY);
- attachmentList.add(new MailAttachment(contentId, image.getImageFile(), image.getUrl(), true));
- });
- }
- if (CollectionUtils.isEmpty(attachmentList)) {
- scheduleLogger.warn("CronJob({}) email content is empty", jobId);
- return;
- }
- scheduleLogger.info("CronJob({}) is ready to send email", cronJob.getId());
- MailContent mailContent = null;
- try {
- mailContent = MailContent.MailContentBuilder.builder()
- .withSubject(cronJobConfig.getSubject())
- .withTo(cronJobConfig.getTo())
- .withCc(cronJobConfig.getCc())
- .withBcc(cronJobConfig.getBcc())
- .withMainContent(MailContentTypeEnum.HTML)
- .withHtmlContent(cronJobConfig.getContent())
- .withTemplate(Constants.SCHEDULE_MAIL_TEMPLATE)
- .withAttachments(attachmentList)
- .build();
- } catch (ServerException e) {
- scheduleLogger.error("CronJob({}) build email content error:{}", jobId, e.getMessage());
- }
- mailUtils.sendMail(mailContent, null);
- scheduleLogger.info("CronJob({}) is finish! --------------", jobId);
- }
- /**
- * 根据job配置生成excel
- *
- * @param jobId
- * @param cronJobConfig
- * @return
- * @throws Exception
- */
- private List<ExcelContent> generateExcels(Long jobId, CronJobConfig cronJobConfig, User user) throws Exception {
- scheduleLogger.info("CronJob({}) fetching excel contents", jobId);
- Map<String, WorkBookContext> workBookContextMap = new HashMap<>();
- Map<String, Integer> vizOrderMap = new HashMap<>();
- Map<Long, Map<Long, Integer>> displayPageMap = new HashMap<>();
- Map<String, Integer> excelEntityOrderMap = new HashMap<>();
- List<CronJobContent> jobContentList = getCronJobContents(cronJobConfig, vizOrderMap, displayPageMap);
- if (CollectionUtils.isEmpty(jobContentList)) {
- scheduleLogger.warn("CronJob({}) excel entity is empty", jobId);
- return null;
- }
- for (CronJobContent cronJobContent : jobContentList) {
- int order = 0;
- if (cronJobContent.getContentType().equalsIgnoreCase(DISPLAY)) {
- if (vizOrderMap.containsKey(DISPLAY + AT_SYMBOL + cronJobContent.getId())) {
- order = vizOrderMap.get(DISPLAY + AT_SYMBOL + cronJobContent.getId());
- }
- Display display = displayMapper.getById(cronJobContent.getId());
- List<WidgetWithVizId> widgetsWithSlideIdList = widgetMapper.queryByDisplayId(cronJobContent.getId());
- if (display != null && !CollectionUtils.isEmpty(widgetsWithSlideIdList)) {
- ProjectDetail projectDetail = projectService.getProjectDetail(display.getProjectId(), user, false);
- boolean isMaintainer = projectService.isMaintainer(projectDetail, user);
- Map<Long, Integer> slidePageMap = displayPageMap.get(cronJobContent.getId());
- Map<Long, List<WidgetWithVizId>> slideWidgetsMap = widgetsWithSlideIdList.stream().collect(Collectors.groupingBy(WidgetWithVizId::getVizId));
- int slidePageSize = slideWidgetsMap.size();
- List<Long> slideIds = new ArrayList<>();
- if (CollectionUtils.isEmpty(cronJobContent.getItems())) {
- //all of slides in display
- slideIds.addAll(slideWidgetsMap.keySet());
- } else {
- //checked slides in display
- slideIds = cronJobContent.getItems();
- }
- for (Long slideId : slideIds) {
- List<WidgetWithVizId> widgets = slideWidgetsMap.get(slideId);
- if (CollectionUtils.isEmpty(widgets)) {
- continue;
- }
- List<WidgetContext> widgetContexts = new ArrayList<>();
- widgets.forEach(widget -> {
- widgetContexts.add(new WidgetContext(widget, isMaintainer, null));
- });
- WorkBookContext workBookContext = WorkBookContext.WorkBookContextBuilder.newBuilder()
- .withWidgets(widgetContexts)
- .withUser(user)
- .withResultLimit(resultLimit)
- .withTaskKey("Schedule_" + jobId)
- .withCustomLogger(scheduleLogger)
- .build();
- int page = slidePageMap.get(slideId);
- String workBookName = slidePageSize == 1 ? display.getName() : display.getName() + "(" + page + ")";
- workBookContextMap.put(workBookName, workBookContext);
- excelEntityOrderMap.put(workBookName, order + page);
- }
- }
- } else {
- if (vizOrderMap.containsKey(DASHBOARD + AT_SYMBOL + cronJobContent.getId())) {
- order = vizOrderMap.get(DASHBOARD + AT_SYMBOL + cronJobContent.getId());
- }
- DashboardWithPortal dashboard = dashboardMapper.getDashboardWithPortalAndProject(cronJobContent.getId());
- excelEntityOrderMap.put(dashboard.getName(), vizOrderMap.get(DASHBOARD + AT_SYMBOL + cronJobContent.getId()));
- ProjectDetail projectDetail = projectService.getProjectDetail(dashboard.getProject().getId(), user, false);
- boolean isMaintainer = projectService.isMaintainer(projectDetail, user);
- List<WidgetWithRelationDashboardId> widgets = widgetMapper.getByDashboard(cronJobContent.getId());
- if (!CollectionUtils.isEmpty(widgets)) {
- List<MemDashboardWidget> mdws = memDashboardWidgetMapper.getByDashboardId(dashboard.getId());
- Map<Long, MemDashboardWidget> mdwMap = mdws.stream().collect(Collectors.toMap(o -> o.getWidgetId(), o -> o, (oldV, newV) -> oldV));
- List<WidgetContext> widgetContexts = new ArrayList<>();
- widgets.forEach(w -> {
- Widget widget = new Widget();
- BeanUtils.copyProperties(w, widget);
- WidgetContext context = new WidgetContext(widget, dashboard, mdwMap.get(widget.getId()), null);
- context.setIsMaintainer(isMaintainer);
- widgetContexts.add(context);
- });
- WorkBookContext workBookContext = WorkBookContext.WorkBookContextBuilder.newBuilder()
- .withWidgets(widgetContexts)
- .withUser(user)
- .withResultLimit(resultLimit)
- .withTaskKey("Schedule_" + jobId)
- .withCustomLogger(scheduleLogger)
- .build();
- workBookContextMap.put(dashboard.getName(), workBookContext);
- excelEntityOrderMap.put(dashboard.getName(), order);
- }
- }
- }
- if (CollectionUtils.isEmpty(workBookContextMap)) {
- scheduleLogger.warn("CronJob({}) workbook context is empty", jobId);
- return null;
- }
- List<ExcelContent> excelContents = new CopyOnWriteArrayList<>();
- Map<String, Future<String>> excelPathFutureMap = new LinkedHashMap<>();
- int contextSize = workBookContextMap.size();
- final AtomicInteger index = new AtomicInteger(1);
- workBookContextMap.forEach((name, context) -> {
- scheduleLogger.info("CronJob({}) submit workbook task:{}, thread:{}, total:{}", jobId, name, index, contextSize);
- try {
- String uuid = UUID.randomUUID().toString().replace("-", EMPTY);
- context.setWrapper(new MsgWrapper(new MsgMailExcel(jobId), ActionEnum.MAIL, uuid));
- excelPathFutureMap.put(name, ExecutorUtils.submitWorkbookTask(context, scheduleLogger));
- }catch (Exception e) {
- scheduleLogger.error("Cronjob({}) submit workbook task error, thread:{}", jobId, index.get());
- scheduleLogger.error(e.getMessage(), e);
- }finally {
- index.incrementAndGet();
- }
- });
- excelPathFutureMap.forEach((name, future) -> {
- String excelPath = null;
- try {
- excelPath = future.get(1, TimeUnit.HOURS);
- scheduleLogger.info("CronJob({}) workbook task:{} finish", jobId, name);
- } catch (Exception e) {
- scheduleLogger.info("CronJob({}) workbook task:{} error", jobId, name);
- scheduleLogger.error(e.getMessage(), e);
- }
- if (!StringUtils.isEmpty(excelPath)) {
- excelContents.add(new ExcelContent(excelEntityOrderMap.get(name), name, excelPath));
- }
- });
- excelContents.sort(Comparator.comparing(ExcelContent::getOrder));
- scheduleLogger.info("CronJob({}) fetched excel contents, count:{}", jobId, excelContents.size());
- return excelContents.isEmpty() ? null : excelContents;
- }
- }
|