caches = new LinkedHashSet<>(Arrays.asList(petriNetById, petriNetByIdentifier, petriNetDefault,
+ petriNetLatest, petriNetCache, loadedModules, globalFunctions));
caches.addAll(additional);
return caches;
}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/configuration/properties/RunnerConfigurationProperties.java b/application-engine/src/main/java/com/netgrif/application/engine/configuration/properties/RunnerConfigurationProperties.java
index ffe6cdd3a3b..03f4bcb0a9b 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/configuration/properties/RunnerConfigurationProperties.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/configuration/properties/RunnerConfigurationProperties.java
@@ -54,9 +54,9 @@ public static class FieldRunnerProperties {
private int functionsCacheSize = 500;
/**
- * The size of the cache used for maintaining field runner namespaces.
+ * The size of the cache used for managing global Petri net functions.
*/
- private int namespaceCacheSize = 500;
+ private int globalFunctionsCacheSize = 500;
}
/**
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/importer/service/FunctionFactory.java b/application-engine/src/main/java/com/netgrif/application/engine/importer/service/FunctionFactory.java
index 68471146753..d32c8bfe752 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/importer/service/FunctionFactory.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/importer/service/FunctionFactory.java
@@ -1,15 +1,21 @@
package com.netgrif.application.engine.importer.service;
+import com.netgrif.application.engine.objects.importer.model.Scope;
import com.netgrif.application.engine.objects.petrinet.domain.Function;
import com.netgrif.application.engine.objects.petrinet.domain.FunctionScope;
+import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
-@Component
@Slf4j
+@Component
+@RequiredArgsConstructor
public final class FunctionFactory {
+ private final IFunctionValidator functionValidator;
+
public Function getFunction(com.netgrif.application.engine.objects.importer.model.Function function) {
+ functionValidator.checkDeprecatedAttributes(function);
Function function1 = new Function();
function1.setDefinition(function.getValue());
@@ -18,4 +24,5 @@ public Function getFunction(com.netgrif.application.engine.objects.importer.mode
return function1;
}
+
}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/importer/service/FunctionValidator.java b/application-engine/src/main/java/com/netgrif/application/engine/importer/service/FunctionValidator.java
new file mode 100644
index 00000000000..d890fd5a50c
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/importer/service/FunctionValidator.java
@@ -0,0 +1,29 @@
+package com.netgrif.application.engine.importer.service;
+
+import com.netgrif.application.engine.objects.importer.model.Function;
+import com.netgrif.application.engine.objects.importer.model.Scope;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+@Component
+@Slf4j
+public class FunctionValidator implements IFunctionValidator {
+
+ private static final String NAMESPACE = "namespace";
+
+ /**
+ * Validates and updates deprecated function attributes.
+ *
+ * This method mutates the input function by replacing deprecated scope values.
+ * Specifically, it replaces the deprecated NAMESPACE scope with GLOBAL scope.
+ *
+ * @param function the function to validate and update (mutated in-place)
+ */
+ @Override
+ public void checkDeprecatedAttributes(Function function) {
+ if (function.getScope() != null && function.getScope().value().equals(NAMESPACE)) {
+ log.warn("Function scope [NAMESPACE] is deprecated. Replacing with [GLOBAL].");
+ function.setScope(Scope.GLOBAL);
+ }
+ }
+}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/importer/service/IFunctionValidator.java b/application-engine/src/main/java/com/netgrif/application/engine/importer/service/IFunctionValidator.java
new file mode 100644
index 00000000000..ef9b3d76853
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/importer/service/IFunctionValidator.java
@@ -0,0 +1,15 @@
+package com.netgrif.application.engine.importer.service;
+
+import com.netgrif.application.engine.objects.importer.model.Function;
+
+public interface IFunctionValidator extends IModelValidator {
+ /**
+ * Validates and updates deprecated function attributes.
+ *
+ * This method mutates the input function by replacing deprecated scope values.
+ * Specifically, it replaces the deprecated NAMESPACE scope with GLOBAL scope.
+ *
+ * @param function the function to validate and update (mutated in-place)
+ */
+ void checkDeprecatedAttributes(Function function);
+}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/menu/services/DashboardItemServiceImpl.java b/application-engine/src/main/java/com/netgrif/application/engine/menu/services/DashboardItemServiceImpl.java
index c0a5627de03..8d20ed2dd55 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/menu/services/DashboardItemServiceImpl.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/menu/services/DashboardItemServiceImpl.java
@@ -8,6 +8,9 @@
import com.netgrif.application.engine.objects.auth.domain.AbstractUser;
import com.netgrif.application.engine.objects.auth.domain.ActorTransformer;
import com.netgrif.application.engine.objects.auth.domain.LoggedUser;
+import com.netgrif.application.engine.objects.common.ResourceNotFoundException;
+import com.netgrif.application.engine.objects.common.ResourceNotFoundExceptionCode;
+import com.netgrif.application.engine.objects.petrinet.domain.PetriNet;
import com.netgrif.application.engine.objects.petrinet.domain.throwable.TransitionNotExecutableException;
import com.netgrif.application.engine.objects.utils.MenuItemUtils;
import com.netgrif.application.engine.objects.workflow.domain.Case;
@@ -62,7 +65,11 @@ public Case getOrCreate(DashboardItemBody body) throws TransitionNotExecutableEx
}
LoggedUser loggedUser = ActorTransformer.toLoggedUser(userService.getLoggedOrSystem());
- itemCase = workflowService.createCase(petriNetService.getNewestVersionByIdentifier(DashboardItemConstants.PROCESS_IDENTIFIER).getStringId(), body.getName().getDefaultValue(), "", loggedUser).getCase();
+ PetriNet petriNet = petriNetService.getDefaultVersionByIdentifier(DashboardItemConstants.PROCESS_IDENTIFIER);
+ if (petriNet == null) {
+ throw new ResourceNotFoundException(ResourceNotFoundExceptionCode.DEFAULT_PROCESS_NOT_FOUND, "Dashboard item process not found");
+ }
+ itemCase = workflowService.createCase(petriNet.getStringId(), body.getName().getDefaultValue(), "", loggedUser).getCase();
ToDataSetOutcome outcome = body.toDataSet();
itemCase = setDataWithExecute(itemCase, DashboardItemConstants.TASK_CONFIGURE, outcome.getDataSet());
return itemCase;
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/menu/services/DashboardManagementServiceImpl.java b/application-engine/src/main/java/com/netgrif/application/engine/menu/services/DashboardManagementServiceImpl.java
index 95a426e88eb..73e6ab67a61 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/menu/services/DashboardManagementServiceImpl.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/menu/services/DashboardManagementServiceImpl.java
@@ -8,7 +8,10 @@
import com.netgrif.application.engine.objects.auth.domain.AbstractUser;
import com.netgrif.application.engine.objects.auth.domain.ActorTransformer;
import com.netgrif.application.engine.objects.auth.domain.LoggedUser;
+import com.netgrif.application.engine.objects.common.ResourceNotFoundException;
+import com.netgrif.application.engine.objects.common.ResourceNotFoundExceptionCode;
import com.netgrif.application.engine.objects.petrinet.domain.I18nString;
+import com.netgrif.application.engine.objects.petrinet.domain.PetriNet;
import com.netgrif.application.engine.objects.petrinet.domain.throwable.TransitionNotExecutableException;
import com.netgrif.application.engine.objects.utils.MenuItemUtils;
import com.netgrif.application.engine.objects.workflow.domain.Case;
@@ -64,7 +67,11 @@ public Case createDashboardManagement(DashboardManagementBody body) throws Trans
}
addReferencedMenuItems(body);
LoggedUser loggedUser = ActorTransformer.toLoggedUser(userService.getLoggedOrSystem());
- managementCase = workflowService.createCase(petriNetService.getNewestVersionByIdentifier(DashboardManagementConstants.PROCESS_IDENTIFIER).getStringId(), body.getName().getDefaultValue(), "", loggedUser).getCase();
+ PetriNet petriNet = petriNetService.getDefaultVersionByIdentifier(DashboardManagementConstants.PROCESS_IDENTIFIER);
+ if (petriNet == null) {
+ throw new ResourceNotFoundException(ResourceNotFoundExceptionCode.DEFAULT_PROCESS_NOT_FOUND, "Dashboard management process not found");
+ }
+ managementCase = workflowService.createCase(petriNet.getStringId(), body.getName().getDefaultValue(), "", loggedUser).getCase();
ToDataSetOutcome outcome = body.toDataSet();
managementCase = setDataWithExecute(managementCase, DashboardItemConstants.TASK_CONFIGURE, outcome.getDataSet());
return managementCase;
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/domain/repositories/PetriNetRepository.java b/application-engine/src/main/java/com/netgrif/application/engine/petrinet/domain/repositories/PetriNetRepository.java
index a8dd005b207..fec35670a91 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/domain/repositories/PetriNetRepository.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/petrinet/domain/repositories/PetriNetRepository.java
@@ -33,6 +33,16 @@ public interface PetriNetRepository extends MongoRepository, Q
*/
PetriNet findByIdentifierAndVersion(String identifier, Version version);
+ /**
+ * Finds a page of {@link PetriNet} entities by its identifier and defaultVersion attribute
+ *
+ * @param identifier the unique identifier of the PetriNet.
+ * @param defaultVersion if true, the default version will be found, otherwise the non-default version will be found
+ * @param pageable the pagination details.
+ * @return the page of {@link PetriNet} entities matching the given identifier and defaultVersion attribute
+ */
+ Page findByIdentifierAndDefaultVersion(String identifier, boolean defaultVersion, Pageable pageable);
+
/**
* Finds a paginated list of {@link PetriNet} entities by their identifier.
*
@@ -68,4 +78,13 @@ public interface PetriNetRepository extends MongoRepository, Q
*/
@Query("{ 'roles.?0' : { $exists: true } }")
Page findAllByRoleId(String roleId, Pageable pageable);
+
+ /**
+ * Find all active Petri Nets
+ *
+ * @param pageable the pagination details
+ *
+ * @return a {@link Page} of active {@link PetriNet} entities
+ * */
+ Page findAllByDefaultVersionTrue(Pageable pageable);
}
\ No newline at end of file
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/PetriNetService.java b/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/PetriNetService.java
index c5867b0ddf7..c50112d65d0 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/PetriNetService.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/PetriNetService.java
@@ -5,21 +5,20 @@
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;
import com.netgrif.application.engine.auth.service.UserService;
import com.netgrif.application.engine.elastic.service.interfaces.IElasticPetriNetMappingService;
import com.netgrif.application.engine.elastic.service.interfaces.IElasticPetriNetService;
-import com.netgrif.application.engine.objects.event.events.Event;
import com.netgrif.application.engine.objects.event.events.petrinet.ProcessDeleteEvent;
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;
@@ -140,15 +139,16 @@ protected Importer getImporter() {
@Override
public void evictAllCaches() {
requireNonNull(cacheManager.getCache(cacheProperties.getPetriNetById()), cacheProperties.getPetriNetById()).clear();
- requireNonNull(cacheManager.getCache(cacheProperties.getPetriNetNewest()), cacheProperties.getPetriNetNewest()).clear();
+ requireNonNull(cacheManager.getCache(cacheProperties.getPetriNetDefault()), cacheProperties.getPetriNetDefault()).clear();
+ requireNonNull(cacheManager.getCache(cacheProperties.getPetriNetLatest()), cacheProperties.getPetriNetLatest()).clear();
requireNonNull(cacheManager.getCache(cacheProperties.getPetriNetCache()), cacheProperties.getPetriNetCache()).clear();
requireNonNull(cacheManager.getCache(cacheProperties.getPetriNetByIdentifier()), cacheProperties.getPetriNetByIdentifier()).clear();
-
}
public void evictCache(PetriNet net) {
requireNonNull(cacheManager.getCache(cacheProperties.getPetriNetById()), cacheProperties.getPetriNetById()).evict(net.getStringId());
- requireNonNull(cacheManager.getCache(cacheProperties.getPetriNetNewest()), cacheProperties.getPetriNetNewest()).evict(net.getIdentifier());
+ requireNonNull(cacheManager.getCache(cacheProperties.getPetriNetDefault()), cacheProperties.getPetriNetDefault()).evict(net.getIdentifier());
+ requireNonNull(cacheManager.getCache(cacheProperties.getPetriNetLatest()), cacheProperties.getPetriNetLatest()).evict(net.getIdentifier());
requireNonNull(cacheManager.getCache(cacheProperties.getPetriNetCache()), cacheProperties.getPetriNetCache()).evict(net.getObjectId());
requireNonNull(cacheManager.getCache(cacheProperties.getPetriNetByIdentifier()), cacheProperties.getPetriNetByIdentifier()).evict(net.getIdentifier() + net.getVersion().toString());
}
@@ -178,63 +178,113 @@ public List get(List petriNetIds) {
@Override
@Deprecated
+ @Transactional
public ImportPetriNetEventOutcome importPetriNet(InputStream xmlFile, String releaseType, LoggedUser author) throws IOException, MissingPetriNetMetaDataException, MissingIconKeyException {
return importPetriNet(xmlFile, VersionType.valueOf(releaseType.trim().toUpperCase()), author);
}
@Override
+ @Transactional
public ImportPetriNetEventOutcome importPetriNet(InputStream xmlFile, VersionType releaseType, LoggedUser author) throws IOException, MissingPetriNetMetaDataException, MissingIconKeyException {
return importPetriNet(xmlFile, releaseType, author, new HashMap<>());
}
@Override
+ @Transactional
public ImportPetriNetEventOutcome importPetriNet(InputStream xmlFile, VersionType releaseType, LoggedUser author, Map params) throws IOException, MissingPetriNetMetaDataException, MissingIconKeyException {
ImportPetriNetEventOutcome outcome = new ImportPetriNetEventOutcome();
ByteArrayOutputStream xmlCopy = new ByteArrayOutputStream();
IOUtils.copy(xmlFile, xmlCopy);
- Optional imported = getImporter().importPetriNet(new ByteArrayInputStream(xmlCopy.toByteArray()));
- if (imported.isEmpty()) {
+ Optional importedProcess = getImporter().importPetriNet(new ByteArrayInputStream(xmlCopy.toByteArray()));
+ if (importedProcess.isEmpty()) {
return outcome;
}
- PetriNet net = imported.get();
-
- PetriNet existingNet = getNewestVersionByIdentifier(net.getIdentifier());
+ PetriNet newProcess = importedProcess.get();
+ PetriNet processToMakeNonDefault = checkAndHandleProcessVersion(newProcess, releaseType);
- if (existingNet != null) {
- if (existingNet.getVersion().equals(net.getVersion())) {
- throw new IllegalArgumentException("Provided Petri net version is already present in the system");
- }
- if (net.getVersion() == null) {
- net.setVersion(existingNet.getVersion());
- net.incrementVersion(releaseType);
- }
- } else if (net.getVersion() == null) {
- net.setVersion(new Version());
- }
-
- processRoleService.saveAll(net.getRoles().values());
- net.setAuthor(ActorTransformer.toActorRef(author));
- functionCacheService.cachePetriNetFunctions(net);
- Path savedPath = getImporter().saveNetFile(net, new ByteArrayInputStream(xmlCopy.toByteArray()));
+ processRoleService.saveAll(newProcess.getRoles().values());
+ newProcess.setAuthor(ActorTransformer.toActorRef(author));
+ Path savedPath = getImporter().saveNetFile(newProcess, new ByteArrayInputStream(xmlCopy.toByteArray()));
xmlCopy.close();
- log.info("Petri net " + net.getTitle() + " (" + net.getInitials() + " v" + net.getVersion() + ") imported successfully and saved in a folder: " + savedPath.toString());
+ log.info("Petri net " + newProcess.getTitle() + " (" + newProcess.getInitials() + " v" + newProcess.getVersion() + ") imported successfully and saved in a folder: " + savedPath.toString());
- outcome.setOutcomes(eventService.runActions(net.getPreUploadActions(), null, Optional.empty(), params));
+ outcome.setOutcomes(eventService.runActions(newProcess.getPreUploadActions(), null, Optional.empty(), params));
publisher.publishEvent(new ProcessDeployEvent(outcome, EventPhase.PRE));
- save(net);
- outcome.setOutcomes(eventService.runActions(net.getPostUploadActions(), null, Optional.empty(), params));
- outcome.setNet(imported.get());
+
+ if (processToMakeNonDefault != null) {
+ doSaveInternal(processToMakeNonDefault);
+ }
+ Optional saveProcessOpt = doSaveInternal(newProcess);
+ functionCacheService.cachePetriNetFunctions(newProcess);
+
+ outcome.setOutcomes(eventService.runActions(newProcess.getPostUploadActions(), null, Optional.empty(), params));
+ outcome.setNet(saveProcessOpt.orElseThrow());
publisher.publishEvent(new ProcessDeployEvent(outcome, EventPhase.POST));
return outcome;
}
- protected void evaluateRules(Event event) {
- publisher.publishEvent(event);
+ /**
+ * Validates the version of an importing process. This method can update 'newProces': initialize version,
+ * initialize default version attribute. This method can also update the current default version of the process if needed.
+ *
+ * Version initialization logic
+ *
+ * - Uploaded process becomes default only if its version is the highest
+ * - Only one process can be default. If the importing process is about to get default, the currently default
+ * process becomes non-default
+ * - If no version is provided, it's initialized to 1.0.0 or by the existing highest version incremented
+ * by 'releaseType' input parameter
+ *
+ *
+ * @param newProcess A process to be checked and updated
+ * @param releaseType requested release type level. It's used for version initialization
+ *
+ * @return The process, which has been made non-default or null if no process updated
+ *
+ * @throws IllegalArgumentException if the version already exists
+ * */
+ private PetriNet checkAndHandleProcessVersion(PetriNet newProcess, VersionType releaseType) {
+ PetriNet processToMakeNonDefault = null;
+
+ if (newProcess.getVersion() != null && self.getPetriNet(newProcess.getIdentifier(), newProcess.getVersion()) != null) {
+ throw new IllegalArgumentException("A process [%s] with such version [%s] already exists"
+ .formatted(newProcess.getIdentifier(), newProcess.getVersion()));
+ }
+ PetriNet existingLatestProcess = self.getLatestVersionByIdentifier(newProcess.getIdentifier());
+ boolean makeNonDefaultCurrentVersion = true;
+ if (existingLatestProcess == null && newProcess.getVersion() == null) {
+ newProcess.setVersion(new Version());
+ } else {
+ if (newProcess.getVersion() == null) {
+ newProcess.setVersion(existingLatestProcess.getVersion().clone());
+ newProcess.incrementVersion(releaseType);
+ } else if (existingLatestProcess != null && newProcess.getVersion().isLowerThan(existingLatestProcess.getVersion())) {
+ makeNonDefaultCurrentVersion = false;
+ }
+ if (makeNonDefaultCurrentVersion && existingLatestProcess != null && existingLatestProcess.isDefaultVersion()) {
+ existingLatestProcess.makeNonDefault();
+ processToMakeNonDefault = existingLatestProcess;
+ } else if (makeNonDefaultCurrentVersion) {
+ PetriNet existingActiveProcess = self.getDefaultVersionByIdentifier(newProcess.getIdentifier());
+ if (existingActiveProcess != null) {
+ existingActiveProcess.makeNonDefault();
+ processToMakeNonDefault = existingActiveProcess;
+ }
+ }
+ }
+ if (makeNonDefaultCurrentVersion) {
+ newProcess.makeDefault();
+ }
+ return processToMakeNonDefault;
}
@Override
public Optional save(PetriNet petriNet) {
+ return doSaveInternal(petriNet);
+ }
+
+ protected final Optional doSaveInternal(PetriNet petriNet) {
petriNet.initializeArcs();
this.evictCache(petriNet);
petriNet = repository.save(petriNet);
@@ -242,7 +292,7 @@ public Optional save(PetriNet petriNet) {
try {
elasticPetriNetService.indexNow(this.petriNetMappingService.transform(petriNet));
} catch (Exception e) {
- log.error("Indexing failed [" + petriNet.getStringId() + "]", e);
+ log.error("Indexing failed [{}]", petriNet.getStringId(), e);
}
return Optional.of(petriNet);
@@ -262,6 +312,9 @@ public PetriNet getPetriNet(String id) {
@Override
@Cacheable(value = "petriNetByIdentifier", key = "#identifier+#version.toString()", unless = "#result == null")
public PetriNet getPetriNet(String identifier, Version version) {
+ if (identifier == null || version == null) {
+ return null;
+ }
PetriNet net = repository.findByIdentifierAndVersion(identifier, version);
if (net == null) {
return null;
@@ -283,13 +336,32 @@ public List findAllById(List ids) {
}
@Override
- @Cacheable(value = "petriNetNewest", unless = "#result == null")
- public PetriNet getNewestVersionByIdentifier(String identifier) {
- List nets = repository.findByIdentifier(identifier, PageRequest.of(0, 1, Sort.Direction.DESC, "version.major", "version.minor", "version.patch")).getContent();
- if (nets.isEmpty()) {
+ @Cacheable(value = "petriNetDefault", unless = "#result == null")
+ public PetriNet getDefaultVersionByIdentifier(String identifier) {
+ if (identifier == null) {
+ return null;
+ }
+
+ List result = repository.findByIdentifierAndDefaultVersion(identifier, true, PageRequest.of(0, 1)).getContent();
+ if (!result.isEmpty()) {
+ return result.getFirst();
+ }
+
+ return null;
+ }
+
+ @Override
+ @Cacheable(value = "petriNetLatest", unless = "#result == null")
+ public PetriNet getLatestVersionByIdentifier(String identifier) {
+ if (identifier == null) {
return null;
}
- return nets.getFirst();
+ List processes = repository.findByIdentifier(identifier, PageRequest.of(0, 1,
+ Sort.Direction.DESC, "version.major", "version.minor", "version.patch")).getContent();
+ if (processes.isEmpty()) {
+ return null;
+ }
+ return processes.getFirst();
}
/**
@@ -342,6 +414,13 @@ public Page getAll(Pageable pageable) {
return nets;
}
+ @Override
+ public Page getAllDefault(Pageable pageable) {
+ Page nets = repository.findAllByDefaultVersionTrue(pageable);
+ nets.forEach(PetriNet::initializeArcs);
+ return nets;
+ }
+
@Override
public FileSystemResource getFile(String netId, String title) {
if (title == null || title.length() == 0) {
@@ -421,7 +500,7 @@ public List getReferencesByUsersProcessRoles(LoggedUser user,
@Override
public PetriNetReference getReference(String identifier, Version version, LoggedUser user, Locale locale) {
- PetriNet net = version == null ? getNewestVersionByIdentifier(identifier) : getPetriNet(identifier, version);
+ PetriNet net = version == null ? getDefaultVersionByIdentifier(identifier) : getPetriNet(identifier, version);
return net != null ? transformToReference(net, locale) : new PetriNetReference();
}
@@ -555,6 +634,15 @@ protected void deletePetriNet(String processId, LoggedUser loggedUser, boolean f
repository.deleteBy_id(petriNet.getObjectId());
evictCache(petriNet);
functionCacheService.reloadCachedFunctions(petriNet);
+ if (petriNet.isDefaultVersion()) {
+ PetriNet processToMakeDefault = self.getLatestVersionByIdentifier(petriNet.getIdentifier());
+ if (processToMakeDefault != null) {
+ log.debug("The default version was removed. Making the latest version of the process [{}] with id [{}] as default...",
+ processToMakeDefault.getIdentifier(), processToMakeDefault.getStringId());
+ processToMakeDefault.makeDefault();
+ save(processToMakeDefault);
+ }
+ }
publisher.publishEvent(new ProcessDeleteEvent(petriNet, EventPhase.POST));
}
@@ -581,4 +669,5 @@ protected T requireNonNull(T obj, Object... item) {
}
return obj;
}
+
}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/interfaces/IPetriNetService.java b/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/interfaces/IPetriNetService.java
index fd16261e0a4..dc1505354d8 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/interfaces/IPetriNetService.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/interfaces/IPetriNetService.java
@@ -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;
@@ -153,12 +150,20 @@ static DataFieldReference transformToReference(PetriNet net, Transition transiti
List findAllById(List ids);
/**
- * Retrieves the newest version of a {@link PetriNet} by its identifier.
+ * Retrieves the default version of a {@link PetriNet} by its identifier.
*
* @param identifier the unique identifier of the PetriNet
- * @return the newest version of the {@link PetriNet} matching the provided identifier
+ * @return the default version of the {@link PetriNet} matching the provided identifier or null if not found
*/
- PetriNet getNewestVersionByIdentifier(String identifier);
+ PetriNet getDefaultVersionByIdentifier(String identifier);
+
+ /**
+ * Retrieves the latest version of a {@link PetriNet} by its identifier.
+ *
+ * @param identifier the unique identifier of the PetriNet
+ * @return the latest version of the {@link PetriNet} matching the provided identifier or null if not found
+ */
+ PetriNet getLatestVersionByIdentifier(String identifier);
/**
* Retrieves a paginated list of all {@link PetriNet} objects.
@@ -168,6 +173,13 @@ static DataFieldReference transformToReference(PetriNet net, Transition transiti
*/
Page getAll(Pageable pageable);
+ /**
+ * Retrieves all default version PetriNets
+ * @param pageable - the pagination information
+ * @return a paginated list of all default {@link PetriNet} objects
+ * */
+ Page getAllDefault(Pageable pageable);
+
/**
* Retrieves a {@link FileSystemResource} representing a file associated with a {@link PetriNet}.
*
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/startup/runner/DefaultFiltersRunner.java b/application-engine/src/main/java/com/netgrif/application/engine/startup/runner/DefaultFiltersRunner.java
index 93a2618d03a..65a80c0610b 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/startup/runner/DefaultFiltersRunner.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/startup/runner/DefaultFiltersRunner.java
@@ -17,10 +17,8 @@
import com.netgrif.application.engine.workflow.service.interfaces.IDataService;
import com.netgrif.application.engine.workflow.service.interfaces.ITaskService;
import com.netgrif.application.engine.workflow.service.interfaces.IWorkflowService;
-import com.netgrif.application.engine.objects.auth.domain.LoggedUser;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.stereotype.Component;
@@ -424,7 +422,7 @@ public Optional createFilter(String title, String icon, String filterType,
}
private Optional createFilterCase(String title, String icon, String filterType, String filterVisibility, String filterQuery, List allowedNets, Map filterMetadata, Map titleTranslations, String originId, boolean viewOrigin, boolean isImported) {
- PetriNet filterNet = this.petriNetService.getNewestVersionByIdentifier("filter");
+ PetriNet filterNet = this.petriNetService.getDefaultVersionByIdentifier("filter");
if (filterNet == null) {
return Optional.empty();
}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/startup/runner/ImpersonationRunner.java b/application-engine/src/main/java/com/netgrif/application/engine/startup/runner/ImpersonationRunner.java
index 44522a25567..4244f1e6079 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/startup/runner/ImpersonationRunner.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/startup/runner/ImpersonationRunner.java
@@ -39,7 +39,7 @@ public void createConfigNets() {
}
public Optional importProcess(final String message, String netIdentifier, String netFileName) {
- PetriNet foundNet = petriNetService.getNewestVersionByIdentifier(netIdentifier);
+ PetriNet foundNet = petriNetService.getDefaultVersionByIdentifier(netIdentifier);
if (foundNet != null) {
log.info("{} has already been imported.", message);
return Optional.of(foundNet);
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/CaseSearchService.java b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/CaseSearchService.java
index 923d17bfa54..7d4850a1692 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/CaseSearchService.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/CaseSearchService.java
@@ -280,7 +280,7 @@ public Predicate fullText(Object petriNetQuery, String searchPhrase) {
// TODO JOFO: unpaged necessary?
petriNets = petriNetService.getAll(Pageable.unpaged()).getContent();
} else {
- petriNets = processes.stream().map(process -> petriNetService.getNewestVersionByIdentifier(process)).collect(Collectors.toList());
+ petriNets = processes.stream().map(process -> petriNetService.getDefaultVersionByIdentifier(process)).collect(Collectors.toList());
}
if (petriNets.isEmpty())
return null;
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/FieldActionsCacheService.java b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/FieldActionsCacheService.java
index 1b996bc60da..e6d739af34d 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/FieldActionsCacheService.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/FieldActionsCacheService.java
@@ -1,7 +1,7 @@
package com.netgrif.application.engine.workflow.service;
-import com.netgrif.application.engine.configuration.properties.RunnerConfigurationProperties;
-import com.netgrif.application.engine.elastic.service.executors.MaxSizeHashMap;
+import com.netgrif.application.engine.configuration.CacheMapKeys;
+import com.netgrif.application.engine.configuration.properties.CacheConfigurationProperties;
import com.netgrif.application.engine.event.IGroovyShellFactory;
import com.netgrif.application.engine.objects.petrinet.domain.PetriNet;
import com.netgrif.application.engine.objects.petrinet.domain.Function;
@@ -14,33 +14,31 @@
import groovy.lang.GroovyShell;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.Cache;
+import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Lazy;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
import java.util.stream.Collectors;
@Service
@Slf4j
public class FieldActionsCacheService implements IFieldActionsCacheService {
- private final RunnerConfigurationProperties.FieldRunnerProperties properties;
+ private final CacheConfigurationProperties properties;
+ private final CacheManager cacheManager;
private IPetriNetService petriNetService;
- private Map actionsCache;
- private Map> namespaceFunctionsCache;
- private Map functionsCache;
private final GroovyShell shell;
- public FieldActionsCacheService(RunnerConfigurationProperties.FieldRunnerProperties properties, IGroovyShellFactory shellFactory) {
+ public FieldActionsCacheService(CacheConfigurationProperties properties, CacheManager cacheManager, IGroovyShellFactory shellFactory) {
this.properties = properties;
- this.actionsCache = new MaxSizeHashMap<>(properties.getActionCacheSize());
- this.functionsCache = new MaxSizeHashMap<>(properties.getFunctionsCacheSize());
- this.namespaceFunctionsCache = new MaxSizeHashMap<>(properties.getNamespaceCacheSize());
+ this.cacheManager = cacheManager;
this.shell = shellFactory.getGroovyShell();
}
@@ -56,46 +54,85 @@ public void cachePetriNetFunctions(PetriNet petriNet) {
return;
}
- List functions = petriNet.getFunctions(FunctionScope.NAMESPACE).stream()
+ List functions = petriNet.getFunctions(FunctionScope.GLOBAL).stream()
.map(function -> CachedFunction.build(shell, function))
.collect(Collectors.toList());
+ Cache globalFunctionsCache = getRequiredCache(properties.getGlobalFunctions());
+
if (!functions.isEmpty()) {
evaluateCachedFunctions(functions);
- namespaceFunctionsCache.put(petriNet.getIdentifier(), functions);
+ globalFunctionsCache.put(petriNet.getIdentifier(), functions);
} else {
- namespaceFunctionsCache.remove(petriNet.getIdentifier());
+ globalFunctionsCache.evictIfPresent(petriNet.getIdentifier());
}
}
+ @Override
+ public void reloadCachedFunctions(String petriNetId) {
+ getRequiredCache(properties.getGlobalFunctions()).evictIfPresent(petriNetId);
+ cachePetriNetFunctions(petriNetService.getDefaultVersionByIdentifier(petriNetId));
+ }
+
@Override
public void reloadCachedFunctions(PetriNet petriNet) {
- namespaceFunctionsCache.remove(petriNet.getIdentifier());
- cachePetriNetFunctions(petriNetService.getNewestVersionByIdentifier(petriNet.getIdentifier()));
+ this.reloadCachedFunctions(petriNet.getIdentifier());
}
@Override
public Closure getCompiledAction(Action action, boolean shouldRewriteCachedActions) {
String stringId = action.getId().toString();
- if (shouldRewriteCachedActions || !actionsCache.containsKey(stringId)) {
- Closure code = (Closure) shell.evaluate("{-> " + action.getDefinition() + "}");
- actionsCache.put(stringId, code);
+ Cache actionsCache = getRequiredCache(CacheMapKeys.ACTIONS);
+ Object nativeActionsCache = actionsCache.getNativeCache();
+
+ if (nativeActionsCache instanceof Map, ?> map) {
+ if (shouldRewriteCachedActions || !map.containsKey(stringId) ) {
+ Closure code = (Closure) shell.evaluate("{-> " + action.getDefinition() + "}");
+ actionsCache.put(stringId, code);
+ }
}
- return actionsCache.get(stringId);
+ return (Closure) actionsCache.get(stringId).get();
}
@Override
- public List getCachedFunctions(List functions) {
+ public List getCachedFunctions(List functions) {
List cachedFunctions = new ArrayList<>(functions.size());
- functions.forEach(function -> {
- if (!functionsCache.containsKey(function.getStringId())) {
- functionsCache.put(function.getStringId(), CachedFunction.build(shell, function));
- }
- cachedFunctions.add(functionsCache.get(function.getStringId()));
- });
+ Cache functionsCache = getRequiredCache(CacheMapKeys.FUNCTIONS);
+ Object nativeFunctionsCache = functionsCache.getNativeCache();
+
+ if (nativeFunctionsCache instanceof Map, ?> map) {
+ functions.forEach(function -> {
+ if (!map.containsKey(function.getStringId())) {
+ functionsCache.put(function.getStringId(), CachedFunction.build(shell, function));
+ }
+ cachedFunctions.add((CachedFunction) functionsCache.get(function.getStringId()).get());
+ });
+ }
return cachedFunctions;
}
+ @Override
+ public void cacheAllPetriNetFunctions() {
+ Pageable pageable = PageRequest.of(0, properties.getFunctionCachingPageSize());
+ Page page = petriNetService.getAllDefault(pageable);
+
+ while (!page.isEmpty()) {
+ for (PetriNet petriNet : page) {
+ try {
+ cachePetriNetFunctions(petriNet);
+ } catch (Exception e) {
+ log.warn("Failed to cache functions for PetriNet id={}", petriNet.getStringId(), e);
+ }
+ }
+
+ if (!page.hasNext()) {
+ break;
+ }
+ pageable = pageable.next();
+ page = petriNetService.getAllDefault(pageable);
+ }
+ }
+
@Override
public void evaluateFunctions(List functions) {
evaluateCachedFunctions(functions.stream().map(function -> CachedFunction.build(shell, function)).collect(Collectors.toList()));
@@ -134,22 +171,30 @@ private String stringifyParameterTypes(Class[] a) {
}
@Override
- public Map> getNamespaceFunctionCache() {
- return new HashMap<>(namespaceFunctionsCache);
+ public Map> getGlobalFunctionsCache() {
+ return new HashMap<>((Map>) getRequiredCache(properties.getGlobalFunctions()).getNativeCache());
}
@Override
public void clearActionCache() {
- this.actionsCache = new MaxSizeHashMap<>(properties.getActionCacheSize());
+ getRequiredCache(CacheMapKeys.ACTIONS).clear();
}
@Override
- public void clearNamespaceFunctionCache() {
- this.namespaceFunctionsCache = new MaxSizeHashMap<>(properties.getNamespaceCacheSize());
+ public void clearGlobalFunctionCache() {
+ getRequiredCache(properties.getGlobalFunctions()).clear();
}
@Override
public void clearFunctionCache() {
- this.functionsCache = new MaxSizeHashMap<>(properties.getFunctionsCacheSize());
+ getRequiredCache(CacheMapKeys.FUNCTIONS).clear();
+ }
+
+ private Cache getRequiredCache(String name) {
+ Cache cache = cacheManager.getCache(name);
+ if (cache == null) {
+ throw new IllegalStateException("Cache '" + name + "' is not configured");
+ }
+ return cache;
}
}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/FilterImportExportService.java b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/FilterImportExportService.java
index 9dd6cea3f5c..5cb67c54798 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/FilterImportExportService.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/FilterImportExportService.java
@@ -9,6 +9,8 @@
import com.netgrif.application.engine.objects.auth.domain.AbstractUser;
import com.netgrif.application.engine.objects.auth.domain.ActorTransformer;
import com.netgrif.application.engine.files.minio.StorageConfigurationProperties;
+import com.netgrif.application.engine.objects.common.ResourceNotFoundException;
+import com.netgrif.application.engine.objects.common.ResourceNotFoundExceptionCode;
import com.netgrif.application.engine.workflow.domain.FilterDeserializer;
import com.netgrif.application.engine.objects.workflow.domain.IllegalFilterFileException;
import com.netgrif.application.engine.auth.service.UserService;
@@ -266,7 +268,10 @@ public void changeFilterField(Collection filterFields) {
filterFields.forEach(f -> {
Task importedFilterTask = taskService.findOne(f);
Case filterCase = workflowService.findOne(importedFilterTask.getCaseId());
- PetriNet filterNet = petriNetService.getNewestVersionByIdentifier(FILTER_NET_IDENTIFIER);
+ PetriNet filterNet = petriNetService.getDefaultVersionByIdentifier(FILTER_NET_IDENTIFIER);
+ if (filterNet == null) {
+ throw new ResourceNotFoundException(ResourceNotFoundExceptionCode.DEFAULT_PROCESS_NOT_FOUND, "No filter process found or active");
+ }
List requiredNets = filterCase.getDataSet().get(FIELD_FILTER).getAllowedNets();
List currentNets = petriNetService.getExistingPetriNetIdentifiersFromIdentifiersList(requiredNets);
if (currentNets.size() < requiredNets.size()) {
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/MenuImportExportService.java b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/MenuImportExportService.java
index 1eb921882b7..5e1030344c9 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/MenuImportExportService.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/MenuImportExportService.java
@@ -237,7 +237,7 @@ public String createMenuItemCase(StringBuilder resultMessage, MenuEntry item, St
String roleImportId = menuEntryRole.getRoleImportId();
String netImportId = menuEntryRole.getNetImportId();
if (netImportId != null) {
- PetriNet net = petriNetService.getNewestVersionByIdentifier(netImportId);
+ PetriNet net = petriNetService.getDefaultVersionByIdentifier(netImportId);
if (net == null) {
resultMessage.append("\n- Missing net with import ID: \"").append(netImportId).append("\"").append("for role ").append(roleImportId).append("\n");
netCheck.set(false);
@@ -261,7 +261,7 @@ public String createMenuItemCase(StringBuilder resultMessage, MenuEntry item, St
}
//Creating new Case of preference_filter_item net and setting its data...
Case menuItemCase = workflowService.createCase(
- petriNetService.getNewestVersionByIdentifier("preference_filter_item").getStringId(),
+ petriNetService.getDefaultVersionByIdentifier("preference_filter_item").getStringId(),
item.getEntryName() + "_" + menuIdentifier,
"",
ActorTransformer.toLoggedUser(userService.getSystem())
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.java b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.java
index 9fdb0e83f11..162c76b0447 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.java
@@ -285,7 +285,7 @@ public CreateCaseEventOutcome createCase(String netId, String title, String colo
@Override
public CreateCaseEventOutcome createCaseByIdentifier(String identifier, String title, String color, LoggedUser user, Locale locale, Map params) {
- PetriNet net = petriNetService.getNewestVersionByIdentifier(identifier);
+ PetriNet net = petriNetService.getDefaultVersionByIdentifier(identifier);
if (net == null) {
throw new IllegalArgumentException("Petri net with identifier [" + identifier + "] does not exist.");
}
@@ -299,7 +299,7 @@ public CreateCaseEventOutcome createCaseByIdentifier(String identifier, String t
@Override
public CreateCaseEventOutcome createCaseByIdentifier(String identifier, String title, String color, LoggedUser user, Map params) {
- PetriNet net = petriNetService.getNewestVersionByIdentifier(identifier);
+ PetriNet net = petriNetService.getDefaultVersionByIdentifier(identifier);
if (net == null) {
throw new IllegalArgumentException("Petri net with identifier [" + identifier + "] does not exist.");
}
@@ -308,7 +308,7 @@ public CreateCaseEventOutcome createCaseByIdentifier(String identifier, String t
@Override
public CreateCaseEventOutcome createCaseByIdentifier(String identifier, String title, String color, LoggedUser user) {
- PetriNet net = petriNetService.getNewestVersionByIdentifier(identifier);
+ PetriNet net = petriNetService.getDefaultVersionByIdentifier(identifier);
if (net == null) {
throw new IllegalArgumentException("Petri net with identifier [" + identifier + "] does not exist.");
}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IFieldActionsCacheService.java b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IFieldActionsCacheService.java
index 6eb25809490..8339be0fe69 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IFieldActionsCacheService.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IFieldActionsCacheService.java
@@ -13,19 +13,23 @@ public interface IFieldActionsCacheService {
void cachePetriNetFunctions(PetriNet petriNet);
+ void reloadCachedFunctions(String petriNetId);
+
void reloadCachedFunctions(PetriNet petriNet);
Closure getCompiledAction(Action action, boolean shouldRewriteCachedActions);
List getCachedFunctions(List functions);
- Map> getNamespaceFunctionCache();
+ Map> getGlobalFunctionsCache();
void evaluateFunctions(List functions);
void clearActionCache();
- void clearNamespaceFunctionCache();
+ void clearGlobalFunctionCache();
+
+ void cacheAllPetriNetFunctions();
void clearFunctionCache();
}
diff --git a/application-engine/src/main/resources/application.yaml b/application-engine/src/main/resources/application.yaml
index 99a9c015817..d95cf455887 100644
--- a/application-engine/src/main/resources/application.yaml
+++ b/application-engine/src/main/resources/application.yaml
@@ -118,6 +118,7 @@ netgrif:
prometheus: metric
exposure:
exclude: shutdown
+ include: "*"
endpoint:
health:
show-details: when_authorized
diff --git a/application-engine/src/test/groovy/com/netgrif/application/engine/TestHelper.groovy b/application-engine/src/test/groovy/com/netgrif/application/engine/TestHelper.groovy
index 7c9c495ab7e..f6921558abe 100644
--- a/application-engine/src/test/groovy/com/netgrif/application/engine/TestHelper.groovy
+++ b/application-engine/src/test/groovy/com/netgrif/application/engine/TestHelper.groovy
@@ -93,7 +93,7 @@ class TestHelper {
roleService.clearCache()
actionsCacheService.clearActionCache()
actionsCacheService.clearFunctionCache()
- actionsCacheService.clearNamespaceFunctionCache()
+ actionsCacheService.clearGlobalFunctionCache()
petriNetService.evictAllCaches()
defaultRoleRunner.run()
diff --git a/application-engine/src/test/groovy/com/netgrif/application/engine/export/service/ExportServiceTest.groovy b/application-engine/src/test/groovy/com/netgrif/application/engine/export/service/ExportServiceTest.groovy
index dab63cbf0f5..a726f2572db 100644
--- a/application-engine/src/test/groovy/com/netgrif/application/engine/export/service/ExportServiceTest.groovy
+++ b/application-engine/src/test/groovy/com/netgrif/application/engine/export/service/ExportServiceTest.groovy
@@ -128,7 +128,7 @@ class ExportServiceTest {
taskService.assignTask(ActorTransformer.toLoggedUser(userService.findByEmail(UserConstants.ADMIN_USER_EMAIL, null)), exportTask)
Thread.sleep(20000) //Elastic wait
- def processId = petriNetService.getNewestVersionByIdentifier("export_test").stringId
+ def processId = petriNetService.getDefaultVersionByIdentifier("export_test").stringId
def taskRequest = new ElasticTaskSearchRequest()
taskRequest.process = [new com.netgrif.application.engine.workflow.web.requestbodies.taskSearch.PetriNet(processId)] as List
taskRequest.transitionId = ["t4"] as List
@@ -146,7 +146,7 @@ class ExportServiceTest {
@Test
void buildDefaultCsvTaskHeaderTest(){
- def processId = petriNetService.getNewestVersionByIdentifier("export_test").stringId
+ def processId = petriNetService.getDefaultVersionByIdentifier("export_test").stringId
String exportTask = mainCase.tasks.find { it.transition == "t4" }.task
taskService.assignTask(ActorTransformer.toLoggedUser(userService.findByEmail(UserConstants.ADMIN_USER_EMAIL, null)), exportTask)
List task = taskRepository.findAll(QTask.task.processId.eq(processId).and(QTask.task.transitionId.eq("t4")))
diff --git a/application-engine/src/test/groovy/com/netgrif/application/engine/impersonation/ImpersonationServiceTest.groovy b/application-engine/src/test/groovy/com/netgrif/application/engine/impersonation/ImpersonationServiceTest.groovy
index b6b97f53520..5fef3a0e8e3 100644
--- a/application-engine/src/test/groovy/com/netgrif/application/engine/impersonation/ImpersonationServiceTest.groovy
+++ b/application-engine/src/test/groovy/com/netgrif/application/engine/impersonation/ImpersonationServiceTest.groovy
@@ -311,7 +311,7 @@ class ImpersonationServiceTest {
}
def createConfigCase(AbstractUser user, String impersonator, List roles = null, List auths = null) {
- def caze = helper.createCase("config", petriNetService.getNewestVersionByIdentifier(ImpersonationRunner.IMPERSONATION_CONFIG_PETRI_NET_IDENTIFIER))
+ def caze = helper.createCase("config", petriNetService.getDefaultVersionByIdentifier(ImpersonationRunner.IMPERSONATION_CONFIG_PETRI_NET_IDENTIFIER))
def owner = new UserFieldValue(user)
caze.dataSet["impersonated"].value = owner
caze.dataSet["impersonated_email"].value = owner.username
diff --git a/application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/domain/ImporterTest.groovy b/application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/domain/ImporterTest.groovy
index 15e6138b78c..09d870976cb 100644
--- a/application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/domain/ImporterTest.groovy
+++ b/application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/domain/ImporterTest.groovy
@@ -130,7 +130,7 @@ class ImporterTest {
assert net.places.size() == 0
// ASSERT IMPORTED NET FROM REPO
- net = petriNetService.getNewestVersionByIdentifier("new_model")
+ net = petriNetService.getDefaultVersionByIdentifier("new_model")
assert net != null
assert net.importId == "new_model"
assert net.version.major == 1
@@ -204,7 +204,7 @@ class ImporterTest {
assert net2.places.size() == 0
// ASSERT NEW NET FROM REPO
- net2 = petriNetService.getNewestVersionByIdentifier("new_model")
+ net2 = petriNetService.getDefaultVersionByIdentifier("new_model")
assert net2 != null
assert net2.importId == "new_model"
assert net2.version.major == 2
diff --git a/application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/domain/PetriNetTest.groovy b/application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/domain/PetriNetTest.groovy
index 7efdd6ca99a..cb6630d5c94 100644
--- a/application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/domain/PetriNetTest.groovy
+++ b/application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/domain/PetriNetTest.groovy
@@ -136,7 +136,7 @@ class PetriNetTest {
try {
petriNetService.importPetriNet(netResource3.inputStream, VersionType.MAJOR, superCreator.loggedSuper)
} catch (Exception e) {
- assert e.getMessage() == "Provided Petri net version is already present in the system"
+ assert e.getMessage() == "A process [test] with such version [0.0.1] already exists"
}
}
diff --git a/application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/service/CachePetriNetServiceTest.groovy b/application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/service/CachePetriNetServiceTest.groovy
index 1c4a7d430ab..bda05fbec7e 100644
--- a/application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/service/CachePetriNetServiceTest.groovy
+++ b/application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/service/CachePetriNetServiceTest.groovy
@@ -67,13 +67,13 @@ class CachePetriNetServiceTest {
@Test
void cacheTest() {
- assert cacheManager.getCache(cacheProperties.getPetriNetNewest()).get("processDeleteTest") == null
+ assert cacheManager.getCache(cacheProperties.getPetriNetDefault()).get("processDeleteTest") == null
ImportPetriNetEventOutcome testNetOptional = petriNetService.importPetriNet(stream(NET_FILE), VersionType.MAJOR, superCreator.getLoggedSuper())
assert testNetOptional.getNet() != null
PetriNet testNet = testNetOptional.getNet()
- assert cacheManager.getCache(cacheProperties.getPetriNetNewest()).get(testNet.getIdentifier()) == null
- PetriNet test = petriNetService.getNewestVersionByIdentifier(testNet.getIdentifier())
- assert cacheManager.getCache(cacheProperties.getPetriNetNewest()).get(testNet.getIdentifier()).get().equals(test)
+ assert cacheManager.getCache(cacheProperties.getPetriNetDefault()).get(testNet.getIdentifier()) == null
+ PetriNet test = petriNetService.getDefaultVersionByIdentifier(testNet.getIdentifier())
+ assert cacheManager.getCache(cacheProperties.getPetriNetDefault()).get(testNet.getIdentifier()).get().equals(test)
}
}
diff --git a/application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/service/PetriNetServiceTest.groovy b/application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/service/PetriNetServiceTest.groovy
index 84ce8b5ee0c..98456188ee3 100644
--- a/application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/service/PetriNetServiceTest.groovy
+++ b/application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/service/PetriNetServiceTest.groovy
@@ -1,29 +1,24 @@
package com.netgrif.application.engine.petrinet.service
import com.netgrif.application.engine.TestHelper
-import com.netgrif.application.engine.objects.auth.domain.ActorRef
-import com.netgrif.application.engine.objects.auth.domain.ActorTransformer
-import com.netgrif.application.engine.objects.auth.domain.Authority
-import com.netgrif.application.engine.objects.auth.domain.User
-import com.netgrif.application.engine.objects.auth.domain.enums.UserState
+import com.netgrif.application.engine.adapter.spring.petrinet.service.ProcessRoleService
import com.netgrif.application.engine.auth.service.UserService
-import com.netgrif.application.engine.objects.elastic.domain.ElasticPetriNet
import com.netgrif.application.engine.elastic.domain.ElasticPetriNetRepository
import com.netgrif.application.engine.ipc.TaskApiTest
+import com.netgrif.application.engine.objects.auth.domain.*
+import com.netgrif.application.engine.objects.auth.domain.enums.UserState
+import com.netgrif.application.engine.objects.elastic.domain.ElasticPetriNet
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.UriContentType
-import com.netgrif.application.engine.objects.petrinet.domain.UriNode
import com.netgrif.application.engine.objects.petrinet.domain.VersionType
-import com.netgrif.application.engine.petrinet.domain.repositories.PetriNetRepository
import com.netgrif.application.engine.objects.petrinet.domain.roles.ProcessRole
-import com.netgrif.application.engine.petrinet.domain.roles.ProcessRoleRepository
import com.netgrif.application.engine.objects.petrinet.domain.version.Version
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.petrinetoutcomes.ImportPetriNetEventOutcome
+import com.netgrif.application.engine.petrinet.domain.repositories.PetriNetRepository
+import com.netgrif.application.engine.petrinet.domain.roles.ProcessRoleRepository
import com.netgrif.application.engine.petrinet.service.interfaces.IPetriNetService
-import com.netgrif.application.engine.adapter.spring.petrinet.service.ProcessRoleService
import com.netgrif.application.engine.startup.ImportHelper
import com.netgrif.application.engine.startup.runner.SuperCreatorRunner
-import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.petrinetoutcomes.ImportPetriNetEventOutcome
import com.netgrif.application.engine.workflow.domain.repositories.CaseRepository
import com.netgrif.application.engine.workflow.domain.repositories.TaskRepository
import com.netgrif.application.engine.workflow.service.interfaces.IWorkflowService
@@ -39,13 +34,15 @@ import org.springframework.data.domain.PageRequest
import org.springframework.test.context.ActiveProfiles
import org.springframework.test.context.junit.jupiter.SpringExtension
-@Disabled
+import static org.junit.jupiter.api.Assertions.assertThrows
+
@ExtendWith(SpringExtension.class)
@ActiveProfiles(["test"])
@SpringBootTest
class PetriNetServiceTest {
public static final String NET_FILE = "process_delete_test.xml"
+ public static final String VERSION_PROCESS_FILE_FORMAT = "petriNets/process_version_%s_0_0.xml"
public static final String NET_SEARCH_FILE = "process_search_test.xml"
public static final String CUSTOMER_USER_MAIL = "customer@netgrif.com"
@@ -100,13 +97,14 @@ class PetriNetServiceTest {
}
@Test
+ @Disabled
void processImportAndDelete() {
long processRoleCount = processRoleRepository.count()
long processCount = petriNetRepository.count()
long taskCount = taskRepository.count()
- ImportPetriNetEventOutcome testNetOptional = petriNetService.importPetriNet(stream(NET_FILE), VersionType.MAJOR, superCreator.getLoggedSuper())
+ ImportPetriNetEventOutcome testNetOptional = importProcess(NET_FILE, superCreator.getLoggedSuper())
assert testNetOptional.getNet() != null
assert petriNetRepository.count() == processCount + 1
PetriNet testNet = testNetOptional.getNet()
@@ -150,14 +148,112 @@ class PetriNetServiceTest {
}
@Test
+ void testVersionsOnImport() {
+ ImportPetriNetEventOutcome outcome = importProcess(VERSION_PROCESS_FILE_FORMAT.formatted("2"), superCreator.loggedSuper)
+ PetriNet petriNetV2 = outcome.getNet()
+ assert petriNetV2 != null
+ assert petriNetV2.defaultVersion
+ Version version = new Version()
+ version.setMajor(2)
+ assert petriNetV2.getVersion() == version
+ Thread.sleep(5000)
+ Optional elasticPetriNetV2Optional = elasticPetriNetRepository.findById(petriNetV2.stringId)
+ assert elasticPetriNetV2Optional.isPresent()
+ assert elasticPetriNetV2Optional.get().isDefaultVersion()
+
+ outcome = importProcess(VERSION_PROCESS_FILE_FORMAT.formatted("4"), superCreator.loggedSuper)
+ PetriNet petriNetV4 = outcome.getNet()
+ assert petriNetV4 != null
+ assert !petriNetService.get(petriNetV2.getObjectId()).isDefaultVersion()
+ assert petriNetV4.isDefaultVersion()
+ version = new Version()
+ version.setMajor(4)
+ assert petriNetV4.getVersion() == version
+ Thread.sleep(5000)
+ elasticPetriNetV2Optional = elasticPetriNetRepository.findById(petriNetV2.stringId)
+ assert !elasticPetriNetV2Optional.get().isDefaultVersion()
+ Optional elasticPetriNetV4Optional = elasticPetriNetRepository.findById(petriNetV4.stringId)
+ assert elasticPetriNetV4Optional.isPresent()
+ assert elasticPetriNetV4Optional.get().isDefaultVersion()
+
+ outcome = importProcess(VERSION_PROCESS_FILE_FORMAT.formatted("1"), superCreator.loggedSuper)
+ PetriNet petriNetV1 = outcome.getNet()
+ assert petriNetV1 != null
+ assert petriNetService.get(petriNetV4.getObjectId()).isDefaultVersion()
+ assert !petriNetV1.isDefaultVersion()
+ version = new Version()
+ version.setMajor(1)
+ assert petriNetV1.getVersion() == version
+
+ assertThrows(IllegalArgumentException.class, {
+ // cannot import already existing version
+ importProcess(VERSION_PROCESS_FILE_FORMAT.formatted("2"), superCreator.loggedSuper)
+ })
+
+ petriNetV2.makeDefault()
+ petriNetV2 = petriNetService.save(petriNetV2).get()
+ assert petriNetV2.defaultVersion
+ petriNetV4.makeNonDefault()
+ petriNetV4 = petriNetService.save(petriNetV4).get()
+ assert !petriNetV4.defaultVersion
+
+ outcome = importProcess(VERSION_PROCESS_FILE_FORMAT.formatted("5"), superCreator.loggedSuper)
+ PetriNet petriNetV5 = outcome.getNet()
+ assert petriNetV5 != null
+ assert !petriNetService.get(petriNetV2.getObjectId()).defaultVersion
+ assert !petriNetService.get(petriNetV4.getObjectId()).defaultVersion
+ assert petriNetV5.defaultVersion
+ version = new Version()
+ version.setMajor(5)
+ assert petriNetV5.getVersion() == version
+ Thread.sleep(5000)
+ elasticPetriNetV2Optional = elasticPetriNetRepository.findById(petriNetV2.stringId)
+ assert !elasticPetriNetV2Optional.get().defaultVersion
+ elasticPetriNetV4Optional = elasticPetriNetRepository.findById(petriNetV4.stringId)
+ assert !elasticPetriNetV4Optional.get().defaultVersion
+ Optional elasticPetriNetV5Optional = elasticPetriNetRepository.findById(petriNetV5.stringId)
+ assert elasticPetriNetV5Optional.isPresent()
+ assert elasticPetriNetV5Optional.get().defaultVersion
+ }
+
+ @Test
+ void testVersionActiveOnDelete() {
+ ImportPetriNetEventOutcome outcome = importProcess(VERSION_PROCESS_FILE_FORMAT.formatted("1"), superCreator.loggedSuper)
+ PetriNet processV1 = outcome.getNet()
+ outcome = importProcess(VERSION_PROCESS_FILE_FORMAT.formatted("2"), superCreator.loggedSuper)
+ PetriNet processV2 = outcome.getNet()
+ outcome = importProcess(VERSION_PROCESS_FILE_FORMAT.formatted("3"), superCreator.loggedSuper)
+ PetriNet processV3 = outcome.getNet()
+
+ assert !petriNetService.get(processV1.getObjectId()).defaultVersion
+ assert !petriNetService.get(processV2.getObjectId()).defaultVersion
+ assert petriNetService.get(processV3.getObjectId()).defaultVersion
+
+ petriNetService.deletePetriNet(processV2.getStringId(), superCreator.loggedSuper)
+
+ assert petriNetRepository.findById(processV2.getStringId()).isEmpty()
+ assert !petriNetService.get(processV1.getObjectId()).defaultVersion
+ assert petriNetService.get(processV3.getObjectId()).defaultVersion
+
+ petriNetService.deletePetriNet(processV3.getStringId(), superCreator.loggedSuper)
+
+ assert petriNetRepository.findById(processV3.getStringId()).isEmpty()
+ assert petriNetService.get(processV1.getObjectId()).defaultVersion
+
+ petriNetService.deletePetriNet(processV1.getStringId(), superCreator.loggedSuper)
+
+ assert petriNetRepository.findById(processV1.getStringId()).isEmpty()
+ }
+
+ @Test
+ @Disabled
void processSearch() {
long processCount = petriNetRepository.count()
-
def user = userService.findUserByUsername(CUSTOMER_USER_MAIL, null)
assert user != null && user.isPresent()
- petriNetService.importPetriNet(stream(NET_FILE), VersionType.MAJOR, superCreator.getLoggedSuper())
- petriNetService.importPetriNet(stream(NET_SEARCH_FILE), VersionType.MAJOR, ActorTransformer.toLoggedUser(user.get()))
+ importProcess(NET_FILE, superCreator.getLoggedSuper())
+ importProcess(NET_SEARCH_FILE, ActorTransformer.toLoggedUser(user.get()))
assert petriNetRepository.count() == processCount + 2
@@ -209,4 +305,8 @@ class PetriNetServiceTest {
search8.setAuthor(author);
assert petriNetService.search(search8, superCreator.getLoggedSuper(), PageRequest.of(0, 50), LocaleContextHolder.locale).getNumberOfElements() == 1;
}
+
+ private ImportPetriNetEventOutcome importProcess(String filePath, LoggedUser author) {
+ return petriNetService.importPetriNet(stream(filePath), VersionType.MAJOR, author)
+ }
}
diff --git a/application-engine/src/test/groovy/com/netgrif/application/engine/workflow/NewInitTest.groovy b/application-engine/src/test/groovy/com/netgrif/application/engine/workflow/NewInitTest.groovy
index 3e7f28bd4d8..c8d55017a17 100644
--- a/application-engine/src/test/groovy/com/netgrif/application/engine/workflow/NewInitTest.groovy
+++ b/application-engine/src/test/groovy/com/netgrif/application/engine/workflow/NewInitTest.groovy
@@ -45,7 +45,7 @@ class NewInitTest {
@Test
void newInitTest() throws IOException, MissingIconKeyException, MissingPetriNetMetaDataException {
petriNetService.importPetriNet(new FileInputStream("src/test/resources/petriNets/nae_1276_Init_value_as_choice.xml"), VersionType.MAJOR, superCreator.getLoggedSuper())
- Case initTestCase = workflowService.createCase(petriNetService.getNewestVersionByIdentifier("new_init_test").stringId, "New init test", "", superCreator.getLoggedSuper()).getCase()
+ Case initTestCase = workflowService.createCase(petriNetService.getDefaultVersionByIdentifier("new_init_test").stringId, "New init test", "", superCreator.getLoggedSuper()).getCase()
assert (initTestCase.dataSet["new_init_multichoice"].value as List).stream().any { it.defaultValue == "Bob" }
assert (initTestCase.dataSet["new_init_multichoice"].value as List).stream().any { it.defaultValue == "Alice" }
assert (initTestCase.dataSet["old_init_multichoice"].value as List).stream().any { it.defaultValue == "Bob" }
diff --git a/application-engine/src/test/resources/change_caseref_value_action_test.xml b/application-engine/src/test/resources/change_caseref_value_action_test.xml
index cf908b29fe9..9d600ef99e1 100644
--- a/application-engine/src/test/resources/change_caseref_value_action_test.xml
+++ b/application-engine/src/test/resources/change_caseref_value_action_test.xml
@@ -29,7 +29,7 @@
caseref: f.caseref;
- def net = petriNetService.getNewestVersionByIdentifier("change_value");
+ def net = petriNetService.getDefaultVersionByIdentifier("change_value");
def newCase = workflowService.createCase(net.stringId, "", "", userService.transformToLoggedUser(userService.getLoggedOrSystem())).getACase()
def newValue = new ArrayList(caseref.value)
newValue.add(newCase)
@@ -43,7 +43,7 @@
caseref: f.caseref;
- def net = petriNetService.getNewestVersionByIdentifier("test");
+ def net = petriNetService.getDefaultVersionByIdentifier("test");
def newCase = workflowService.createCase(net.stringId, "", "", userService.transformToLoggedUser(userService.getLoggedOrSystem())).getACase()
def newValue = new ArrayList(caseref.value)
newValue.add(newCase)
diff --git a/application-engine/src/test/resources/petriNets/NAE-1290_Export_actions.xml b/application-engine/src/test/resources/petriNets/NAE-1290_Export_actions.xml
index 33794373055..08fe3fd77ea 100644
--- a/application-engine/src/test/resources/petriNets/NAE-1290_Export_actions.xml
+++ b/application-engine/src/test/resources/petriNets/NAE-1290_Export_actions.xml
@@ -217,7 +217,7 @@
export
- def processId = petriNetService.getNewestVersionByIdentifier("export_test").stringId
+ def processId = petriNetService.getDefaultVersionByIdentifier("export_test").stringId
def config = new com.netgrif.application.engine.export.domain.ExportDataConfig()
config.setDataToExport(["immediate_multichoice","immediate_number", "text"] as LinkedHashSet)
exportTasksToFile({it.processId.eq(processId) & it.transitionId.eq("t3")},"src/test/resources/csv/task_mongo_export.csv", config)
diff --git a/application-engine/src/test/resources/petriNets/process_version_1_0_0.xml b/application-engine/src/test/resources/petriNets/process_version_1_0_0.xml
new file mode 100644
index 00000000000..63594046899
--- /dev/null
+++ b/application-engine/src/test/resources/petriNets/process_version_1_0_0.xml
@@ -0,0 +1,9 @@
+
+
+ process_version_test
+ 1.0.0
+ PVT
+ Process Version 1.0.0 test
+ false
+
diff --git a/application-engine/src/test/resources/petriNets/process_version_2_0_0.xml b/application-engine/src/test/resources/petriNets/process_version_2_0_0.xml
new file mode 100644
index 00000000000..f095c407ae6
--- /dev/null
+++ b/application-engine/src/test/resources/petriNets/process_version_2_0_0.xml
@@ -0,0 +1,9 @@
+
+
+ process_version_test
+ 2.0.0
+ PVT
+ Process Version 2.0.0 test
+ false
+
diff --git a/application-engine/src/test/resources/petriNets/process_version_3_0_0.xml b/application-engine/src/test/resources/petriNets/process_version_3_0_0.xml
new file mode 100644
index 00000000000..fdf75f42944
--- /dev/null
+++ b/application-engine/src/test/resources/petriNets/process_version_3_0_0.xml
@@ -0,0 +1,9 @@
+
+
+ process_version_test
+ 3.0.0
+ PVT
+ Process Version 3.0.0 test
+ false
+
diff --git a/application-engine/src/test/resources/petriNets/process_version_4_0_0.xml b/application-engine/src/test/resources/petriNets/process_version_4_0_0.xml
new file mode 100644
index 00000000000..58e472c139b
--- /dev/null
+++ b/application-engine/src/test/resources/petriNets/process_version_4_0_0.xml
@@ -0,0 +1,9 @@
+
+
+ process_version_test
+ 4.0.0
+ PVT
+ Process Version 4.0.0 test
+ false
+
diff --git a/application-engine/src/test/resources/petriNets/process_version_5_0_0.xml b/application-engine/src/test/resources/petriNets/process_version_5_0_0.xml
new file mode 100644
index 00000000000..21b309f9bed
--- /dev/null
+++ b/application-engine/src/test/resources/petriNets/process_version_5_0_0.xml
@@ -0,0 +1,9 @@
+
+
+ process_version_test
+ 5.0.0
+ PVT
+ Process Version 5.0.0 test
+ false
+
diff --git a/docs/process/functions.md b/docs/process/functions.md
new file mode 100644
index 00000000000..3d1eb4dcd1c
--- /dev/null
+++ b/docs/process/functions.md
@@ -0,0 +1,68 @@
+# PetriNet functions
+
+This document contains information about new Petriflow functions introduced in NAE 5.6.0.
+
+## Overview
+
+Petriflow functions provide opportunity to declare your own functions without any changes in applications code.
+
+### Scopes
+
+Functions can have ``process`` and ``global`` scope. Functions declared in ``process`` scope are visible only for specific process exactly like private functions in Java. ``Global`` functions are visible like public functions and we can access them via process identifier in other processes or in process they are declared in, just with function name and parameters.
+
+### Usage
+
+Functions are written in Groovy Closure style:
+
+```xml
+
+ { monthly, loan, period ->
+ change monthly value { (loan + loan * 0.02 * period) / (period * 12) }
+ }
+
+```
+
+```xml
+
+ loan_amount
+ Loan amount in EUR
+ inrange 10000,1000000
+ 100000
+
+ loan: f.loan_amount,
+ period: f.period,
+ monthly: f.monthly_payment;
+ calc(monthly, loan.value, period.value)
+
+
+```
+
+Only one function per element is allowed. Method overloading is also implemented and if more than one method with same method signature are present exception is thrown. Functions are compiled in run-time and like actions have access to ``ActionDelegate``. Actions have access to one each other with one exception that global functions can call only other global function, not process functions.
+
+```xml
+
+ all_data
+ All Data
+ ALL
+
+
+ { Double x, Double y ->
+ return x + y
+ }
+
+
+
+
+ number
+ Number
+ 10000
+
+ number: f.number,
+ number2: f.number2,
+ result: f.result;
+ change result value { all_data.sum(number.value, number2.value) }
+
+
+ ...
+
+```
diff --git a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/common/ResourceNotFoundExceptionCode.java b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/common/ResourceNotFoundExceptionCode.java
index 797b7999d59..a158a4f392b 100644
--- a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/common/ResourceNotFoundExceptionCode.java
+++ b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/common/ResourceNotFoundExceptionCode.java
@@ -6,7 +6,8 @@
public enum ResourceNotFoundExceptionCode {
DEFAULT_SYSTEM_GROUP_NOT_FOUND("defaultSystemGroupNotFound"),
- DEFAULT_USER_GROUP_NOT_FOUND("defaultUserGroupNotFound");
+ DEFAULT_USER_GROUP_NOT_FOUND("defaultUserGroupNotFound"),
+ DEFAULT_PROCESS_NOT_FOUND("defaultProcessNotFound");
private final String key;
diff --git a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/elastic/domain/ElasticPetriNet.java b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/elastic/domain/ElasticPetriNet.java
index bdec2b24c71..1a6fae31bcf 100644
--- a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/elastic/domain/ElasticPetriNet.java
+++ b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/elastic/domain/ElasticPetriNet.java
@@ -24,6 +24,8 @@ public abstract class ElasticPetriNet {
private Version version;
+ private boolean defaultVersion;
+
private String uriNodeId;
private I18nField title;
@@ -38,6 +40,7 @@ public ElasticPetriNet(PetriNet net) {
this.id = net.getStringId();
this.identifier = net.getIdentifier();
this.version = net.getVersion();
+ this.defaultVersion = net.isDefaultVersion();
this.uriNodeId = net.getUriNodeId();
this.title = this.transformToField(net.getTitle());
this.initials = net.getInitials();
@@ -46,6 +49,7 @@ public ElasticPetriNet(PetriNet net) {
public void update(ElasticPetriNet net) {
this.version = net.getVersion();
+ this.defaultVersion = net.isDefaultVersion();
if (net.getUriNodeId() != null) {
this.uriNodeId = net.getUriNodeId();
}
diff --git a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/petrinet/domain/FunctionScope.java b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/petrinet/domain/FunctionScope.java
index 3d22260234d..55f4ee7d027 100644
--- a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/petrinet/domain/FunctionScope.java
+++ b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/petrinet/domain/FunctionScope.java
@@ -1,9 +1,21 @@
package com.netgrif.application.engine.objects.petrinet.domain;
+/**
+ * Enum representing the scope of a function.
+ *
+ * This enumeration defines the possible scopes in which a function can operate.
+ */
public enum FunctionScope {
- NAMESPACE("namespace"),
- PROCESS("process");
+ /**
+ * Represents the process-specific scope of a function.
+ */
+ PROCESS("process"),
+
+ /**
+ * Represents the global scope of a function.
+ */
+ GLOBAL("global");
private final String value;
diff --git a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/petrinet/domain/PetriNet.java b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/petrinet/domain/PetriNet.java
index a8b2fa447cd..d8042d177c8 100644
--- a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/petrinet/domain/PetriNet.java
+++ b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/petrinet/domain/PetriNet.java
@@ -1,5 +1,6 @@
package com.netgrif.application.engine.objects.petrinet.domain;
+import com.netgrif.application.engine.objects.annotations.Indexed;
import com.netgrif.application.engine.objects.auth.domain.ActorRef;
import com.netgrif.application.engine.objects.petrinet.domain.arcs.Arc;
import com.netgrif.application.engine.objects.petrinet.domain.arcs.reference.Referencable;
@@ -30,7 +31,7 @@ public abstract class PetriNet extends PetriNetObject {
@Getter
@Setter
- private String identifier; //combination of identifier and version must be unique ... maybe use @CompoundIndex?
+ private String identifier; // todo: combination of identifier and version must be unique ... maybe use @CompoundIndex?
@Getter
@Setter
@@ -72,6 +73,11 @@ public abstract class PetriNet extends PetriNetObject {
@Setter
private Version version;
+ @Getter
+ @Setter
+ @Indexed
+ private boolean defaultVersion;
+
@Getter
@Setter
private ActorRef author;
@@ -141,22 +147,23 @@ public PetriNet() {
this.title = new I18nString("");
this.importId = "";
this.version = new Version();
- defaultCaseName = new I18nString("");
- initialized = false;
- creationDate = LocalDateTime.now();
- places = new LinkedHashMap<>();
- transitions = new LinkedHashMap<>();
- arcs = new LinkedHashMap<>();
- dataSet = new LinkedHashMap<>();
- roles = new LinkedHashMap<>();
- negativeViewRoles = new LinkedList<>();
- transactions = new LinkedHashMap<>();
- processEvents = new LinkedHashMap<>();
- caseEvents = new LinkedHashMap<>();
- permissions = new HashMap<>();
- userRefs = new HashMap<>();
- functions = new LinkedList<>();
- tags = new HashMap<>();
+ this.defaultCaseName = new I18nString("");
+ this.initialized = false;
+ this.creationDate = LocalDateTime.now();
+ this.places = new LinkedHashMap<>();
+ this.transitions = new LinkedHashMap<>();
+ this.arcs = new LinkedHashMap<>();
+ this.dataSet = new LinkedHashMap<>();
+ this.roles = new LinkedHashMap<>();
+ this.negativeViewRoles = new LinkedList<>();
+ this.transactions = new LinkedHashMap<>();
+ this.processEvents = new LinkedHashMap<>();
+ this.caseEvents = new LinkedHashMap<>();
+ this.permissions = new HashMap<>();
+ this.userRefs = new HashMap<>();
+ this.functions = new LinkedList<>();
+ this.tags = new HashMap<>();
+ this.makeNonDefault();
}
public PetriNet(PetriNet petriNet) {
@@ -167,6 +174,7 @@ public PetriNet(PetriNet petriNet) {
this.title = petriNet.getTitle();
this.importId = petriNet.getImportId();
this.version = petriNet.getVersion();
+ this.defaultVersion = petriNet.isDefaultVersion();
this.defaultCaseName = petriNet.getDefaultCaseName();
this.defaultCaseNameExpression = petriNet.getDefaultCaseNameExpression();
this.initials = petriNet.getInitials();
@@ -430,6 +438,14 @@ public boolean hasDynamicCaseName() {
return defaultCaseNameExpression != null;
}
+ public void makeDefault() {
+ this.setDefaultVersion(true);
+ }
+
+ public void makeNonDefault() {
+ this.setDefaultVersion(false);
+ }
+
@Override
public String getStringId() {
return _id.toString();
diff --git a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/petrinet/domain/version/Version.java b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/petrinet/domain/version/Version.java
index 3c5c2d84be6..50dd1f5481d 100644
--- a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/petrinet/domain/version/Version.java
+++ b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/petrinet/domain/version/Version.java
@@ -52,6 +52,12 @@ public void increment(VersionType type) {
}
}
+ /**
+ * Compares this version to the other version
+ *
+ * @param other other version to be compared with
+ * @return 0 if the versions equal, <0 if this is lower than other, >0 if this is higher than other0>
+ */
public int compareTo(Version other) {
if (this.major != other.major) {
return Long.compare(this.major, other.major);
@@ -62,6 +68,24 @@ public int compareTo(Version other) {
return Long.compare(this.patch, other.patch);
}
+ /**
+ * Checks if this version is higher than the other
+ * @param other other version to be compared with
+ * @return true if this version is higher than the other
+ */
+ public boolean isHigherThan(Version other) {
+ return compareTo(other) > 0;
+ }
+
+ /**
+ * Checks if this version is lower than the other
+ * @param other other version to be compared with
+ * @return true if this version is lower than the other
+ */
+ public boolean isLowerThan(Version other) {
+ return compareTo(other) < 0;
+ }
+
@Override
public Version clone() {
diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/petrinet/domain/PetriNet.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/petrinet/domain/PetriNet.java
index 7e91f07c13f..4076351e98f 100644
--- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/petrinet/domain/PetriNet.java
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/petrinet/domain/PetriNet.java
@@ -60,6 +60,7 @@ public LinkedHashMap getRoles() {
return super.getRoles();
}
+ // todo: delete clone method if not needed
// @Override
// public PetriNet clone() {
// PetriNet clone = new PetriNet();