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.time.ZonedDateTime;
020import java.time.format.DateTimeFormatter;
021import java.util.Collections;
022import java.util.Map;
023import java.util.regex.Pattern;
024
025import javax.mail.MessagingException;
026
027import org.apache.avalon.framework.activity.Initializable;
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.core.schedule.Schedulable;
036import org.ametys.core.util.I18nUtils;
037import org.ametys.core.util.JSONUtils;
038import org.ametys.core.util.mail.SendMailHelper;
039import org.ametys.plugins.core.impl.schedule.AbstractStaticSchedulable;
040import org.ametys.plugins.core.schedule.Scheduler;
041import org.ametys.plugins.extraction.ExtractionConstants;
042import org.ametys.plugins.extraction.execution.pipeline.PipelineDescriptor;
043import org.ametys.plugins.extraction.execution.pipeline.PipelineManager;
044import org.ametys.runtime.config.Config;
045import org.ametys.runtime.i18n.I18nizableText;
046
047/**
048 * A {@link Schedulable} job which execute an extraction
049 */
050public class ExecuteExtractionSchedulable extends AbstractStaticSchedulable implements Initializable
051{
052    /** The key for the extraction definition file */
053    public static final String DEFINITION_FILE_PATH_KEY = "definitionFilePath";
054    /** The key for the variables values */
055    public static final String VARIABLES_KEY = "variables";
056    /** The key for the recipient */
057    public static final String RECIPIENT_KEY = "recipient";
058    /** The key for the pipeline */
059    public static final String PIPELINE_KEY = "pipeline";
060    
061    private static final String __JOBDATAMAP_DEFINITION_FILE_PATH_KEY = Scheduler.PARAM_VALUES_PREFIX + DEFINITION_FILE_PATH_KEY;
062    private static final String __JOBDATAMAP_VARIABLES_KEY = Scheduler.PARAM_VALUES_PREFIX + VARIABLES_KEY;
063    private static final String __JOBDATAMAP_RECIPIENT_KEY = Scheduler.PARAM_VALUES_PREFIX + RECIPIENT_KEY;
064    private static final String __JOBDATAMAP_PIPELINE_KEY = Scheduler.PARAM_VALUES_PREFIX + PIPELINE_KEY;
065    
066    private static final DateTimeFormatter RESULT_FILE_NAME_DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd'T'HH.mm.ss");
067    
068    private JSONUtils _jsonUtils;
069    private I18nUtils _i18nUtils;
070    private String _mailFrom;
071    private PipelineManager _pipelineManager;
072    private ExtractionExecutor _extractionExecutor;
073    
074    @Override
075    public void service(ServiceManager manager) throws ServiceException
076    {
077        super.service(manager);
078        _jsonUtils = (JSONUtils) manager.lookup(JSONUtils.ROLE);
079        _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE);
080        _pipelineManager = (PipelineManager) manager.lookup(PipelineManager.ROLE);
081        _extractionExecutor = (ExtractionExecutor) manager.lookup(ExtractionExecutor.ROLE);
082    }
083    
084    @Override
085    public void initialize() throws Exception
086    {
087        _mailFrom = Config.getInstance().getValue("smtp.mail.from");
088    }
089
090    @Override
091    public void execute(JobExecutionContext context) throws Exception
092    {
093        JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
094        String definitionFilePath = jobDataMap.getString(__JOBDATAMAP_DEFINITION_FILE_PATH_KEY);
095        
096        // Get email address to send one when the extraction is complete (or if there is an error)
097        String recipient = jobDataMap.getString(__JOBDATAMAP_RECIPIENT_KEY);
098        
099        String mailBody = null;
100        try
101        {
102            PipelineDescriptor pipeline = _pipelineManager.get(jobDataMap.getString(__JOBDATAMAP_PIPELINE_KEY));
103            String defaultResultFileName = _getResultFileName(definitionFilePath, pipeline);
104            Map<String, Object> parameters = _getExtractionParameters(jobDataMap);
105            String lang = (String) parameters.get("lang");
106            _extractionExecutor.execute(definitionFilePath, defaultResultFileName, lang, parameters, pipeline);
107            
108            mailBody = _getSuccessMailBody(definitionFilePath);
109        }
110        catch (Exception e)
111        {
112            mailBody = _getFailureMailBody(definitionFilePath, e);
113            throw e;
114        }
115        finally
116        {
117            if (!StringUtils.isEmpty(recipient))
118            {
119                _sendMail(recipient, mailBody);
120            }
121        }
122    }
123    
124    private Map<String, Object> _getExtractionParameters(JobDataMap jobDataMap)
125    {
126        // variables parameters
127        String variablesAsString = jobDataMap.getString(__JOBDATAMAP_VARIABLES_KEY);
128        Map<String, Object> variablesAsMap = _jsonUtils.convertJsonToMap(variablesAsString);
129        return variablesAsMap;
130    }
131
132    private String _getResultFileName(String definitionFilePath, PipelineDescriptor pipeline)
133    {
134        String[] definitionFilePathSegments = definitionFilePath.split(Pattern.quote(File.separator));
135        String definitionFileName = definitionFilePathSegments[definitionFilePathSegments.length - 1];
136        
137        int lastIndexOfDot = definitionFileName.lastIndexOf('.');
138        if (-1 != lastIndexOfDot)
139        {
140            definitionFileName = definitionFileName.substring(0, lastIndexOfDot);
141        }
142        
143        String extractionDate = ZonedDateTime.now().format(RESULT_FILE_NAME_DATE_TIME_FORMATTER);
144        
145        StringBuilder resultFileName = new StringBuilder();
146        resultFileName.append(definitionFileName).append("-").append(extractionDate);
147        resultFileName.append(".").append(pipeline.getDefaultExtension());
148        return resultFileName.toString();
149    }
150    
151    private String _getSuccessMailBody(String definitionFileName)
152    {
153        I18nizableText bodyKey = new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_MAIL_SUCCESS_BODY", Collections.singletonList(definitionFileName));
154        return _i18nUtils.translate(bodyKey, null); // FIXME Use user preference language
155    }
156    
157    private String _getFailureMailBody (String definitionFileName, Throwable exception)
158    {
159        StringBuilder body = new StringBuilder();
160        
161        I18nizableText bodyKey = new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_MAIL_FAILURE_BODY", Collections.singletonList(definitionFileName));
162        String intro = _i18nUtils.translate(bodyKey, null); // FIXME Use user preference language
163        
164        body.append(intro).append("\n\n").append(ExceptionUtils.getStackTrace(exception));
165        return body.toString();
166    }
167    
168    private void _sendMail(String recipient, String body)
169    {
170        String subject = _getMailSubject();
171        try
172        {
173            SendMailHelper.sendMail(subject, null, body, recipient, _mailFrom);
174        }
175        catch (MessagingException e)
176        {
177            if (getLogger().isWarnEnabled())
178            {
179                getLogger().warn("Fail to send email to " + recipient, e); 
180            }
181        }
182    }
183    
184    private String _getMailSubject ()
185    {
186        I18nizableText subjectKey = new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_MAIL_SUBJECT");
187        return _i18nUtils.translate(subjectKey, null); // FIXME Use user preference language
188    }
189}