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.Optional; 024import java.util.Set; 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.cms.contenttype.ContentType; 036import org.ametys.cms.contenttype.ContentTypeExtensionPoint; 037import org.ametys.cms.contenttype.ContentTypesHelper; 038import org.ametys.core.schedule.Runnable; 039import org.ametys.core.ui.Callable; 040import org.ametys.core.ui.StaticClientSideElement; 041import org.ametys.core.user.User; 042import org.ametys.core.user.UserIdentity; 043import org.ametys.core.user.UserManager; 044import org.ametys.core.util.JSONUtils; 045import org.ametys.plugins.core.schedule.Scheduler; 046import org.ametys.plugins.extraction.ExtractionConstants; 047import org.ametys.plugins.extraction.execution.Extraction.ClausesVariable; 048import org.ametys.plugins.extraction.execution.Extraction.ClausesVariableType; 049import org.ametys.plugins.extraction.execution.pipeline.PipelineManager; 050import org.ametys.runtime.i18n.I18nizableText; 051 052/** 053 * This client site element creates a button to execute an extraction 054 */ 055public class ExecuteExtractionClientSideElement extends StaticClientSideElement 056{ 057 private UserManager _userManager; 058 private ExtractionDefinitionReader _reader; 059 private SourceResolver _sourceResolver; 060 private JSONUtils _jsonUtils; 061 private Scheduler _scheduler; 062 private PipelineManager _pipelineManager; 063 private ContentTypeExtensionPoint _contentTypeExtensionPoint; 064 private ContentTypesHelper _contentTypesHelper; 065 066 @Override 067 public void service(ServiceManager serviceManager) throws ServiceException 068 { 069 super.service(serviceManager); 070 _userManager = (UserManager) serviceManager.lookup(UserManager.ROLE); 071 _reader = (ExtractionDefinitionReader) serviceManager.lookup(ExtractionDefinitionReader.ROLE); 072 _sourceResolver = (SourceResolver) serviceManager.lookup(SourceResolver.ROLE); 073 _jsonUtils = (JSONUtils) serviceManager.lookup(JSONUtils.ROLE); 074 _scheduler = (Scheduler) serviceManager.lookup(Scheduler.ROLE); 075 _pipelineManager = (PipelineManager) serviceManager.lookup(PipelineManager.ROLE); 076 _contentTypeExtensionPoint = (ContentTypeExtensionPoint) serviceManager.lookup(ContentTypeExtensionPoint.ROLE); 077 _contentTypesHelper = (ContentTypesHelper) serviceManager.lookup(ContentTypesHelper.ROLE); 078 } 079 080 /** 081 * Retrieve needed extraction parameters. 082 * @param definitionFile The extraction definition file path 083 * @return a <code>Map</code> containing parameters infos used to configure form to fill the parameters 084 * @throws Exception if an error occurs 085 */ 086 @Callable (rights = ExtractionConstants.EXECUTE_EXTRACTION_RIGHT_ID) 087 public Map<String, Object> getExecutionParameters(String definitionFile) throws Exception 088 { 089 Map<String, Object> executionParameters = new LinkedHashMap<>(); 090 091 String definitionFilePath = ExtractionConstants.DEFINITIONS_DIR + definitionFile; 092 Source src = _sourceResolver.resolveURI(definitionFilePath); 093 File file = ((FileSource) src).getFile(); 094 095 if (!file.exists()) 096 { 097 throw new IllegalArgumentException("The file " + definitionFilePath + " does not exist."); 098 } 099 100 executionParameters.put("pipeline", _getPipelineInputConfig(definitionFile)); 101 102 Extraction extraction = _reader.readExtractionDefinitionFile(file); 103 104 List<ClausesVariable> clausesVariables = extraction.getClausesVariables(); 105 List<String> optionalColumns = extraction.getDisplayOptionalColumnsNames(); 106 107 if (!clausesVariables.isEmpty()) 108 { 109 Map<String, Object> clausesVariablesFieldSet = new HashMap<>(); 110 clausesVariablesFieldSet.put("role", "fieldset"); 111 clausesVariablesFieldSet.put("label", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_CLAUSES_VARIABLES_FIELDSET_LABEL")); 112 113 Map<String, Object> clausesVariablesFieldSetElements = new HashMap<>(); 114 for (ClausesVariable clausesVariable : clausesVariables) 115 { 116 clausesVariablesFieldSetElements.put(clausesVariable.name(), _getClausesVariableInputConfig(clausesVariable)); 117 } 118 clausesVariablesFieldSet.put("elements", clausesVariablesFieldSetElements); 119 120 executionParameters.put("clausesVariables", clausesVariablesFieldSet); 121 } 122 123 if (!optionalColumns.isEmpty()) 124 { 125 Map<String, Object> optionalColumnsFieldSet = new HashMap<>(); 126 optionalColumnsFieldSet.put("role", "fieldset"); 127 optionalColumnsFieldSet.put("label", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_OPTIONAL_COLUMNS_FIELDSET_LABEL")); 128 129 Map<String, Object> optionalColumnsFieldSetElements = new HashMap<>(); 130 for (String optionalColumn : optionalColumns) 131 { 132 optionalColumnsFieldSetElements.put(optionalColumn, _getOptionalColumnsInputConfig(optionalColumn)); 133 } 134 optionalColumnsFieldSet.put("elements", optionalColumnsFieldSetElements); 135 136 executionParameters.put("optionalColumns", optionalColumnsFieldSet); 137 } 138 139 executionParameters.put("recipient", _getRecipientInputConfig()); 140 141 return executionParameters; 142 } 143 144 private Map<String, Object> _getPipelineInputConfig(String definitionFile) 145 { 146 Map<String, Object> inputConfig = new HashMap<>(); 147 148 inputConfig.put("label", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_PIPELINE_INPUT_LABEL")); 149 inputConfig.put("description", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_PIPELINE_INPUT_DESCRIPTION")); 150 inputConfig.put("type", "string"); 151 152 inputConfig.put("default-value", _pipelineManager.getDefaultPipeline()); 153 inputConfig.put("validation", _getMandatoryValidation()); 154 155 inputConfig.put("widget", "edition.select-pipeline"); 156 157 Map<String, Object> widgetParams = new HashMap<>(); 158 widgetParams.put("extraction", definitionFile); 159 inputConfig.put("widget-params", widgetParams); 160 161 return inputConfig; 162 } 163 164 private Map<String, Object> _getClausesVariableInputConfig(ClausesVariable clausesVariable) 165 { 166 Map<String, Object> inputConfig = new HashMap<>(); 167 168 inputConfig.put("label", clausesVariable.name()); 169 170 if (ClausesVariableType.SOLR_REQUEST.equals(clausesVariable.type())) 171 { 172 inputConfig.put("description", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_CLAUSES_VARIABLE_SOLR_REQUEST_INPUT_DESCRIPTION")); 173 174 inputConfig.put("type", "string"); 175 inputConfig.put("widget", "edition.solr-code"); 176 177 Map<String, Object> widgetParams = new HashMap<>(); 178 179 Set<String> commonAncestors = _contentTypesHelper.getCommonAncestors(clausesVariable.contentTypeIds()); 180 widgetParams.put("ctypes", commonAncestors); 181 widgetParams.put("singleLine", true); 182 widgetParams.put("height", 66); 183 widgetParams.put("mode", "text/x-solr-ametys"); 184 185 inputConfig.put("widget-params", widgetParams); 186 } 187 else 188 { 189 inputConfig.put("description", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_CLAUSES_VARIABLE_SELECT_CONTENTS_INPUT_DESCRIPTION")); 190 191 inputConfig.put("type", "content"); 192 inputConfig.put("multiple", true); 193 194 String widget = "edition.select-content"; 195 Map<String, Object> widgetParams = new HashMap<>(); 196 197 Optional<String> contentTypeId = clausesVariable.contentTypeIds().stream().findFirst(); 198 if (contentTypeId.isPresent()) 199 { 200 ContentType contentType = _contentTypeExtensionPoint.getExtension(contentTypeId.get()); 201 if (contentType.isReferenceTable()) 202 { 203 widget = "edition.select-referencetable-content"; 204 } 205 206 widgetParams.put("contentType", contentTypeId.get()); 207 } 208 209 clausesVariable.solrRequest() 210 .ifPresent(solrRequest -> widgetParams.put("solrRequest", solrRequest)); 211 212 inputConfig.put("widget", widget); 213 inputConfig.put("widget-params", widgetParams); 214 } 215 216 inputConfig.put("validation", _getMandatoryValidation()); 217 218 return inputConfig; 219 } 220 221 private Map<String, Object> _getOptionalColumnsInputConfig(String optionalColumn) 222 { 223 Map<String, Object> inputConfig = new HashMap<>(); 224 225 inputConfig.put("label", optionalColumn); 226 inputConfig.put("description", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_OPTIONAL_COLUMNS_INPUTS_DESCRIPTION")); 227 228 inputConfig.put("type", "boolean"); 229 inputConfig.put("widget", "edition.checkbox"); 230 231 inputConfig.put("validation", _getMandatoryValidation()); 232 233 return inputConfig; 234 } 235 236 private Map<String, Object> _getRecipientInputConfig() 237 { 238 Map<String, Object> inputConfig = new HashMap<>(); 239 240 // Get current user email 241 String currentUserEmail = null; 242 UserIdentity currentUser = _currentUserProvider.getUser(); 243 244 String login = currentUser.getLogin(); 245 if (StringUtils.isNotBlank(login)) 246 { 247 String userPopulationId = currentUser.getPopulationId(); 248 User user = _userManager.getUser(userPopulationId, login); 249 currentUserEmail = user.getEmail(); 250 } 251 252 inputConfig.put("label", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_RECIPIENT_INPUT_LABEL")); 253 inputConfig.put("description", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_RECIPIENT_INPUT_DESCRIPTION")); 254 inputConfig.put("type", "string"); 255 inputConfig.put("default-value", currentUserEmail); 256 257 return inputConfig; 258 } 259 260 private Map<String, Object> _getMandatoryValidation() 261 { 262 Map<String, Object> mandatoryValidation = new HashMap<>(); 263 mandatoryValidation.put("mandatory", true); 264 return mandatoryValidation; 265 } 266 267 /** 268 * Execute the extraction 269 * @param definitionFilePath The extraction definition file path 270 * @param variables clauses variables and optional columns 271 * @param recipient An email will be sent at this address when the extraction is complete 272 * @param pipelineId The id of the extraction pipeline 273 * @return a Map with error if one occurs 274 * @throws Exception if an error occurs 275 */ 276 @Callable (rights = ExtractionConstants.EXECUTE_EXTRACTION_RIGHT_ID) 277 public Map<String, Object> executeExtraction(String definitionFilePath, Map<String, Object> variables, String recipient, String pipelineId) throws Exception 278 { 279 Map<String, Object> result = new HashMap<>(); 280 281 try 282 { 283 String variablesAsString = _jsonUtils.convertObjectToJson(variables); 284 Runnable executeExtractionRunnable = new ExecuteExtractionRunnable(definitionFilePath, variablesAsString, recipient, pipelineId); 285 JobKey jobKey = new JobKey(executeExtractionRunnable.getId(), Scheduler.JOB_GROUP); 286 if (_scheduler.getScheduler().checkExists(jobKey)) 287 { 288 _scheduler.getScheduler().deleteJob(jobKey); 289 } 290 _scheduler.scheduleJob(executeExtractionRunnable); 291 getLogger().info("Scheduled extraction execution of " + definitionFilePath); 292 } 293 catch (SchedulerException e) 294 { 295 if (getLogger().isErrorEnabled()) 296 { 297 getLogger().error("An error occured when trying to schedule the extraction execution of " + definitionFilePath, e); 298 } 299 result.put("error", "scheduler-error"); 300 return result; 301 } 302 303 result.put("definitionFilePath", definitionFilePath); 304 return result; 305 } 306}