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        inputConfig.put("multiple", true);
164        
165        Map<String, Object> widgetParams = new HashMap<>();
166        widgetParams.put("contentType", clausesVariable.getValue());
167        inputConfig.put("widget-params", widgetParams);
168        
169        inputConfig.put("validation", _getMandatoryValidation());
170        
171        return inputConfig;
172    }
173    
174    private Map<String, Object> _getOptionalColumnsInputConfig(String optionalColumn)
175    {
176        Map<String, Object> inputConfig = new HashMap<>();
177        
178        inputConfig.put("label", optionalColumn);
179        inputConfig.put("description", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_OPTIONAL_COLUMNS_INPUTS_DESCRIPTION"));
180        
181        inputConfig.put("type", "boolean");
182        inputConfig.put("widget", "edition.checkbox");
183        
184        inputConfig.put("validation", _getMandatoryValidation());
185        
186        return inputConfig;
187    }
188    
189    private Map<String, Object> _getRecipientInputConfig()
190    {
191        Map<String, Object> inputConfig = new HashMap<>();
192        
193        // Get current user email
194        String currentUserEmail = null;
195        UserIdentity currentUser = _currentUserProvider.getUser();
196        
197        String login = currentUser.getLogin();
198        if (StringUtils.isNotBlank(login))
199        {
200            String userPopulationId = currentUser.getPopulationId();
201            User user = _userManager.getUser(userPopulationId, login);
202            currentUserEmail = user.getEmail();
203        }
204        
205        inputConfig.put("label", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_RECIPIENT_INPUT_LABEL"));
206        inputConfig.put("description", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_RECIPIENT_INPUT_DESCRIPTION"));
207        inputConfig.put("type", "string");
208        inputConfig.put("default-value", currentUserEmail);
209        
210        return inputConfig;
211    }
212    
213    private Map<String, Object> _getMandatoryValidation()
214    {
215        Map<String, Object> mandatoryValidation = new HashMap<>();
216        mandatoryValidation.put("mandatory", true);
217        return mandatoryValidation;
218    }
219    
220    /**
221     * Execute the extraction
222     * @param definitionFilePath The extraction definition file path
223     * @param variables clauses variables and optional columns
224     * @param recipient An email will be sent at this address when the extraction is complete
225     * @param pipelineId The id of the extraction pipeline
226     * @return a Map with error if one occurs
227     * @throws Exception if an error occurs
228     */
229    @Callable (right = ExtractionConstants.EXECUTE_EXTRACTION_RIGHT_ID)
230    public Map<String, Object> executeExtraction(String definitionFilePath, Map<String, Object> variables, String recipient, String pipelineId) throws Exception
231    {
232        Map<String, Object> result = new HashMap<>();
233        
234        try
235        {
236            String variablesAsString = _jsonUtils.convertObjectToJson(variables);
237            Runnable executeExtractionRunnable = new ExecuteExtractionRunnable(definitionFilePath, variablesAsString, recipient, pipelineId);
238            JobKey jobKey = new JobKey(executeExtractionRunnable.getId(), Scheduler.JOB_GROUP);
239            if (_scheduler.getScheduler().checkExists(jobKey))
240            {
241                _scheduler.getScheduler().deleteJob(jobKey);
242            }
243            _scheduler.scheduleJob(executeExtractionRunnable);
244            getLogger().info("Scheduled extraction execution of " + definitionFilePath);
245        }
246        catch (SchedulerException e)
247        {
248            if (getLogger().isErrorEnabled())
249            {
250                getLogger().error("An error occured when trying to schedule the extraction execution of " + definitionFilePath, e);
251            }
252            result.put("error", "scheduler-error");
253            return result;
254        }
255        
256        result.put("definitionFilePath", definitionFilePath);
257        return result;
258    }
259}