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.WorkflowStepUniversalSpec; 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.control.EntityInstanceControl; 024import com.echothree.model.control.core.server.logic.EntityInstanceLogic; 025import com.echothree.model.control.workflow.common.exception.MissingRequiredWorkflowNameException; 026import com.echothree.model.control.workflow.common.exception.UnknownDefaultWorkflowStepException; 027import com.echothree.model.control.workflow.common.exception.UnknownWorkflowStepNameException; 028import com.echothree.model.control.workflow.server.control.WorkflowControl; 029import com.echothree.model.data.core.server.entity.EntityInstance; 030import com.echothree.model.data.workflow.server.entity.Workflow; 031import com.echothree.model.data.workflow.server.entity.WorkflowEntityStatus; 032import com.echothree.model.data.workflow.server.entity.WorkflowStep; 033import com.echothree.util.common.exception.BaseException; 034import com.echothree.util.common.message.ExecutionErrors; 035import com.echothree.util.common.persistence.BasePK; 036import com.echothree.util.server.control.BaseLogic; 037import com.echothree.util.server.message.ExecutionErrorAccumulator; 038import com.echothree.util.server.persistence.BaseEntity; 039import com.echothree.util.server.persistence.EntityPermission; 040import com.echothree.util.server.validation.ParameterUtils; 041import java.util.Arrays; 042import java.util.HashSet; 043import java.util.Set; 044import javax.enterprise.context.ApplicationScoped; 045import javax.enterprise.inject.spi.CDI; 046import javax.inject.Inject; 047 048@ApplicationScoped 049public class WorkflowStepLogic 050 extends BaseLogic { 051 052 @Inject 053 EntityInstanceControl entityInstanceControl; 054 055 @Inject 056 WorkflowControl workflowControl; 057 058 @Inject 059 EntityInstanceLogic entityInstanceLogic; 060 061 @Inject 062 WorkflowLogic workflowLogic; 063 064 protected WorkflowStepLogic() { 065 super(); 066 } 067 068 public static WorkflowStepLogic getInstance() { 069 return CDI.current().select(WorkflowStepLogic.class).get(); 070 } 071 072 public WorkflowStep getWorkflowStepByName(final Class<? extends BaseException> unknownWorkflowException, final ExecutionErrors unknownWorkflowExecutionError, 073 final Class<? extends BaseException> unknownWorkflowStepException, final ExecutionErrors unknownWorkflowStepExecutionError, 074 final ExecutionErrorAccumulator eea, final String workflowName, final String workflowStepName) { 075 var workflow = workflowLogic.getWorkflowByName(unknownWorkflowException, unknownWorkflowExecutionError, 076 eea, workflowName, EntityPermission.READ_ONLY); 077 WorkflowStep workflowStep = null; 078 079 if(eea == null || !eea.hasExecutionErrors()) { 080 workflowStep = getWorkflowStepByName(unknownWorkflowStepException, unknownWorkflowStepExecutionError, eea, 081 workflow, workflowStepName); 082 } 083 084 return workflowStep; 085 } 086 087 public WorkflowStep getWorkflowStepByName(final Class<? extends BaseException> unknownException, final ExecutionErrors unknownExecutionError, 088 final ExecutionErrorAccumulator eea, final Workflow workflow, final String workflowStepName, EntityPermission entityPermission) { 089 var workflowStep = workflowControl.getWorkflowStepByName(workflow, workflowStepName, entityPermission); 090 091 if(workflowStep == null) { 092 handleExecutionError(unknownException, eea, unknownExecutionError.name(), workflow.getLastDetail().getWorkflowName(), 093 workflowStepName); 094 } 095 096 return workflowStep; 097 } 098 099 public WorkflowStep getWorkflowStepByName(final Class<? extends BaseException> unknownException, final ExecutionErrors unknownExecutionError, 100 final ExecutionErrorAccumulator eea, final Workflow workflow, final String workflowStepName) { 101 return getWorkflowStepByName(unknownException, unknownExecutionError, eea, workflow, workflowStepName, EntityPermission.READ_ONLY); 102 } 103 104 public WorkflowStep getWorkflowStepByNameForUpdate(final Class<? extends BaseException> unknownException, final ExecutionErrors unknownExecutionError, 105 final ExecutionErrorAccumulator eea, final Workflow workflow, final String workflowStepName) { 106 return getWorkflowStepByName(unknownException, unknownExecutionError, eea, workflow, workflowStepName, EntityPermission.READ_WRITE); 107 } 108 109 public WorkflowStep getWorkflowStepByName(final ExecutionErrorAccumulator eea, final Workflow workflow, final String workflowStepName, 110 final EntityPermission entityPermission) { 111 return getWorkflowStepByName(UnknownWorkflowStepNameException.class, ExecutionErrors.UnknownWorkflowStepName, 112 eea, workflow, workflowStepName, entityPermission); 113 } 114 115 public WorkflowStep getWorkflowStepByName(final ExecutionErrorAccumulator eea, final Workflow workflow, final String workflowStepName) { 116 return getWorkflowStepByName(UnknownWorkflowStepNameException.class, ExecutionErrors.UnknownWorkflowStepName, 117 eea, workflow, workflowStepName); 118 } 119 120 public WorkflowStep getWorkflowStepByNameForUpdate(final ExecutionErrorAccumulator eea, final Workflow workflow, final String workflowStepName) { 121 return getWorkflowStepByNameForUpdate(UnknownWorkflowStepNameException.class, ExecutionErrors.UnknownWorkflowStepName, 122 eea, workflow, workflowStepName); 123 } 124 125 public WorkflowStep getWorkflowStepByName(final ExecutionErrorAccumulator eea, final String workflowName, final String workflowStepName, 126 final EntityPermission entityPermission) { 127 var workflow = workflowLogic.getWorkflowByName(eea, workflowName); 128 WorkflowStep workflowStep = null; 129 130 if(eea == null || !eea.hasExecutionErrors()) { 131 workflowStep = getWorkflowStepByName(UnknownWorkflowStepNameException.class, ExecutionErrors.UnknownWorkflowStepName, 132 eea, workflow, workflowStepName, entityPermission); 133 } 134 135 return workflowStep; 136 } 137 138 public WorkflowStep getWorkflowStepByName(final ExecutionErrorAccumulator eea, final String workflowName, final String workflowStepName) { 139 return getWorkflowStepByName(eea, workflowName, workflowStepName, EntityPermission.READ_ONLY); 140 } 141 142 public WorkflowStep getWorkflowStepByNameForUpdate(final ExecutionErrorAccumulator eea, final String workflowName, final String workflowStepName) { 143 return getWorkflowStepByName(eea, workflowName, workflowStepName, EntityPermission.READ_WRITE); 144 } 145 146 public WorkflowStep getWorkflowStepByUniversalSpec(final ExecutionErrorAccumulator eea, final WorkflowStepUniversalSpec universalSpec, 147 final boolean allowDefault, final EntityPermission entityPermission) { 148 var workflowName = universalSpec.getWorkflowName(); 149 var workflowStepName = universalSpec.getWorkflowStepName(); 150 var nameParameterCount= ParameterUtils.getInstance().countNonNullParameters(workflowName, workflowStepName); 151 var possibleEntitySpecs= entityInstanceLogic.countPossibleEntitySpecs(universalSpec); 152 WorkflowStep workflowStep = null; 153 154 if(nameParameterCount < 3 && possibleEntitySpecs == 0) { 155 Workflow workflow = null; 156 157 if(workflowName != null) { 158 workflow = workflowLogic.getWorkflowByName(eea, workflowName); 159 } else { 160 handleExecutionError(MissingRequiredWorkflowNameException.class, eea, ExecutionErrors.MissingRequiredWorkflowName.name()); 161 } 162 163 if(eea == null || !eea.hasExecutionErrors()) { 164 if(workflowStepName == null) { 165 if(allowDefault) { 166 workflowStep = workflowControl.getDefaultWorkflowStep(workflow, entityPermission); 167 168 if(workflowStep == null) { 169 handleExecutionError(UnknownDefaultWorkflowStepException.class, eea, ExecutionErrors.UnknownDefaultWorkflowStep.name()); 170 } 171 } else { 172 handleExecutionError(InvalidParameterCountException.class, eea, ExecutionErrors.InvalidParameterCount.name()); 173 } 174 } else { 175 workflowStep = getWorkflowStepByName(eea, workflow, workflowStepName, entityPermission); 176 } 177 } 178 } else if(nameParameterCount == 0 && possibleEntitySpecs == 1) { 179 var entityInstance = entityInstanceLogic.getEntityInstance(eea, universalSpec, 180 ComponentVendors.ECHO_THREE.name(), EntityTypes.WorkflowStep.name()); 181 182 if(eea == null || !eea.hasExecutionErrors()) { 183 workflowStep = workflowControl.getWorkflowStepByEntityInstance(entityInstance, entityPermission); 184 } 185 } else { 186 handleExecutionError(InvalidParameterCountException.class, eea, ExecutionErrors.InvalidParameterCount.name()); 187 } 188 189 return workflowStep; 190 } 191 192 public WorkflowStep getWorkflowStepByUniversalSpec(final ExecutionErrorAccumulator eea, final WorkflowStepUniversalSpec universalSpec, 193 boolean allowDefault) { 194 return getWorkflowStepByUniversalSpec(eea, universalSpec, allowDefault, EntityPermission.READ_ONLY); 195 } 196 197 public WorkflowStep getWorkflowStepByUniversalSpecForUpdate(final ExecutionErrorAccumulator eea, final WorkflowStepUniversalSpec universalSpec, 198 boolean allowDefault) { 199 return getWorkflowStepByUniversalSpec(eea, universalSpec, allowDefault, EntityPermission.READ_WRITE); 200 } 201 202 public Set<WorkflowEntityStatus> isEntityInWorkflowSteps(final ExecutionErrorAccumulator eea, final String workflowName, final BaseEntity baseEntity, 203 String... workflowStepNames) { 204 return isEntityInWorkflowSteps(eea, workflowName, baseEntity, EntityPermission.READ_ONLY, workflowStepNames); 205 } 206 207 public Set<WorkflowEntityStatus> isEntityInWorkflowStepsForUpdate(final ExecutionErrorAccumulator eea, final String workflowName, final BaseEntity baseEntity, 208 String... workflowStepNames) { 209 return isEntityInWorkflowSteps(eea, workflowName, baseEntity, EntityPermission.READ_WRITE, workflowStepNames); 210 } 211 212 public Set<WorkflowEntityStatus> isEntityInWorkflowSteps(final ExecutionErrorAccumulator eea, final String workflowName, final BaseEntity baseEntity, 213 EntityPermission entityPermission, String... workflowStepNames) { 214 return isEntityInWorkflowSteps(eea, workflowName, baseEntity.getPrimaryKey(), entityPermission, workflowStepNames); 215 } 216 217 public Set<WorkflowEntityStatus> isEntityInWorkflowSteps(final ExecutionErrorAccumulator eea, final String workflowName, final BasePK pk, 218 String... workflowStepNames) { 219 return isEntityInWorkflowSteps(eea, workflowName, pk, EntityPermission.READ_ONLY, workflowStepNames); 220 } 221 222 public Set<WorkflowEntityStatus> isEntityInWorkflowStepsForUpdate(final ExecutionErrorAccumulator eea, final String workflowName, final BasePK pk, 223 String... workflowStepNames) { 224 return isEntityInWorkflowSteps(eea, workflowName, pk, EntityPermission.READ_WRITE, workflowStepNames); 225 } 226 227 public Set<WorkflowEntityStatus> isEntityInWorkflowSteps(final ExecutionErrorAccumulator eea, final String workflowName, final BasePK pk, 228 EntityPermission entityPermission, String... workflowStepNames) { 229 var entityInstance = entityInstanceControl.getEntityInstanceByBasePK(pk); 230 231 return isEntityInWorkflowSteps(eea, workflowName, entityInstance, entityPermission, workflowStepNames); 232 } 233 234 public Set<WorkflowEntityStatus> isEntityInWorkflowSteps(final ExecutionErrorAccumulator eea, final String workflowName, final EntityInstance entityInstance, 235 final String... workflowStepNames) { 236 return isEntityInWorkflowSteps(eea, workflowName, entityInstance, EntityPermission.READ_ONLY, workflowStepNames); 237 } 238 239 public Set<WorkflowEntityStatus> isEntityInWorkflowStepsForUpdate(final ExecutionErrorAccumulator eea, final String workflowName, final EntityInstance entityInstance, 240 final String... workflowStepNames) { 241 return isEntityInWorkflowSteps(eea, workflowName, entityInstance, EntityPermission.READ_WRITE, workflowStepNames); 242 } 243 244 private Set<WorkflowEntityStatus> isEntityInWorkflowSteps(final ExecutionErrorAccumulator eea, final String workflowName, final EntityInstance entityInstance, 245 final EntityPermission entityPermission, final String... workflowStepNames) { 246 var workflow = workflowLogic.getWorkflowByName(eea, workflowName); 247 Set<WorkflowEntityStatus> result = new HashSet<>(); 248 249 if(!hasExecutionErrors(eea)) { 250 var workflowEntityStatuses = workflowControl.getWorkflowEntityStatusesByEntityInstance(workflow, entityInstance, entityPermission); 251 Set<String> possibleWorkflowStepNames = new HashSet<>(workflowStepNames.length); 252 253 possibleWorkflowStepNames.addAll(Arrays.asList(workflowStepNames)); 254 255 workflowEntityStatuses.forEach((workflowEntityStatus) -> { 256 var workflowStepDetail = workflowEntityStatus.getWorkflowStep().getLastDetail(); 257 if (workflowStepDetail.getWorkflow().equals(workflow)) { 258 var workflowStepName = workflowStepDetail.getWorkflowStepName(); 259 if (possibleWorkflowStepNames.contains(workflowStepName)) { 260 result.add(workflowEntityStatus); 261 } 262 } 263 }); 264 265 } 266 267 return result; 268 } 269 270 public boolean isWorkflowStepInSet(Set<WorkflowEntityStatus> workflowEntityStatuses, String workflowStepName) { 271 var result = false; 272 273 for(var workflowEntityStatus : workflowEntityStatuses) { 274 if(result |= workflowEntityStatus.getWorkflowStep().getLastDetail().getWorkflowStepName().equals(workflowStepName)) { 275 break; 276 } 277 } 278 279 return result; 280 } 281 282}