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