Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: purely in-memory (non-database) DataManager implementations for various entity types #3531

Closed
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
drop table if exists FLW_RU_BATCH_PART cascade constraints;
drop table if exists FLW_RU_BATCH cascade constraints;
drop table if exists FLW_RU_BATCH_PART cascade;
drop table if exists FLW_RU_BATCH cascade;

drop index if exists FLW_IDX_BATCH_PART;
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,13 @@ protected DM getDataManager() {
return dataManager;
}

protected void setDataManager(DM dataManager) {
/**
* Set the DataManager of this EntityManager
*
* @param dataManager
* The new DataManager of this entity manager
*/
public void setDataManager(DM dataManager) {
this.dataManager = dataManager;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
Expand Down Expand Up @@ -103,6 +102,7 @@
import org.flowable.common.engine.impl.persistence.cache.EntityCacheImpl;
import org.flowable.common.engine.impl.persistence.deploy.DefaultDeploymentCache;
import org.flowable.common.engine.impl.persistence.deploy.DeploymentCache;
import org.flowable.common.engine.impl.persistence.entity.AbstractEntityManager;
import org.flowable.common.engine.impl.persistence.entity.ByteArrayEntityManager;
import org.flowable.common.engine.impl.persistence.entity.PropertyEntityManager;
import org.flowable.common.engine.impl.persistence.entity.TableDataManager;
Expand Down Expand Up @@ -4014,9 +4014,13 @@ public ProcessEngineConfigurationImpl setAttachmentDataManager(AttachmentDataMan
return this;
}

@SuppressWarnings("unchecked")
@Override
public ProcessEngineConfigurationImpl setByteArrayDataManager(ByteArrayDataManager byteArrayDataManager) {
this.byteArrayDataManager = byteArrayDataManager;
if (this.byteArrayEntityManager instanceof AbstractEntityManager) {
((AbstractEntityManager< ? , ByteArrayDataManager>) this.byteArrayEntityManager).setDataManager(byteArrayDataManager);
}
return this;
}

Expand Down Expand Up @@ -4051,17 +4055,25 @@ public ExecutionDataManager getExecutionDataManager() {
return executionDataManager;
}

@SuppressWarnings("unchecked")
public ProcessEngineConfigurationImpl setExecutionDataManager(ExecutionDataManager executionDataManager) {
this.executionDataManager = executionDataManager;
if (this.executionEntityManager instanceof AbstractEntityManager) {
((AbstractEntityManager< ? , ExecutionDataManager>) this.executionEntityManager).setDataManager(executionDataManager);
}
return this;
}

public ActivityInstanceDataManager getActivityInstanceDataManager() {
return activityInstanceDataManager;
}

@SuppressWarnings("unchecked")
public ProcessEngineConfigurationImpl setActivityInstanceDataManager(ActivityInstanceDataManager activityInstanceDataManager) {
this.activityInstanceDataManager = activityInstanceDataManager;
if (this.activityInstanceEntityManager instanceof AbstractEntityManager) {
((AbstractEntityManager< ? , ActivityInstanceDataManager>) this.activityInstanceEntityManager).setDataManager(activityInstanceDataManager);
}
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,11 @@ public void deleteProcessInstancesByProcessDefinition(String processDefinitionId
List<String> processInstanceIds = dataManager.findProcessInstanceIdsByProcessDefinitionId(processDefinitionId);

for (String processInstanceId : processInstanceIds) {
deleteProcessInstanceCascade(findById(processInstanceId), deleteReason, cascade, true);
ExecutionEntity execution = findById(processInstanceId);
if (execution == null) {
continue;
}
deleteProcessInstanceCascade(execution, deleteReason, cascade, true);
}

if (cascade) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.util.UUID;

import org.flowable.common.engine.impl.AbstractServiceConfiguration;
import org.flowable.common.engine.impl.persistence.entity.AbstractEntityManager;
import org.flowable.eventsubscription.service.impl.EventSubscriptionServiceImpl;
import org.flowable.eventsubscription.service.impl.persistence.entity.EventSubscriptionEntityManager;
import org.flowable.eventsubscription.service.impl.persistence.entity.EventSubscriptionEntityManagerImpl;
Expand All @@ -33,33 +34,34 @@ public class EventSubscriptionServiceConfiguration extends AbstractServiceConfig
// /////////////////////////////////////////////////////////////////

protected EventSubscriptionService eventSubscriptionService = new EventSubscriptionServiceImpl(this);

// DATA MANAGERS
// /////////////////////////////////////////////////

protected EventSubscriptionDataManager eventSubscriptionDataManager;

// ENTITY MANAGERS
// ///////////////////////////////////////////////

protected EventSubscriptionEntityManager eventSubscriptionEntityManager;

// LOCKING
// //////////////////////////////////////////////

/**
* The amount of time an event subscription is locked.
* A lock on an event subscription is used when using the 'unique process/case instance on start' feature.
* The amount of time an event subscription is locked. A lock on an event
* subscription is used when using the 'unique process/case instance on
* start' feature.
*/
private Duration eventSubscriptionLockTime = Duration.ofMinutes(10);

/**
* The value that should be used when locking eventsubscriptions.
*/
private String lockOwner = UUID.randomUUID().toString();

protected ObjectMapper objectMapper;

public EventSubscriptionServiceConfiguration(String engineName) {
super(engineName);
}
Expand Down Expand Up @@ -93,7 +95,7 @@ public void initEntityManagers() {
public EventSubscriptionServiceConfiguration getIdentityLinkServiceConfiguration() {
return this;
}

public EventSubscriptionService getEventSubscriptionService() {
return eventSubscriptionService;
}
Expand All @@ -102,16 +104,20 @@ public EventSubscriptionServiceConfiguration setEventSubscriptionService(EventSu
this.eventSubscriptionService = eventSubscriptionService;
return this;
}

public EventSubscriptionDataManager getEventSubscriptionDataManager() {
return eventSubscriptionDataManager;
}

@SuppressWarnings("unchecked")
public EventSubscriptionServiceConfiguration setEventSubscriptionDataManager(EventSubscriptionDataManager eventSubscriptionDataManager) {
this.eventSubscriptionDataManager = eventSubscriptionDataManager;
if (this.eventSubscriptionEntityManager instanceof AbstractEntityManager) {
((AbstractEntityManager< ? , EventSubscriptionDataManager>) this.eventSubscriptionEntityManager).setDataManager(eventSubscriptionDataManager);
}
return this;
}

public EventSubscriptionEntityManager getEventSubscriptionEntityManager() {
return eventSubscriptionEntityManager;
}
Expand All @@ -120,7 +126,7 @@ public EventSubscriptionServiceConfiguration setEventSubscriptionEntityManager(E
this.eventSubscriptionEntityManager = eventSubscriptionEntityManager;
return this;
}

@Override
public ObjectMapper getObjectMapper() {
return objectMapper;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import org.flowable.common.engine.impl.AbstractServiceConfiguration;
import org.flowable.common.engine.impl.history.HistoryLevel;
import org.flowable.common.engine.impl.persistence.entity.AbstractEntityManager;
import org.flowable.identitylink.service.impl.HistoricIdentityLinkServiceImpl;
import org.flowable.identitylink.service.impl.IdentityLinkServiceImpl;
import org.flowable.identitylink.service.impl.persistence.entity.HistoricIdentityLinkEntityManager;
Expand Down Expand Up @@ -134,8 +135,12 @@ public IdentityLinkDataManager getIdentityLinkDataManager() {
return identityLinkDataManager;
}

@SuppressWarnings("unchecked")
public IdentityLinkServiceConfiguration setIdentityLinkDataManager(IdentityLinkDataManager identityLinkDataManager) {
this.identityLinkDataManager = identityLinkDataManager;
if (this.identityLinkEntityManager instanceof AbstractEntityManager) {
((AbstractEntityManager< ? , IdentityLinkDataManager>) this.identityLinkEntityManager).setDataManager(identityLinkDataManager);
}
return this;
}

Expand Down
58 changes: 58 additions & 0 deletions modules/flowable-inmemory-data/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<name>Flowable - In Memory DataManagers</name>
<artifactId>flowable-inmemory-data</artifactId>

<packaging>jar</packaging>

<parent>
<groupId>org.flowable</groupId>
<artifactId>flowable-root</artifactId>
<relativePath>../..</relativePath>
<version>7.1.0-SNAPSHOT</version>
</parent>

<dependencies>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-engine</artifactId>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-cmmn-engine</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/* 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.engine.data.inmemory;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.flowable.common.engine.api.query.Query.NullHandlingOnOrder;
import org.flowable.common.engine.impl.db.ListQueryParameterObject;
import org.flowable.common.engine.impl.db.ListQueryParameterObject.OrderBy;

/**
* Abstract base for various {@link Entity} comparator implementations.
*
* @author ikaakkola (Qvantel Finland Oy)
*/
public abstract class AbstractEntityComparator {

private static final String NULL_HANDLING_FIRST = "FIRST";

private static final String ORDER_BY = "order by "; // trailing space on
// purpose

protected int compareString(String s1, String s2, String direction, NullHandlingOnOrder nullHandling) {
if (s1 == null && s2 == null) {
return 0;
}
if (s1 == null) {
return NullHandlingOnOrder.NULLS_FIRST == nullHandling ? -1 : 1;
}
if (s2 == null) {
return NullHandlingOnOrder.NULLS_FIRST == nullHandling ? 1 : -1;
}
int i = s1.compareTo(s2);
return ListQueryParameterObject.SORTORDER_ASC.equals(direction) ? i : -i;
}

protected static int compareDate(Date d1, Date d2, String direction, NullHandlingOnOrder nullHandling) {
if (d1 == null && d2 == null) {
return 0;
}
if (d1 == null) {
return NullHandlingOnOrder.NULLS_FIRST == nullHandling ? -1 : 1;
}
if (d2 == null) {
return NullHandlingOnOrder.NULLS_FIRST == nullHandling ? 1 : -1;
}
int i = d1.compareTo(d2);
return ListQueryParameterObject.SORTORDER_ASC.equals(direction) ? i : -i;
}

protected static int compareLong(Long l1, Long l2, String direction, NullHandlingOnOrder nullHandling) {
if (l1 == null && l2 == null) {
return 0;
}
if (l1 == null) {
return NullHandlingOnOrder.NULLS_FIRST == nullHandling ? -1 : 1;
}
if (l2 == null) {
return NullHandlingOnOrder.NULLS_FIRST == nullHandling ? 1 : -1;
}
int i = l1.compareTo(l2);
return ListQueryParameterObject.SORTORDER_ASC.equals(direction) ? i : -i;
}

protected static int compareInt(Integer l1, Integer l2, String direction, NullHandlingOnOrder nullHandling) {
if (l1 == null && l2 == null) {
return 0;
}
if (l1 == null) {
return NullHandlingOnOrder.NULLS_FIRST == nullHandling ? -1 : 1;
}
if (l2 == null) {
return NullHandlingOnOrder.NULLS_FIRST == nullHandling ? 1 : -1;
}
int i = l1.compareTo(l2);
return ListQueryParameterObject.SORTORDER_ASC.equals(direction) ? i : -i;
}

protected static List<OrderBy> resolveOrderBy(String orderBy) {

List<OrderBy> result = null;
if (orderBy != null) {
String[] parts = StringUtils.split(orderBy, ',');
for (String part : parts) {
if (part.startsWith(ORDER_BY)) {
part = part.substring(ORDER_BY.length());
}
String[] values = StringUtils.split(part, ' ');
if (values.length != 2 && values.length != 4) {
throw new IllegalArgumentException(
"Unsupported sort '" + part + "', expected 2 or 4 parts ('column direction') but got " + values.length + " instead!");
}
if (result == null) {
result = new ArrayList<>();
}
result.add(new OrderBy(StringUtils.trim(values[0]), StringUtils.trim(values[1]), values.length > 3 ? resolveNullHandling(values[3]) : null));
}
}

return result;
}

protected static NullHandlingOnOrder resolveNullHandling(String firstOrLast) {
return NULL_HANDLING_FIRST.equalsIgnoreCase(firstOrLast) ? NullHandlingOnOrder.NULLS_FIRST : NullHandlingOnOrder.NULLS_LAST;
}
}
Loading