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