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