001// -------------------------------------------------------------------------------- 002// Copyright 2002-2026 Echo Three, LLC 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// -------------------------------------------------------------------------------- 016 017package com.echothree.model.control.workflow.server.logic; 018 019import com.echothree.control.user.workflow.common.spec.WorkflowDestinationUniversalSpec; 020import com.echothree.model.control.core.common.ComponentVendors; 021import com.echothree.model.control.core.common.EntityTypes; 022import com.echothree.model.control.core.common.exception.InvalidParameterCountException; 023import com.echothree.model.control.core.server.logic.EntityInstanceLogic; 024import com.echothree.model.control.party.server.logic.PartyLogic; 025import com.echothree.model.control.security.server.logic.SecurityRoleLogic; 026import com.echothree.model.control.selector.server.logic.SelectorLogic; 027import com.echothree.model.control.workflow.common.exception.MissingRequiredWorkflowNameException; 028import com.echothree.model.control.workflow.common.exception.MissingRequiredWorkflowStepNameException; 029import com.echothree.model.control.workflow.common.exception.UnknownDefaultWorkflowDestinationException; 030import com.echothree.model.control.workflow.common.exception.UnknownDestinationWorkflowNameException; 031import com.echothree.model.control.workflow.common.exception.UnknownDestinationWorkflowStepNameException; 032import com.echothree.model.control.workflow.common.exception.UnknownWorkflowDestinationPartyTypeException; 033import com.echothree.model.control.workflow.common.exception.UnknownWorkflowDestinationSecurityRoleException; 034import com.echothree.model.control.workflow.common.exception.UnknownWorkflowDestinationSelectorException; 035import com.echothree.model.control.workflow.common.exception.UnknownWorkflowDestinationStepException; 036import com.echothree.model.control.workflow.common.exception.UnknownWorkflowNameException; 037import com.echothree.model.control.workflow.common.exception.WorkflowMissingSecurityRoleGroupException; 038import com.echothree.model.control.workflow.common.exception.WorkflowMissingSelectorTypeException; 039import com.echothree.model.control.workflow.server.control.WorkflowControl; 040import com.echothree.model.data.party.server.entity.PartyType; 041import com.echothree.model.data.workflow.server.entity.Workflow; 042import com.echothree.model.data.workflow.server.entity.WorkflowDestination; 043import com.echothree.model.data.workflow.server.entity.WorkflowDestinationPartyType; 044import com.echothree.model.data.workflow.server.entity.WorkflowDestinationSecurityRole; 045import com.echothree.model.data.workflow.server.entity.WorkflowDestinationSelector; 046import com.echothree.model.data.workflow.server.entity.WorkflowDestinationStep; 047import com.echothree.model.data.workflow.server.entity.WorkflowStep; 048import com.echothree.util.common.message.ExecutionErrors; 049import com.echothree.util.server.control.BaseLogic; 050import com.echothree.util.server.message.ExecutionErrorAccumulator; 051import com.echothree.util.server.persistence.EntityPermission; 052import com.echothree.util.server.validation.ParameterUtils; 053import java.util.HashMap; 054import java.util.HashSet; 055import java.util.Map; 056import java.util.Set; 057import javax.enterprise.context.ApplicationScoped; 058import javax.inject.Inject; 059 060@ApplicationScoped 061public class WorkflowDestinationLogic 062 extends BaseLogic { 063 064 @Inject 065 WorkflowControl workflowControl; 066 067 @Inject 068 EntityInstanceLogic entityInstanceLogic; 069 070 @Inject 071 PartyLogic partyLogic; 072 073 @Inject 074 SecurityRoleLogic securityRoleLogic; 075 076 @Inject 077 SelectorLogic selectorLogic; 078 079 @Inject 080 WorkflowStepLogic workflowStepLogic; 081 082 protected WorkflowDestinationLogic() { 083 super(); 084 } 085 086 public WorkflowDestination getWorkflowDestinationByName(final ExecutionErrorAccumulator eea, final WorkflowStep workflowStep, 087 final String workflowDestinationName, final EntityPermission entityPermission) { 088 var workflowDestination = workflowControl.getWorkflowDestinationByName(workflowStep, workflowDestinationName, 089 entityPermission); 090 091 if(workflowDestination == null) { 092 var workflowStepDetail = workflowStep.getLastDetail(); 093 094 handleExecutionError(UnknownWorkflowNameException.class, eea, ExecutionErrors.UnknownWorkflowDestinationName.name(), 095 workflowStepDetail.getWorkflow().getLastDetail().getWorkflowName(), workflowStepDetail.getWorkflowStepName(), workflowDestinationName); 096 } 097 098 return workflowDestination; 099 } 100 101 public WorkflowDestination getWorkflowDestinationByName(final ExecutionErrorAccumulator eea, final WorkflowStep workflowStep, 102 final String workflowDestinationName) { 103 return getWorkflowDestinationByName(eea, workflowStep, workflowDestinationName, EntityPermission.READ_ONLY); 104 } 105 106 public WorkflowDestination getWorkflowDestinationByNameForUpdate(final ExecutionErrorAccumulator eea, final WorkflowStep workflowStep, 107 final String workflowDestinationName) { 108 return getWorkflowDestinationByName(eea, workflowStep, workflowDestinationName, EntityPermission.READ_WRITE); 109 } 110 111 public WorkflowDestination getWorkflowDestinationByName(final ExecutionErrorAccumulator eea, final Workflow workflow, final String workflowStepName, 112 final String workflowDestinationName) { 113 var workflowStep = workflowStepLogic.getWorkflowStepByName(eea, workflow, workflowStepName); 114 WorkflowDestination workflowDestination = null; 115 116 if(eea == null || !eea.hasExecutionErrors()) { 117 workflowDestination = getWorkflowDestinationByName(eea, workflowStep, workflowDestinationName, EntityPermission.READ_ONLY); 118 } 119 120 return workflowDestination; 121 } 122 123 public WorkflowDestination getWorkflowDestinationByName(final ExecutionErrorAccumulator eea, final String workflowName, final String workflowStepName, 124 final String workflowDestinationName) { 125 var workflowStep = workflowStepLogic.getWorkflowStepByName(eea, workflowName, workflowStepName); 126 WorkflowDestination workflowDestination = null; 127 128 if(eea == null || !eea.hasExecutionErrors()) { 129 workflowDestination = getWorkflowDestinationByName(eea, workflowStep, workflowDestinationName, EntityPermission.READ_ONLY); 130 } 131 132 return workflowDestination; 133 } 134 135 public WorkflowDestination getWorkflowDestinationByUniversalSpec(final ExecutionErrorAccumulator eea, final WorkflowDestinationUniversalSpec universalSpec, 136 final boolean allowDefault, final EntityPermission entityPermission) { 137 var workflowName = universalSpec.getWorkflowName(); 138 var workflowStepName = universalSpec.getWorkflowStepName(); 139 var workflowDestinationName = universalSpec.getWorkflowDestinationName(); 140 var nameParameterCount= ParameterUtils.getInstance().countNonNullParameters(workflowName, workflowStepName, workflowDestinationName); 141 var possibleEntitySpecs= entityInstanceLogic.countPossibleEntitySpecs(universalSpec); 142 WorkflowDestination workflowDestination = null; 143 144 if(nameParameterCount < 4 && possibleEntitySpecs == 0) { 145 WorkflowStep workflowStep = null; 146 147 if(workflowName != null && workflowStepName != null) { 148 workflowStep = workflowStepLogic.getWorkflowStepByName(eea, workflowName, workflowStepName); 149 } else { 150 if(workflowName != null) { 151 handleExecutionError(MissingRequiredWorkflowNameException.class, eea, ExecutionErrors.MissingRequiredWorkflowName.name()); 152 } 153 154 if(workflowStepName != null) { 155 handleExecutionError(MissingRequiredWorkflowStepNameException.class, eea, ExecutionErrors.MissingRequiredWorkflowStepName.name()); 156 } 157 } 158 159 if(eea == null || !eea.hasExecutionErrors()) { 160 if(workflowDestinationName == null) { 161 if(allowDefault) { 162 workflowDestination = workflowControl.getDefaultWorkflowDestination(workflowStep, entityPermission); 163 164 if(workflowDestination == null) { 165 handleExecutionError(UnknownDefaultWorkflowDestinationException.class, eea, ExecutionErrors.UnknownDefaultWorkflowDestination.name()); 166 } 167 } else { 168 handleExecutionError(InvalidParameterCountException.class, eea, ExecutionErrors.InvalidParameterCount.name()); 169 } 170 } else { 171 workflowDestination = getWorkflowDestinationByName(eea, workflowStep, workflowDestinationName, entityPermission); 172 } 173 } 174 } else if(nameParameterCount == 0 && possibleEntitySpecs == 1) { 175 var entityInstance = entityInstanceLogic.getEntityInstance(eea, universalSpec, 176 ComponentVendors.ECHO_THREE.name(), EntityTypes.WorkflowDestination.name()); 177 178 if(eea == null || !eea.hasExecutionErrors()) { 179 workflowDestination = workflowControl.getWorkflowDestinationByEntityInstance(entityInstance, entityPermission); 180 } 181 } else { 182 handleExecutionError(InvalidParameterCountException.class, eea, ExecutionErrors.InvalidParameterCount.name()); 183 } 184 185 return workflowDestination; 186 } 187 188 public WorkflowDestination getWorkflowDestinationByUniversalSpec(final ExecutionErrorAccumulator eea, final WorkflowDestinationUniversalSpec universalSpec, 189 boolean allowDefault) { 190 return getWorkflowDestinationByUniversalSpec(eea, universalSpec, allowDefault, EntityPermission.READ_ONLY); 191 } 192 193 public WorkflowDestination getWorkflowDestinationByUniversalSpecForUpdate(final ExecutionErrorAccumulator eea, final WorkflowDestinationUniversalSpec universalSpec, 194 boolean allowDefault) { 195 return getWorkflowDestinationByUniversalSpec(eea, universalSpec, allowDefault, EntityPermission.READ_WRITE); 196 } 197 198 public Set<WorkflowStep> getWorkflowDestinationStepsAsSet(final WorkflowDestination workflowDestination) { 199 var workflowDestinationSteps = workflowControl.getWorkflowDestinationStepsByWorkflowDestination(workflowDestination); 200 Set<WorkflowStep> workflowSteps = new HashSet<>(workflowDestinationSteps.size()); 201 202 workflowDestinationSteps.forEach((workflowDestinationStep) -> { 203 workflowSteps.add(workflowDestinationStep.getWorkflowStep()); 204 }); 205 206 return workflowSteps; 207 } 208 209 public Map<String, Set<String>> getWorkflowDestinationsAsMap(final WorkflowDestination workflowDestination) { 210 var workflowDestinationSteps = workflowControl.getWorkflowDestinationStepsByWorkflowDestination(workflowDestination); 211 Map<String, Set<String>> map = new HashMap<>(); 212 213 workflowDestinationSteps.stream().map((workflowDestinationStep) -> workflowDestinationStep.getWorkflowStep().getLastDetail()).forEach((workflowStepDetail) -> { 214 var workflowStepName = workflowStepDetail.getWorkflowStepName(); 215 var workflowName = workflowStepDetail.getWorkflow().getLastDetail().getWorkflowName(); 216 217 workflowDestinationMapContainsStep(map, workflowName, workflowStepName, true); 218 }); 219 220 return map; 221 } 222 223 private boolean workflowDestinationMapContainsStep(final Map<String, Set<String>> map, final String workflowName, 224 final String workflowStepName, final boolean addIt) { 225 var workflowSteps = map.get(workflowName); 226 227 if(workflowSteps == null && addIt) { 228 workflowSteps = new HashSet<>(); 229 map.put(workflowName, workflowSteps); 230 } 231 232 var found = workflowSteps != null && workflowSteps.contains(workflowStepName); 233 234 if(!found && addIt) { 235 workflowSteps.add(workflowStepName); 236 } 237 238 return found; 239 } 240 241 public boolean workflowDestinationMapContainsStep(final Map<String, Set<String>> map, final String workflowName, 242 final String workflowStepName) { 243 return workflowDestinationMapContainsStep(map, workflowName, workflowStepName, false); 244 } 245 246 public WorkflowDestinationPartyType getWorkflowDestinationPartyType(final ExecutionErrorAccumulator eea, final WorkflowDestination workflowDestination, 247 final PartyType partyType, final EntityPermission entityPermission) { 248 WorkflowDestinationPartyType workflowDestinationPartyType = null; 249 250 if(eea == null || !eea.hasExecutionErrors()) { 251 workflowDestinationPartyType = workflowControl.getWorkflowDestinationPartyType(workflowDestination, partyType, entityPermission); 252 253 if(workflowDestinationPartyType == null) { 254 var workflowDestinationDetail = workflowDestination.getLastDetail(); 255 var workflowStepDetail = workflowDestinationDetail.getWorkflowStep().getLastDetail(); 256 257 handleExecutionError(UnknownWorkflowDestinationPartyTypeException.class, eea, ExecutionErrors.UnknownWorkflowDestinationPartyType.name(), 258 workflowStepDetail.getWorkflow().getLastDetail().getWorkflowName(), workflowStepDetail.getWorkflowStepName(), 259 workflowDestinationDetail.getWorkflowDestinationName(), partyType.getPartyTypeName()); 260 } 261 } 262 263 return workflowDestinationPartyType; 264 } 265 266 public WorkflowDestinationPartyType getWorkflowDestinationPartyType(final ExecutionErrorAccumulator eea, final WorkflowDestination workflowDestination, 267 final PartyType partyType) { 268 return getWorkflowDestinationPartyType(eea, workflowDestination, partyType, EntityPermission.READ_ONLY); 269 } 270 271 public WorkflowDestinationPartyType getWorkflowDestinationPartyTypeForUpdate(final ExecutionErrorAccumulator eea, final WorkflowDestination workflowDestination, 272 final PartyType partyType) { 273 return getWorkflowDestinationPartyType(eea, workflowDestination, partyType, EntityPermission.READ_WRITE); 274 } 275 276 public WorkflowDestinationPartyType getWorkflowDestinationPartyTypeByName(final ExecutionErrorAccumulator eea, final String workflowName, 277 final String workflowStepName, final String workflowDestinationName, final String partyTypeName, final EntityPermission entityPermission) { 278 var workflowDestination = getWorkflowDestinationByName(eea, workflowName, workflowStepName, workflowDestinationName); 279 var partyType = partyLogic.getPartyTypeByName(eea, partyTypeName); 280 281 return getWorkflowDestinationPartyType(eea, workflowDestination, partyType, entityPermission); 282 } 283 284 public WorkflowDestinationPartyType getWorkflowDestinationPartyTypeByName(final ExecutionErrorAccumulator eea, final String workflowName, 285 final String workflowStepName, final String workflowDestinationName, final String partyTypeName) { 286 return getWorkflowDestinationPartyTypeByName(eea, workflowName, workflowStepName, workflowDestinationName, partyTypeName, 287 EntityPermission.READ_ONLY); 288 } 289 290 291 public WorkflowDestinationPartyType getWorkflowDestinationPartyTypeByNameForUpdate(final ExecutionErrorAccumulator eea, final String workflowName, 292 final String workflowStepName, final String workflowDestinationName, final String partyTypeName) { 293 return getWorkflowDestinationPartyTypeByName(eea, workflowName, workflowStepName, workflowDestinationName, partyTypeName, 294 EntityPermission.READ_WRITE); 295 } 296 297 public WorkflowDestinationSecurityRole getWorkflowDestinationSecurityRoleByName(final ExecutionErrorAccumulator eea, final String workflowName, 298 final String workflowStepName, final String workflowDestinationName, final String partyTypeName, final String securityRoleName, 299 final EntityPermission entityPermission) { 300 var workflowDestination = getWorkflowDestinationByName(eea, workflowName, workflowStepName, workflowDestinationName); 301 var partyType = partyLogic.getPartyTypeByName(eea, partyTypeName); 302 WorkflowDestinationSecurityRole workflowDestinationSecurityRole = null; 303 304 if(eea == null || !eea.hasExecutionErrors()) { 305 var securityRoleGroup = workflowDestination.getLastDetail().getWorkflowStep().getLastDetail().getWorkflow().getLastDetail().getSecurityRoleGroup(); 306 307 if(securityRoleGroup != null) { 308 var securityRole = securityRoleLogic.getSecurityRoleByName(eea, securityRoleGroup, securityRoleName); 309 310 if(eea == null || !eea.hasExecutionErrors()) { 311 var workflowDestinationPartyType = getWorkflowDestinationPartyType(eea, workflowDestination, partyType); 312 313 if(eea == null || !eea.hasExecutionErrors()) { 314 workflowDestinationSecurityRole = workflowControl.getWorkflowDestinationSecurityRole(workflowDestinationPartyType, 315 securityRole, entityPermission); 316 317 if(workflowDestinationSecurityRole == null) { 318 var workflowDestinationDetail = workflowDestination.getLastDetail(); 319 var workflowStepDetail = workflowDestinationDetail.getWorkflowStep().getLastDetail(); 320 var securityRoleDetail = securityRole.getLastDetail(); 321 322 handleExecutionError(UnknownWorkflowDestinationSecurityRoleException.class, eea, ExecutionErrors.UnknownWorkflowDestinationSecurityRole.name(), 323 workflowStepDetail.getWorkflow().getLastDetail().getWorkflowName(), 324 workflowStepDetail.getWorkflowStepName(), workflowDestinationDetail.getWorkflowDestinationName(), 325 partyType.getPartyTypeName(), securityRoleDetail.getSecurityRole().getLastDetail().getSecurityRoleName()); 326 } 327 } 328 } 329 } else { 330 var workflowStepDetail = workflowDestination.getLastDetail().getWorkflowStep().getLastDetail(); 331 332 handleExecutionError(WorkflowMissingSecurityRoleGroupException.class, eea, ExecutionErrors.WorkflowMissingSecurityRoleGroup.name(), 333 workflowStepDetail.getWorkflow().getLastDetail().getWorkflowName()); 334 } 335 } 336 337 return workflowDestinationSecurityRole; 338 } 339 340 public WorkflowDestinationSecurityRole getWorkflowDestinationSecurityRoleByName(final ExecutionErrorAccumulator eea, final String workflowName, 341 final String workflowStepName, final String workflowDestinationName, final String partyTypeName, final String securityRoleName) { 342 return getWorkflowDestinationSecurityRoleByName(eea, workflowName, workflowStepName, workflowDestinationName, partyTypeName, 343 securityRoleName, EntityPermission.READ_ONLY); 344 } 345 346 347 public WorkflowDestinationSecurityRole getWorkflowDestinationSecurityRoleByNameForUpdate(final ExecutionErrorAccumulator eea, final String workflowName, 348 final String workflowStepName, final String workflowDestinationName, final String partyTypeName, final String securityRoleName) { 349 return getWorkflowDestinationSecurityRoleByName(eea, workflowName, workflowStepName, workflowDestinationName, partyTypeName, 350 securityRoleName, EntityPermission.READ_WRITE); 351 } 352 353 public WorkflowDestinationSelector getWorkflowDestinationSelectorByName(final ExecutionErrorAccumulator eea, final String workflowName, 354 final String workflowStepName, final String workflowDestinationName, final String selectorName, 355 final EntityPermission entityPermission) { 356 var workflowDestination = getWorkflowDestinationByName(eea, workflowName, workflowStepName, workflowDestinationName); 357 WorkflowDestinationSelector workflowDestinationSelector = null; 358 359 if(eea == null || !eea.hasExecutionErrors()) { 360 var selectorType = workflowDestination.getLastDetail().getWorkflowStep().getLastDetail().getWorkflow().getLastDetail().getSelectorType(); 361 362 if(selectorType != null) { 363 var selector = selectorLogic.getSelectorByName(eea, selectorType, selectorName); 364 365 if(eea == null || !eea.hasExecutionErrors()) { 366 workflowDestinationSelector = workflowControl.getWorkflowDestinationSelector(workflowDestination, 367 selector, entityPermission); 368 369 if(workflowDestinationSelector == null) { 370 var workflowDestinationDetail = workflowDestination.getLastDetail(); 371 var workflowStepDetail = workflowDestinationDetail.getWorkflowStep().getLastDetail(); 372 var selectorDetail = selector.getLastDetail(); 373 374 handleExecutionError(UnknownWorkflowDestinationSelectorException.class, eea, ExecutionErrors.UnknownWorkflowDestinationSelector.name(), 375 workflowStepDetail.getWorkflow().getLastDetail().getWorkflowName(), 376 workflowStepDetail.getWorkflowStepName(), workflowDestinationDetail.getWorkflowDestinationName(), 377 selectorDetail.getSelector().getLastDetail().getSelectorName()); 378 } 379 } 380 } else { 381 var workflowStepDetail = workflowDestination.getLastDetail().getWorkflowStep().getLastDetail(); 382 383 handleExecutionError(WorkflowMissingSelectorTypeException.class, eea, ExecutionErrors.WorkflowMissingSelectorType.name(), 384 workflowStepDetail.getWorkflow().getLastDetail().getWorkflowName()); 385 } 386 } 387 388 return workflowDestinationSelector; 389 } 390 391 public WorkflowDestinationSelector getWorkflowDestinationSelectorByName(final ExecutionErrorAccumulator eea, final String workflowName, 392 final String workflowStepName, final String workflowDestinationName, final String selectorName) { 393 return getWorkflowDestinationSelectorByName(eea, workflowName, workflowStepName, workflowDestinationName, selectorName, 394 EntityPermission.READ_ONLY); 395 } 396 397 398 public WorkflowDestinationSelector getWorkflowDestinationSelectorByNameForUpdate(final ExecutionErrorAccumulator eea, final String workflowName, 399 final String workflowStepName, final String workflowDestinationName, final String selectorName) { 400 return getWorkflowDestinationSelectorByName(eea, workflowName, workflowStepName, workflowDestinationName, selectorName, 401 EntityPermission.READ_WRITE); 402 } 403 404 public WorkflowStep getDestinationWorkflowStep(final ExecutionErrorAccumulator eea, final String destinationWorkflowName, 405 final String destinationWorkflowStepName) { 406 return workflowStepLogic.getWorkflowStepByName( 407 UnknownDestinationWorkflowNameException.class, ExecutionErrors.UnknownDestinationWorkflowName, 408 UnknownDestinationWorkflowStepNameException.class, ExecutionErrors.UnknownDestinationWorkflowStepName, 409 eea, destinationWorkflowName, destinationWorkflowStepName); 410 } 411 412 public WorkflowDestinationStep getWorkflowDestinationStep(final ExecutionErrorAccumulator eea, 413 WorkflowDestination workflowDestination, WorkflowStep destinationWorkflowStep) { 414 var workflowDestinationStep = workflowControl.getWorkflowDestinationStep(workflowDestination, destinationWorkflowStep); 415 416 if(workflowDestinationStep == null) { 417 var workflowDestinationDetail = workflowDestination.getLastDetail(); 418 var destinationWorkflowStepDetail = destinationWorkflowStep.getLastDetail(); 419 420 handleExecutionError(UnknownWorkflowDestinationStepException.class, eea, ExecutionErrors.UnknownWorkflowDestinationStep.name(), 421 workflowDestinationDetail.getWorkflowStep().getLastDetail().getWorkflow().getLastDetail().getWorkflowName(), 422 workflowDestinationDetail.getWorkflowStep().getLastDetail().getWorkflowStepName(), 423 workflowDestinationDetail.getWorkflowDestinationName(), 424 destinationWorkflowStepDetail.getWorkflow().getLastDetail().getWorkflowName(), 425 destinationWorkflowStepDetail.getWorkflowStepName()); 426 } 427 428 return workflowDestinationStep; 429 } 430 431 public WorkflowDestinationStep getWorkflowDestinationStepByName(final ExecutionErrorAccumulator eea, 432 final String workflowName, final String workflowStepName, final String workflowDestinationName, 433 final String destinationWorkflowName, final String destinationWorkflowStepName) { 434 var workflowDestination = getWorkflowDestinationByName(eea, workflowName, workflowStepName, workflowDestinationName); 435 var destinationWorkflowStep = getDestinationWorkflowStep(eea, destinationWorkflowName, destinationWorkflowStepName); 436 WorkflowDestinationStep workflowDestinationStep = null; 437 438 if(eea == null || !eea.hasExecutionErrors()) { 439 workflowDestinationStep = getWorkflowDestinationStep(eea, workflowDestination, destinationWorkflowStep); 440 } 441 442 return workflowDestinationStep; 443 } 444 445}