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.util.HashMap;
020import java.util.LinkedHashMap;
021import java.util.List;
022import java.util.Map;
023import java.util.Map.Entry;
024
025import org.apache.avalon.framework.service.ServiceException;
026import org.apache.avalon.framework.service.ServiceManager;
027import org.apache.commons.lang.StringUtils;
028import org.apache.excalibur.source.Source;
029import org.apache.excalibur.source.SourceResolver;
030import org.apache.excalibur.source.impl.FileSource;
031import org.quartz.JobKey;
032import org.quartz.SchedulerException;
033
034import org.ametys.core.schedule.Runnable;
035import org.ametys.core.ui.Callable;
036import org.ametys.core.ui.StaticClientSideElement;
037import org.ametys.core.user.User;
038import org.ametys.core.user.UserIdentity;
039import org.ametys.core.user.UserManager;
040import org.ametys.core.util.JSONUtils;
041import org.ametys.plugins.core.schedule.Scheduler;
042import org.ametys.plugins.extraction.ExtractionConstants;
043import org.ametys.plugins.extraction.execution.pipeline.PipelineManager;
044import org.ametys.runtime.i18n.I18nizableText;
045
046/**
047 * This client site element creates a button to execute an extraction
048 */
049public class ExecuteExtractionClientSideElement extends StaticClientSideElement
050{
051    private UserManager _userManager;
052    private ExtractionDefinitionReader _reader;
053    private SourceResolver _sourceResolver;
054    private JSONUtils _jsonUtils;
055    private Scheduler _scheduler;
056    private PipelineManager _pipelineManager;
057    
058    @Override
059    public void service(ServiceManager serviceManager) throws ServiceException
060    {
061        super.service(serviceManager);
062        _userManager = (UserManager) serviceManager.lookup(UserManager.ROLE);
063        _reader = (ExtractionDefinitionReader) serviceManager.lookup(ExtractionDefinitionReader.ROLE);
064        _sourceResolver = (SourceResolver) serviceManager.lookup(SourceResolver.ROLE);
065        _jsonUtils = (JSONUtils) serviceManager.lookup(JSONUtils.ROLE);
066        _scheduler = (Scheduler) serviceManager.lookup(Scheduler.ROLE);
067        _pipelineManager = (PipelineManager) serviceManager.lookup(PipelineManager.ROLE);
068    }
069    
070    /**
071     * Retrieve needed extraction parameters.
072     * @param definitionFile The extraction definition file path
073     * @return a <code>Map</code> containing parameters infos used to configure form to fill the parameters
074     * @throws Exception if an error occurs
075     */
076    @Callable (right = ExtractionConstants.EXECUTE_EXTRACTION_RIGHT_ID)
077    public Map<String, Object> getExecutionParameters(String definitionFile) throws Exception
078    {
079        Map<String, Object> executionParameters = new LinkedHashMap<>();
080
081        String definitionFilePath = ExtractionConstants.DEFINITIONS_DIR + definitionFile;
082        Source src = _sourceResolver.resolveURI(definitionFilePath);
083        File file = ((FileSource) src).getFile();
084        
085        if (!file.exists())
086        {
087            throw new IllegalArgumentException("The file " + definitionFilePath + " does not exist.");
088        }
089
090        executionParameters.put("pipeline", _getPipelineInputConfig(definitionFile));
091        
092        Extraction extraction = _reader.readExtractionDefinitionFile(file);
093        
094        Map<String, String> clasuesVariables = extraction.getQueryVariablesNamesAndContentTypes();
095        List<String> optionalColumns = extraction.getDisplayOptionalColumnsNames();
096
097        if (!clasuesVariables.isEmpty())
098        {
099            Map<String, Object> clausesVariablesFieldSet = new HashMap<>();
100            clausesVariablesFieldSet.put("role", "fieldset");
101            clausesVariablesFieldSet.put("label", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_CLAUSES_VARIABLES_FIELDSET_LABEL"));
102        
103            Map<String, Object> clausesVariablesFieldSetElements = new HashMap<>();
104            for (Map.Entry<String, String> clausesVariable : clasuesVariables.entrySet())
105            {
106                clausesVariablesFieldSetElements.put(clausesVariable.getKey(), _getClauseVariableInputConfig(clausesVariable));
107            }
108            clausesVariablesFieldSet.put("elements", clausesVariablesFieldSetElements);
109            
110            executionParameters.put("clausesVariables", clausesVariablesFieldSet);
111        }
112        
113        if (!optionalColumns.isEmpty())
114        {
115            Map<String, Object> optionalColumnsFieldSet = new HashMap<>();
116            optionalColumnsFieldSet.put("role", "fieldset");
117            optionalColumnsFieldSet.put("label", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_OPTIONAL_COLUMNS_FIELDSET_LABEL"));
118        
119            Map<String, Object> optionalColumnsFieldSetElements = new HashMap<>();
120            for (String optionalColumn : optionalColumns)
121            {
122                optionalColumnsFieldSetElements.put(optionalColumn, _getOptionalColumnsInputConfig(optionalColumn));
123            }
124            optionalColumnsFieldSet.put("elements", optionalColumnsFieldSetElements);
125            
126            executionParameters.put("optionalColumns", optionalColumnsFieldSet);
127        }
128            
129        executionParameters.put("recipient", _getRecipientInputConfig());
130        
131        return executionParameters;
132    }
133    
134    private Map<String, Object> _getPipelineInputConfig(String definitionFile)
135    {
136        Map<String, Object> inputConfig = new HashMap<>();
137        
138        inputConfig.put("label", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_PIPELINE_INPUT_LABEL"));
139        inputConfig.put("description", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_PIPELINE_INPUT_DESCRIPTION"));
140        inputConfig.put("type", "string");
141        
142        inputConfig.put("default-value", _pipelineManager.getDefaultPipeline());
143        inputConfig.put("validation", _getMandatoryValidation());
144        
145        inputConfig.put("widget", "edition.select-pipeline");
146        
147        Map<String, Object> widgetParams = new HashMap<>();
148        widgetParams.put("extraction", definitionFile);
149        inputConfig.put("widget-params", widgetParams);
150        
151        return inputConfig;
152    }
153    
154    private Map<String, Object> _getClauseVariableInputConfig(Entry<String, String> clausesVariable)
155    {
156        Map<String, Object> inputConfig = new HashMap<>();
157        
158        inputConfig.put("label", clausesVariable.getKey());
159        inputConfig.put("description", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_CLAUSES_VARIABLE_INPUTS_DESCRIPTION"));
160        
161        inputConfig.put("type", "content");
162        inputConfig.put("widget", "edition.select-content");
163        
164        Map<String, Object> widgetParams = new HashMap<>();
165        widgetParams.put("contentType", clausesVariable.getValue());
166        inputConfig.put("widget-params", widgetParams);
167        
168        inputConfig.put("validation", _getMandatoryValidation());
169        
170        return inputConfig;
171    }
172    
173    private Map<String, Object> _getOptionalColumnsInputConfig(String optionalColumn)
174    {
175        Map<String, Object> inputConfig = new HashMap<>();
176        
177        inputConfig.put("label", optionalColumn);
178        inputConfig.put("description", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_OPTIONAL_COLUMNS_INPUTS_DESCRIPTION"));
179        
180        inputConfig.put("type", "boolean");
181        inputConfig.put("widget", "edition.checkbox");
182        
183        inputConfig.put("validation", _getMandatoryValidation());
184        
185        return inputConfig;
186    }
187    
188    private Map<String, Object> _getRecipientInputConfig()
189    {
190        Map<String, Object> inputConfig = new HashMap<>();
191        
192        // Get current user email
193        String currentUserEmail = null;
194        UserIdentity currentUser = _currentUserProvider.getUser();
195        
196        String login = currentUser.getLogin();
197        if (StringUtils.isNotBlank(login))
198        {
199            String userPopulationId = currentUser.getPopulationId();
200            User user = _userManager.getUser(userPopulationId, login);
201            currentUserEmail = user.getEmail();
202        }
203        
204        inputConfig.put("label", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_RECIPIENT_INPUT_LABEL"));
205        inputConfig.put("description", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_RECIPIENT_INPUT_DESCRIPTION"));
206        inputConfig.put("type", "string");
207        inputConfig.put("default-value", currentUserEmail);
208        
209        return inputConfig;
210    }
211    
212    private Map<String, Object> _getMandatoryValidation()
213    {
214        Map<String, Object> mandatoryValidation = new HashMap<>();
215        mandatoryValidation.put("mandatory", true);
216        return mandatoryValidation;
217    }
218    
219    /**
220     * Execute the extraction
221     * @param definitionFilePath The extraction definition file path
222     * @param variables clauses variables and optional columns
223     * @param recipient An email will be sent at this address when the extraction is complete
224     * @param pipelineId The id of the extraction pipeline
225     * @return a Map with error if one occurs
226     * @throws Exception if an error occurs
227     */
228    @Callable (right = ExtractionConstants.EXECUTE_EXTRACTION_RIGHT_ID)
229    public Map<String, Object> executeExtraction(String definitionFilePath, Map<String, Object> variables, String recipient, String pipelineId) throws Exception
230    {
231        Map<String, Object> result = new HashMap<>();
232        
233        try
234        {
235            String variablesAsString = _jsonUtils.convertObjectToJson(variables);
236            Runnable executeExtractionRunnable = new ExecuteExtractionRunnable(definitionFilePath, variablesAsString, recipient, pipelineId);
237            JobKey jobKey = new JobKey(executeExtractionRunnable.getId(), Scheduler.JOB_GROUP);
238            if (_scheduler.getScheduler().checkExists(jobKey))
239            {
240                _scheduler.getScheduler().deleteJob(jobKey);
241            }
242            _scheduler.scheduleJob(executeExtractionRunnable);
243            getLogger().info("Scheduled extraction execution of " + definitionFilePath);
244        }
245        catch (SchedulerException e)
246        {
247            if (getLogger().isErrorEnabled())
248            {
249                getLogger().error("An error occured when trying to schedule the extraction execution of " + definitionFilePath, e);
250            }
251            result.put("error", "scheduler-error");
252            return result;
253        }
254        
255        result.put("definitionFilePath", definitionFilePath);
256        return result;
257    }
258}