Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
import org.flowable.cmmn.engine.impl.deployer.CaseDefinitionDiagramHelper;
import org.flowable.cmmn.engine.impl.deployer.CmmnDeployer;
import org.flowable.cmmn.engine.impl.deployer.CmmnDeploymentManager;
import org.flowable.cmmn.engine.impl.deployer.SameDeploymentCaseDefinitionLookup;
import org.flowable.cmmn.engine.impl.el.CmmnExpressionManager;
import org.flowable.cmmn.engine.impl.eventregistry.CmmnEventInstanceOutParameterHandler;
import org.flowable.cmmn.engine.impl.eventregistry.CmmnEventInstanceOutParameterHandlerImpl;
Expand Down Expand Up @@ -424,6 +425,17 @@ public class CmmnEngineConfiguration extends AbstractBuildableEngineConfiguratio

protected int caseDefinitionCacheLimit = -1;
protected DeploymentCache<CaseDefinitionCacheEntry> caseDefinitionCache;
protected DeploymentCache<String> sameDeploymentDefinitionCache;

/**
* Set to true (the default) to read a cached definition id from the database on every hit (one select by id), so that
* a definition that was undeployed on another node is detected and the lookup falls back to the query.
* <p>
* When false, the cached definition is taken from the definition cache without a select, and a definition that was
* undeployed on another cluster node is still returned on this node until it is evicted or the node is restarted.
* This can only happen when a single child deployment is deleted while its parent deployment stays.
*/
protected boolean verifyCachedSameDeploymentDefinitions = true;

protected CmmnParser cmmnParser;
protected List<CmmnParseHandler> preCmmnParseHandlers;
Expand Down Expand Up @@ -1161,6 +1173,14 @@ protected void initCaseDefinitionCache() {
caseDefinitionCache = new DefaultDeploymentCache<>(caseDefinitionCacheLimit);
}
}

if (sameDeploymentDefinitionCache == null) {
if (caseDefinitionCacheLimit <= 0) {
sameDeploymentDefinitionCache = new DefaultDeploymentCache<>();
} else {
sameDeploymentDefinitionCache = new DefaultDeploymentCache<>(caseDefinitionCacheLimit);
}
}
}

protected void initDeploymentManager() {
Expand All @@ -1172,6 +1192,10 @@ protected void initDeploymentManager() {
deploymentManager.setCaseDefinitionEntityManager(caseDefinitionEntityManager);
deploymentManager.setDeploymentEntityManager(cmmnDeploymentEntityManager);
}

if (deploymentManager.getSameDeploymentCaseDefinitionLookup() == null) {
deploymentManager.setSameDeploymentCaseDefinitionLookup(new SameDeploymentCaseDefinitionLookup(sameDeploymentDefinitionCache, this));
}
}

public void initCmmnParser() {
Expand Down Expand Up @@ -2529,6 +2553,24 @@ public CmmnEngineConfiguration setCaseDefinitionCache(DeploymentCache<CaseDefini
return this;
}

public DeploymentCache<String> getSameDeploymentDefinitionCache() {
return sameDeploymentDefinitionCache;
}

public CmmnEngineConfiguration setSameDeploymentDefinitionCache(DeploymentCache<String> sameDeploymentDefinitionCache) {
this.sameDeploymentDefinitionCache = sameDeploymentDefinitionCache;
return this;
}

public boolean isVerifyCachedSameDeploymentDefinitions() {
return verifyCachedSameDeploymentDefinitions;
}

public CmmnEngineConfiguration setVerifyCachedSameDeploymentDefinitions(boolean verifyCachedSameDeploymentDefinitions) {
this.verifyCachedSameDeploymentDefinitions = verifyCachedSameDeploymentDefinitions;
return this;
}

public ProcessInstanceService getProcessInstanceService() {
return processInstanceService;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
package org.flowable.cmmn.engine.impl.deployer;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
Expand Down Expand Up @@ -103,6 +104,7 @@ public void deploy(EngineDeployment deployment, Map<String, Object> deploymentSe
Map<CaseDefinitionEntity, CaseDefinitionEntity> mapOfNewCaseDefinitionToPreviousVersion = getPreviousVersionsOfCaseDefinitions(parseResult);
setCaseDefinitionVersionsAndIds(parseResult, mapOfNewCaseDefinitionToPreviousVersion);
persistCaseDefinitions(parseResult);
evictSameDeploymentCaseDefinitions(parseResult);
updateEventSubscriptions(parseResult, mapOfNewCaseDefinitionToPreviousVersion);

} else {
Expand All @@ -113,6 +115,15 @@ public void deploy(EngineDeployment deployment, Map<String, Object> deploymentSe
updateCachingAndArtifacts(parseResult);
}

protected void evictSameDeploymentCaseDefinitions(CmmnParseResult parseResult) {
List<String> caseDefinitionKeys = new ArrayList<>();
for (CaseDefinitionEntity caseDefinition : parseResult.getAllCaseDefinitions()) {
caseDefinitionKeys.add(caseDefinition.getKey());
}
cmmnEngineConfiguration.getDeploymentManager()
.evictSameDeploymentCaseDefinitions(((CmmnDeploymentEntity) parseResult.getDeployment()).getParentDeploymentId(), caseDefinitionKeys);
}

public static boolean isCmmnResource(String resourceName) {
for (String suffix : CMMN_RESOURCE_SUFFIXES) {
if (resourceName.endsWith(suffix)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@
package org.flowable.cmmn.engine.impl.deployer;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.flowable.cmmn.api.repository.CaseDefinition;
import org.flowable.cmmn.engine.CmmnEngineConfiguration;
import org.flowable.cmmn.engine.impl.persistence.entity.CaseDefinitionEntity;
Expand All @@ -35,11 +37,13 @@
import org.flowable.common.engine.impl.EngineDeployer;
import org.flowable.common.engine.impl.event.FlowableEntityEventImpl;
import org.flowable.common.engine.impl.interceptor.EngineConfigurationConstants;
import org.flowable.common.engine.impl.persistence.deploy.AbstractSameDeploymentDefinitionLookup;
import org.flowable.common.engine.impl.persistence.deploy.DeploymentCache;

public class CmmnDeploymentManager {

protected DeploymentCache<CaseDefinitionCacheEntry> caseDefinitionCache;
protected SameDeploymentCaseDefinitionLookup sameDeploymentCaseDefinitionLookup;
protected List<EngineDeployer> deployers;
protected CmmnEngineConfiguration cmmnEngineConfiguration;
protected CmmnDeploymentEntityManager deploymentEntityManager;
Expand Down Expand Up @@ -121,6 +125,32 @@ public CaseDefinitionCacheEntry resolveCaseDefinition(CaseDefinition caseDefinit
return cachedCaseDefinition;
}

/**
* Returns the case definition with the given key in the deployments of the given parent deployment, or null when
* there is none.
*/
public CaseDefinition findCaseDefinitionByParentDeploymentAndKey(String parentDeploymentId, String caseDefinitionKey, String tenantId) {
String cacheKey = AbstractSameDeploymentDefinitionLookup.parentDeploymentKey(parentDeploymentId, caseDefinitionKey);
return sameDeploymentCaseDefinitionLookup.find(cacheKey, tenantId, sameDeploymentCaseDefinitionLookup.isCacheMisses(), () -> {
if (tenantId != null && !CmmnEngineConfiguration.NO_TENANT_ID.equals(tenantId)) {
return caseDefinitionEntityManager.findCaseDefinitionByParentDeploymentAndKeyAndTenantId(parentDeploymentId, caseDefinitionKey, tenantId);
}
return caseDefinitionEntityManager.findCaseDefinitionByParentDeploymentAndKey(parentDeploymentId, caseDefinitionKey);
});
}

/**
* Removes the cached lookups of the given case definition keys in the given parent deployment.
*/
public void evictSameDeploymentCaseDefinitions(String parentDeploymentId, Collection<String> caseDefinitionKeys) {
if (StringUtils.isEmpty(parentDeploymentId)) {
return;
}
for (String caseDefinitionKey : caseDefinitionKeys) {
sameDeploymentCaseDefinitionLookup.evict(AbstractSameDeploymentDefinitionLookup.parentDeploymentKey(parentDeploymentId, caseDefinitionKey));
}
}

public void removeDeployment(String deploymentId) {
removeDeployment(deploymentId, true);
}
Expand All @@ -143,13 +173,24 @@ public void removeDeployment(String deploymentId, boolean cascade) {
deploymentEntityManager.deleteDeploymentAndRelatedData(deploymentId, cascade);

FlowableEventDispatcher eventDispatcher = cmmnEngineConfiguration.getEventDispatcher();
List<String> caseDefinitionKeys = new ArrayList<>();
for (CaseDefinition caseDefinition : caseDefinitions) {
caseDefinitionCache.remove(caseDefinition.getId());
caseDefinitionKeys.add(caseDefinition.getKey());
if (eventDispatcher != null && eventDispatcher.isEnabled()) {
eventDispatcher.dispatchEvent(new FlowableEntityEventImpl(caseDefinition, FlowableEngineEventType.DEFINITION_UNDEPLOYED),
EngineConfigurationConstants.KEY_CMMN_ENGINE_CONFIG);
}
}
evictSameDeploymentCaseDefinitions(deployment.getParentDeploymentId(), caseDefinitionKeys);
}

public SameDeploymentCaseDefinitionLookup getSameDeploymentCaseDefinitionLookup() {
return sameDeploymentCaseDefinitionLookup;
}

public void setSameDeploymentCaseDefinitionLookup(SameDeploymentCaseDefinitionLookup sameDeploymentCaseDefinitionLookup) {
this.sameDeploymentCaseDefinitionLookup = sameDeploymentCaseDefinitionLookup;
}

public List<EngineDeployer> getDeployers() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/* 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.flowable.cmmn.engine.impl.deployer;

import org.flowable.cmmn.api.repository.CaseDefinition;
import org.flowable.cmmn.engine.CmmnEngineConfiguration;
import org.flowable.cmmn.engine.impl.persistence.entity.deploy.CaseDefinitionCacheEntry;
import org.flowable.common.engine.impl.persistence.deploy.AbstractSameDeploymentDefinitionLookup;
import org.flowable.common.engine.impl.persistence.deploy.DeploymentCache;

/**
* Looks up case definitions by key in the deployments of a parent deployment, caching the found definition ids.
*/
public class SameDeploymentCaseDefinitionLookup extends AbstractSameDeploymentDefinitionLookup<CaseDefinition> {

protected CmmnEngineConfiguration cmmnEngineConfiguration;

public SameDeploymentCaseDefinitionLookup(DeploymentCache<String> cache, CmmnEngineConfiguration cmmnEngineConfiguration) {
super(cache, cmmnEngineConfiguration);
this.cmmnEngineConfiguration = cmmnEngineConfiguration;
}

@Override
protected boolean isVerifyCachedDefinitions() {
return cmmnEngineConfiguration.isVerifyCachedSameDeploymentDefinitions();
}

@Override
protected CaseDefinition findCachedDefinition(String definitionId) {
CaseDefinitionCacheEntry cacheEntry = cmmnEngineConfiguration.getCaseDefinitionCache().get(definitionId);
return cacheEntry != null ? cacheEntry.getCaseDefinition() : null;
}

@Override
protected CaseDefinition findPersistedDefinition(String definitionId) {
return cmmnEngineConfiguration.getCaseDefinitionEntityManager().findById(definitionId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ public CaseDefinition resolveCaseDefinition(String caseDefinitionKey, String ten

if (tenantId != null && !CmmnEngineConfiguration.NO_TENANT_ID.equals(tenantId)) {
if (parentDeploymentId != null) {
caseDefinition = caseDefinitionEntityManager
.findCaseDefinitionByParentDeploymentAndKeyAndTenantId(parentDeploymentId, caseDefinitionKey, tenantId);
caseDefinition = cmmnEngineConfiguration.getDeploymentManager()
.findCaseDefinitionByParentDeploymentAndKey(parentDeploymentId, caseDefinitionKey, tenantId);
}
if (caseDefinition == null) {
caseDefinition = caseDefinitionEntityManager.findLatestCaseDefinitionByKeyAndTenantId(caseDefinitionKey, tenantId);
Expand All @@ -137,7 +137,8 @@ public CaseDefinition resolveCaseDefinition(String caseDefinitionKey, String ten
}
} else {
if (parentDeploymentId != null) {
caseDefinition = caseDefinitionEntityManager.findCaseDefinitionByParentDeploymentAndKey(parentDeploymentId, caseDefinitionKey);
caseDefinition = cmmnEngineConfiguration.getDeploymentManager()
.findCaseDefinitionByParentDeploymentAndKey(parentDeploymentId, caseDefinitionKey, tenantId);
}
if (caseDefinition == null) {
caseDefinition = caseDefinitionEntityManager.findLatestCaseDefinitionByKey(caseDefinitionKey);
Expand Down
Loading
Loading