org.activiti.engine.impl.bpmn.deployer.BpmnDeployer.java Source code

Java tutorial

Introduction

Here is the source code for org.activiti.engine.impl.bpmn.deployer.BpmnDeployer.java

Source

/* Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.activiti.engine.impl.bpmn.deployer;

import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.activiti.bpmn.constants.BpmnXMLConstants;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.ExtensionElement;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.SubProcess;
import org.activiti.bpmn.model.UserTask;
import org.activiti.bpmn.model.ValuedDataObject;
import org.activiti.engine.DynamicBpmnConstants;
import org.activiti.engine.DynamicBpmnService;
import org.activiti.engine.delegate.event.ActivitiEventType;
import org.activiti.engine.delegate.event.impl.ActivitiEventBuilder;
import org.activiti.engine.impl.cfg.IdGenerator;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.deploy.Deployer;
import org.activiti.engine.impl.persistence.entity.DeploymentEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntityManager;
import org.activiti.engine.impl.persistence.entity.ResourceEntity;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class BpmnDeployer implements Deployer {

    private static final Logger log = LoggerFactory.getLogger(BpmnDeployer.class);

    protected IdGenerator idGenerator;
    protected ParsedDeploymentBuilderFactory parsedDeploymentBuilderFactory;
    protected BpmnDeploymentHelper bpmnDeploymentHelper;
    protected CachingAndArtifactsManager cachingAndArtifactsManager;

    @Override
    public void deploy(DeploymentEntity deployment, Map<String, Object> deploymentSettings) {
        log.debug("Processing deployment {}", deployment.getName());

        // The ParsedDeployment represents the deployment, the process definitions, and the BPMN
        // resource, parse, and model associated with each process definition.
        ParsedDeployment parsedDeployment = parsedDeploymentBuilderFactory
                .getBuilderForDeploymentAndSettings(deployment, deploymentSettings).build();

        bpmnDeploymentHelper.verifyProcessDefinitionsDoNotShareKeys(parsedDeployment.getAllProcessDefinitions());

        bpmnDeploymentHelper.copyDeploymentValuesToProcessDefinitions(parsedDeployment.getDeployment(),
                parsedDeployment.getAllProcessDefinitions());
        bpmnDeploymentHelper.setResourceNamesOnProcessDefinitions(parsedDeployment);

        //    createAndPersistNewDiagramsIfNeeded(parsedDeployment);
        setProcessDefinitionDiagramNames(parsedDeployment);

        if (deployment.isNew()) {
            Map<ProcessDefinitionEntity, ProcessDefinitionEntity> mapOfNewProcessDefinitionToPreviousVersion = getPreviousVersionsOfProcessDefinitions(
                    parsedDeployment);
            setProcessDefinitionVersionsAndIds(parsedDeployment, mapOfNewProcessDefinitionToPreviousVersion);
            persistProcessDefinitionsAndAuthorizations(parsedDeployment);
            updateTimersAndEvents(parsedDeployment, mapOfNewProcessDefinitionToPreviousVersion);
            dispatchProcessDefinitionEntityInitializedEvent(parsedDeployment);
        } else {
            makeProcessDefinitionsConsistentWithPersistedVersions(parsedDeployment);
        }

        cachingAndArtifactsManager.updateCachingAndArtifacts(parsedDeployment);

        for (ProcessDefinitionEntity processDefinition : parsedDeployment.getAllProcessDefinitions()) {
            BpmnModel bpmnModel = parsedDeployment.getBpmnModelForProcessDefinition(processDefinition);
            createLocalizationValues(processDefinition.getId(),
                    bpmnModel.getProcessById(processDefinition.getKey()));
        }
    }
    //
    //  /**
    //   * Creates new diagrams for process definitions if the deployment is new, the process definition in
    //   * question supports it, and the engine is configured to make new diagrams.
    //   *
    //   * When this method creates a new diagram, it also persists it via the ResourceEntityManager
    //   * and adds it to the resources of the deployment.
    //   */
    //  protected void createAndPersistNewDiagramsIfNeeded(ParsedDeployment parsedDeployment) {
    //
    //    final ProcessEngineConfigurationImpl processEngineConfiguration = Context.getProcessEngineConfiguration();
    //    final DeploymentEntity deploymentEntity = parsedDeployment.getDeployment();
    //
    //    final ResourceEntityManager resourceEntityManager = processEngineConfiguration.getResourceEntityManager();
    //
    //    for (ProcessDefinitionEntity processDefinition : parsedDeployment.getAllProcessDefinitions()) {
    //      if (processDefinitionDiagramHelper.shouldCreateDiagram(processDefinition, deploymentEntity)) {
    //        ResourceEntity resource = processDefinitionDiagramHelper.createDiagramForProcessDefinition(
    //            processDefinition, parsedDeployment.getBpmnParseForProcessDefinition(processDefinition));
    //        if (resource != null) {
    //          resourceEntityManager.insert(resource, false);
    //          deploymentEntity.addResource(resource);  // now we'll find it if we look for the diagram name later.
    //        }
    //      }
    //    }
    //  }

    /**
     * Updates all the process definition entities to have the correct diagram resource name.  Must
     * be called after createAndPersistNewDiagramsAsNeeded to ensure that any newly-created diagrams
     * already have their resources attached to the deployment.
     */
    protected void setProcessDefinitionDiagramNames(ParsedDeployment parsedDeployment) {
        Map<String, ResourceEntity> resources = parsedDeployment.getDeployment().getResources();

        for (ProcessDefinitionEntity processDefinition : parsedDeployment.getAllProcessDefinitions()) {
            String diagramResourceName = ResourceNameUtil
                    .getProcessDiagramResourceNameFromDeployment(processDefinition, resources);
            processDefinition.setDiagramResourceName(diagramResourceName);
        }
    }

    /**
     * Constructs a map from new ProcessDefinitionEntities to the previous version by key and tenant.
     * If no previous version exists, no map entry is created.
     */
    protected Map<ProcessDefinitionEntity, ProcessDefinitionEntity> getPreviousVersionsOfProcessDefinitions(
            ParsedDeployment parsedDeployment) {

        Map<ProcessDefinitionEntity, ProcessDefinitionEntity> result = new LinkedHashMap<ProcessDefinitionEntity, ProcessDefinitionEntity>();

        for (ProcessDefinitionEntity newDefinition : parsedDeployment.getAllProcessDefinitions()) {
            ProcessDefinitionEntity existingDefinition = bpmnDeploymentHelper
                    .getMostRecentVersionOfProcessDefinition(newDefinition);

            if (existingDefinition != null) {
                result.put(newDefinition, existingDefinition);
            }
        }

        return result;
    }

    /**
     * Sets the version on each process definition entity, and the identifier.  If the map contains
     * an older version for a process definition, then the version is set to that older entity's
     * version plus one; otherwise it is set to 1.  Also dispatches an ENTITY_CREATED event.
     */
    protected void setProcessDefinitionVersionsAndIds(ParsedDeployment parsedDeployment,
            Map<ProcessDefinitionEntity, ProcessDefinitionEntity> mapNewToOldProcessDefinitions) {
        CommandContext commandContext = Context.getCommandContext();

        for (ProcessDefinitionEntity processDefinition : parsedDeployment.getAllProcessDefinitions()) {
            int version = 1;

            ProcessDefinitionEntity latest = mapNewToOldProcessDefinitions.get(processDefinition);
            if (latest != null) {
                version = latest.getVersion() + 1;
            }

            processDefinition.setVersion(version);
            processDefinition.setId(getIdForNewProcessDefinition(processDefinition));

            if (commandContext.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
                commandContext.getProcessEngineConfiguration().getEventDispatcher()
                        .dispatchEvent(ActivitiEventBuilder.createEntityEvent(ActivitiEventType.ENTITY_CREATED,
                                processDefinition));
            }
        }
    }

    /**
     * Saves each process definition.  It is assumed that the deployment is new, the definitions
     * have never been saved before, and that they have all their values properly set up.
     */
    protected void persistProcessDefinitionsAndAuthorizations(ParsedDeployment parsedDeployment) {
        CommandContext commandContext = Context.getCommandContext();
        ProcessDefinitionEntityManager processDefinitionManager = commandContext
                .getProcessDefinitionEntityManager();

        for (ProcessDefinitionEntity processDefinition : parsedDeployment.getAllProcessDefinitions()) {
            processDefinitionManager.insert(processDefinition, false);
            bpmnDeploymentHelper.addAuthorizationsForNewProcessDefinition(
                    parsedDeployment.getProcessModelForProcessDefinition(processDefinition), processDefinition);
        }
    }

    protected void updateTimersAndEvents(ParsedDeployment parsedDeployment,
            Map<ProcessDefinitionEntity, ProcessDefinitionEntity> mapNewToOldProcessDefinitions) {

        for (ProcessDefinitionEntity processDefinition : parsedDeployment.getAllProcessDefinitions()) {
            bpmnDeploymentHelper.updateTimersAndEvents(processDefinition,
                    mapNewToOldProcessDefinitions.get(processDefinition), parsedDeployment);
        }
    }

    protected void dispatchProcessDefinitionEntityInitializedEvent(ParsedDeployment parsedDeployment) {
        CommandContext commandContext = Context.getCommandContext();
        for (ProcessDefinitionEntity processDefinitionEntity : parsedDeployment.getAllProcessDefinitions()) {
            if (commandContext.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
                commandContext.getProcessEngineConfiguration().getEventDispatcher()
                        .dispatchEvent(ActivitiEventBuilder.createEntityEvent(ActivitiEventType.ENTITY_INITIALIZED,
                                processDefinitionEntity));
            }
        }
    }

    /**
     * Returns the ID to use for a new process definition; subclasses may override this to provide
     * their own identification scheme.
     * <p>
     * Process definition ids NEED to be unique accross the whole engine!
     */
    protected String getIdForNewProcessDefinition(ProcessDefinitionEntity processDefinition) {
        String nextId = idGenerator.getNextId();

        String result = processDefinition.getKey() + ":" + processDefinition.getVersion() + ":" + nextId; // ACT-505
        // ACT-115: maximum id length is 64 characters
        if (result.length() > 64) {
            result = nextId;
        }

        return result;
    }

    /**
     * Loads the persisted version of each process definition and set values on the in-memory
     * version to be consistent.
     */
    protected void makeProcessDefinitionsConsistentWithPersistedVersions(ParsedDeployment parsedDeployment) {
        for (ProcessDefinitionEntity processDefinition : parsedDeployment.getAllProcessDefinitions()) {
            ProcessDefinitionEntity persistedProcessDefinition = bpmnDeploymentHelper
                    .getPersistedInstanceOfProcessDefinition(processDefinition);

            if (persistedProcessDefinition != null) {
                processDefinition.setId(persistedProcessDefinition.getId());
                processDefinition.setVersion(persistedProcessDefinition.getVersion());
                processDefinition.setSuspensionState(persistedProcessDefinition.getSuspensionState());
            }
        }
    }

    protected void createLocalizationValues(String processDefinitionId, Process process) {
        if (process == null) {
            return;
        }

        CommandContext commandContext = Context.getCommandContext();
        DynamicBpmnService dynamicBpmnService = commandContext.getProcessEngineConfiguration()
                .getDynamicBpmnService();
        ObjectNode infoNode = dynamicBpmnService.getProcessDefinitionInfo(processDefinitionId);

        boolean localizationValuesChanged = false;
        List<ExtensionElement> localizationElements = process.getExtensionElements().get("localization");
        if (localizationElements != null) {
            for (ExtensionElement localizationElement : localizationElements) {
                if (BpmnXMLConstants.ACTIVITI_EXTENSIONS_PREFIX.equals(localizationElement.getNamespacePrefix())) {
                    String locale = localizationElement.getAttributeValue(null, "locale");
                    String name = localizationElement.getAttributeValue(null, "name");
                    String documentation = null;
                    List<ExtensionElement> documentationElements = localizationElement.getChildElements()
                            .get("documentation");
                    if (documentationElements != null) {
                        for (ExtensionElement documentationElement : documentationElements) {
                            documentation = StringUtils.trimToNull(documentationElement.getElementText());
                            break;
                        }
                    }

                    String processId = process.getId();
                    if (isEqualToCurrentLocalizationValue(locale, processId, "name", name, infoNode) == false) {
                        dynamicBpmnService.changeLocalizationName(locale, processId, name, infoNode);
                        localizationValuesChanged = true;
                    }

                    if (documentation != null && isEqualToCurrentLocalizationValue(locale, processId, "description",
                            documentation, infoNode) == false) {
                        dynamicBpmnService.changeLocalizationDescription(locale, processId, documentation,
                                infoNode);
                        localizationValuesChanged = true;
                    }

                    break;
                }
            }
        }

        boolean isFlowElementLocalizationChanged = localizeFlowElements(process.getFlowElements(), infoNode);
        boolean isDataObjectLocalizationChanged = localizeDataObjectElements(process.getDataObjects(), infoNode);
        if (isFlowElementLocalizationChanged || isDataObjectLocalizationChanged) {
            localizationValuesChanged = true;
        }

        if (localizationValuesChanged) {
            dynamicBpmnService.saveProcessDefinitionInfo(processDefinitionId, infoNode);
        }
    }

    protected boolean localizeFlowElements(Collection<FlowElement> flowElements, ObjectNode infoNode) {
        boolean localizationValuesChanged = false;

        if (flowElements == null) {
            return localizationValuesChanged;
        }

        CommandContext commandContext = Context.getCommandContext();
        DynamicBpmnService dynamicBpmnService = commandContext.getProcessEngineConfiguration()
                .getDynamicBpmnService();

        for (FlowElement flowElement : flowElements) {
            if (flowElement instanceof UserTask || flowElement instanceof SubProcess) {
                List<ExtensionElement> localizationElements = flowElement.getExtensionElements()
                        .get("localization");
                if (localizationElements != null) {
                    for (ExtensionElement localizationElement : localizationElements) {
                        if (BpmnXMLConstants.ACTIVITI_EXTENSIONS_PREFIX
                                .equals(localizationElement.getNamespacePrefix())) {
                            String locale = localizationElement.getAttributeValue(null, "locale");
                            String name = localizationElement.getAttributeValue(null, "name");
                            String documentation = null;
                            List<ExtensionElement> documentationElements = localizationElement.getChildElements()
                                    .get("documentation");
                            if (documentationElements != null) {
                                for (ExtensionElement documentationElement : documentationElements) {
                                    documentation = StringUtils.trimToNull(documentationElement.getElementText());
                                    break;
                                }
                            }

                            String flowElementId = flowElement.getId();
                            if (isEqualToCurrentLocalizationValue(locale, flowElementId, "name", name,
                                    infoNode) == false) {
                                dynamicBpmnService.changeLocalizationName(locale, flowElementId, name, infoNode);
                                localizationValuesChanged = true;
                            }

                            if (documentation != null && isEqualToCurrentLocalizationValue(locale, flowElementId,
                                    "description", documentation, infoNode) == false) {
                                dynamicBpmnService.changeLocalizationDescription(locale, flowElementId,
                                        documentation, infoNode);
                                localizationValuesChanged = true;
                            }

                            break;
                        }
                    }
                }

                if (flowElement instanceof SubProcess) {
                    SubProcess subprocess = (SubProcess) flowElement;
                    boolean isFlowElementLocalizationChanged = localizeFlowElements(subprocess.getFlowElements(),
                            infoNode);
                    boolean isDataObjectLocalizationChanged = localizeDataObjectElements(
                            subprocess.getDataObjects(), infoNode);
                    if (isFlowElementLocalizationChanged || isDataObjectLocalizationChanged) {
                        localizationValuesChanged = true;
                    }
                }
            }
        }

        return localizationValuesChanged;
    }

    protected boolean isEqualToCurrentLocalizationValue(String language, String id, String propertyName,
            String propertyValue, ObjectNode infoNode) {
        boolean isEqual = false;
        JsonNode localizationNode = infoNode.path("localization").path(language).path(id).path(propertyName);
        if (localizationNode.isMissingNode() == false && localizationNode.isNull() == false
                && localizationNode.asText().equals(propertyValue)) {
            isEqual = true;
        }
        return isEqual;
    }

    protected boolean localizeDataObjectElements(List<ValuedDataObject> dataObjects, ObjectNode infoNode) {
        boolean localizationValuesChanged = false;
        CommandContext commandContext = Context.getCommandContext();
        DynamicBpmnService dynamicBpmnService = commandContext.getProcessEngineConfiguration()
                .getDynamicBpmnService();

        for (ValuedDataObject dataObject : dataObjects) {
            List<ExtensionElement> localizationElements = dataObject.getExtensionElements().get("localization");
            if (localizationElements != null) {
                for (ExtensionElement localizationElement : localizationElements) {
                    if (BpmnXMLConstants.ACTIVITI_EXTENSIONS_PREFIX
                            .equals(localizationElement.getNamespacePrefix())) {
                        String locale = localizationElement.getAttributeValue(null, "locale");
                        String name = localizationElement.getAttributeValue(null, "name");
                        String documentation = null;

                        List<ExtensionElement> documentationElements = localizationElement.getChildElements()
                                .get("documentation");
                        if (documentationElements != null) {
                            for (ExtensionElement documentationElement : documentationElements) {
                                documentation = StringUtils.trimToNull(documentationElement.getElementText());
                                break;
                            }
                        }

                        if (name != null && isEqualToCurrentLocalizationValue(locale, dataObject.getId(),
                                DynamicBpmnConstants.LOCALIZATION_NAME, name, infoNode) == false) {
                            dynamicBpmnService.changeLocalizationName(locale, dataObject.getId(), name, infoNode);
                            localizationValuesChanged = true;
                        }

                        if (documentation != null && isEqualToCurrentLocalizationValue(locale, dataObject.getId(),
                                DynamicBpmnConstants.LOCALIZATION_DESCRIPTION, documentation, infoNode) == false) {

                            dynamicBpmnService.changeLocalizationDescription(locale, dataObject.getId(),
                                    documentation, infoNode);
                            localizationValuesChanged = true;
                        }
                    }
                }
            }
        }

        return localizationValuesChanged;
    }

    public IdGenerator getIdGenerator() {
        return idGenerator;
    }

    public void setIdGenerator(IdGenerator idGenerator) {
        this.idGenerator = idGenerator;
    }

    public ParsedDeploymentBuilderFactory getExParsedDeploymentBuilderFactory() {
        return parsedDeploymentBuilderFactory;
    }

    public void setParsedDeploymentBuilderFactory(ParsedDeploymentBuilderFactory parsedDeploymentBuilderFactory) {
        this.parsedDeploymentBuilderFactory = parsedDeploymentBuilderFactory;
    }

    public BpmnDeploymentHelper getBpmnDeploymentHelper() {
        return bpmnDeploymentHelper;
    }

    public void setBpmnDeploymentHelper(BpmnDeploymentHelper bpmnDeploymentHelper) {
        this.bpmnDeploymentHelper = bpmnDeploymentHelper;
    }

    public CachingAndArtifactsManager getCachingAndArtifcatsManager() {
        return cachingAndArtifactsManager;
    }

    public void setCachingAndArtifactsManager(CachingAndArtifactsManager manager) {
        this.cachingAndArtifactsManager = manager;
    }
}