All Downloads are FREE. Search and download functionalities are using the official Maven repository.

optimajet.workflow.ravendb.RavenDbProvider Maven / Gradle / Ivy

The newest version!
package optimajet.workflow.ravendb;

import com.fasterxml.jackson.core.type.TypeReference;
import com.mysema.query.types.expr.BooleanExpression;
import lombok.Getter;
import net.ravendb.client.IDocumentSession;
import net.ravendb.client.document.DocumentQueryCustomizationFactory;
import net.ravendb.client.document.DocumentStore;
import optimajet.workflow.core.DefiningParametersSerializer;
import optimajet.workflow.core.HashHelper;
import optimajet.workflow.core.fault.*;
import optimajet.workflow.core.model.*;
import optimajet.workflow.core.persistence.ErrorLevel;
import optimajet.workflow.core.persistence.ProcessStatus;
import optimajet.workflow.core.provider.WorkflowDocumentProvider;
import optimajet.workflow.core.runtime.ParametersSerializer;
import optimajet.workflow.core.runtime.ProcessHistoryItem;
import optimajet.workflow.core.runtime.TimerToExecute;
import optimajet.workflow.core.runtime.WorkflowRuntime;
import optimajet.workflow.core.util.CollectionUtil;
import optimajet.workflow.core.util.DocumentUtil;
import optimajet.workflow.core.util.JsonConvert;
import optimajet.workflow.core.util.StringUtil;
import org.w3c.dom.Document;

import java.util.*;

import static optimajet.workflow.core.util.CollectionUtil.select;
import static optimajet.workflow.core.util.CollectionUtil.singleOrDefault;

public class RavenDbProvider implements WorkflowDocumentProvider {

    @Getter
    private final DocumentStore documentStore;
    private WorkflowRuntime runtime;

    /**
     * Constructor
     *
     * @param documentStore DocumentStore object
     */
    public RavenDbProvider(DocumentStore documentStore) {
        this.documentStore = documentStore;
        this.documentStore.initialize();
    }

    @Override
    public void init(WorkflowRuntime runtime) {
        this.runtime = runtime;
    }

    @Override
    public void initializeProcess(ProcessInstance processInstance) {
        try (IDocumentSession session = documentStore.openSession()) {
            WorkflowProcessInstance oldProcess = session.load(WorkflowProcessInstance.class, processInstance.getProcessId());
            if (oldProcess != null) {
                throw new ProcessAlreadyExistsException(processInstance.getProcessId());
            }
            WorkflowProcessInstance newProcess = new WorkflowProcessInstance();
            newProcess.setId(processInstance.getProcessId());
            newProcess.setSchemeId(processInstance.getSchemeId());
            newProcess.setActivityName(processInstance.getProcessScheme().getInitialActivity().getName());
            newProcess.setStateName(processInstance.getProcessScheme().getInitialActivity().getState());
            newProcess.setRootProcessId(processInstance.getRootProcessId());
            newProcess.setParentProcessId(processInstance.getParentProcessId());
            newProcess.setPersistence(new ArrayList());
            session.store(newProcess);
            session.saveChanges();
        }
    }

    @Override
    public void bindProcessToNewScheme(ProcessInstance processInstance) throws ProcessNotFoundException {
        bindProcessToNewScheme(processInstance, false);
    }

    @Override
    public void bindProcessToNewScheme(ProcessInstance processInstance, boolean resetIsDeterminingParametersChanged) throws ProcessNotFoundException {
        try (IDocumentSession session = documentStore.openSession()) {
            WorkflowProcessInstance oldProcess = session.load(WorkflowProcessInstance.class, processInstance.getProcessId());
            if (oldProcess == null) {
                throw new ProcessNotFoundException(processInstance.getProcessId());
            }

            oldProcess.setSchemeId(processInstance.getSchemeId());
            if (resetIsDeterminingParametersChanged) {
                oldProcess.setDeterminingParametersChanged(false);
            }
            session.saveChanges();
        }
    }

    @Override
    public void fillProcessParameters(ProcessInstance processInstance) {
        processInstance.addParameters(getProcessParameters(processInstance.getProcessId(), processInstance.getProcessScheme()));
    }

    @Override
    public void fillPersistedProcessParameters(ProcessInstance processInstance) {
        processInstance.addParameters(getPersistedProcessParameters(processInstance.getProcessId(), processInstance.getProcessScheme()));
    }

    @Override
    public void fillSystemProcessParameters(ProcessInstance processInstance) {
        processInstance.addParameters(getSystemProcessParameters(processInstance.getProcessId(), processInstance.getProcessScheme()));
    }

    @Override
    public void savePersistenceParameters(ProcessInstance processInstance) {
        List parametersToPersistList = new ArrayList<>();
        for (ParameterDefinitionWithValue ptp : processInstance.getProcessParameters()) {
            if (ptp.getPurpose() == ParameterPurpose.Persistence) {
                ParameterDefinitionWithValue parameterDefinitionWithValue = new ParameterDefinitionWithValue();
                parameterDefinitionWithValue.setParameterDefinition(ptp);
                if (ptp.getType().equals(UnknownParameterType.class)) {
                    parameterDefinitionWithValue.setValue(ptp.getValue());
                } else {
                    parameterDefinitionWithValue.setValue(ParametersSerializer.serialize(ptp.getValue()));
                }
                parametersToPersistList.add(parameterDefinitionWithValue);
            }
        }

        try (IDocumentSession session = documentStore.openSession()) {
            WorkflowProcessInstance process = session.load(WorkflowProcessInstance.class, processInstance.getProcessId());
            if (process != null && process.getPersistence() != null) {
                List persistedParameters = process.getPersistence();
                for (final ParameterDefinitionWithValue parameterDefinitionWithValue : parametersToPersistList) {
                    WorkflowProcessInstancePersistence persistence = singleOrDefault(persistedParameters,
                            new CollectionUtil.ItemCondition() {
                                @Override
                                public boolean check(WorkflowProcessInstancePersistence pp) {
                                    return pp.getParameterName().equals(parameterDefinitionWithValue.getName());
                                }
                            });

                    if (persistence == null) {
                        if (parameterDefinitionWithValue.getValue() instanceof String) {
                            persistence = new WorkflowProcessInstancePersistence();
                            persistence.setParameterName(parameterDefinitionWithValue.getName());
                            persistence.setValue((String) parameterDefinitionWithValue.getValue());
                            process.getPersistence().add(persistence);
                        }
                    } else {
                        if (parameterDefinitionWithValue.getValue() instanceof String) {
                            persistence.setValue((String) parameterDefinitionWithValue.getValue());
                        } else {
                            process.getPersistence().remove(persistence);
                        }
                    }
                }
                session.store(process);
                session.saveChanges();
            }
        }
    }

    @Override
    public void setWorkflowInitialized(ProcessInstance processInstance) {
        try (IDocumentSession session = documentStore.openSession()) {
            WorkflowProcessInstanceStatus instanceStatus = session.load(WorkflowProcessInstanceStatus.class, processInstance.getProcessId());
            if (instanceStatus == null) {
                instanceStatus = new WorkflowProcessInstanceStatus();
                instanceStatus.setId(processInstance.getProcessId());
                instanceStatus.setLock(UUID.randomUUID());
                instanceStatus.setStatus(ProcessStatus.Initialized.getId());

                session.store(instanceStatus);
            } else {
                instanceStatus.setStatus(ProcessStatus.Initialized.getId());
                session.store(instanceStatus);
            }
            session.saveChanges();
        }
    }

    @Override
    public void setWorkflowIdled(ProcessInstance processInstance) {
        setCustomStatus(processInstance.getProcessId(), ProcessStatus.Idled);
    }

    @Override
    public void setWorkflowRunning(ProcessInstance processInstance) {
        try (IDocumentSession session = documentStore.openSession()) {
            WorkflowProcessInstanceStatus instanceStatus = session.load(WorkflowProcessInstanceStatus.class, processInstance.getProcessId());

            if (instanceStatus == null) {
                throw new StatusNotDefinedException();
            }

            if (instanceStatus.getStatus() == ProcessStatus.Running.getId()) {
                throw new ImpossibleToSetStatusException();
            }

            instanceStatus.setLock(UUID.randomUUID());
            instanceStatus.setStatus(ProcessStatus.Running.getId());
            session.store(instanceStatus);
            session.saveChanges();
        }
    }

    @Override
    public void setWorkflowFinalized(ProcessInstance processInstance) {
        setCustomStatus(processInstance.getProcessId(), ProcessStatus.Finalized);
    }

    @Override
    public void setWorkflowTerminated(ProcessInstance processInstance, ErrorLevel level, String errorMessage) {
        setCustomStatus(processInstance.getProcessId(), ProcessStatus.Terminated);
    }

    @Override
    public void resetWorkflowRunning() {
        do {
            try (IDocumentSession session = documentStore.openSession()) {
                QWorkflowProcessInstanceStatus qwpis = QWorkflowProcessInstanceStatus.workflowProcessInstanceStatus;
                List instanceStatusList = session.query(WorkflowProcessInstanceStatus.class)
                        .customize(new DocumentQueryCustomizationFactory().waitForNonStaleResultsAsOfNow())
                        .where(qwpis.status.eq(ProcessStatus.Running.getId()))
                        .toList();

                if (instanceStatusList.isEmpty()) {
                    break;
                }

                for (WorkflowProcessInstanceStatus workflowProcessInstanceStatus : instanceStatusList) {
                    workflowProcessInstanceStatus.setStatus(ProcessStatus.Idled.getId());
                }

                session.saveChanges();
            }
        } while (true);
    }

    @Override
    public void updatePersistenceState(ProcessInstance processInstance, TransitionDefinition transition) {
        ParameterDefinitionWithValue paramIdentityId = processInstance.getParameter(DefaultDefinitions.PARAMETER_IDENTITY_ID);
        ParameterDefinitionWithValue paramImpIdentityId = processInstance.getParameter(DefaultDefinitions.PARAMETER_IMPERSONATED_IDENTITY_ID);

        String identityId = paramIdentityId == null ? StringUtil.EMPTY : (String) paramIdentityId.getValue();
        String impIdentityId = paramImpIdentityId == null ? identityId : (String) paramImpIdentityId.getValue();

        try (IDocumentSession session = documentStore.openSession()) {
            WorkflowProcessInstance instance = session.load(WorkflowProcessInstance.class, processInstance.getProcessId());

            if (instance != null) {
                if (!StringUtil.isNullOrEmpty(transition.getTo().getState())) {
                    instance.setStateName(transition.getTo().getState());
                }

                instance.setActivityName(transition.getTo().getName());
                instance.setPreviousActivity(transition.getFrom().getName());

                if (!StringUtil.isNullOrEmpty(transition.getFrom().getState())) {
                    instance.setPreviousState(transition.getFrom().getState());
                }

                if (transition.getClassifier() == TransitionClassifier.Direct) {
                    instance.setPreviousActivityForDirect(transition.getFrom().getName());

                    if (!StringUtil.isNullOrEmpty(transition.getFrom().getState())) {
                        instance.setPreviousStateForDirect(transition.getFrom().getState());
                    }
                } else if (transition.getClassifier() == TransitionClassifier.Reverse) {
                    instance.setPreviousActivityForReverse(transition.getFrom().getName());
                    if (!StringUtil.isNullOrEmpty(transition.getFrom().getState())) {
                        instance.setPreviousStateForReverse(transition.getFrom().getState());
                    }
                }

                instance.setParentProcessId(processInstance.getParentProcessId());
                instance.setRootProcessId(processInstance.getRootProcessId());
            }

            WorkflowProcessTransitionHistory history = new WorkflowProcessTransitionHistory();
            history.setActorIdentityId(impIdentityId);
            history.setExecutorIdentityId(identityId);
            history.setId(UUID.randomUUID());
            history.setFinalised(transition.getTo().isFinalActivity());
            history.setProcessId(processInstance.getProcessId());
            history.setFromActivityName(transition.getFrom().getName());
            history.setFromStateName(transition.getFrom().getState());
            history.setToActivityName(transition.getTo().getName());
            history.setToStateName(transition.getTo().getState());
            history.setTransitionClassifier(transition.getClassifier().toString());
            history.setTransitionTime(runtime.getRuntimeDateTimeNow());
            history.setTriggerName(StringUtil.isNullOrEmpty(processInstance.getExecutedTimer()) ? processInstance.getCurrentCommand() : processInstance.getExecutedTimer());

            session.store(history);
            session.saveChanges();
        }
    }

    @Override
    public boolean isProcessExists(UUID processId) {
        try (IDocumentSession session = documentStore.openSession()) {
            return session.load(WorkflowProcessInstance.class, processId) != null;
        }
    }

    @Override
    public ProcessStatus getInstanceStatus(UUID processId) {
        try (IDocumentSession session = documentStore.openSession()) {
            WorkflowProcessInstanceStatus instance = session.load(WorkflowProcessInstanceStatus.class, processId);
            if (instance == null) {
                return ProcessStatus.NotFound;
            }
            return ProcessStatus.getById(instance.getStatus());
        }
    }

    private void setCustomStatus(UUID processId, ProcessStatus status) {
        try (IDocumentSession session = documentStore.openSession()) {
            WorkflowProcessInstanceStatus instanceStatus = session.load(WorkflowProcessInstanceStatus.class, processId);
            if (instanceStatus == null) {
                throw new StatusNotDefinedException();
            }
            instanceStatus.setStatus(status.getId());

            session.store(instanceStatus);
            session.saveChanges();
        }
    }

    private Collection getProcessParameters(UUID processId, ProcessDefinition processDefinition) {
        List parameters = new ArrayList<>(processDefinition.getParameters().size());
        parameters.addAll(getPersistedProcessParameters(processId, processDefinition));
        parameters.addAll(getSystemProcessParameters(processId, processDefinition));
        return parameters;
    }

    private Collection getSystemProcessParameters(UUID processId,
                                                                                ProcessDefinition processDefinition) {
        WorkflowProcessInstance processInstance = getProcessInstance(processId);

        Collection systemParameters = CollectionUtil.where(processDefinition.getParameters(),
                new CollectionUtil.ItemCondition() {
                    @Override
                    public boolean check(ParameterDefinition p) {
                        return p.getPurpose() == ParameterPurpose.System;
                    }
                });

        List parameters = new ArrayList<>(systemParameters.size());
        parameters.add(createSystemParameter(systemParameters, DefaultDefinitions.PARAMETER_PROCESS_ID, processId));
        parameters.add(createSystemParameter(systemParameters, DefaultDefinitions.PARAMETER_PREVIOUS_STATE, processInstance.getPreviousState()));
        parameters.add(createSystemParameter(systemParameters, DefaultDefinitions.PARAMETER_CURRENT_STATE, processInstance.getStateName()));
        parameters.add(createSystemParameter(systemParameters, DefaultDefinitions.PARAMETER_PREVIOUS_STATE_FOR_DIRECT, processInstance.getPreviousStateForDirect()));
        parameters.add(createSystemParameter(systemParameters, DefaultDefinitions.PARAMETER_PREVIOUS_STATE_FOR_REVERSE, processInstance.getPreviousStateForReverse()));
        parameters.add(createSystemParameter(systemParameters, DefaultDefinitions.PARAMETER_PREVIOUS_ACTIVITY, processInstance.getPreviousActivity()));
        parameters.add(createSystemParameter(systemParameters, DefaultDefinitions.PARAMETER_CURRENT_ACTIVITY, processInstance.getActivityName()));
        parameters.add(createSystemParameter(systemParameters, DefaultDefinitions.PARAMETER_PREVIOUS_ACTIVITY_FOR_DIRECT, processInstance.getPreviousActivityForDirect()));
        parameters.add(createSystemParameter(systemParameters, DefaultDefinitions.PARAMETER_PREVIOUS_ACTIVITY_FOR_REVERSE, processInstance.getPreviousActivityForReverse()));
        parameters.add(createSystemParameter(systemParameters, DefaultDefinitions.PARAMETER_SCHEME_CODE, processDefinition.getName()));
        parameters.add(createSystemParameter(systemParameters, DefaultDefinitions.PARAMETER_SCHEME_ID, processInstance.getSchemeId()));
        parameters.add(createSystemParameter(systemParameters, DefaultDefinitions.PARAMETER_IS_PRE_EXECUTION, Boolean.FALSE));
        parameters.add(createSystemParameter(systemParameters, DefaultDefinitions.PARAMETER_PARENT_PROCESS_ID, processInstance.getParentProcessId()));
        parameters.add(createSystemParameter(systemParameters, DefaultDefinitions.PARAMETER_ROOT_PROCESS_ID, processInstance.getRootProcessId()));

        return parameters;
    }

    private ParameterDefinitionWithValue createSystemParameter(Collection systemParameters,
                                                               final ParameterDefinition definition,
                                                               Object value) {
        ParameterDefinition parameterDefinition = CollectionUtil.single(systemParameters,
                new CollectionUtil.ItemCondition() {
                    @Override
                    public boolean check(ParameterDefinition sp) {
                        return sp.getName().equals(definition.getName());
                    }
                });
        return ParameterDefinitionWithValue.create(parameterDefinition, value);
    }

    private Collection getPersistedProcessParameters(UUID processId, ProcessDefinition processDefinition) {
        Collection persistenceParameters = processDefinition.getPersistenceParameters();
        List parameters = new ArrayList<>();

        Collection persistedParameters;

        try (IDocumentSession session = documentStore.openSession()) {
            WorkflowProcessInstance process = session.load(WorkflowProcessInstance.class, processId);
            if (process != null && process.getPersistence() != null) {
                persistedParameters = process.getPersistence();
            } else {
                return parameters;
            }
        }

        for (final WorkflowProcessInstancePersistence persistedParameter : persistedParameters) {
            ParameterDefinition parameterDefinition = CollectionUtil.firstOrDefault(persistenceParameters,
                    new CollectionUtil.ItemCondition() {
                        @Override
                        public boolean check(ParameterDefinition p) {
                            return p.getName().equals(persistedParameter.getParameterName());
                        }
                    });
            if (parameterDefinition == null) {
                parameterDefinition = ParameterDefinition.create(persistedParameter.getParameterName(),
                        UnknownParameterType.class, ParameterPurpose.Persistence);
                parameters.add(ParameterDefinitionWithValue.create(parameterDefinition, persistedParameter.getValue()));
            } else {
                parameters.add(ParameterDefinitionWithValue.create(parameterDefinition,
                        ParametersSerializer.deserialize(persistedParameter.getValue(), parameterDefinition.getType())));
            }
        }

        return parameters;
    }

    private WorkflowProcessInstance getProcessInstance(UUID processId) throws ProcessNotFoundException {
        try (IDocumentSession session = documentStore.openSession()) {
            WorkflowProcessInstance processInstance = session.load(WorkflowProcessInstance.class, processId);
            if (processInstance == null) {
                throw new ProcessNotFoundException(processId);
            }
            return processInstance;
        }
    }

    @Override
    public void deleteProcess(UUID[] processIds) {
        for (UUID processId : processIds) {
            deleteProcess(processId);
        }
    }

    @Override
    public  void saveGlobalParameter(String type, String name, T value) {
        try (IDocumentSession session = documentStore.openSession()) {
            QWorkflowGlobalParameter qWorkflowGlobalParameter = QWorkflowGlobalParameter.workflowGlobalParameter;
            WorkflowGlobalParameter parameter = session.query(WorkflowGlobalParameter.class)
                    .customize(new DocumentQueryCustomizationFactory().waitForNonStaleResultsAsOfNow())
                    .where(qWorkflowGlobalParameter.type.eq(type).and(
                            qWorkflowGlobalParameter.name.eq(name)))
                    .firstOrDefault();

            if (parameter == null) {
                parameter = new WorkflowGlobalParameter();
                parameter.setId(UUID.randomUUID());
                parameter.setType(type);
                parameter.setName(name);
                parameter.setValue(JsonConvert.serializeObject(value));
                session.store(parameter);
            } else {
                parameter.setValue(JsonConvert.serializeObject(value));
            }

            session.saveChanges();
        }
    }

    @Override
    public  T loadGlobalParameter(String type, String name, Class cls) {
        try (IDocumentSession session = documentStore.openSession()) {
            QWorkflowGlobalParameter qWorkflowGlobalParameter = QWorkflowGlobalParameter.workflowGlobalParameter;
            WorkflowGlobalParameter parameter = session.query(WorkflowGlobalParameter.class)
                    .customize(new DocumentQueryCustomizationFactory().waitForNonStaleResultsAsOfNow())
                    .where(qWorkflowGlobalParameter.type.eq(type).and(
                            qWorkflowGlobalParameter.name.eq(name)))
                    .firstOrDefault();

            if (parameter == null) {
                return null;
            }

            return JsonConvert.deserializeObject(parameter.getValue(), cls);
        }
    }

    @Override
    public  T loadGlobalParameter(String type, String name, TypeReference typeReference) {
        try (IDocumentSession session = documentStore.openSession()) {
            QWorkflowGlobalParameter qWorkflowGlobalParameter = QWorkflowGlobalParameter.workflowGlobalParameter;
            WorkflowGlobalParameter parameter = session.query(WorkflowGlobalParameter.class)
                    .customize(new DocumentQueryCustomizationFactory().waitForNonStaleResultsAsOfNow())
                    .where(qWorkflowGlobalParameter.type.eq(type).and(
                            qWorkflowGlobalParameter.name.eq(name)))
                    .firstOrDefault();

            if (parameter == null) {
                return null;
            }

            return JsonConvert.deserializeTypeObject(parameter.getValue(), typeReference);
        }
    }

    @Override
    public  Collection loadGlobalParameters(String type, final Class cls) {
        Collection result = new ArrayList<>();
        int skip = 0;
        try (IDocumentSession session = documentStore.openSession()) {
            do {
                QWorkflowGlobalParameter qWorkflowGlobalParameter = QWorkflowGlobalParameter.workflowGlobalParameter;
                List parameters = session.query(WorkflowGlobalParameter.class)
                        .customize(new DocumentQueryCustomizationFactory().waitForNonStaleResultsAsOfNow())
                        .where(qWorkflowGlobalParameter.type.eq(type))
                        .skip(skip)
                        .take(session.advanced().getMaxNumberOfRequestsPerSession())
                        .toList();

                result.addAll(select(parameters, new CollectionUtil.ItemTransformer() {
                    @Override
                    public T transform(WorkflowGlobalParameter p) {
                        return JsonConvert.deserializeObject(p.getValue(), cls);
                    }
                }));

                if (parameters.isEmpty()) {
                    break;
                }
                skip += session.advanced().getMaxNumberOfRequestsPerSession();
            } while (true);
        }
        return result;
    }

    @Override
    public void deleteGlobalParameters(String type) {
        deleteGlobalParameters(type, null);
    }

    @Override
    public void deleteGlobalParameters(String type, String name) {
        List globalParameterList;
        do {
            try (IDocumentSession session = documentStore.openSession()) {
                QWorkflowGlobalParameter qWorkflowGlobalParameter = QWorkflowGlobalParameter.workflowGlobalParameter;
                if (StringUtil.isNullOrEmpty(name)) {
                    globalParameterList = session.query(WorkflowGlobalParameter.class)
                            .customize(new DocumentQueryCustomizationFactory().waitForNonStaleResultsAsOfNow())
                            .where(qWorkflowGlobalParameter.type.eq(type))
                            .toList();
                } else {
                    globalParameterList = session.query(WorkflowGlobalParameter.class)
                            .customize(new DocumentQueryCustomizationFactory().waitForNonStaleResultsAsOfNow())
                            .where(qWorkflowGlobalParameter.type.eq(type).and(
                                    qWorkflowGlobalParameter.name.eq(name)))
                            .toList();
                }

                for (WorkflowGlobalParameter workflowGlobalParameter : globalParameterList) {
                    session.delete(workflowGlobalParameter);
                }
                session.saveChanges();
            }

        } while (!globalParameterList.isEmpty());
    }

    @Override
    public void deleteProcess(UUID processId) {
        try (IDocumentSession session = documentStore.openSession()) {
            WorkflowProcessInstance workflowProcessInstance = session.load(WorkflowProcessInstance.class, processId);
            if (workflowProcessInstance != null) {
                session.delete(workflowProcessInstance);
            }

            WorkflowProcessInstanceStatus instanceStatus = session.load(WorkflowProcessInstanceStatus.class, processId);
            if (instanceStatus != null) {
                session.delete(instanceStatus);

                session.saveChanges();
            }
        }

        List transitionHistories;
        do {
            try (IDocumentSession session = documentStore.openSession()) {
                QWorkflowProcessTransitionHistory qwpth = QWorkflowProcessTransitionHistory.workflowProcessTransitionHistory;
                transitionHistories = session.query(WorkflowProcessTransitionHistory.class)
                        .customize(new DocumentQueryCustomizationFactory().waitForNonStaleResultsAsOfNow())
                        .where(qwpth.processId.eq(processId))
                        .toList();

                for (WorkflowProcessTransitionHistory history : transitionHistories) {
                    session.delete(history);
                }

                session.saveChanges();
            }
        } while (!transitionHistories.isEmpty());

        List timers;
        do {
            try (IDocumentSession session = documentStore.openSession()) {
                QWorkflowProcessTimer qWorkflowProcessTimer = QWorkflowProcessTimer.workflowProcessTimer;
                timers = session.query(WorkflowProcessTimer.class)
                        .customize(new DocumentQueryCustomizationFactory().waitForNonStaleResultsAsOfNow())
                        .where(qWorkflowProcessTimer.processId.eq(processId))
                        .toList();

                for (WorkflowProcessTimer timer : timers) {
                    session.delete(timer);
                }

                session.saveChanges();
            }
        } while (!timers.isEmpty());
    }

    @Override
    public void registerTimer(UUID processId, String name, Date nextExecutionDateTime, boolean notOverrideIfExists) {
        try (IDocumentSession session = documentStore.openSession()) {
            QWorkflowProcessTimer qWorkflowProcessTimer = QWorkflowProcessTimer.workflowProcessTimer;
            WorkflowProcessTimer timer = session.query(WorkflowProcessTimer.class)
                    .customize(new DocumentQueryCustomizationFactory().waitForNonStaleResultsAsOfNow())
                    .where(qWorkflowProcessTimer.processId.eq(processId).and(
                            qWorkflowProcessTimer.name.eq(name)))
                    .firstOrDefault();
            if (timer == null) {
                timer = new WorkflowProcessTimer();
                timer.setId(UUID.randomUUID());
                timer.setName(name);
                timer.setNextExecutionDateTime(nextExecutionDateTime);
                timer.setProcessId(processId);
                timer.setIgnore(false);
                session.store(timer);

            } else if (!notOverrideIfExists) {
                timer.setNextExecutionDateTime(nextExecutionDateTime);
            }

            session.saveChanges();
        }
    }

    @Override
    public void clearTimers(UUID processId, Collection timersIgnoreList) {
        List workflowProcessTimers;
        do {
            try (IDocumentSession session = documentStore.openSession()) {
                QWorkflowProcessTimer qWorkflowProcessTimer = QWorkflowProcessTimer.workflowProcessTimer;
                workflowProcessTimers = session.query(WorkflowProcessTimer.class)
                        .customize(new DocumentQueryCustomizationFactory().waitForNonStaleResultsAsOfNow())
                        .where(qWorkflowProcessTimer.processId.eq(processId)
                                .and(qWorkflowProcessTimer.name.notIn(timersIgnoreList)))
                        .toList();

                for (WorkflowProcessTimer timer : workflowProcessTimers) {
                    session.delete(timer);
                }
                session.saveChanges();
            }
        } while (!workflowProcessTimers.isEmpty());
    }

    @Override
    public void clearTimersIgnore() {
        List workflowProcessTimers;
        do {
            try (IDocumentSession session = documentStore.openSession()) {
                QWorkflowProcessTimer qWorkflowProcessTimer = QWorkflowProcessTimer.workflowProcessTimer;
                workflowProcessTimers = session.query(WorkflowProcessTimer.class)
                        .customize(new DocumentQueryCustomizationFactory().waitForNonStaleResultsAsOfNow())
                        .where(qWorkflowProcessTimer.ignore.eq(Boolean.TRUE))
                        .toList();

                for (WorkflowProcessTimer timer : workflowProcessTimers) {
                    timer.setIgnore(false);
                }
                session.saveChanges();
            }
        } while (!workflowProcessTimers.isEmpty());
    }

    @Override
    public void clearTimerIgnore(UUID timerId) {
        try (IDocumentSession session = documentStore.openSession()) {
            WorkflowProcessTimer timer = session.load(WorkflowProcessTimer.class, timerId);
            if (timer != null) {
                timer.setIgnore(false);
                session.saveChanges();
            }
        }
    }

    @Override
    public void clearTimer(UUID timerId) {
        try (IDocumentSession session = documentStore.openSession()) {
            WorkflowProcessTimer timer = session.load(WorkflowProcessTimer.class, timerId);
            if (timer != null) {
                session.delete(timer);
                session.saveChanges();
            }
        }
    }

    @Override
    public Date getCloseExecutionDateTime() {
        try (IDocumentSession session = documentStore.openSession()) {
            QWorkflowProcessTimer qWorkflowProcessTimer = QWorkflowProcessTimer.workflowProcessTimer;
            WorkflowProcessTimer timer = session.query(WorkflowProcessTimer.class)
                    .customize(new DocumentQueryCustomizationFactory().waitForNonStaleResultsAsOfNow())
                    .where(qWorkflowProcessTimer.ignore.eq(Boolean.FALSE))
                    .orderBy(qWorkflowProcessTimer.nextExecutionDateTime.asc())
                    .firstOrDefault();
            if (timer == null) {
                return null;
            }

            return timer.getNextExecutionDateTime();
        }
    }

    @Override
    public List getTimersToExecute() {
        Date now = runtime.getRuntimeDateTimeNow();
        List timers = new ArrayList<>();
        List workflowProcessTimers;
        do {
            try (IDocumentSession session = documentStore.openSession()) {
                QWorkflowProcessTimer qWorkflowProcessTimer = QWorkflowProcessTimer.workflowProcessTimer;
                workflowProcessTimers = session.query(WorkflowProcessTimer.class)
                        .customize(new DocumentQueryCustomizationFactory().waitForNonStaleResultsAsOfNow())
                        .where(qWorkflowProcessTimer.ignore.eq(Boolean.FALSE).and(
                                qWorkflowProcessTimer.nextExecutionDateTime.loe(now)))
                        .toList();
                for (WorkflowProcessTimer workflowProcessTimer : workflowProcessTimers) {
                    workflowProcessTimer.setIgnore(true);
                }

                timers.addAll(workflowProcessTimers);
                session.saveChanges();
            }
        } while (!workflowProcessTimers.isEmpty());

        Collection result = CollectionUtil.select(timers, new CollectionUtil.ItemTransformer() {
            @Override
            public TimerToExecute transform(WorkflowProcessTimer t) {
                TimerToExecute timerToExecute = new TimerToExecute();
                timerToExecute.setName(t.getName());
                timerToExecute.setProcessId(t.getProcessId());
                timerToExecute.setTimerId(t.getId());
                return timerToExecute;
            }
        });
        return new ArrayList<>(result);
    }

    @Override
    public List getProcessHistory(UUID processId) {
        List result = new ArrayList<>();
        int skip = 0;
        try (IDocumentSession session = documentStore.openSession()) {
            do {
                QWorkflowProcessTransitionHistory qWorkflowProcessTransitionHistory = QWorkflowProcessTransitionHistory.workflowProcessTransitionHistory;
                List transitionHistories = session.query(WorkflowProcessTransitionHistory.class)
                        .customize(new DocumentQueryCustomizationFactory().waitForNonStaleResultsAsOfNow())
                        .where(qWorkflowProcessTransitionHistory.processId.eq(processId))
                        .skip(skip)
                        .take(session.advanced().getMaxNumberOfRequestsPerSession())
                        .toList();

                for (WorkflowProcessTransitionHistory item : transitionHistories) {
                    ProcessHistoryItem processHistoryItem = new ProcessHistoryItem();
                    processHistoryItem.setActorIdentityId(item.getActorIdentityId());
                    processHistoryItem.setExecutorIdentityId(item.getExecutorIdentityId());
                    processHistoryItem.setFromActivityName(item.getFromActivityName());
                    processHistoryItem.setFromStateName(item.getFromStateName());
                    processHistoryItem.setFinalised(item.isFinalised());
                    processHistoryItem.setProcessId(item.getProcessId());
                    processHistoryItem.setToActivityName(item.getToActivityName());
                    processHistoryItem.setToStateName(item.getToStateName());
                    processHistoryItem.setTransitionClassifier(TransitionClassifier.valueOf(item.getTransitionClassifier()));
                    processHistoryItem.setTransitionTime(item.getTransitionTime());
                    processHistoryItem.setTriggerName(item.getTriggerName());
                    result.add(processHistoryItem);
                }

                if (transitionHistories.isEmpty()) {
                    break;
                }
                skip += session.advanced().getMaxNumberOfRequestsPerSession();
            } while (true);
        }
        return result;
    }

    @Override
    public SchemeDefinition getProcessSchemeByProcessId(UUID processId) {
        try (IDocumentSession session = documentStore.openSession()) {
            WorkflowProcessInstance processInstance = session.load(WorkflowProcessInstance.class, processId);

            if (processInstance == null) {
                throw new ProcessNotFoundException(processId);
            }
            if (processInstance.getSchemeId() == null) {
                throw new SchemeNotFoundException(processId, SchemeLocation.WorkflowProcessInstance);
            }
            SchemeDefinition schemeDefinition = getProcessSchemeBySchemeId(processInstance.getSchemeId());
            schemeDefinition.setDeterminingParametersChanged(processInstance.isDeterminingParametersChanged());
            return schemeDefinition;
        }
    }

    @Override
    public SchemeDefinition getProcessSchemeBySchemeId(UUID schemeId) {
        try (IDocumentSession session = documentStore.openSession()) {
            WorkflowProcessScheme processScheme = session.load(WorkflowProcessScheme.class, schemeId);
            if (processScheme == null || StringUtil.isNullOrEmpty(processScheme.getScheme())) {
                throw new SchemeNotFoundException(schemeId, SchemeLocation.WorkflowProcessScheme);
            }
            return convertToSchemeDefinition(processScheme);
        }
    }

    @Override
    public SchemeDefinition getProcessSchemeWithParameters(String schemeCode, String definingParameters,
                                                                     UUID rootSchemeId, boolean ignoreObsolete) {
        Collection processSchemes;
        String hash = HashHelper.generateStringHash(definingParameters);
        try (IDocumentSession session = documentStore.openSession()) {
            QWorkflowProcessScheme qWorkflowProcessScheme = QWorkflowProcessScheme.workflowProcessScheme;
            final BooleanExpression rootSchemeCondition = rootSchemeId == null
                    ? qWorkflowProcessScheme.rootSchemeId.isNull()
                    : qWorkflowProcessScheme.rootSchemeId.eq(rootSchemeId);
            if (ignoreObsolete) {
                processSchemes = session.query(WorkflowProcessScheme.class)
                        .customize(new DocumentQueryCustomizationFactory().waitForNonStaleResultsAsOfNow())
                        .where(qWorkflowProcessScheme.schemeCode.eq(schemeCode).and(
                                qWorkflowProcessScheme.definingParametersHash.eq(hash).and(
                                        rootSchemeCondition.and(qWorkflowProcessScheme.obsolete.eq(Boolean.FALSE)))))
                        .toList();
            } else {
                processSchemes = session.query(WorkflowProcessScheme.class)
                        .customize(new DocumentQueryCustomizationFactory().waitForNonStaleResultsAsOfNow())
                        .where(qWorkflowProcessScheme.schemeCode.eq(schemeCode).and(
                                qWorkflowProcessScheme.definingParametersHash.eq(hash).and(rootSchemeCondition)))
                        .toList();
            }
        }

        if (processSchemes.isEmpty()) {
            throw new SchemeNotFoundException(schemeCode, SchemeLocation.WorkflowProcessScheme, definingParameters);
        }

        if (processSchemes.size() == 1) {
            WorkflowProcessScheme scheme = CollectionUtil.first(processSchemes);
            return convertToSchemeDefinition(scheme);
        }

        for (WorkflowProcessScheme processScheme : processSchemes) {
            if (processScheme.getDefiningParameters().equals(definingParameters)) {
                return convertToSchemeDefinition(processScheme);
            }
        }

        throw new SchemeNotFoundException(schemeCode, SchemeLocation.WorkflowProcessScheme, definingParameters);
    }

    @Override
    public void setSchemeIsObsolete(String schemeCode, Map parameters) {
        String definingParameters = DefiningParametersSerializer.serialize(parameters);
        String definingParametersHash = HashHelper.generateStringHash(definingParameters);

        do {
            try (IDocumentSession session = documentStore.openSession()) {
                QWorkflowProcessScheme qWorkflowProcessScheme = QWorkflowProcessScheme.workflowProcessScheme;
                List oldSchemes = session.query(WorkflowProcessScheme.class)
                        .customize(new DocumentQueryCustomizationFactory().waitForNonStaleResultsAsOfNow())
                        .where(qWorkflowProcessScheme.schemeCode.eq(schemeCode).or(
                                qWorkflowProcessScheme.rootSchemeCode.eq(schemeCode)).and(
                                qWorkflowProcessScheme.obsolete.eq(Boolean.FALSE).and(
                                        qWorkflowProcessScheme.definingParametersHash.eq(definingParametersHash))))
                        .toList();
                if (oldSchemes.isEmpty()) {
                    break;
                }

                for (WorkflowProcessScheme scheme : oldSchemes) {
                    scheme.setObsolete(true);
                }
                session.saveChanges();

                if (session.advanced().getNumberOfRequests() < session.advanced().getMaxNumberOfRequestsPerSession() - 2) {
                    break;
                }
            }
        } while (true);
    }

    @Override
    public void setSchemeIsObsolete(String schemeCode) {
        do {
            try (IDocumentSession session = documentStore.openSession()) {
                QWorkflowProcessScheme qWorkflowProcessScheme = QWorkflowProcessScheme.workflowProcessScheme;
                List oldSchemes = session.query(WorkflowProcessScheme.class)
                        .customize(new DocumentQueryCustomizationFactory().waitForNonStaleResultsAsOfNow())
                        .where(qWorkflowProcessScheme.schemeCode.eq(schemeCode).or(
                                qWorkflowProcessScheme.rootSchemeCode.eq(schemeCode)).and(
                                qWorkflowProcessScheme.obsolete.eq(Boolean.FALSE)
                        ))
                        .toList();
                if (oldSchemes.isEmpty()) {
                    break;
                }

                for (WorkflowProcessScheme scheme : oldSchemes) {
                    scheme.setObsolete(true);
                }
                session.saveChanges();

                if (session.advanced().getNumberOfRequests() < session.advanced().getMaxNumberOfRequestsPerSession() - 2) {
                    break;
                }
            }
        } while (true);
    }

    @Override
    public void saveScheme(SchemeDefinition scheme) {
        final String definingParameters = scheme.getDefiningParameters();
        String definingParametersHash = HashHelper.generateStringHash(definingParameters);

        try (IDocumentSession session = documentStore.openSession()) {
            QWorkflowProcessScheme qWorkflowProcessScheme = QWorkflowProcessScheme.workflowProcessScheme;
            List oldSchemes = session.query(WorkflowProcessScheme.class)
                    .customize(new DocumentQueryCustomizationFactory().waitForNonStaleResultsAsOfNow())
                    .where(qWorkflowProcessScheme.definingParametersHash.eq(definingParametersHash).and(
                            qWorkflowProcessScheme.schemeCode.eq(scheme.getSchemeCode()).and(
                                    qWorkflowProcessScheme.obsolete.eq(scheme.isObsolete()))))
                    .toList();

            boolean any = CollectionUtil.any(oldSchemes, new CollectionUtil.ItemCondition() {
                @Override
                public boolean check(WorkflowProcessScheme oldScheme) {
                    return oldScheme.getDefiningParameters().equals(definingParameters);
                }
            });
            if (any) {
                throw new SchemeAlreadyExistsException(scheme.getSchemeCode(), SchemeLocation.WorkflowProcessScheme,
                        scheme.getDefiningParameters());
            }

            WorkflowProcessScheme newProcessScheme = new WorkflowProcessScheme();
            newProcessScheme.setId(scheme.getId());
            newProcessScheme.setDefiningParameters(definingParameters);
            newProcessScheme.setDefiningParametersHash(definingParametersHash);
            newProcessScheme.setScheme(DocumentUtil.serialize(scheme.getScheme()));
            newProcessScheme.setSchemeCode(scheme.getSchemeCode());
            newProcessScheme.setRootSchemeCode(scheme.getRootSchemeCode());
            newProcessScheme.setRootSchemeId(scheme.getRootSchemeId());
            newProcessScheme.setAllowedActivities(scheme.getAllowedActivities());
            newProcessScheme.setStartingTransition(scheme.getStartingTransition());
            newProcessScheme.setObsolete(scheme.isObsolete());

            session.store(newProcessScheme);
            session.saveChanges();
        }
    }

    @Override
    public void saveScheme(String schemaCode, String scheme) {
        try (IDocumentSession session = documentStore.openSession()) {
            QWorkflowScheme qWorkflowScheme = QWorkflowScheme.workflowScheme;
            WorkflowScheme wfScheme = session.query(WorkflowScheme.class)
                    .customize(new DocumentQueryCustomizationFactory().waitForNonStaleResultsAsOfNow())
                    .firstOrDefault(qWorkflowScheme.code.eq(schemaCode));
            if (wfScheme == null) {
                wfScheme = new WorkflowScheme();
                wfScheme.setId(schemaCode);
                wfScheme.setCode(schemaCode);
                wfScheme.setScheme(scheme);
                session.store(wfScheme);
            } else {
                wfScheme.setScheme(scheme);
            }
            session.saveChanges();
        }
    }

    @Override
    public Document getScheme(String code) {
        try (IDocumentSession session = documentStore.openSession()) {
            QWorkflowScheme qWorkflowScheme = QWorkflowScheme.workflowScheme;
            WorkflowScheme scheme = session.query(WorkflowScheme.class)
                    .customize(new DocumentQueryCustomizationFactory().waitForNonStaleResultsAsOfNow())
                    .firstOrDefault(qWorkflowScheme.code.eq(code));
            if (scheme == null || StringUtil.isNullOrEmpty(scheme.getScheme())) {
                throw new SchemeNotFoundException(code, SchemeLocation.WorkflowScheme);
            }

            return DocumentUtil.parse(scheme.getScheme());
        }
    }

    @Override
    public Document generate(String schemeCode, UUID schemeId, Map parameters) {
        if (!parameters.isEmpty()) {
            throw new IllegalArgumentException("Parameters not supported");
        }

        return getScheme(schemeCode);
    }

    private SchemeDefinition convertToSchemeDefinition(WorkflowProcessScheme workflowProcessScheme) {
        return new SchemeDefinition<>(workflowProcessScheme.getId(), workflowProcessScheme.getRootSchemeId(),
                workflowProcessScheme.getSchemeCode(), workflowProcessScheme.getRootSchemeCode(),
                DocumentUtil.parse(workflowProcessScheme.getScheme()), workflowProcessScheme.isObsolete(), false,
                workflowProcessScheme.getAllowedActivities(),
                workflowProcessScheme.getStartingTransition(),
                workflowProcessScheme.getDefiningParameters());
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy