001/* 002 * Copyright 2023 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.workflow.dao; 017 018import java.util.ArrayList; 019import java.util.Collections; 020import java.util.HashMap; 021import java.util.List; 022import java.util.Map; 023import java.util.Map.Entry; 024import java.util.Set; 025import java.util.stream.Collectors; 026 027import org.apache.avalon.framework.component.Component; 028import org.apache.avalon.framework.service.ServiceException; 029import org.apache.avalon.framework.service.ServiceManager; 030import org.apache.avalon.framework.service.Serviceable; 031import org.apache.cocoon.ProcessingException; 032import org.apache.commons.lang.StringUtils; 033import org.apache.commons.lang3.tuple.Pair; 034 035import org.ametys.core.ui.Callable; 036import org.ametys.plugins.workflow.EnhancedFunction; 037import org.ametys.plugins.workflow.EnhancedFunction.FunctionType; 038import org.ametys.plugins.workflow.EnhancedFunctionExtensionPoint; 039import org.ametys.plugins.workflow.ModelItemTypeExtensionPoint; 040import org.ametys.plugins.workflow.component.WorkflowArgument; 041import org.ametys.plugins.workflow.support.AvalonTypeResolver; 042import org.ametys.plugins.workflow.support.WorflowRightHelper; 043import org.ametys.plugins.workflow.support.WorkflowElementDefinitionHelper; 044import org.ametys.plugins.workflow.support.WorkflowHelper.WorkflowVisibility; 045import org.ametys.plugins.workflow.support.WorkflowSessionHelper; 046import org.ametys.runtime.i18n.I18nizableText; 047import org.ametys.runtime.model.DefinitionContext; 048import org.ametys.runtime.model.ElementDefinition; 049import org.ametys.runtime.model.Model; 050import org.ametys.runtime.model.SimpleViewItemGroup; 051import org.ametys.runtime.model.StaticEnumerator; 052import org.ametys.runtime.model.View; 053import org.ametys.runtime.model.ViewElement; 054import org.ametys.runtime.model.disableconditions.DisableCondition; 055import org.ametys.runtime.model.disableconditions.DisableCondition.OPERATOR; 056import org.ametys.runtime.model.disableconditions.DisableConditions; 057import org.ametys.runtime.model.disableconditions.DisableConditions.ASSOCIATION_TYPE; 058import org.ametys.runtime.model.disableconditions.VoidRelativeDisableCondition; 059import org.ametys.runtime.model.disableconditions.VoidRelativeDisableConditions; 060import org.ametys.runtime.plugin.component.AbstractLogEnabled; 061 062import com.opensymphony.workflow.FunctionProvider; 063import com.opensymphony.workflow.TypeResolver; 064import com.opensymphony.workflow.WorkflowException; 065import com.opensymphony.workflow.loader.ActionDescriptor; 066import com.opensymphony.workflow.loader.DescriptorFactory; 067import com.opensymphony.workflow.loader.FunctionDescriptor; 068import com.opensymphony.workflow.loader.StepDescriptor; 069import com.opensymphony.workflow.loader.WorkflowDescriptor; 070 071/** 072 * DAO for workflow element's pre and pos functions 073 */ 074public class WorkflowFunctionDAO extends AbstractLogEnabled implements Component, Serviceable 075{ 076 /** Extension point for workflow arguments data type */ 077 protected static ModelItemTypeExtensionPoint _workflowArgumentDataTypeExtensionPoint; 078 079 private static final String __FUNCTION_DEFAULT_TYPE = "avalon"; 080 private static final String __ATTRIBUTE_FUNCTIONS_LIST = "functions-list"; 081 private static final String __ATTRIBUTE_FUNCTION_TYPES = "function-types"; 082 083 084 /** The workflow session helper */ 085 protected WorkflowSessionHelper _workflowSessionHelper; 086 087 /** The workflow right helper */ 088 protected WorflowRightHelper _workflowRightHelper; 089 090 /** The workflow step DAO */ 091 protected WorkflowStepDAO _workflowStepDAO; 092 093 /** The workflow transition DAO */ 094 protected WorkflowTransitionDAO _workflowTransitionDAO; 095 096 /** The service manager */ 097 protected ServiceManager _manager; 098 099 /** Extension point for EnhancedFunctions */ 100 protected EnhancedFunctionExtensionPoint _enhancedFunctionExtensionPoint; 101 102 public void service(ServiceManager smanager) throws ServiceException 103 { 104 _workflowSessionHelper = (WorkflowSessionHelper) smanager.lookup(WorkflowSessionHelper.ROLE); 105 _workflowRightHelper = (WorflowRightHelper) smanager.lookup(WorflowRightHelper.ROLE); 106 _workflowStepDAO = (WorkflowStepDAO) smanager.lookup(WorkflowStepDAO.ROLE); 107 _workflowTransitionDAO = (WorkflowTransitionDAO) smanager.lookup(WorkflowTransitionDAO.ROLE); 108 _enhancedFunctionExtensionPoint = (EnhancedFunctionExtensionPoint) smanager.lookup(EnhancedFunctionExtensionPoint.ROLE); 109 _workflowArgumentDataTypeExtensionPoint = (ModelItemTypeExtensionPoint) smanager.lookup(ModelItemTypeExtensionPoint.ROLE_WORKFLOW); 110 _manager = smanager; 111 } 112 113 /** 114 * Get the function's parameters as fields to configure edition form panel 115 * @return the parameters field as Json readable map 116 * @throws ProcessingException exception while saxing view to json 117 */ 118 @Callable(rights = {"Workflow_Right_Edit", "Workflow_Right_Edit_User"}) 119 public Map<String, Object> getFunctionsModel() throws ProcessingException 120 { 121 Map<String, Object> response = new HashMap<>(); 122 123 View view = new View(); 124 SimpleViewItemGroup fieldset = new SimpleViewItemGroup(); 125 fieldset.setName("functions"); 126 127 Set<Pair<String, EnhancedFunction>> enhancedFunctions = _enhancedFunctionExtensionPoint.getAllFunctions() 128 .stream() 129 .filter(this::_hasFunctionRight) 130 .collect(Collectors.toSet()); 131 132 List<ElementDefinition> modelItems = new ArrayList<>(); 133 modelItems.add(_getFunctionListModelItem(enhancedFunctions)); 134 modelItems.addAll(_getArgumentsAndTypeModelItems(enhancedFunctions)); 135 Model.of("functions", "worklow", modelItems.toArray(new ElementDefinition[modelItems.size()])); 136 137 for (ElementDefinition functionArgument : modelItems) 138 { 139 ViewElement argumentView = new ViewElement(); 140 argumentView.setDefinition(functionArgument); 141 fieldset.addViewItem(argumentView); 142 } 143 144 view.addViewItem(fieldset); 145 146 response.put("parameters", view.toJSON(DefinitionContext.newInstance().withEdition(true))); 147 148 return response; 149 } 150 151 private boolean _hasFunctionRight(Pair<String, EnhancedFunction> function) 152 { 153 List<WorkflowVisibility> functionVisibilities = function.getRight().getVisibilities(); 154 if (functionVisibilities.contains(WorkflowVisibility.USER)) 155 { 156 return _workflowRightHelper.hasEditUserRight(); 157 } 158 else if (functionVisibilities.contains(WorkflowVisibility.SYSTEM)) 159 { 160 return _workflowRightHelper.hasEditSystemRight(); 161 } 162 return false; 163 } 164 165 /** 166 * Get a list of workflow arguments model items with disable conditions on non related function selected 167 * @param enhancedFunctions a list of Pair with id and enhanced function 168 * @return the list of model items 169 */ 170 protected List<ElementDefinition> _getArgumentsAndTypeModelItems(Set<Pair<String, EnhancedFunction>> enhancedFunctions) 171 { 172 List<ElementDefinition> argumentModelItems = new ArrayList<>(); 173 for (Pair<String, EnhancedFunction> functionPair : enhancedFunctions) 174 { 175 String functionId = functionPair.getLeft(); 176 177 DisableCondition disableCondition = new VoidRelativeDisableCondition(__ATTRIBUTE_FUNCTIONS_LIST, OPERATOR.NEQ, functionId); 178 179 EnhancedFunction function = functionPair.getRight(); 180 if (function.getFunctionExecType().equals(FunctionType.BOTH)) 181 { 182 argumentModelItems.add(_getFunctionTypeModelItem(functionId, disableCondition)); 183 } 184 185 for (WorkflowArgument arg : function.getArguments()) 186 { 187 arg.setName(functionId + "-" + arg.getName()); 188 DisableConditions disableConditions = arg.getDisableConditions(); 189 if (disableConditions == null) 190 { 191 disableConditions = new VoidRelativeDisableConditions(); 192 } 193 disableConditions.setAssociation(ASSOCIATION_TYPE.OR); 194 disableConditions.getConditions().add(disableCondition); 195 arg.setDisableConditions(disableConditions); 196 argumentModelItems.add(arg); 197 } 198 } 199 return argumentModelItems; 200 } 201 202 /** 203 * Get the model item for the list of functions 204 * @param enhancedFunctions the list of enhanced functions 205 * @return an enum of the functions as a model item 206 */ 207 protected ElementDefinition<String> _getFunctionListModelItem(Set<Pair<String, EnhancedFunction>> enhancedFunctions) 208 { 209 ElementDefinition<String> functionsList = WorkflowElementDefinitionHelper.getElementDefinition( 210 __ATTRIBUTE_FUNCTIONS_LIST, 211 new I18nizableText("plugin.workflow", "PLUGINS_WORKFLOW_ADD_FUNCTION_DIALOG_ROLE"), 212 new I18nizableText("plugin.workflow", "PLUGINS_WORKFLOW_ADD_FUNCTION_DIALOG_ROLE_DESC"), 213 true, 214 false 215 ); 216 StaticEnumerator<String> functionsStaticEnumerator = new StaticEnumerator<>(); 217 for (Pair<String, EnhancedFunction> function : enhancedFunctions) 218 { 219 functionsStaticEnumerator.add(function.getRight().getLabel(), function.getLeft()); 220 } 221 functionsList.setEnumerator(functionsStaticEnumerator); 222 223 return functionsList; 224 } 225 226 /** 227 * Get the view item for the fonctions types 228 * @param functionId id of current function 229 * @param disableCondition the condition for disabling the field 230 * @return the view element 231 */ 232 protected ElementDefinition<String> _getFunctionTypeModelItem(String functionId, DisableCondition disableCondition) 233 { 234 DisableConditions disableConditions = new VoidRelativeDisableConditions(); 235 disableConditions.getConditions().add(disableCondition); 236 237 StaticEnumerator<String> functionTypeStaticEnum = new StaticEnumerator<>(); 238 functionTypeStaticEnum.add(new I18nizableText("plugin.workflow", "PLUGINS_WORKFLOW_ADD_FUNCTION_DIALOG_PREFUNCTION_TYPE"), FunctionType.PRE.name()); 239 functionTypeStaticEnum.add(new I18nizableText("plugin.workflow", "PLUGINS_WORKFLOW_ADD_FUNCTION_DIALOG_POSTFUNCTION_TYPE"), FunctionType.POST.name()); 240 241 ElementDefinition<String> functionTypes = WorkflowElementDefinitionHelper.getElementDefinition( 242 __ATTRIBUTE_FUNCTION_TYPES + "-" + functionId, 243 new I18nizableText("plugin.workflow", "PLUGINS_WORKFLOW_ADD_FUNCTION_DIALOG_TYPES_LABEL"), 244 new I18nizableText("plugin.workflow", "PLUGINS_WORKFLOW_ADD_FUNCTION_DIALOG_TYPES_DESC"), 245 true, 246 false 247 ); 248 functionTypes.setDisableConditions(disableConditions); 249 functionTypes.setEnumerator(functionTypeStaticEnum); 250 251 return functionTypes; 252 } 253 254 /** 255 * Get the function's parameters as a json view and their current values 256 * @param workflowName the workflow's unique name 257 * @param stepId the parent step's id 258 * @param actionId the parent action's id can be null 259 * @param type whether the function is a pre of post function 260 * @param id the function's id 261 * @param index the function's index in the pre/post function list 262 * @return map of the function's infos 263 */ 264 @Callable(rights = Callable.CHECKED_BY_IMPLEMENTATION) 265 public Map<String, Object> getFunctionParametersValues(String workflowName, Integer stepId, Integer actionId, String type, String id, Integer index) 266 { 267 WorkflowDescriptor workflowDescriptor = _workflowSessionHelper.getWorkflowDescriptor(workflowName, false); 268 269 // Check user right 270 _workflowRightHelper.checkEditRight(workflowDescriptor); 271 272 Map<String, String> args = new HashMap<>(); 273 274 FunctionDescriptor function = _getFunction(workflowDescriptor, stepId, actionId, type, index); 275 276 //change arguments key to make them unique 277 Map<String, String> arguments = function.getArgs(); 278 for (Entry<String, String> entry : arguments.entrySet()) 279 { 280 String argName = entry.getKey().equals("id") ? __ATTRIBUTE_FUNCTIONS_LIST : id + "-" + entry.getKey(); 281 args.put(argName, entry.getValue()); 282 } 283 284 Map<String, Object> results = new HashMap<>(); 285 results.put("parametersValues", args); 286 return results; 287 } 288 289 private FunctionDescriptor _getFunction(WorkflowDescriptor workflowDescriptor, Integer stepId, Integer actionId, String type, Integer index) 290 { 291 List<FunctionDescriptor> functions = _getTypedFunctions(workflowDescriptor, stepId, actionId, type); 292 FunctionDescriptor function = functions.get(index); 293 return function; 294 } 295 296 /** 297 * Add a function to the workflow element 298 * @param workflowName the workflow's unique name 299 * @param stepId the parent step's id 300 * @param actionId the parent action's id can be null 301 * @param params Map of the function arguments 302 * @return map of the function's infos 303 */ 304 @Callable(rights = Callable.CHECKED_BY_IMPLEMENTATION) 305 public Map<String, Object> addFunction(String workflowName, Integer stepId, Integer actionId, Map<String, Object> params) 306 { 307 WorkflowDescriptor workflowDescriptor = _workflowSessionHelper.getWorkflowDescriptor(workflowName, true); 308 309 // Check user right 310 _workflowRightHelper.checkEditRight(workflowDescriptor); 311 312 String functionId = (String) params.get(__ATTRIBUTE_FUNCTIONS_LIST); 313 EnhancedFunction enhancedFunction = _enhancedFunctionExtensionPoint.getExtension(functionId); 314 315 String functionType = enhancedFunction.getFunctionExecType().equals(FunctionType.BOTH) 316 ? (String) params.get(__ATTRIBUTE_FUNCTION_TYPES + "-" + functionId) 317 : enhancedFunction.getFunctionExecType().name(); 318 319 List<FunctionDescriptor> functions = _getTypedFunctions(workflowDescriptor, stepId, actionId, functionType); 320 Map<String, String> functionParams = _getFunctionParamsValuesAsString(enhancedFunction, functionId, params); 321 FunctionDescriptor newFunction = _createFunctionDescriptor(functionParams); 322 functions.add(newFunction); 323 324 _workflowSessionHelper.updateWorkflowDescriptor(workflowDescriptor); 325 326 return _getFunctionInfos(workflowDescriptor, stepId, actionId, functionType, functionId, functions.size() - 1, true); 327 } 328 329 private FunctionDescriptor _createFunctionDescriptor(Map<String, String> functionParams) 330 { 331 DescriptorFactory factory = new DescriptorFactory(); 332 FunctionDescriptor newFunction = factory.createFunctionDescriptor(); 333 newFunction.setType(__FUNCTION_DEFAULT_TYPE); 334 newFunction.getArgs().putAll(functionParams); 335 336 return newFunction; 337 } 338 339 /** 340 * Get the list of arguments as String, parse multiple arguments 341 * @param enhancedFunction the current function class 342 * @param functionId the function's id 343 * @param params List of function arguments with values 344 * @return the map of arguments formated for condition descriptor 345 */ 346 protected Map<String, String> _getFunctionParamsValuesAsString(EnhancedFunction enhancedFunction, String functionId, Map<String, Object> params) 347 { 348 Map<String, String> functionParams = new HashMap<>(); 349 functionParams.put("id", functionId); 350 List<WorkflowArgument> arguments = enhancedFunction.getArguments(); 351 if (!arguments.isEmpty()) 352 { 353 for (WorkflowArgument argument : arguments) 354 { 355 String paramKey = functionId + "-" + argument.getName(); 356 String paramValue = argument.isMultiple() 357 ? _getListAsString(params, paramKey) 358 : (String) params.get(paramKey); 359 if (StringUtils.isNotBlank(paramValue)) 360 { 361 functionParams.put(argument.getName(), paramValue); 362 } 363 } 364 } 365 return functionParams; 366 } 367 368 @SuppressWarnings("unchecked") 369 private String _getListAsString(Map<String, Object> params, String paramKey) 370 { 371 List<String> values = (List<String>) params.get(paramKey); 372 return values == null ? "" : String.join(",", values); 373 } 374 375 /** 376 * Get the list where belong a function can be either the prefunction list or the postfunctions 377 * @param workflowDescriptor the current workflow 378 * @param stepId id of current step 379 * @param actionId id of current action can be null if selection is a step 380 * @param functionType the type of function 381 * @return the typed list 382 */ 383 protected List<FunctionDescriptor> _getTypedFunctions(WorkflowDescriptor workflowDescriptor, Integer stepId, Integer actionId, String functionType) 384 { 385 List<FunctionDescriptor> functions = new ArrayList<>(); 386 if (actionId != null) 387 { 388 ActionDescriptor action = workflowDescriptor.getAction(actionId); 389 functions = functionType.equals(FunctionType.PRE.name()) ? action.getPreFunctions() : action.getPostFunctions(); 390 } 391 else 392 { 393 StepDescriptor step = workflowDescriptor.getStep(stepId); 394 functions = functionType.equals(FunctionType.PRE.name()) ? step.getPreFunctions() : step.getPostFunctions(); 395 } 396 return functions; 397 } 398 399 /** 400 * Edit the function 401 * @param workflowName the workflow's unique name 402 * @param stepId the parent step's id 403 * @param actionId the parent action's id can be null 404 * @param oldType the saved type for this fonction 405 * @param params Map of the function arguments 406 * @param indexOfFunction the function's index in the pre/post function list 407 * @return map of the function's infos 408 */ 409 @Callable(rights = Callable.CHECKED_BY_IMPLEMENTATION) 410 public Map<String, Object> editFunction(String workflowName, Integer stepId, Integer actionId, String oldType, Map<String, Object> params, int indexOfFunction) 411 { 412 WorkflowDescriptor workflow = _workflowSessionHelper.getWorkflowDescriptor(workflowName, true); 413 414 // Check user right 415 _workflowRightHelper.checkEditRight(workflow); 416 417 List<FunctionDescriptor> functions = _getTypedFunctions(workflow, stepId, actionId, oldType); 418 FunctionDescriptor function = functions.get(indexOfFunction); 419 420 int index = indexOfFunction; 421 String functionId = (String) params.get(__ATTRIBUTE_FUNCTIONS_LIST); 422 EnhancedFunction enhancedFunction = _enhancedFunctionExtensionPoint.getExtension(functionId); 423 424 String functionType = (String) params.get(__ATTRIBUTE_FUNCTION_TYPES + "-" + functionId); 425 String newType = StringUtils.isBlank(functionType) ? enhancedFunction.getFunctionExecType().name() : functionType; 426 427 if (!oldType.equals(newType)) //Move function into the other typed list 428 { 429 functions.remove(function); 430 functions = _getTypedFunctions(workflow, stepId, actionId, newType); 431 functions.add(function); 432 index = functions.size() - 1; 433 } 434 435 _updateFunctionArguments(function, functionId, enhancedFunction, params); 436 _workflowSessionHelper.updateWorkflowDescriptor(workflow); 437 438 return _getFunctionInfos(workflow, stepId, actionId, newType, functionId, index, _isLast(functions, indexOfFunction)); 439 } 440 441 private void _updateFunctionArguments(FunctionDescriptor function, String functionId, EnhancedFunction enhancedFunction, Map<String, Object> params) 442 { 443 Map<String, String> args = function.getArgs(); 444 args.clear(); 445 args.putAll(_getFunctionParamsValuesAsString(enhancedFunction, functionId, params)); 446 } 447 448 /** 449 * Remove the function from its parent 450 * @param workflowName the workflow's unique name 451 * @param stepId the parent step's id 452 * @param actionId the parent action's id can be null 453 * @param functionType whether the function is a pre of post function 454 * @param id the function's id 455 * @param indexToRemove the function's index in the pre/post function list 456 * @return map of the function's infos 457 */ 458 @Callable(rights = Callable.CHECKED_BY_IMPLEMENTATION) 459 public Map<String, Object> deleteFunction(String workflowName, Integer stepId, Integer actionId, String functionType, String id, int indexToRemove) 460 { 461 WorkflowDescriptor workflow = _workflowSessionHelper.getWorkflowDescriptor(workflowName, true); 462 463 // Check user right 464 _workflowRightHelper.checkEditRight(workflow); 465 466 List<FunctionDescriptor> functions = _getTypedFunctions(workflow, stepId, actionId, functionType); 467 functions.remove(indexToRemove); 468 _workflowSessionHelper.updateWorkflowDescriptor(workflow); 469 470 return _getFunctionInfos(workflow, stepId, actionId, functionType, id, indexToRemove, _isLast(functions, indexToRemove)); 471 } 472 473 /** 474 * Swap the function with the one before it in the parent's pre/post function list 475 * @param workflowName the workflow's unique name 476 * @param stepId the parent step's id 477 * @param actionId the parent action's id can be null 478 * @param functionType whether the function is a pre of post function 479 * @param functionIndex the function's index in the pre/post function list 480 * @return map of the function's infos 481 */ 482 @Callable(rights = Callable.CHECKED_BY_IMPLEMENTATION) 483 public Map<String, Object> moveUp(String workflowName, Integer stepId, Integer actionId, String functionType, int functionIndex) 484 { 485 WorkflowDescriptor workflow = _workflowSessionHelper.getWorkflowDescriptor(workflowName, true); 486 487 // Check user right 488 _workflowRightHelper.checkEditRight(workflow); 489 490 if (functionIndex == 0) 491 { 492 return Map.of("message", "top-queue"); 493 } 494 List<FunctionDescriptor> functions = _getTypedFunctions(workflow, stepId, actionId, functionType); 495 FunctionDescriptor functionToMove = functions.get(functionIndex); 496 Collections.swap(functions, functionIndex, functionIndex - 1); 497 _workflowSessionHelper.updateWorkflowDescriptor(workflow); 498 499 return _getFunctionInfos(workflow, stepId, actionId, functionType, (String) functionToMove.getArgs().get("id"), functionIndex - 1, false); 500 } 501 502 /** 503 * Swap the function with the one after it in the parent's pre/post function list 504 * @param workflowName the workflow's unique name 505 * @param stepId the parent step's id 506 * @param actionId the parent action's id can be null 507 * @param functionType whether the function is a pre of post function 508 * @param functionIndex the function's index in the pre/post function list 509 * @return map of the function's infos 510 */ 511 @Callable(rights = Callable.CHECKED_BY_IMPLEMENTATION) 512 public Map<String, Object> moveDown(String workflowName, Integer stepId, Integer actionId, String functionType, int functionIndex) 513 { 514 WorkflowDescriptor workflow = _workflowSessionHelper.getWorkflowDescriptor(workflowName, true); 515 516 // Check user right 517 _workflowRightHelper.checkEditRight(workflow); 518 519 List<FunctionDescriptor> functions = _getTypedFunctions(workflow, stepId, actionId, functionType); 520 if (functionIndex == functions.size() - 1) 521 { 522 return Map.of("message", "bottom-queue"); 523 } 524 FunctionDescriptor functionToMove = functions.get(functionIndex); 525 Collections.swap(functions, functionIndex, functionIndex + 1); 526 _workflowSessionHelper.updateWorkflowDescriptor(workflow); 527 528 return _getFunctionInfos(workflow, stepId, actionId, functionType, (String) functionToMove.getArgs().get("id"), functionIndex + 1, _isLast(functions, functionIndex + 1)); 529 } 530 531 /** 532 * Check if function can have bigger index in its parent's pre/post function list 533 * @param functions the current list of functions 534 * @param functionIndex the function's index in the pre/post function list 535 * @return true if the function can move down 536 */ 537 protected boolean _isLast(List<FunctionDescriptor> functions, int functionIndex) 538 { 539 return functionIndex == functions.size() - 1; 540 } 541 542 /** 543 * Get pre and postfunctions of current step 544 * @param workflowName the workflow unique name 545 * @param stepId id of the current step 546 * @return a list of the step's functions 547 */ 548 @SuppressWarnings("unchecked") 549 @Callable(rights = Callable.CHECKED_BY_IMPLEMENTATION) 550 public Map<String, Object> getStepFunctions(String workflowName, Integer stepId) 551 { 552 WorkflowDescriptor workflowDescriptor = _workflowSessionHelper.getWorkflowDescriptor(workflowName, false); 553 List<Map<String, Object>> functions2json = new ArrayList<>(); 554 if (_workflowRightHelper.canRead(workflowDescriptor)) 555 { 556 StepDescriptor step = workflowDescriptor.getStep(stepId); 557 if (step != null) 558 { 559 functions2json.addAll(_functions2JSON(step.getPreFunctions(), FunctionType.PRE.name())); 560 functions2json.addAll(_functions2JSON(step.getPostFunctions(), FunctionType.POST.name())); 561 } 562 } 563 return Map.of("data", functions2json); 564 } 565 566 /** 567 * Get pre and postfunctions of current action 568 * @param workflowName the workflow unique name 569 * @param actionId id of the current action 570 * @return a list of the action's functions 571 */ 572 @SuppressWarnings("unchecked") 573 @Callable(rights = Callable.CHECKED_BY_IMPLEMENTATION) 574 public Map<String, Object> getActionFunctions(String workflowName, Integer actionId) 575 { 576 WorkflowDescriptor workflowDescriptor = _workflowSessionHelper.getWorkflowDescriptor(workflowName, false); 577 List<Map<String, Object>> functions2json = new ArrayList<>(); 578 if (_workflowRightHelper.canRead(workflowDescriptor)) 579 { 580 ActionDescriptor action = workflowDescriptor.getAction(actionId); 581 if (action != null) 582 { 583 functions2json.addAll(_functions2JSON(action.getPreFunctions(), FunctionType.PRE.name())); 584 functions2json.addAll(_functions2JSON(action.getPostFunctions(), FunctionType.POST.name())); 585 } 586 } 587 588 return Map.of("data", functions2json); 589 } 590 591 private List<Map<String, Object>> _functions2JSON(List<FunctionDescriptor> functions, String type) 592 { 593 List<Map<String, Object>> functions2json = new ArrayList<>(); 594 for (int index = 0; index < functions.size(); index++) 595 { 596 functions2json.add(_function2JSON(functions.get(index), type, index, _isLast(functions, index))); 597 } 598 return functions2json; 599 } 600 601 private Map<String, Object> _function2JSON(FunctionDescriptor workflowFunction, String type, int index, boolean isLast) 602 { 603 String id = (String) workflowFunction.getArgs().get("id"); 604 Map<String, Object> functionInfos = new HashMap<>(); 605 functionInfos.put("type", type); 606 functionInfos.put("id", id); 607 functionInfos.put("index", index); 608 functionInfos.put("isLast", isLast); 609 610 try 611 { 612 TypeResolver typeResolver = new AvalonTypeResolver(_manager); 613 FunctionProvider function = typeResolver.getFunction(workflowFunction.getType(), workflowFunction.getArgs()); 614 if (function instanceof EnhancedFunction enhancedFunction) 615 { 616 I18nizableText description = _getFunctionDescription(workflowFunction, enhancedFunction); 617 if (description != null) 618 { 619 functionInfos.put("description", description); 620 } 621 } 622 } 623 catch (WorkflowException e) 624 { 625 getLogger().error("Function " + id + " couldn't be resolved", e); 626 } 627 return functionInfos; 628 } 629 630 private I18nizableText _getFunctionDescription(FunctionDescriptor workflowFunction, EnhancedFunction enhancedFunction) 631 { 632 List<WorkflowArgument> arguments = enhancedFunction.getArguments(); 633 Map<String, String> values = new HashMap<>(); 634 for (WorkflowArgument arg : arguments) 635 { 636 values.put(arg.getName(), (String) workflowFunction.getArgs().get(arg.getName())); 637 } 638 639 I18nizableText description = enhancedFunction.getFullLabel(values); 640 return description; 641 } 642 643 /** 644 * Get the function's description 645 * @param workflowName the workflow's unique name 646 * @param stepId the parent step's id 647 * @param actionId the parent action's id can be null 648 * @param type whether the function is a pre of post function 649 * @param id the enhanced function's id 650 * @param index the function's index in the pre/post function list 651 * @return the function's description 652 */ 653 @Callable(rights = Callable.CHECKED_BY_IMPLEMENTATION) 654 public I18nizableText getFunctionDescription(String workflowName, Integer stepId, Integer actionId, String type, String id, Integer index) 655 { 656 WorkflowDescriptor workflow = _workflowSessionHelper.getWorkflowDescriptor(workflowName, false); 657 658 // Check user right 659 _workflowRightHelper.checkReadRight(workflow); 660 661 FunctionDescriptor function = _getFunction(workflow, stepId, actionId, type, index); 662 EnhancedFunction enhancedFunction = _enhancedFunctionExtensionPoint.getExtension(id); 663 return _getFunctionDescription(function, enhancedFunction); 664 } 665 666 private Map<String, Object> _getFunctionInfos(WorkflowDescriptor workflow, Integer stepId, Integer actionId, String type, String id, int index, boolean isLast) 667 { 668 Map<String, Object> results = new HashMap<>(); 669 results.put("workflowId", workflow.getName()); 670 results.put("stepId", stepId); 671 results.put("stepLabel", _workflowStepDAO.getStepLabel(workflow, stepId)); 672 if (actionId != null) 673 { 674 ActionDescriptor action = workflow.getAction(actionId); 675 results.put("actionId", actionId); 676 results.put("actionLabel", _workflowTransitionDAO.getActionLabel(action)); 677 } 678 results.put("type", type); 679 results.put("id", id); 680 results.put("index", index); 681 results.put("isLast", isLast); 682 return results; 683 } 684 685}