001/* 002 * Copyright 2017 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.plugins.extraction.execution; 017 018import java.io.File; 019import java.nio.file.Path; 020import java.time.ZonedDateTime; 021import java.time.format.DateTimeFormatter; 022import java.util.HashMap; 023import java.util.Map; 024import java.util.Optional; 025import java.util.Set; 026import java.util.regex.Pattern; 027 028import org.apache.avalon.framework.service.ServiceException; 029import org.apache.avalon.framework.service.ServiceManager; 030import org.apache.commons.lang3.StringUtils; 031import org.apache.commons.lang3.exception.ExceptionUtils; 032import org.quartz.JobDataMap; 033import org.quartz.JobExecutionContext; 034 035import org.ametys.cms.schedule.AbstractSendingMailSchedulable; 036import org.ametys.core.schedule.Schedulable; 037import org.ametys.core.util.I18nUtils; 038import org.ametys.core.util.JSONUtils; 039import org.ametys.plugins.core.schedule.Scheduler; 040import org.ametys.plugins.extraction.ExtractionConstants; 041import org.ametys.plugins.extraction.execution.pipeline.PipelineDescriptor; 042import org.ametys.plugins.extraction.execution.pipeline.PipelineManager; 043import org.ametys.runtime.config.Config; 044import org.ametys.runtime.i18n.I18nizableText; 045import org.ametys.runtime.i18n.I18nizableTextParameter; 046import org.ametys.runtime.util.AmetysHomeHelper; 047 048/** 049 * A {@link Schedulable} job which execute an extraction 050 */ 051public class ExecuteExtractionSchedulable extends AbstractSendingMailSchedulable 052{ 053 /** The key for the extraction definition file */ 054 public static final String DEFINITION_FILE_PATH_KEY = "definitionFilePath"; 055 /** The key for the variables values */ 056 public static final String VARIABLES_KEY = "variables"; 057 /** The key for the recipient */ 058 public static final String RECIPIENT_KEY = "recipient"; 059 /** The key for the pipeline */ 060 public static final String PIPELINE_KEY = "pipeline"; 061 062 private static final String __JOBDATAMAP_DEFINITION_FILE_PATH_KEY = Scheduler.PARAM_VALUES_PREFIX + DEFINITION_FILE_PATH_KEY; 063 private static final String __JOBDATAMAP_VARIABLES_KEY = Scheduler.PARAM_VALUES_PREFIX + VARIABLES_KEY; 064 private static final String __JOBDATAMAP_RECIPIENT_KEY = Scheduler.PARAM_VALUES_PREFIX + RECIPIENT_KEY; 065 private static final String __JOBDATAMAP_PIPELINE_KEY = Scheduler.PARAM_VALUES_PREFIX + PIPELINE_KEY; 066 067 private static final String __RESULT_FILE_PATHS = "resultFilePaths"; 068 069 private static final DateTimeFormatter RESULT_FILE_NAME_DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd'T'HH.mm.ss"); 070 071 private JSONUtils _jsonUtils; 072 private PipelineManager _pipelineManager; 073 private ExtractionExecutor _extractionExecutor; 074 075 @Override 076 public void service(ServiceManager manager) throws ServiceException 077 { 078 super.service(manager); 079 _jsonUtils = (JSONUtils) manager.lookup(JSONUtils.ROLE); 080 _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE); 081 _pipelineManager = (PipelineManager) manager.lookup(PipelineManager.ROLE); 082 _extractionExecutor = (ExtractionExecutor) manager.lookup(ExtractionExecutor.ROLE); 083 } 084 085 @Override 086 public void _doExecute(JobExecutionContext context) throws Exception 087 { 088 JobDataMap jobDataMap = context.getJobDetail().getJobDataMap(); 089 090 String definitionFilePath = _getDefinitionFilePath(context); 091 PipelineDescriptor pipeline = _pipelineManager.get(jobDataMap.getString(__JOBDATAMAP_PIPELINE_KEY)); 092 String defaultResultFileName = _getDefaultResultFileName(definitionFilePath, pipeline); 093 094 Map<String, Object> parameters = _getExtractionParameters(jobDataMap); 095 String lang = (String) parameters.get("lang"); 096 097 Set<Path> resultFilePaths = _extractionExecutor.execute(definitionFilePath, defaultResultFileName, lang, parameters, pipeline); 098 context.put(__RESULT_FILE_PATHS, resultFilePaths); 099 } 100 101 private String _getDefaultResultFileName(String definitionFilePath, PipelineDescriptor pipeline) 102 { 103 String[] definitionFilePathSegments = definitionFilePath.split(Pattern.quote(File.separator)); 104 String definitionFileName = definitionFilePathSegments[definitionFilePathSegments.length - 1]; 105 106 int lastIndexOfDot = definitionFileName.lastIndexOf('.'); 107 if (-1 != lastIndexOfDot) 108 { 109 definitionFileName = definitionFileName.substring(0, lastIndexOfDot); 110 } 111 112 String extractionDate = ZonedDateTime.now().format(RESULT_FILE_NAME_DATE_TIME_FORMATTER); 113 114 StringBuilder resultFileName = new StringBuilder(); 115 resultFileName.append(definitionFileName).append("-").append(extractionDate); 116 resultFileName.append(".").append(pipeline.getDefaultExtension()); 117 return resultFileName.toString(); 118 } 119 120 private Map<String, Object> _getExtractionParameters(JobDataMap jobDataMap) 121 { 122 // variables parameters 123 String variablesAsString = jobDataMap.getString(__JOBDATAMAP_VARIABLES_KEY); 124 Map<String, Object> variablesAsMap = _jsonUtils.convertJsonToMap(variablesAsString); 125 return variablesAsMap; 126 } 127 128 @Override 129 protected Optional<String> _getRecipient(JobExecutionContext context) 130 { 131 JobDataMap jobDataMap = context.getJobDetail().getJobDataMap(); 132 return Optional.ofNullable(jobDataMap.getString(__JOBDATAMAP_RECIPIENT_KEY)) 133 .filter(StringUtils::isNotEmpty); 134 } 135 136 @Override 137 protected boolean _isMailBodyInHTML(JobExecutionContext context) 138 { 139 return true; 140 } 141 142 @Override 143 protected I18nizableText _getSuccessMailSubject(JobExecutionContext context) 144 { 145 String extractionName = _getDefinitionFilePath(context); 146 return new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_MAIL_SUCCESS_SUBJECT", Map.of("extractionName", new I18nizableText(extractionName))); 147 } 148 149 @Override 150 protected I18nizableText _getSuccessMailBody(JobExecutionContext context) 151 { 152 Map<String, I18nizableTextParameter> params = new HashMap<>(); 153 154 String extractionName = _getDefinitionFilePath(context); 155 params.put("extractionName", new I18nizableText(extractionName)); 156 157 I18nizableText resultsToolLabel = new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_RESULTS_LIST_TOOL_LABEL"); 158 params.put("toolLabel", resultsToolLabel); 159 160 @SuppressWarnings("unchecked") 161 Set<Path> resultFilePaths = (Set<Path>) context.get(__RESULT_FILE_PATHS); 162 if (resultFilePaths.size() == 1) 163 { 164 String downloadLink = _getResultFileDownloadLink(resultFilePaths.iterator().next()); 165 params.put("link", new I18nizableText(downloadLink)); 166 167 return new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_MAIL_SUCCESS_BODY_ONE_RESULT", params); 168 } 169 else 170 { 171 StringBuilder downloadLinks = new StringBuilder(); 172 for (Path resultFilePath : resultFilePaths) 173 { 174 downloadLinks.append("<li>").append(_getResultFileDownloadLink(resultFilePath)).append("</li>"); 175 } 176 params.put("links", new I18nizableText(downloadLinks.toString())); 177 178 return new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_MAIL_SUCCESS_BODY_SEVERAL_RESULTS", params); 179 } 180 } 181 182 @Override 183 protected I18nizableText _getErrorMailSubject(JobExecutionContext context) 184 { 185 String extractionName = _getDefinitionFilePath(context); 186 return new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_MAIL_ERROR_SUBJECT", Map.of("extractionName", new I18nizableText(extractionName))); 187 } 188 189 @Override 190 protected I18nizableText _getErrorMailBody(JobExecutionContext context, Throwable throwable) 191 { 192 String extractionName = _getDefinitionFilePath(context); 193 String error = ExceptionUtils.getStackTrace(throwable); 194 195 Map<String, I18nizableTextParameter> params = Map.of( 196 "extractionName", new I18nizableText(extractionName), 197 "error", new I18nizableText(error) 198 ); 199 200 return new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_MAIL_ERROR_BODY", params); 201 } 202 203 private String _getDefinitionFilePath(JobExecutionContext context) 204 { 205 JobDataMap jobDataMap = context.getJobDetail().getJobDataMap(); 206 return jobDataMap.getString(__JOBDATAMAP_DEFINITION_FILE_PATH_KEY); 207 } 208 209 private String _getResultFileDownloadLink(Path resultFilePath) 210 { 211 Path resultsBasePath = AmetysHomeHelper.getAmetysHomeData().toPath().resolve(ExtractionConstants.RESULT_EXTRACTION_DIR_NAME); 212 String resultFileRelativePath = resultsBasePath.relativize(resultFilePath).toString(); 213 214 String downloadURL = Config.getInstance().getValue("cms.url") + "/plugins/extraction/result/download/" + resultFileRelativePath; 215 216 return "<a href=\"" + downloadURL + "\">" + resultFileRelativePath + "</a>"; 217 } 218 219}