package nebula.flow; import java.util.ArrayList; import java.util.List; import nebula.data.DataRepos; import nebula.data.DataStore; import nebula.data.Entity; import nebula.data.impl.EditableEntity; import nebula.lang.Field; import nebula.lang.Flow; import nebula.lang.Flow.Step; import nebula.lang.NebulaNative; import nebula.lang.RuntimeContext; import com.google.common.base.Preconditions; public class FlowEngine { final Flow flow; final DataRepos datarepos; final DataStore<Entity> datastore; public FlowEngine(DataRepos datarepos, final Flow flow) { this.datarepos = datarepos; this.flow = flow; this.datastore = datarepos.define(String.class, Entity.class, flow.getName()); } public EditableEntity start(final RuntimeContext context) { EditableEntity data = new EditableEntity(); data.put("ID", System.currentTimeMillis()); data.put("steps", new ArrayList<Entity>()); stepIn(context, flow.getSteps().get(Step.Begin), data); return data; } private void stepIn(final RuntimeContext context, Step step, EditableEntity data) { Step currentStep = step; EditableEntity currentStepEntity = new EditableEntity(); // copy data from flow for (Field f : currentStep.getType().getDeclaredFields()) { if (!f.isInternal()) currentStepEntity.put(f.getName(), data.get(f.getName())); } NebulaNative.ctor(context, datarepos, currentStepEntity, step.getType()); currentStepEntity.put(Step.Field_ActualCurrrentStep, currentStep.getName()); data.put("curStep", currentStep.getDisplayName()); Field action = step.getType().getActionByName(Step.Init); Preconditions.checkNotNull(action); action.getActionAsm().exec(context, datarepos, currentStepEntity); if ((Boolean) currentStepEntity.get(Step.Field_DoItNow) != null && (Boolean) currentStepEntity.get(Step.Field_DoItNow)) { String next = (String) currentStepEntity.get(Step.Field_NextStep); Step nextStep = null; if (Step.Next.equals(next)) { nextStep = flow.getSteps().get(currentStep.getIndex() + 1); } else if (Step.Previous.equals(next)) { nextStep = flow.getSteps().get(currentStep.getIndex() - 1); } else { nextStep = flow.getSteps().get(next); } currentStepEntity.put(Step.Field_ActualNextStep, nextStep.getName()); addStepEntity(data, currentStepEntity); stepIn(context, nextStep, data); return; } else { addStepEntity(data, currentStepEntity); } } @SuppressWarnings("unchecked") private void addStepEntity(EditableEntity data, Entity currentStepEntity) { ((List<Entity>) data.get("steps")).add(currentStepEntity); } public void stepSubmit(final RuntimeContext context, String actionName, EditableEntity data) { List<Entity> steps = data.get("steps"); Entity currentStepEntity = steps.get(steps.size() - 1); Step currentStep = flow.getSteps().get((String) currentStepEntity.get(Step.Field_ActualCurrrentStep)); // copy data to flow for (Field f : currentStep.getType().getDeclaredFields()) { if (!f.isInternal()) data.put(f.getName(), currentStepEntity.get(f.getName())); } Field action = currentStep.getType().getActionByName(actionName); Preconditions.checkNotNull(action); action.getActionAsm().exec(context, datarepos, currentStepEntity); if ((Boolean) currentStepEntity.get(Step.Field_DoItNow) != null && (Boolean) currentStepEntity.get(Step.Field_DoItNow)) { String next = (String) currentStepEntity.get(Step.Field_NextStep); Step nextStep = null; if (Step.Next.equals(next)) { nextStep = flow.getSteps().get(currentStep.getIndex() + 1); } else { nextStep = flow.getSteps().get(next); } currentStepEntity.put(Step.Next, nextStep.getName()); stepIn(context, nextStep, data); } datastore.add(data); datastore.flush(); } public void stepSubmit(final RuntimeContext context, EditableEntity data) { stepSubmit(context, Step.Submit, data); } }