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

org.bonitasoft.engine.operation.TransientDataLeftOperandHandler Maven / Gradle / Ivy

There is a newer version: 10.2.0
Show newest version
/**
 * Copyright (C) 2015 BonitaSoft S.A.
 * BonitaSoft, 32 rue Gustave Eiffel - 38000 Grenoble
 * This library is free software; you can redistribute it and/or modify it under the terms
 * of the GNU Lesser General Public License as published by the Free Software Foundation
 * version 2.1 of the License.
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 * You should have received a copy of the GNU Lesser General Public License along with this
 * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA 02110-1301, USA.
 **/
package org.bonitasoft.engine.operation;

import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.bonitasoft.engine.bpm.model.impl.BPMInstancesCreator;
import org.bonitasoft.engine.core.data.instance.TransientDataService;
import org.bonitasoft.engine.core.expression.control.model.SExpressionContext;
import org.bonitasoft.engine.core.operation.LeftOperandHandler;
import org.bonitasoft.engine.core.operation.exception.SOperationExecutionException;
import org.bonitasoft.engine.core.operation.model.SLeftOperand;
import org.bonitasoft.engine.core.process.definition.ProcessDefinitionService;
import org.bonitasoft.engine.core.process.definition.exception.SProcessDefinitionNotFoundException;
import org.bonitasoft.engine.core.process.definition.model.SActivityDefinition;
import org.bonitasoft.engine.core.process.definition.model.SProcessDefinition;
import org.bonitasoft.engine.core.process.instance.api.FlowNodeInstanceService;
import org.bonitasoft.engine.core.process.instance.api.exceptions.SFlowNodeNotFoundException;
import org.bonitasoft.engine.core.process.instance.api.exceptions.SFlowNodeReadException;
import org.bonitasoft.engine.core.process.instance.model.SFlowNodeInstance;
import org.bonitasoft.engine.data.definition.model.SDataDefinition;
import org.bonitasoft.engine.data.instance.api.DataInstanceContainer;
import org.bonitasoft.engine.data.instance.exception.SDataInstanceException;
import org.bonitasoft.engine.data.instance.exception.SDataInstanceNotFoundException;
import org.bonitasoft.engine.data.instance.model.SDataInstance;
import org.bonitasoft.engine.expression.exception.SExpressionException;
import org.bonitasoft.engine.log.technical.TechnicalLogSeverity;
import org.bonitasoft.engine.log.technical.TechnicalLoggerService;
import org.bonitasoft.engine.persistence.SBonitaReadException;
import org.bonitasoft.engine.recorder.model.EntityUpdateDescriptor;

/**
 * @author Baptiste Mesta
 * @author Matthieu Chaffotte
 */
public class TransientDataLeftOperandHandler implements LeftOperandHandler {

    private static final String TRANSIENT_DATA = "%TRANSIENT_DATA%_";
    private final TransientDataService transientDataService;

    private final FlowNodeInstanceService flownodeInstanceService;

    private final ProcessDefinitionService processDefinitionService;

    private final BPMInstancesCreator bpmInstancesCreator;

    private final TechnicalLoggerService logger;

    public TransientDataLeftOperandHandler(final TransientDataService transientDataService, final FlowNodeInstanceService flownodeInstanceService,
            final ProcessDefinitionService processDefinitionService, final BPMInstancesCreator bpmInstancesCreator, final TechnicalLoggerService logger) {
        this.transientDataService = transientDataService;
        this.flownodeInstanceService = flownodeInstanceService;
        this.processDefinitionService = processDefinitionService;
        this.bpmInstancesCreator = bpmInstancesCreator;
        this.logger = logger;
    }

    @Override
    public String getType() {
        return LeftOperand.TYPE_TRANSIENT_DATA;
    }

    @Override
    public Object update(final SLeftOperand sLeftOperand, Map inputValues, final Object newValue, final long containerId, final String containerType)
            throws SOperationExecutionException {
        SDataInstance dataInstance;
        try {

            dataInstance = (SDataInstance) inputValues.get(TRANSIENT_DATA + sLeftOperand.getName());
            if(dataInstance == null){
                dataInstance = retrieve(sLeftOperand, containerId, containerType);
            }
            final EntityUpdateDescriptor descriptor = new EntityUpdateDescriptor();
            descriptor.addField("value", newValue);
            logger.log(
                    getClass(),
                    TechnicalLogSeverity.WARNING,
                    "The value of the transient data "
                            + sLeftOperand.getName()
                            + " of "
                            + containerId
                            + " "
                            + containerType
                            + " is being updated, be carefull if the application server is restarted this new value will be lost and the data will be reset to its initial value. "
                            + "We advise you to change the design of your process. If you understand the risks and want to hide this warning, change the logging level of this class to error.");
            transientDataService.updateDataInstance(dataInstance, descriptor);
            return newValue;
        } catch (final SDataInstanceException | SBonitaReadException e) {
            throw new SOperationExecutionException("Unable to update the transient data", e);
        }
    }

    @Override
    public void delete(final SLeftOperand leftOperand, final long containerId, final String containerType) throws SOperationExecutionException {
        throw new SOperationExecutionException("Deleting a transient data is not supported");
    }

    @Override
    public void loadLeftOperandInContext(final SLeftOperand sLeftOperand, final SExpressionContext expressionContext, Map contextToSet) throws SBonitaReadException {
        final Long containerId = expressionContext.getContainerId();
        final String containerType = expressionContext.getContainerType();
        String name = sLeftOperand.getName();
        SDataInstance dataInstance = retrieve(sLeftOperand, containerId, containerType);
        contextToSet.put(TRANSIENT_DATA + name, dataInstance);
        if (!contextToSet.containsKey(name)) {
            contextToSet.put(name, dataInstance.getValue());
        }
    }

    private SDataInstance retrieve(final SLeftOperand sLeftOperand, final Long containerId, final String containerType) throws SBonitaReadException {
        try {
            // if not found reevaluate
            return transientDataService.getDataInstance(sLeftOperand.getName(), containerId, containerType);
        } catch (final SDataInstanceNotFoundException e) {
            try {
                logger.log(getClass(), TechnicalLogSeverity.WARNING, "The value of the transient data " + sLeftOperand.getName() + "  " + containerId + " "
                        + containerType);
                reevaluateTransientData(sLeftOperand.getName(), containerId, containerType, flownodeInstanceService, processDefinitionService,
                        bpmInstancesCreator);
                return transientDataService.getDataInstance(sLeftOperand.getName(), containerId, containerType);
            } catch (final SDataInstanceException e1) {
                throw new SBonitaReadException("Unable to read the transient data", e);
            }
        } catch (final SDataInstanceException e) {
            throw new SBonitaReadException("Unable to read the transient data", e);
        }
    }

    public static void reevaluateTransientData(final String name, final long containerId, final String containerType,
            final FlowNodeInstanceService flowNodeInstanceService, final ProcessDefinitionService processDefinitionService,
            final BPMInstancesCreator bpmInstancesCreator) throws SBonitaReadException {

        try {
            final SFlowNodeInstance flowNodeInstance = flowNodeInstanceService.getFlowNodeInstance(containerId);
            final long flowNodeDefinitionId = flowNodeInstance.getFlowNodeDefinitionId();
            final long processDefinitionId = flowNodeInstance.getProcessDefinitionId();
            final SProcessDefinition processDefinition = processDefinitionService.getProcessDefinition(processDefinitionId);
            final SActivityDefinition flowNode = (SActivityDefinition) processDefinition.getProcessContainer().getFlowNode(flowNodeDefinitionId);
            final List sDataDefinitions = flowNode.getSDataDefinitions();
            SDataDefinition theTransientData = null;
            for (final SDataDefinition sDataDefinition : sDataDefinitions) {
                if (sDataDefinition.getName().equals(name)) {
                    theTransientData = sDataDefinition;
                    break;
                }
            }
            if (theTransientData == null) {
                throw new SBonitaReadException(
                        "Transient data was not found and we were unable to reevaluate it because it was not found in the definition, name=<" + name
                        + "> process definition=<" + processDefinition.getName() + "," + processDefinition.getVersion() + "> flow node=<"
                                + flowNode.getName() + ">");
            }
            bpmInstancesCreator.createDataInstances(Collections.singletonList(theTransientData), containerId, DataInstanceContainer.ACTIVITY_INSTANCE,
                    new SExpressionContext(containerId, containerType, processDefinitionId));
        } catch (final SDataInstanceException | SProcessDefinitionNotFoundException | SBonitaReadException | SFlowNodeReadException | SFlowNodeNotFoundException | SExpressionException e) {
            throwBonitaReadException(name, e);
        }
    }

    private static void throwBonitaReadException(final String name, final Exception e) throws SBonitaReadException {
        throw new SBonitaReadException("Transient data was not found and we were unable to reevaluate it, name=<" + name + ">", e);
    }


    @Override
    public void loadLeftOperandInContext(final List sLeftOperand, final SExpressionContext expressionContext, Map contextToSet) throws SBonitaReadException {
        for (SLeftOperand leftOperand : sLeftOperand) {
            loadLeftOperandInContext(leftOperand, expressionContext, contextToSet);
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy