Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/* 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.test;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;

import java.util.Map;

import org.flowable.common.engine.impl.cfg.CommandExecutorImpl;
import org.flowable.common.engine.impl.db.DbSqlSessionFactory;
import org.flowable.common.engine.impl.interceptor.CommandExecutor;
import org.flowable.common.engine.impl.interceptor.CommandInterceptor;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.test.profiler.FlowableProfiler;
import org.flowable.engine.test.profiler.ProfilingDbSqlSessionFactory;
import org.flowable.engine.test.profiler.TotalExecutionTimeCommandInterceptor;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledIfSystemProperty;

/**
* @author Filip Hrisafov
*/
@DisabledIfSystemProperty(named = "disableWhen", matches = "cockroachdb")
public class VerifyDatabaseOperationsTest extends AbstractProcessEngineIntegrationTest {

protected DbSqlSessionFactory oldDbSqlSessionFactory;

@BeforeEach
protected void setUp() {
// The process and the CMMN engine share the session factories
ProcessEngineConfigurationImpl processEngineConfigurationImpl = (ProcessEngineConfigurationImpl) processEngineConfiguration;
this.oldDbSqlSessionFactory = processEngineConfigurationImpl.getDbSqlSessionFactory();
DbSqlSessionFactory newDbSqlSessionFactory = new ProfilingDbSqlSessionFactory(processEngineConfigurationImpl.isUsePrefixId());
newDbSqlSessionFactory.setBulkInserteableEntityClasses(oldDbSqlSessionFactory.getBulkInserteableEntityClasses());
newDbSqlSessionFactory.setInsertionOrder(oldDbSqlSessionFactory.getInsertionOrder());
newDbSqlSessionFactory.setDeletionOrder(oldDbSqlSessionFactory.getDeletionOrder());
newDbSqlSessionFactory.setDatabaseType(oldDbSqlSessionFactory.getDatabaseType());
newDbSqlSessionFactory.setDatabaseTablePrefix(oldDbSqlSessionFactory.getDatabaseTablePrefix());
newDbSqlSessionFactory.setTablePrefixIsSchema(oldDbSqlSessionFactory.isTablePrefixIsSchema());
newDbSqlSessionFactory.setDatabaseCatalog(oldDbSqlSessionFactory.getDatabaseCatalog());
newDbSqlSessionFactory.setDatabaseSchema(oldDbSqlSessionFactory.getDatabaseSchema());
newDbSqlSessionFactory.setSqlSessionFactory(oldDbSqlSessionFactory.getSqlSessionFactory());
newDbSqlSessionFactory.setDbHistoryUsed(oldDbSqlSessionFactory.isDbHistoryUsed());
newDbSqlSessionFactory.setDatabaseSpecificStatements(oldDbSqlSessionFactory.getDatabaseSpecificStatements());
newDbSqlSessionFactory.setLogicalNameToClassMapping(oldDbSqlSessionFactory.getLogicalNameToClassMapping());
processEngineConfigurationImpl.addSessionFactory(newDbSqlSessionFactory);
}

@AfterEach
protected void tearDown() {
((ProcessEngineConfigurationImpl) processEngineConfiguration).addSessionFactory(oldDbSqlSessionFactory);
FlowableProfiler.getInstance().reset();
}

@Test
public void testCaseWithProcessTaskFromSameDeployment() {
processEngineRepositoryService.createDeployment()
.addClasspathResource("org/flowable/cmmn/test/processTaskSameDeploymentTrue.cmmn")
.addClasspathResource("org/flowable/cmmn/test/oneTaskProcess.bpmn20.xml")
.deploy();

Map<String, Long> selects = profileDatabaseSelects(cmmnEngineConfiguration.getCommandExecutor(), "org.flowable.cmmn.engine.impl.cmd.StartCaseInstanceCmd",
() -> cmmnRuntimeService.createCaseInstanceBuilder()
.caseDefinitionKey("oneProcessTaskCase")
.start());

// The cached case definition has the parent deployment id, so the CMMN deployment is not selected
assertThat(selects).containsOnly(
entry("selectLatestCaseDefinitionByKey", 1L),
entry("selectProcessDefinitionByParentDeploymentAndKey", 1L),
entry("selectProcessDefinitionInfoByProcessDefinitionId", 1L),
entry("selectPlanItemInstancesByCaseInstanceIdAndPlanItemId", 1L),
entry("selectEntityLinksByQuery", 2L)
);
assertThat(processEngineRuntimeService.createProcessInstanceQuery().count()).isOne();
}

@Test
public void testCaseWithCaseTaskFromSameDeployment() {
cmmnRepositoryService.createDeployment()
.addClasspathResource("org/flowable/cmmn/test/caseTaskSameDeploymentTrue.cmmn")
.addClasspathResource("org/flowable/cmmn/test/oneHumanTaskCase.cmmn")
.deploy();

Map<String, Long> selects = profileDatabaseSelects(cmmnEngineConfiguration.getCommandExecutor(), "org.flowable.cmmn.engine.impl.cmd.StartCaseInstanceCmd",
() -> cmmnRuntimeService.createCaseInstanceBuilder()
.caseDefinitionKey("oneCaseTaskCase")
.start());

// The cached case definition has the parent deployment id, so the CMMN deployment is not selected
assertThat(selects).containsOnly(
entry("selectLatestCaseDefinitionByKey", 1L),
entry("selectCaseDefinitionByParentDeploymentAndKey", 1L),
entry("selectPlanItemInstancesByCaseInstanceIdAndPlanItemId", 2L),
entry("selectEntityLinksByQuery", 2L)
);
assertThat(cmmnRuntimeService.createCaseInstanceQuery().caseDefinitionKey("oneHumanTaskCase").count()).isOne();
}

@Test
public void testProcessWithCaseTaskFromSameDeployment() {
processEngineRepositoryService.createDeployment()
.addClasspathResource("org/flowable/cmmn/test/caseTaskProcessWithSameDeployment.bpmn20.xml")
.addClasspathResource("org/flowable/cmmn/test/oneHumanTaskCase.cmmn")
.deploy();

Map<String, Long> selects = profileDatabaseSelects(processEngineConfiguration.getCommandExecutor(), "org.flowable.engine.impl.cmd.StartProcessInstanceCmd",
() -> processEngineRuntimeService.createProcessInstanceBuilder()
.processDefinitionKey("caseTask")
.start());

// The cached process definition has the parent deployment id, so the process deployment is not selected
assertThat(selects).containsOnly(
entry("selectLatestProcessDefinitionByKey", 1L),
entry("selectCaseDefinitionByParentDeploymentAndKey", 1L),
entry("selectProcessDefinitionInfoByProcessDefinitionId", 1L),
entry("selectPlanItemInstancesByCaseInstanceIdAndPlanItemId", 1L),
entry("selectEntityLinksByQuery", 2L)
);
assertThat(cmmnRuntimeService.createCaseInstanceQuery().count()).isOne();
}

protected Map<String, Long> profileDatabaseSelects(CommandExecutor commandExecutor, String commandClass, Runnable runnable) {
// Only the outer command is profiled, the commands of the other engine reuse its command context
CommandExecutorImpl commandExecutorImpl = (CommandExecutorImpl) commandExecutor;
CommandInterceptor oldFirstCommandInterceptor = commandExecutorImpl.getFirst();
TotalExecutionTimeCommandInterceptor timeCommandInterceptor = new TotalExecutionTimeCommandInterceptor();
timeCommandInterceptor.setNext(oldFirstCommandInterceptor);
commandExecutorImpl.setFirst(timeCommandInterceptor);

FlowableProfiler profiler = FlowableProfiler.getInstance();
profiler.reset();
profiler.startProfileSession("Profiling session");
try {
runnable.run();
} finally {
profiler.stopCurrentProfileSession();
commandExecutorImpl.setFirst(oldFirstCommandInterceptor);
}

return profiler.getProfileSessions().get(0).calculateSummaryStatistics().get(commandClass).getDbSelects();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/CMMN/20151109/MODEL"
xmlns:flowable="http://flowable.org/cmmn"
targetNamespace="http://flowable.org/cmmn">

<case id="oneCaseTaskCase">
<casePlanModel id="myPlanModel" name="My CasePlanModel">

<planItem id="planItem1" name="The Case" definitionRef="theCase"/>

<caseTask id="theCase" caseRef="oneHumanTaskCase" flowable:sameDeployment="true"/>

</casePlanModel>
</case>

</definitions>
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import java.util.Set;

import org.flowable.cmmn.api.repository.CaseDefinition;
import org.flowable.cmmn.api.repository.CmmnDeployment;
import org.flowable.cmmn.engine.impl.repository.CaseDefinitionUtil;
import org.flowable.cmmn.engine.impl.util.CommandContextUtil;
import org.flowable.cmmn.model.Case;
Expand Down Expand Up @@ -96,16 +95,11 @@ protected List<DmnDecision> getDecisionsFromModel(Case caseModel, CaseDefinition

protected void addDecisionToCollection(List<DmnDecision> decisions, String decisionKey, CaseDefinition caseDefinition) {
DmnDecisionQuery definitionQuery = dmnRepositoryService.createDecisionQuery().decisionKey(decisionKey);
CmmnDeployment deployment = CommandContextUtil.getCmmnDeploymentEntityManager().findById(caseDefinition.getDeploymentId());
if (deployment.getParentDeploymentId() != null) {
List<DmnDeployment> dmnDeployments = dmnRepositoryService.createDeploymentQuery().parentDeploymentId(deployment.getParentDeploymentId()).list();

if (dmnDeployments != null && dmnDeployments.size() > 0) {
definitionQuery.deploymentId(dmnDeployments.get(0).getId());
} else {
definitionQuery.latestVersion();
}

String parentDeploymentId = CaseDefinitionUtil.getDefinitionDeploymentId(caseDefinition, CommandContextUtil.getCmmnEngineConfiguration());
List<DmnDeployment> dmnDeployments = dmnRepositoryService.createDeploymentQuery().parentDeploymentId(parentDeploymentId).list();

if (!dmnDeployments.isEmpty()) {
definitionQuery.deploymentId(dmnDeployments.get(0).getId());
} else {
definitionQuery.latestVersion();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

import org.apache.commons.lang3.StringUtils;
import org.flowable.cmmn.api.repository.CaseDefinition;
import org.flowable.cmmn.api.repository.CmmnDeployment;
import org.flowable.cmmn.engine.impl.repository.CaseDefinitionUtil;
import org.flowable.cmmn.engine.impl.util.CommandContextUtil;
import org.flowable.cmmn.model.Case;
Expand Down Expand Up @@ -94,16 +93,11 @@ protected List<FormDefinition> getFormDefinitionsFromModel(Case caseModel, CaseD

protected void addFormDefinitionToCollection(List<FormDefinition> formDefinitions, String formKey, CaseDefinition caseDefinition) {
FormDefinitionQuery formDefinitionQuery = formRepositoryService.createFormDefinitionQuery().formDefinitionKey(formKey);
CmmnDeployment deployment = CommandContextUtil.getCmmnDeploymentEntityManager().findById(caseDefinition.getDeploymentId());
if (deployment.getParentDeploymentId() != null) {
List<FormDeployment> formDeployments = formRepositoryService.createDeploymentQuery().parentDeploymentId(deployment.getParentDeploymentId()).list();

if (formDeployments != null && formDeployments.size() > 0) {
formDefinitionQuery.deploymentId(formDeployments.get(0).getId());
} else {
formDefinitionQuery.latestVersion();
}

String parentDeploymentId = CaseDefinitionUtil.getDefinitionDeploymentId(caseDefinition, CommandContextUtil.getCmmnEngineConfiguration());
List<FormDeployment> formDeployments = formRepositoryService.createDeploymentQuery().parentDeploymentId(parentDeploymentId).list();

if (!formDeployments.isEmpty()) {
formDefinitionQuery.deploymentId(formDeployments.get(0).getId());
} else {
formDefinitionQuery.latestVersion();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

import org.apache.commons.lang3.StringUtils;
import org.flowable.cmmn.api.repository.CaseDefinition;
import org.flowable.cmmn.api.repository.CmmnDeployment;
import org.flowable.cmmn.engine.CmmnEngineConfiguration;
import org.flowable.cmmn.engine.impl.repository.CaseDefinitionUtil;
import org.flowable.cmmn.engine.impl.util.CommandContextUtil;
Expand Down Expand Up @@ -62,8 +61,8 @@ public FormInfo execute(CommandContext commandContext) {
Stage planModel = caseModel.getPlanModel();

if (StringUtils.isNotEmpty(planModel.getFormKey())) {
CmmnDeployment deployment = CommandContextUtil.getCmmnDeploymentEntityManager(commandContext).findById(caseDefinition.getDeploymentId());
formInfo = formService.getFormInstanceModelByKeyAndParentDeploymentIdAndScopeId(planModel.getFormKey(), deployment.getParentDeploymentId(),
String parentDeploymentId = CaseDefinitionUtil.getDefinitionDeploymentId(caseDefinition, cmmnEngineConfiguration);
formInfo = formService.getFormInstanceModelByKeyAndParentDeploymentIdAndScopeId(planModel.getFormKey(), parentDeploymentId,
caseInstanceId, ScopeTypes.CMMN, null, caseDefinition.getTenantId(), cmmnEngineConfiguration.isFallbackToDefaultTenant());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,12 +275,14 @@ protected void verifyCaseDefinitionsDoNotShareKeys(Collection<CaseDefinitionEnti
protected void copyDeploymentValuesToCaseDefinitions(EngineDeployment deployment, List<CaseDefinitionEntity> caseDefinitionEntities) {
String tenantId = deployment.getTenantId();
String deploymentId = deployment.getId();
String parentDeploymentId = ((CmmnDeploymentEntity) deployment).getParentDeploymentId();

for (CaseDefinitionEntity caseDefinitionEntity : caseDefinitionEntities) {
if (tenantId != null) {
caseDefinitionEntity.setTenantId(tenantId);
}
caseDefinitionEntity.setDeploymentId(deploymentId);
caseDefinitionEntity.setParentDeploymentId(parentDeploymentId);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,13 @@ public interface CaseDefinitionEntity extends Entity, CaseDefinition {

void setTenantId(String tenantId);

/**
* The parent deployment id of the deployment of this case definition.
* This is not persisted, it is only set on the case definitions that are put in the case definition cache.
*/
String getParentDeploymentId();

void setParentDeploymentId(String parentDeploymentId);

List<IdentityLinkEntity> getIdentityLinks();
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ public class CaseDefinitionEntityImpl extends AbstractCmmnEngineEntity implement
protected List<IdentityLinkEntity> definitionIdentityLinkEntities = new ArrayList<>();
protected String localizedName;
protected String localizedDescription;

// Not persisted, set by the deployer
protected String parentDeploymentId;

@Override
public Object getPersistentState() {
Expand Down Expand Up @@ -198,4 +201,14 @@ public String getLocalizedDescription() {
public void setLocalizedDescription(String localizedDescription) {
this.localizedDescription = localizedDescription;
}

@Override
public String getParentDeploymentId() {
return parentDeploymentId;
}

@Override
public void setParentDeploymentId(String parentDeploymentId) {
this.parentDeploymentId = parentDeploymentId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.flowable.cmmn.api.repository.CaseDefinition;
import org.flowable.cmmn.engine.CmmnEngineConfiguration;
import org.flowable.cmmn.engine.impl.deployer.CmmnDeploymentManager;
import org.flowable.cmmn.engine.impl.persistence.entity.CaseDefinitionEntity;
import org.flowable.cmmn.engine.impl.persistence.entity.CmmnDeploymentEntity;
import org.flowable.cmmn.engine.impl.persistence.entity.deploy.CaseDefinitionCacheEntry;
import org.flowable.cmmn.engine.impl.util.CommandContextUtil;
Expand Down Expand Up @@ -46,12 +47,33 @@ public static String getDefinitionDeploymentId(String caseDefinitionId, CmmnEngi

public static String getDefinitionDeploymentId(CaseDefinition caseDefinition, CmmnEngineConfiguration cmmnEngineConfiguration) {
CmmnDeploymentManager deploymentManager = cmmnEngineConfiguration.getDeploymentManager();
String parentDeploymentId = getParentDeploymentId(caseDefinition);
if (parentDeploymentId == null) {
// A case definition loaded from the database does not have the parent deployment id, the cached one has it
CaseDefinitionCacheEntry cacheEntry = deploymentManager.getCaseDefinitionCache().get(caseDefinition.getId());
if (cacheEntry != null) {
parentDeploymentId = getParentDeploymentId(cacheEntry.getCaseDefinition());
}
}

if (parentDeploymentId != null) {
return parentDeploymentId;
}

CmmnDeploymentEntity caseDeployment = deploymentManager.getDeploymentEntityManager().findById(caseDefinition.getDeploymentId());
if (StringUtils.isEmpty(caseDeployment.getParentDeploymentId())) {
return caseDefinition.getDeploymentId();
}
return caseDeployment.getParentDeploymentId();
}

protected static String getParentDeploymentId(CaseDefinition caseDefinition) {
if (caseDefinition instanceof CaseDefinitionEntity caseDefinitionEntity
&& StringUtils.isNotEmpty(caseDefinitionEntity.getParentDeploymentId())) {
return caseDefinitionEntity.getParentDeploymentId();
}
return null;
}

protected static CaseDefinition getCaseDefinition(String caseDefinitionId, CmmnDeploymentManager deploymentManager, CaseDefinitionCacheEntry cacheEntry) {
if (cacheEntry != null) {
Expand Down
Loading
Loading