Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
dd58002
NAE-2182 - Implementation of an endpoint for clearing the action cache
dominikvozr Sep 1, 2025
5b98ca4
NAE-2182 - Implementation of custom cache wrapper to use in cacheManager
dominikvozr Sep 1, 2025
e917f76
NAE-2182 - Implementation of generic map cache and created actuator c…
dominikvozr Sep 2, 2025
bd719b5
NAE-2182 - cache FunctionsNamespace and functions if not found
dominikvozr Sep 3, 2025
e976081
NAE-2182 - prevent multi thread unexpected behaviour and prevent cach…
dominikvozr Sep 4, 2025
8323adb
NAE-2182 - Implementation of generic map cache and changed store for …
dominikvozr Sep 16, 2025
f9796d6
NAE-2182 - removal of unused methods, correction of several issues du…
dominikvozr Sep 16, 2025
d2227d0
NAE-2182 - optimized imports, added helper and refactor code
dominikvozr Sep 25, 2025
cb1505f
Merge remote-tracking branch 'origin/release/7.0.0-rev8' into NAE-2182
machacjozef Sep 30, 2025
c18561f
Merge branch 'NAE-2212' into NAE-2182
renczesstefan Dec 18, 2025
f7b61be
Refactor caching logic in FieldActionsCacheService and improve annota…
renczesstefan Dec 18, 2025
75b903d
Merge branch 'NAE-2266' into NAE-2182
renczesstefan Jan 9, 2026
749db25
Update function to use the default Petri net version
renczesstefan Jan 9, 2026
94724c5
Merge branch 'NAE-2212' into NAE-2182
renczesstefan Jan 9, 2026
0f7bb9b
Merge branch 'NAE-2212' into NAE-2182
renczesstefan Jan 9, 2026
ebaa5a9
Merge remote-tracking branch 'origin/NAE-2182' into NAE-2182
renczesstefan Jan 9, 2026
d573cf2
Refactor function caching property configuration
renczesstefan Jan 9, 2026
4c1cf75
[NAE-2182] Refactor GenericMapCache to use ConcurrentHashMap.computeI…
dominikvozr Jan 9, 2026
89164d5
Merge remote-tracking branch 'origin/release/7.0.0-rev9' into NAE-2182
machacjozef Jan 13, 2026
376da58
- clarified error message in createCaseByIdentifier
renczesstefan Jan 13, 2026
dc1394b
- corrected properties error according to rabbit ai
renczesstefan Jan 13, 2026
299c4f1
- removed trailing white space from functions.md
renczesstefan Jan 13, 2026
a54ea6d
- clarified documentation
renczesstefan Jan 13, 2026
21b597f
- added check for existing petri net version
renczesstefan Jan 13, 2026
03cb8ea
Refactor cache configuration and global functions handling.
renczesstefan Jan 13, 2026
173592d
Refactor cache implementation and optimize method usage
renczesstefan Jan 13, 2026
8604c85
Refactor caching mechanism for improved concurrency and logic.
renczesstefan Jan 13, 2026
790b359
Handle null PetriNet in reloadCachedGlobalFunctions
renczesstefan Jan 13, 2026
b4aef9b
Rename cacheSize to initialCapacity in GenericMapCache
renczesstefan Jan 13, 2026
e297242
Handle null values in GenericMapCache.put method
renczesstefan Jan 14, 2026
271c93f
Fix class cast check for List elements in GenericMapCache
renczesstefan Jan 14, 2026
7a57310
Refactor cache implementation to support generic element types
renczesstefan Jan 14, 2026
b0f3476
Evict global functions cache during reload.
renczesstefan Jan 14, 2026
07aa67f
Remove unused import from CacheConfiguration.java
renczesstefan Jan 14, 2026
64e0c8b
Refactor method to optimize cache eviction sequence
renczesstefan Jan 14, 2026
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
@@ -1,31 +1,61 @@
package com.netgrif.application.engine.configuration;

import com.netgrif.application.engine.configuration.properties.CacheConfigurationProperties;
import com.netgrif.application.engine.workflow.domain.CachedFunction;
import groovy.lang.Closure;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.CachingConfigurer;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.cache.interceptor.CacheResolver;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;


import java.util.*;
import java.util.stream.Collectors;

@Configuration
@EnableCaching
public class CacheConfiguration extends CachingConfigurerSupport {

@RequiredArgsConstructor
public class CacheConfiguration implements CachingConfigurer {
private final CacheConfigurationProperties properties;

public CacheConfiguration(CacheConfigurationProperties properties) {
this.properties = properties;
}

@Bean
@Primary
@Override
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager(properties.getAllCaches().toArray(String[]::new));
Set<String> cacheNames = properties.getAllCaches();
List<Cache> caches = cacheNames.stream()
.map(ConcurrentMapCache::new)
.collect(Collectors.toCollection(ArrayList::new));

caches.add(new GenericMapCache<>(
CacheMapKeys.ACTIONS,
Closure.class,
null,
properties.getActionCacheSize()
));
caches.add(new GenericMapCache<>(
CacheMapKeys.FUNCTIONS,
CachedFunction.class,
null,
properties.getFunctionsCacheSize()
));
caches.add(new GenericMapCache<>(
CacheMapKeys.GLOBAL_FUNCTIONS,
List.class,
CachedFunction.class,
properties.getGlobalFunctionsCacheSize()
));

SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(caches);
return cacheManager;
}

@Bean
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.netgrif.application.engine.configuration;

public final class CacheMapKeys {
private CacheMapKeys() {}
public static final String ACTIONS = "actions";
public static final String FUNCTIONS = "functions";
public static final String GLOBAL_FUNCTIONS = "globalFunctions";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package com.netgrif.application.engine.configuration;

import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;

import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
public class GenericMapCache<V, E> implements Cache {
private final String name;
private final Class<V> valueType;
private final Class<E> elementType;
private final ConcurrentHashMap<String, V> map;

public GenericMapCache(String name, Class<V> valueType, Class<E> elementType, int initialCapacity) {
this.name = name;
this.valueType = valueType;
this.elementType = elementType;
this.map = new ConcurrentHashMap<>(initialCapacity);
}

@Override public @NotNull String getName() { return name; }

@Override public @NotNull Object getNativeCache() { return Map.copyOf(map); }

@Override
public <T> T get(Object key, Callable<T> loader) {
final String stringKey = String.valueOf(key);
try {
V value = map.computeIfAbsent(stringKey, cacheValue -> {
try {
T computed = loader.call();
if (computed == null) return null;
return safeCast(computed);
}
catch (Exception e) {
throw new RuntimeException(e);
}
});
return (T) value;
} catch (RuntimeException e) {
Throwable cause = (e.getCause() != null) ? e.getCause() : e;
throw new Cache.ValueRetrievalException(stringKey, loader, cause);
}
}

@Override
public ValueWrapper get(Object key) {
String stringKey = String.valueOf(key);
Object valueObject = map.get(stringKey);
return valueObject != null ? new SimpleValueWrapper(valueObject) : null;
}

@Override
public <T> T get(Object key, Class<T> type) {
String stringKey = String.valueOf(key);
Object valueObject = map.get(stringKey);
return valueObject != null ? type.cast(valueObject) : null;
}

@Override
public void put(Object key, Object value) {
if (value == null) {
evict(key);
return;
}
map.put(String.valueOf(key), safeCast(value));
}

@Override
public void evict(Object key) {
map.remove(String.valueOf(key));
}

@Override
public void clear() {
map.clear();
}

@SuppressWarnings("unchecked")
private V safeCast(Object value) {
if (value == null) {
return null;
}

if (valueType.isInstance(value)) {
return (V) value;
}

// Check if the value is a list and the cache type is List<Element>
if (value instanceof List && List.class.isAssignableFrom(valueType)) {
List<?> list = (List<?>) value;

// Check only if the list is non-empty
if (!list.isEmpty()) {
Object firstElement = list.getFirst();

// Validate element type
if (elementType != null && !elementType.isInstance(firstElement)) {
throw new ClassCastException(
String.format("Cannot cast list element of type %s to %s",
firstElement.getClass().getName(),
elementType.getName()
)
);
}
}

return (V) list; // Safe cast to desired list type
}

throw new ClassCastException(
String.format("Cannot cast value of type %s to %s",
value.getClass().getName(),
valueType.getName()
)
);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.netgrif.application.engine.configuration.properties;

import jakarta.validation.constraints.Min;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
Expand Down Expand Up @@ -46,17 +47,38 @@ public class CacheConfigurationProperties {
*/
private String loadedModules = "loadedModules";

/**
* Default cache name for caching global functions of PetriNet global scoped functions.
*/
private String globalFunctions = "globalFunctions";

/**
* A list of additional custom cache names.
* Allows users to define their own cache names for specific use cases.
*/
private List<String> additional = new ArrayList<>();

/**
* The size of pages used for caching functions when processing large sets of data.
* This property determines the maximum number of functions to include in a single page during caching operations.
* Default value is 500.
*/
@Min(1)
private int functionCachingPageSize = 500;

/**
* The size of the cache used for handling field runner actions.
*/
@Min(1)
private int actionCacheSize = 500;

/**
* The size of the cache used for managing field runner functions.
*/
@Min(1)
private int functionsCacheSize = 500;

/**
* The size of the cache used for managing global Petri net functions.
*/
@Min(1)
private int globalFunctionsCacheSize = 500;

/**
* Retrieves a set of all configured cache names.
* Includes the default caches and any additional user-defined cache names.
Expand All @@ -65,7 +87,7 @@ public class CacheConfigurationProperties {
*/
public Set<String> getAllCaches() {
Set<String> caches = new LinkedHashSet<>(Arrays.asList(petriNetById, petriNetByIdentifier, petriNetDefault,
petriNetLatest, petriNetCache, loadedModules, globalFunctions));
petriNetLatest, petriNetCache, loadedModules));
caches.addAll(additional);
return caches;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,6 @@ public class RunnerConfigurationProperties {
*/
private ExpressionRunnerProperties expressionRunner = new ExpressionRunnerProperties();

/**
* Configuration for the field runner, including action, function, and namespace cache sizes.
*/
private FieldRunnerProperties fieldRunner = new FieldRunnerProperties();

/**
* Configuration specific to the expression runner component.
*/
Expand All @@ -36,36 +31,6 @@ public static class ExpressionRunnerProperties {

}

/**
* Configuration specific to the field runner component.
*/
@Data
@ConfigurationProperties(prefix = "netgrif.engine.runner.field-runner")
public static class FieldRunnerProperties {

/**
* The size of the cache used for handling field runner actions.
*/
private int actionCacheSize = 500;

/**
* The size of the cache used for managing field runner functions.
*/
private int functionsCacheSize = 500;

/**
* The size of the cache used for managing global Petri net functions.
*/
private int globalFunctionsCacheSize = 500;


/**
* The size of pages used for caching functions when processing large sets of data.
* This property determines the maximum number of functions to include in a single page during caching operations.
* Default value is 500.
*/
private int functionCachingPageSize = 500;
}

/**
* Configuration specific to the application runner component.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
import com.netgrif.application.engine.objects.auth.domain.ActorTransformer;
import com.netgrif.application.engine.configuration.properties.CacheConfigurationProperties;
import com.netgrif.application.engine.files.minio.StorageConfigurationProperties;
import com.netgrif.application.engine.objects.petrinet.domain.PetriNet;
import com.netgrif.application.engine.objects.petrinet.domain.PetriNetSearch;
import com.netgrif.application.engine.objects.petrinet.domain.Transition;
import com.netgrif.application.engine.objects.petrinet.domain.VersionType;
import com.netgrif.application.engine.petrinet.service.interfaces.IPetriNetService;
import com.netgrif.application.engine.petrinet.web.responsebodies.ArcImportReference;
import com.netgrif.application.engine.objects.auth.domain.LoggedUser;
Expand All @@ -15,10 +19,6 @@
import com.netgrif.application.engine.objects.event.events.petrinet.ProcessDeployEvent;
import com.netgrif.application.engine.importer.service.Importer;
import com.netgrif.application.engine.auth.service.GroupService;
import com.netgrif.application.engine.objects.petrinet.domain.PetriNet;
import com.netgrif.application.engine.objects.petrinet.domain.PetriNetSearch;
import com.netgrif.application.engine.objects.petrinet.domain.Transition;
import com.netgrif.application.engine.objects.petrinet.domain.VersionType;
import com.netgrif.application.engine.objects.petrinet.domain.dataset.logic.action.Action;
import com.netgrif.application.engine.petrinet.domain.dataset.logic.action.FieldActionsRunner;
import com.netgrif.application.engine.objects.petrinet.domain.events.EventPhase;
Expand Down Expand Up @@ -633,7 +633,7 @@ protected void deletePetriNet(String processId, LoggedUser loggedUser, boolean f
publisher.publishEvent(new ProcessDeleteEvent(petriNet, EventPhase.PRE));
repository.deleteBy_id(petriNet.getObjectId());
evictCache(petriNet);
functionCacheService.reloadCachedFunctions(petriNet);
functionCacheService.reloadCachedGlobalFunctions(petriNet);
if (petriNet.isDefaultVersion()) {
PetriNet processToMakeDefault = self.getLatestVersionByIdentifier(petriNet.getIdentifier());
if (processToMakeDefault != null) {
Expand Down Expand Up @@ -669,4 +669,5 @@ protected <T> T requireNonNull(T obj, Object... item) {
}
return obj;
}

}
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package com.netgrif.application.engine.petrinet.service.interfaces;

import com.netgrif.application.engine.objects.auth.domain.LoggedUser;
import com.netgrif.application.engine.objects.petrinet.domain.PetriNet;
import com.netgrif.application.engine.objects.petrinet.domain.PetriNetSearch;
import com.netgrif.application.engine.objects.petrinet.domain.Transition;
import com.netgrif.application.engine.objects.petrinet.domain.VersionType;
import com.netgrif.application.engine.objects.petrinet.domain.*;
import com.netgrif.application.engine.objects.petrinet.domain.dataset.Field;
import com.netgrif.application.engine.objects.petrinet.domain.dataset.logic.action.Action;
import com.netgrif.application.engine.objects.petrinet.domain.throwable.MissingIconKeyException;
Expand Down
Loading
Loading