Skip to content

Commit

Permalink
Merge branch 'main' of github.com:flowable/flowable-engine into flowa…
Browse files Browse the repository at this point in the history
…ble-release-7.0.0
  • Loading branch information
tijsrademakers committed Sep 1, 2023
2 parents b129092 + 5ebb788 commit f9187b6
Show file tree
Hide file tree
Showing 53 changed files with 1,436 additions and 67 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Flowable (V6)
Flowable (V7)
========

[Maven Central:
Expand Down Expand Up @@ -33,9 +33,11 @@ The Flowable downloads can be found on https://www.flowable.org/downloads.html.

The distribution contains most of the sources as jar files. The source code of Flowable can be found on https://github.com/flowable/flowable-engine.

### JDK 8+
### JDK 17+

Flowable runs on a JDK higher than or equal to version 8. Use the JDK packaged with your Linux distribution or go to [adoptium.net](https://adoptium.net/) and click on the *Latest LTS Release* button. There are installation instructions on that page as well. To verify that your installation was successful, run `java -version` on the command line. That should print the installed version of your JDK.
Flowable V7 runs on a Java higher than or equal to version 17. Use the JDK packaged with your Linux distribution or go to [adoptium.net](https://adoptium.net/) and click on the *Latest LTS Release* button. There are installation instructions on that page as well. To verify that your installation was successful, run `java -version` on the command line. That should print the installed version of your JDK.

[Flowable V6](https://github.com/flowable/flowable-engine/tree/flowable6.x) is still maintained and supports Java 8+.

### Contributing

Expand Down
12 changes: 6 additions & 6 deletions distro/src/notice.txt
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ org.apache.httpcomponents httpclient 4.5.13 Apac
org.apache.httpcomponents httpcore 4.4.15 Apache License, Version 2.0
org.apache.httpcomponents httpmime 4.5.13 Apache License, Version 2.0
org.apache.geronimo.bundles json 20090211_1 The Apache Software License, Version 2.0
org.apache.groovy groovy 4.0.13 The Apache Software License, Version 2.0
org.apache.groovy groovy-jsr223 4.0.13 The Apache Software License, Version 2.0
org.apache.groovy groovy 4.0.14 The Apache Software License, Version 2.0
org.apache.groovy groovy-jsr223 4.0.14 The Apache Software License, Version 2.0
org.eclipse.angus angus-mail 2.0.2 EDL 1.0 / EPL 2.0
org.liquibase liquibase-core 4.5.0 Apache License, Version 2.0
org.mybatis mybatis 3.5.11 The Apache Software License, Version 2.0
Expand All @@ -119,10 +119,10 @@ org.springframework spring-aop 6.0.11 The
org.springframework spring-core 6.0.11 The Apache Software License, Version 2.0
org.springframework spring-expression 6.0.11 The Apache Software License, Version 2.0
org.springframework spring-orm 6.0.11 The Apache Software License, Version 2.0
org.springframework.security spring-security-config 6.1.2 The Apache Software License, Version 2.0
org.springframework.security spring-security-core 6.1.2 The Apache Software License, Version 2.0
org.springframework.security spring-security-crypto 6.1.2 The Apache Software License, Version 2.0
org.springframework.security spring-security-web 6.1.2 The Apache Software License, Version 2.0
org.springframework.security spring-security-config 6.1.3 The Apache Software License, Version 2.0
org.springframework.security spring-security-core 6.1.3 The Apache Software License, Version 2.0
org.springframework.security spring-security-crypto 6.1.3 The Apache Software License, Version 2.0
org.springframework.security spring-security-web 6.1.3 The Apache Software License, Version 2.0
org.tinyjee.jgraphx jgraphx 1.10.4.1 JGraph Ltd - 3 clause BSD license
org.yaml snakeyaml 1.17 The Apache Software License, Version 2.0
xerces xercesImpl 2.12.1 The Apache Software License, Version 2.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,16 @@ public interface CmmnManagementService {
*/
CmmnExternalWorkerTransitionBuilder createCmmnExternalWorkerTransitionBuilder(String externalJobId, String workerId);

/**
* Unaquire a locked external worker job.
*/
void unacquireExternalWorkerJob(String jobId, String workerId);

/**
* Unaquire all locked external worker jobs for worker.
*/
void unacquireAllExternalWorkerJobsForWorker(String workerId);

/**
* Create a {@link ChangeTenantIdBuilder} that can be used to change the tenant id of the case instances
* and all the related instances. See {@link CmmnChangeTenantIdEntityTypes} for related instances.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@
import org.flowable.job.service.impl.cmd.MoveTimerToExecutableJobCmd;
import org.flowable.job.service.impl.cmd.SetJobRetriesCmd;
import org.flowable.job.service.impl.cmd.SetTimerJobRetriesCmd;
import org.flowable.job.service.impl.cmd.UnacquireAllExternalWorkerJobsForWorkerCmd;
import org.flowable.job.service.impl.cmd.UnacquireExternalWorkerJobCmd;

/**
* @author Joram Barrez
Expand Down Expand Up @@ -294,6 +296,16 @@ public CmmnExternalWorkerTransitionBuilder createCmmnExternalWorkerTransitionBui
return new CmmnExternalWorkerTransitionBuilderImpl(commandExecutor, externalJobId, workerId);
}

@Override
public void unacquireExternalWorkerJob(String jobId, String workerId) {
commandExecutor.execute(new UnacquireExternalWorkerJobCmd(jobId, workerId, configuration.getJobServiceConfiguration()));
}

@Override
public void unacquireAllExternalWorkerJobsForWorker(String workerId) {
commandExecutor.execute(new UnacquireAllExternalWorkerJobsForWorkerCmd(workerId, configuration.getJobServiceConfiguration()));
}

@Override
public ChangeTenantIdBuilder createChangeTenantIdBuilder(String fromTenantId, String toTenantId) {
return new ChangeTenantIdBuilderImpl(fromTenantId, toTenantId, configuration.getChangeTenantIdManager());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,14 @@
import org.flowable.cmmn.api.repository.CaseDefinition;
import org.flowable.cmmn.api.runtime.CaseInstanceBuilder;
import org.flowable.cmmn.api.runtime.CaseInstanceQuery;
import org.flowable.cmmn.api.runtime.PlanItemInstanceState;
import org.flowable.cmmn.converter.CmmnXmlConstants;
import org.flowable.cmmn.engine.CmmnEngineConfiguration;
import org.flowable.cmmn.engine.impl.persistence.entity.PlanItemInstanceEntity;
import org.flowable.cmmn.model.CmmnModel;
import org.flowable.cmmn.model.EventListener;
import org.flowable.cmmn.model.ExtensionElement;
import org.flowable.cmmn.model.PlanItem;
import org.flowable.common.engine.api.constant.ReferenceTypes;
import org.flowable.common.engine.api.scope.ScopeTypes;
import org.flowable.common.engine.impl.lock.LockManager;
Expand Down Expand Up @@ -76,23 +80,37 @@ protected EventRegistryProcessingInfo eventReceived(EventInstance eventInstance)
for (EventSubscription eventSubscription : eventSubscriptions) {
EventConsumerInfo eventConsumerInfo = new EventConsumerInfo(eventSubscription.getId(), eventSubscription.getSubScopeId(),
eventSubscription.getScopeDefinitionId(), ScopeTypes.CMMN);
handleEventSubscription(cmmnRuntimeService, eventSubscription, eventInstance, correlationKeys, eventConsumerInfo);
eventRegistryProcessingInfo.addEventConsumerInfo(eventConsumerInfo);
boolean eventSubscriptionHandled = handleEventSubscription(cmmnRuntimeService, eventSubscription, eventInstance, correlationKeys, eventConsumerInfo);

if (eventSubscriptionHandled) {
eventRegistryProcessingInfo.addEventConsumerInfo(eventConsumerInfo);
}
}

return eventRegistryProcessingInfo;
}

protected void handleEventSubscription(CmmnRuntimeService cmmnRuntimeService, EventSubscription eventSubscription,
protected boolean handleEventSubscription(CmmnRuntimeService cmmnRuntimeService, EventSubscription eventSubscription,
EventInstance eventInstance, Collection<CorrelationKey> correlationKeys, EventConsumerInfo eventConsumerInfo) {

if (eventSubscription.getSubScopeId() != null) {

// When a subscope id is set, this means that a plan item instance is waiting for the event

cmmnRuntimeService.createPlanItemInstanceTransitionBuilder(eventSubscription.getSubScopeId())
.transientVariable(EventConstants.EVENT_INSTANCE, eventInstance)
.trigger();
PlanItemInstanceEntity planItemInstanceEntity = (PlanItemInstanceEntity) cmmnRuntimeService.createPlanItemInstanceQuery().planItemInstanceId(eventSubscription.getSubScopeId()).singleResult();
CmmnModel cmmnModel = cmmnEngineConfiguration.getCmmnRepositoryService().getCmmnModel(planItemInstanceEntity.getCaseDefinitionId());
PlanItem planItem = cmmnModel.findPlanItemByPlanItemDefinitionId(planItemInstanceEntity.getPlanItemDefinitionId());
if (PlanItemInstanceState.ACTIVE.equals(planItemInstanceEntity.getState())
|| (planItem != null && planItem.getPlanItemDefinition() instanceof EventListener
&& PlanItemInstanceState.AVAILABLE.equals(planItemInstanceEntity.getState()))) {

cmmnRuntimeService.createPlanItemInstanceTransitionBuilder(eventSubscription.getSubScopeId())
.transientVariable(EventConstants.EVENT_INSTANCE, eventInstance)
.trigger();

} else {
return false;
}

} else if (eventSubscription.getScopeDefinitionId() != null
&& eventSubscription.getScopeId() == null
Expand Down Expand Up @@ -122,7 +140,7 @@ protected void handleEventSubscription(CmmnRuntimeService cmmnRuntimeService, Ev
// Returning, no new instance should be started
eventConsumerInfo.setHasExistingInstancesForUniqueCorrelation(true);
LOGGER.debug("Event received to start a new case instance, but a unique instance already exists.");
return;
return true;

} else if (cmmnEngineConfiguration.isEventRegistryUniqueCaseInstanceCheckWithLock()) {

Expand Down Expand Up @@ -161,36 +179,35 @@ protected void handleEventSubscription(CmmnRuntimeService cmmnRuntimeService, Ev
// Returning, no new instance should be started
eventConsumerInfo.setHasExistingInstancesForUniqueCorrelation(true);
LOGGER.debug("Event received to start a new case instance, but a unique instance already exists.");
return;
return true;
}

startCaseInstance(caseInstanceBuilder, correlationKeyWithAllParameters.getValue(), ReferenceTypes.EVENT_CASE);
return;
return true;

} finally {
lockManager.releaseAndDeleteLock();

}

} else {
LOGGER.info(
"Lock for {} was not acquired. This means that another event has already acquired that lock and will start a new case instance. Ignoring this one.",
countLockName);
return;
LOGGER.info("Lock for {} was not acquired. This means that another event has already acquired that lock and will start a new case instance. Ignoring this one.", countLockName);
return true;

}

} else {
startCaseInstance(caseInstanceBuilder, correlationKeyWithAllParameters.getValue(), ReferenceTypes.EVENT_CASE);
return;
return true;
}

}
}

startCaseInstance(caseInstanceBuilder, null, null);

}

return true;
}

protected long countCaseInstances(CmmnRuntimeService cmmnRuntimeService, EventInstance eventInstance,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ protected ChangePlanItemStateBuilderImpl prepareChangeStateBuilder(CaseInstance
CmmnEngineConfiguration cmmnEngineConfiguration = CommandContextUtil.getCmmnEngineConfiguration(commandContext);
if (cmmnEngineConfiguration.isFallbackToDefaultTenant() && cmmnEngineConfiguration.getDefaultTenantProvider() != null) {

if (!Objects.equals(destinationTenantId, cmmnEngineConfiguration.getDefaultTenantProvider().getDefaultTenant(caseInstance.getId(), ScopeTypes.CMMN, caseDefinitionToMigrateTo.getKey()))) {
if (!Objects.equals(destinationTenantId, cmmnEngineConfiguration.getDefaultTenantProvider().getDefaultTenant(caseInstance.getTenantId(), ScopeTypes.CMMN, caseDefinitionToMigrateTo.getKey()))) {
throw new FlowableException("Tenant mismatch between Case Instance ('" + caseInstance.getTenantId() + "') and Case Definition ('" + destinationTenantId + "') to migrate to");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,15 @@
import org.flowable.cmmn.engine.interceptor.CreateCmmnExternalWorkerJobInterceptor;
import org.flowable.cmmn.engine.test.CmmnDeployment;
import org.flowable.cmmn.engine.test.FlowableCmmnTestCase;
import org.flowable.common.engine.api.FlowableException;
import org.flowable.common.engine.api.FlowableIllegalArgumentException;
import org.flowable.common.engine.api.scope.ScopeTypes;
import org.flowable.identitylink.api.IdentityLink;
import org.flowable.identitylink.api.IdentityLinkType;
import org.flowable.identitylink.service.impl.persistence.entity.IdentityLinkEntity;
import org.flowable.job.api.AcquiredExternalWorkerJob;
import org.flowable.job.api.ExternalWorkerJob;
import org.flowable.job.api.ExternalWorkerJobQuery;
import org.flowable.job.api.Job;
import org.flowable.job.service.impl.persistence.entity.JobEntity;
import org.flowable.task.api.TaskInfo;
Expand Down Expand Up @@ -1179,6 +1181,95 @@ public void testAcquireByTenantId() {

cmmnManagementService.createExternalWorkerJobFailureBuilder(acmeJob.getId(), "testWorker").fail();
}

@Test
@CmmnDeployment(resources = "org/flowable/cmmn/test/externalworker/ExternalWorkerServiceTaskTest.testSimple.cmmn")
public void testUnaquireWithJobId() {
cmmnRuntimeService.createCaseInstanceBuilder()
.caseDefinitionKey("simpleExternalWorker")
.start();

cmmnManagementService.createExternalWorkerJobAcquireBuilder()
.topic("simple", Duration.ofMinutes(10))
.acquireAndLock(1, "testWorker1");

ExternalWorkerJobQuery query = cmmnManagementService.createExternalWorkerJobQuery().lockOwner("testWorker1");
assertThat(query.count()).isEqualTo(1);
assertThat(query.list())
.extracting(ExternalWorkerJob::getElementId)
.containsExactlyInAnyOrder("externalWorkerTask");

ExternalWorkerJob job = query.singleResult();

cmmnManagementService.unacquireExternalWorkerJob(job.getId(), "testWorker1");

assertThat(query.count()).isEqualTo(0);

query = cmmnManagementService.createExternalWorkerJobQuery().jobId(job.getId());
job = query.singleResult();
assertThat(job.getLockOwner()).isNull();
assertThat(job.getLockExpirationTime()).isNull();
}

@Test
@CmmnDeployment(resources = "org/flowable/cmmn/test/externalworker/ExternalWorkerServiceTaskTest.testSimple.cmmn")
public void testUnaquireWithJobIdWrongWorkerId() {
cmmnRuntimeService.createCaseInstanceBuilder()
.caseDefinitionKey("simpleExternalWorker")
.start();

cmmnManagementService.createExternalWorkerJobAcquireBuilder()
.topic("simple", Duration.ofMinutes(10))
.acquireAndLock(1, "testWorker1");

ExternalWorkerJobQuery query = cmmnManagementService.createExternalWorkerJobQuery().lockOwner("testWorker1");
assertThat(query.count()).isEqualTo(1);

final ExternalWorkerJob job = query.singleResult();

assertThatThrownBy(() -> {
cmmnManagementService.unacquireExternalWorkerJob(job.getId(), "testWorker2");

}).isInstanceOf(FlowableException.class)
.hasMessageContaining("Job is locked with a different worker id");

cmmnManagementService.unacquireExternalWorkerJob(job.getId(), "testWorker1");
assertThat(query.count()).isEqualTo(0);

query = cmmnManagementService.createExternalWorkerJobQuery().jobId(job.getId());
ExternalWorkerJob unacquiredJob = query.singleResult();
assertThat(unacquiredJob.getLockOwner()).isNull();
assertThat(unacquiredJob.getLockExpirationTime()).isNull();
}

@Test
@CmmnDeployment(resources = "org/flowable/cmmn/test/externalworker/ExternalWorkerServiceTaskTest.testSimple.cmmn")
public void testUnaquireWithWorkerId() {
cmmnRuntimeService.createCaseInstanceBuilder()
.caseDefinitionKey("simpleExternalWorker")
.start();

cmmnManagementService.createExternalWorkerJobAcquireBuilder()
.topic("simple", Duration.ofMinutes(10))
.acquireAndLock(1, "testWorker1");

ExternalWorkerJobQuery query = cmmnManagementService.createExternalWorkerJobQuery().lockOwner("testWorker1");
assertThat(query.count()).isEqualTo(1);
assertThat(query.list())
.extracting(ExternalWorkerJob::getElementId)
.containsExactlyInAnyOrder("externalWorkerTask");

ExternalWorkerJob job = query.singleResult();

cmmnManagementService.unacquireAllExternalWorkerJobsForWorker("testWorker1");

assertThat(query.count()).isEqualTo(0);

query = cmmnManagementService.createExternalWorkerJobQuery().jobId(job.getId());
job = query.singleResult();
assertThat(job.getLockOwner()).isNull();
assertThat(job.getLockExpirationTime()).isNull();
}

protected void addUserIdentityLinkToJob(Job job, String userId) {
cmmnEngineConfiguration.getCommandExecutor()
Expand Down
Loading

0 comments on commit f9187b6

Please sign in to comment.