in flux/src/main/java/software/amazon/aws/clients/swf/flux/wf/graph/WorkflowGraphBuilder.java [442:534]
public WorkflowGraph build() {
WorkflowStep actualFirstStep = firstStep;
// if we have any pre-workflow hooks, insert the pre-workflow-hook anchor step and assign the workflow hooks to it.
List<WorkflowStepHook> preWorkflowHooks = workflowHooksByType.get(StepHook.HookType.PRE);
if (preWorkflowHooks != null && !preWorkflowHooks.isEmpty()) {
actualFirstStep = new PreWorkflowHookAnchor();
addStep(actualFirstStep);
alwaysTransition(actualFirstStep, firstStep);
addStepHooks(PreWorkflowHookAnchor.class, preWorkflowHooks);
}
// verify that all of the steps in stepImpls have behavior defined in the steps map
if (!steps.keySet().containsAll(stepImpls.keySet())) {
Set<Class<? extends WorkflowStep>> diff = new HashSet<>(stepImpls.keySet());
diff.removeAll(steps.keySet());
Set<String> names = diff.stream().map(Class::getSimpleName).collect(Collectors.toSet());
throw new WorkflowGraphBuildException("Found one or more steps with undefined behavior: " + String.join(", ", names));
}
// if we have any post-workflow hooks, add the post-workflow-hook anchor step and assign the workflow hooks to it.
// we will add transitions to it below when we encounter CloseWorkflow transitions.
List<WorkflowStepHook> postWorkflowHooks = workflowHooksByType.get(StepHook.HookType.POST);
if (postWorkflowHooks != null && !postWorkflowHooks.isEmpty()) {
addStep(new PostWorkflowHookAnchor());
addStepHooks(PostWorkflowHookAnchor.class, postWorkflowHooks);
// we'll force all of the CloseWorkflow transitions to PostWorkflowHookAnchor instead
for (Class<? extends WorkflowStep> step : steps.keySet()) {
for (String resultCode : steps.get(step).keySet()) {
if (steps.get(step).get(resultCode) == CloseWorkflow.class) {
steps.get(step).put(resultCode, PostWorkflowHookAnchor.class);
}
}
}
// finally we'll add in the transition from the anchor to CloseWorkflow.
alwaysTransition(PostWorkflowHookAnchor.class, CloseWorkflow.class);
}
Map<Class<? extends WorkflowStep>, WorkflowGraphNode> nodes = new HashMap<>();
for (Entry<Class<? extends WorkflowStep>, WorkflowStep> entry : stepImpls.entrySet()) {
nodes.put(entry.getKey(), new WorkflowGraphNodeImpl(entry.getValue()));
}
Set<Class<? extends WorkflowStep>> reachable = new HashSet<>();
reachable.add(actualFirstStep.getClass()); // the first step is always reachable
for (Class<? extends WorkflowStep> step : steps.keySet()) {
WorkflowGraphNode node = nodes.get(step);
// now look up the nodes for each of the transitions defined for this step,
// and add a transition entry for it to this step's node
for (String resultCode : steps.get(step).keySet()) {
Class<? extends WorkflowStep> nextStep = steps.get(step).get(resultCode);
if (CloseWorkflow.class.isAssignableFrom(nextStep)) {
// if the transition is to CloseWorkflow, we put a null transition in so we end the workflow
node.addTransition(resultCode, null);
} else if (!nodes.containsKey(nextStep)) {
throw new WorkflowGraphBuildException("A transition to step " + nextStep.getSimpleName()
+ " was defined from " + step.getSimpleName()
+ " but no behavior was specified for " + nextStep.getSimpleName());
} else {
WorkflowGraphNode nextNode = nodes.get(nextStep);
node.addTransition(resultCode, nextNode);
reachable.add(nextNode.getStep().getClass());
}
}
}
// verify that there are no unreachable nodes in the graph
if (!reachable.containsAll(steps.keySet())) {
Set<Class<? extends WorkflowStep>> diff = new HashSet<>(steps.keySet());
diff.removeAll(reachable);
Set<String> names = diff.stream().map(Class::getSimpleName).collect(Collectors.toSet());
throw new WorkflowGraphBuildException("Found one or more unreachable steps: " + String.join(", ", names));
}
verifyNoLoops(actualFirstStep.getClass(), nodes, new HashSet<>());
// now we'll loop through hooksForAllSteps and add each entry to every step
if (!hooksForAllSteps.isEmpty()) {
for (Class<? extends WorkflowStep> step : steps.keySet()) {
addStepHooks(step, hooksForAllSteps);
}
}
if (shouldValidateAttributeAvailability) {
validateAttributeAvailability(actualFirstStep, nodes, initialAttributes, stepHooks);
}
return new WorkflowGraphImpl(actualFirstStep, nodes, stepHooks);
}