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