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