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