-
Notifications
You must be signed in to change notification settings - Fork 6
[NAE-2266] Introduce active version of process #389
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: release/7.0.0-rev9
Are you sure you want to change the base?
Conversation
- add attribute isVersionActive in PetriNet - introduce PetriNetService.getActiveVersionByIdentifier - rename PetriNetService.getNewestVersionByIdentifier to PetriNetService.getLatestVersionByIdentifier - switch usage of getNewestVersionByIdentifier to getActiveVersionByIdentifier - enhance process import validations
- fix repository query - fix null pointer exception - fix unwanted java reference
- fix version initialization
- implement tests to test the version
- implement API to activate the process
- fix logging
- fix log message
- remove unused PetriNetService.evaluateRules method - remove the explicit rollback when saving process changes -> resolved in EE as transactions
- remove todos - implement PetriNetServiceTest.testMakeVersionActive
- split PetriNetService.save into two methods
- rename version active attribute in PetriNet
- remove makeVersionActive API
- update PetriNetService.deletePetriNet to handle versionActive attribute - implement another test for process deletion
- mark methods import petriNet method transactional
- update javadoc
WalkthroughReplaces usages of newest-version PetriNet lookups with active-version semantics, introduces distinct "active" and "latest" caches, adds versionActive to domain models, adjusts import/delete to manage active flag, and updates many call sites and tests to use getActiveVersionByIdentifier()/getLatestVersionByIdentifier(). Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant PetriNetService
participant Repo as PetriNetRepository
participant Cache as Cache Layer
participant ES as ElasticSearch/Index
Client->>PetriNetService: importPetriNet(stream, versionType, user)
activate PetriNetService
PetriNetService->>Repo: find existing versions by identifier
Repo-->>PetriNetService: existing versions
alt existing versions present
PetriNetService->>Repo: mark existing versions inactive (versionActive=false)
PetriNetService->>Cache: evict petriNetActive[id]
PetriNetService->>Cache: evict petriNetLatest[id]
Cache->>ES: evict/index cleanup
end
PetriNetService->>PetriNetService: create new PetriNet version and set versionActive=true
PetriNetService->>Repo: save(newVersion)
Repo->>ES: index(newVersion)
PetriNetService->>Cache: populate petriNetActive[id], petriNetLatest[id]
PetriNetService-->>Client: import result
deactivate PetriNetService
Client->>PetriNetService: getActiveVersionByIdentifier(id)
activate PetriNetService
PetriNetService->>Cache: check petriNetActive[id]
alt cache hit
Cache-->>PetriNetService: return cached active version
else cache miss
PetriNetService->>Repo: findByIdentifierAndVersionActive(id, true)
Repo-->>PetriNetService: active version
PetriNetService->>Cache: store petriNetActive[id]
end
PetriNetService-->>Client: returned active PetriNet
deactivate PetriNetService
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Possibly related PRs
Pre-merge checks❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: ASSERTIVE Plan: Pro 📒 Files selected for processing (6)
🧰 Additional context used🧠 Learnings (6)📓 Common learnings📚 Learning: 2025-07-31T23:40:46.499ZApplied to files:
📚 Learning: 2025-06-23T13:30:13.096ZApplied to files:
📚 Learning: 2025-09-29T10:31:31.469ZApplied to files:
📚 Learning: 2025-09-29T10:31:57.325ZApplied to files:
📚 Learning: 2025-11-14T10:22:01.634ZApplied to files:
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
🔇 Additional comments (6)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/petrinet/domain/PetriNet.java (1)
63-107: Consider fully removing or restoring the commented clone method.The extensive commented-out
clone()method (lines 64–107) with the TODO comment suggests deferred maintenance. If the method is genuinely not needed, delete it to reduce clutter and maintenance burden; if it may be useful in the future, restore and test it instead of leaving it commented out.application-engine/src/main/java/com/netgrif/application/engine/workflow/service/MenuImportExportService.java (1)
236-261: Role/net resolution now depends on active versions; consider aligning messaging and null‑safety
- Using
petriNetService.getActiveVersionByIdentifier(netImportId)(Line 240) andgetActiveVersionByIdentifier("preference_filter_item")(Line 264) correctly aligns this flow with the new “active version” semantics.- The log text on Line 255 still says “latest present version of net”, which is slightly misleading now that you explicitly use the active version. Consider updating it to “active version of net” for clarity.
getActiveVersionByIdentifier("preference_filter_item")is dereferenced without a null check. This was structurally identical before with the “newest” call, but with the stricter “active” constraint it might now be easier to end up with no active version configured. If that’s a realistic state, adding an explicit check (and a clear error/log) would make this more robust.Also applies to: 262-268
application-engine/src/main/java/com/netgrif/application/engine/startup/runner/ImpersonationRunner.java (1)
41-54: Config net existence now depends on an active versionSwitching to
petriNetService.getActiveVersionByIdentifier(netIdentifier)means that if a config net exists only in inactive versions,importProcesswill reimport it instead of treating it as already present. For system configuration processes this may be exactly what you want, but it is a behavioral change from the previous “any newest version” check. Please confirm that reimporting when no active version exists is the intended behavior.application-engine/src/main/java/com/netgrif/application/engine/workflow/service/CaseSearchService.java (1)
267-285: Potential NPE in full‑text search when no active PetriNet version existsHere:
petriNets = processes.stream() .map(process -> petriNetService.getActiveVersionByIdentifier(process)) .collect(Collectors.toList());you later do
petriNets.forEach(net -> net.getImmediateFields().forEach(...))without checking for nulls. If anyprocesshas no active version (identifier exists but all versions inactive, or data not yet migrated),getActiveVersionByIdentifiercan returnnulland you’ll get an NPE at runtime.Consider defensively filtering out nulls and treating “no active nets resolved” as “no full‑text predicates”:
- petriNets = processes.stream() - .map(process -> petriNetService.getActiveVersionByIdentifier(process)) - .collect(Collectors.toList()); + petriNets = processes.stream() + .map(petriNetService::getActiveVersionByIdentifier) + .filter(Objects::nonNull) + .collect(Collectors.toList());and keep the existing
if (petriNets.isEmpty()) return null;behavior.This avoids NPEs while still restricting the search to active nets.
application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/domain/PetriNetTest.groovy (1)
131-140:testVersioningConflictsdoes not fail if no exception is thrown; message assertion is fragileRight now, if
importPetriNetstops throwing for this scenario, the test will still pass because all assertions are inside thecatchblock. Also, asserting the full exception message string is brittle to minor wording changes.Consider tightening the test like this:
- try { - petriNetService.importPetriNet(netResource3.inputStream, VersionType.MAJOR, superCreator.loggedSuper) - } catch (Exception e) { - assert e.getMessage() == "A process [test] with such version [0.0.1] already exists" - } + try { + petriNetService.importPetriNet(netResource3.inputStream, VersionType.MAJOR, superCreator.loggedSuper) + assert false: "Expected importPetriNet to fail for duplicate process version" + } catch (Exception e) { + assert e.getMessage() == "A process [test] with such version [0.0.1] already exists" + }Optionally, you could relax the message check a bit (e.g. check that it contains the identifier and version, rather than matching the whole string) to reduce brittleness while still verifying the key dynamic parts.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (34)
application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/ActionDelegate.groovy(1 hunks)application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/delegate/RoleActionDelegate.groovy(2 hunks)application-engine/src/main/groovy/com/netgrif/application/engine/startup/ImportHelper.groovy(2 hunks)application-engine/src/main/java/com/netgrif/application/engine/configuration/properties/CacheConfigurationProperties.java(2 hunks)application-engine/src/main/java/com/netgrif/application/engine/menu/services/DashboardItemServiceImpl.java(1 hunks)application-engine/src/main/java/com/netgrif/application/engine/menu/services/DashboardManagementServiceImpl.java(1 hunks)application-engine/src/main/java/com/netgrif/application/engine/petrinet/domain/repositories/PetriNetRepository.java(1 hunks)application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/PetriNetService.java(6 hunks)application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/interfaces/IPetriNetService.java(1 hunks)application-engine/src/main/java/com/netgrif/application/engine/startup/runner/DefaultFiltersRunner.java(1 hunks)application-engine/src/main/java/com/netgrif/application/engine/startup/runner/ImpersonationRunner.java(1 hunks)application-engine/src/main/java/com/netgrif/application/engine/workflow/service/CaseSearchService.java(1 hunks)application-engine/src/main/java/com/netgrif/application/engine/workflow/service/FieldActionsCacheService.java(1 hunks)application-engine/src/main/java/com/netgrif/application/engine/workflow/service/FilterImportExportService.java(1 hunks)application-engine/src/main/java/com/netgrif/application/engine/workflow/service/MenuImportExportService.java(2 hunks)application-engine/src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.java(3 hunks)application-engine/src/test/groovy/com/netgrif/application/engine/export/service/ExportServiceTest.groovy(2 hunks)application-engine/src/test/groovy/com/netgrif/application/engine/impersonation/ImpersonationServiceTest.groovy(1 hunks)application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/domain/ImporterTest.groovy(2 hunks)application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/domain/PetriNetTest.groovy(1 hunks)application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/service/CachePetriNetServiceTest.groovy(1 hunks)application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/service/PetriNetServiceTest.groovy(5 hunks)application-engine/src/test/groovy/com/netgrif/application/engine/workflow/NewInitTest.groovy(1 hunks)application-engine/src/test/resources/change_caseref_value_action_test.xml(2 hunks)application-engine/src/test/resources/petriNets/NAE-1290_Export_actions.xml(1 hunks)application-engine/src/test/resources/petriNets/process_version_1_0_0.xml(1 hunks)application-engine/src/test/resources/petriNets/process_version_2_0_0.xml(1 hunks)application-engine/src/test/resources/petriNets/process_version_3_0_0.xml(1 hunks)application-engine/src/test/resources/petriNets/process_version_4_0_0.xml(1 hunks)application-engine/src/test/resources/petriNets/process_version_5_0_0.xml(1 hunks)nae-object-library/src/main/java/com/netgrif/application/engine/objects/elastic/domain/ElasticPetriNet.java(3 hunks)nae-object-library/src/main/java/com/netgrif/application/engine/objects/petrinet/domain/PetriNet.java(6 hunks)nae-object-library/src/main/java/com/netgrif/application/engine/objects/petrinet/domain/version/Version.java(2 hunks)nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/petrinet/domain/PetriNet.java(1 hunks)
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: tuplle
Repo: netgrif/application-engine PR: 334
File: application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/PetriNetService.java:204-214
Timestamp: 2025-07-31T23:40:46.499Z
Learning: In the PetriNetService.importPetriNet method, existingNet.getVersion() cannot be null because all existing nets in the system were deployed through processes that ensure every net always has a version assigned.
📚 Learning: 2025-07-31T23:40:46.499Z
Learnt from: tuplle
Repo: netgrif/application-engine PR: 334
File: application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/PetriNetService.java:204-214
Timestamp: 2025-07-31T23:40:46.499Z
Learning: In the PetriNetService.importPetriNet method, existingNet.getVersion() cannot be null because all existing nets in the system were deployed through processes that ensure every net always has a version assigned.
Applied to files:
application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/domain/PetriNetTest.groovyapplication-engine/src/test/resources/petriNets/process_version_2_0_0.xmlapplication-engine/src/main/java/com/netgrif/application/engine/workflow/service/FilterImportExportService.javaapplication-engine/src/main/java/com/netgrif/application/engine/petrinet/service/interfaces/IPetriNetService.javaapplication-engine/src/main/java/com/netgrif/application/engine/workflow/service/CaseSearchService.javaapplication-engine/src/test/resources/change_caseref_value_action_test.xmlapplication-engine/src/main/java/com/netgrif/application/engine/petrinet/domain/repositories/PetriNetRepository.javaapplication-engine/src/main/java/com/netgrif/application/engine/workflow/service/MenuImportExportService.javaapplication-engine/src/test/groovy/com/netgrif/application/engine/impersonation/ImpersonationServiceTest.groovynae-object-library/src/main/java/com/netgrif/application/engine/objects/petrinet/domain/PetriNet.javaapplication-engine/src/test/groovy/com/netgrif/application/engine/export/service/ExportServiceTest.groovyapplication-engine/src/test/groovy/com/netgrif/application/engine/petrinet/service/PetriNetServiceTest.groovyapplication-engine/src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.javaapplication-engine/src/test/groovy/com/netgrif/application/engine/workflow/NewInitTest.groovyapplication-engine/src/main/java/com/netgrif/application/engine/startup/runner/DefaultFiltersRunner.javanae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/petrinet/domain/PetriNet.javaapplication-engine/src/test/resources/petriNets/process_version_3_0_0.xmlnae-object-library/src/main/java/com/netgrif/application/engine/objects/elastic/domain/ElasticPetriNet.javaapplication-engine/src/test/groovy/com/netgrif/application/engine/petrinet/domain/ImporterTest.groovyapplication-engine/src/main/groovy/com/netgrif/application/engine/startup/ImportHelper.groovyapplication-engine/src/main/java/com/netgrif/application/engine/startup/runner/ImpersonationRunner.javaapplication-engine/src/test/resources/petriNets/process_version_1_0_0.xmlapplication-engine/src/main/java/com/netgrif/application/engine/petrinet/service/PetriNetService.javaapplication-engine/src/test/resources/petriNets/NAE-1290_Export_actions.xmlapplication-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/delegate/RoleActionDelegate.groovyapplication-engine/src/test/groovy/com/netgrif/application/engine/petrinet/service/CachePetriNetServiceTest.groovy
📚 Learning: 2025-09-05T10:21:54.893Z
Learnt from: renczesstefan
Repo: netgrif/application-engine PR: 350
File: application-engine/src/test/groovy/com/netgrif/application/engine/export/service/ExportServiceTest.groovy:135-135
Timestamp: 2025-09-05T10:21:54.893Z
Learning: In ExportServiceTest.groovy, writing to src/test/resources is intentional to simulate production behavior where the working tree is mutated during file exports. This mirrors how the system works in production.
Applied to files:
application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/domain/PetriNetTest.groovyapplication-engine/src/test/groovy/com/netgrif/application/engine/export/service/ExportServiceTest.groovyapplication-engine/src/test/groovy/com/netgrif/application/engine/petrinet/service/PetriNetServiceTest.groovyapplication-engine/src/test/groovy/com/netgrif/application/engine/workflow/NewInitTest.groovyapplication-engine/src/test/resources/petriNets/NAE-1290_Export_actions.xml
📚 Learning: 2025-10-20T11:46:37.958Z
Learnt from: renczesstefan
Repo: netgrif/application-engine PR: 373
File: application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java:105-107
Timestamp: 2025-10-20T11:46:37.958Z
Learning: In ActionApiImpl, the processIdentifier parameter in searchCases() is intentionally unused because it's required by the ActionApi interface for plugin implementations. This implementation returns cases from all processes without filtering by processIdentifier.
Applied to files:
application-engine/src/main/java/com/netgrif/application/engine/workflow/service/CaseSearchService.java
📚 Learning: 2025-06-23T13:30:13.096Z
Learnt from: renczesstefan
Repo: netgrif/application-engine PR: 318
File: nae-object-library/src/main/java/com/netgrif/application/engine/objects/workflow/domain/menu/MenuItemConstants.java:60-62
Timestamp: 2025-06-23T13:30:13.096Z
Learning: In MenuItemConstants enum in nae-object-library/src/main/java/com/netgrif/application/engine/objects/workflow/domain/menu/MenuItemConstants.java, the field `attributeId` will be renamed to `value` to make it more generic and appropriate for both dataset attribute identifiers and technical constants like PATH_SEPARATOR.
Applied to files:
application-engine/src/main/java/com/netgrif/application/engine/workflow/service/MenuImportExportService.java
📚 Learning: 2025-07-29T17:19:18.300Z
Learnt from: tuplle
Repo: netgrif/application-engine PR: 331
File: application-engine/src/main/java/com/netgrif/application/engine/elastic/service/ElasticPetriNetService.java:45-46
Timestamp: 2025-07-29T17:19:18.300Z
Learning: In ElasticPetriNetService class, petriNetService is properly initialized using Lazy setter injection rather than constructor injection. This pattern with Lazy Autowired setter methods is commonly used in Spring to resolve circular dependencies and is a valid alternative to constructor injection.
Applied to files:
nae-object-library/src/main/java/com/netgrif/application/engine/objects/petrinet/domain/PetriNet.javaapplication-engine/src/test/groovy/com/netgrif/application/engine/petrinet/service/PetriNetServiceTest.groovynae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/petrinet/domain/PetriNet.javanae-object-library/src/main/java/com/netgrif/application/engine/objects/elastic/domain/ElasticPetriNet.java
📚 Learning: 2025-09-29T10:31:57.325Z
Learnt from: renczesstefan
Repo: netgrif/application-engine PR: 362
File: application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/ProcessRoleService.java:513-529
Timestamp: 2025-09-29T10:31:57.325Z
Learning: PetriNet.getStringId() returns a simple ObjectId string representation (_id.toString()), not a composite Netgrif ID format, so new ObjectId(petriNetId) works correctly when petriNetId comes from PetriNet.getStringId().
Applied to files:
application-engine/src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.javaapplication-engine/src/main/groovy/com/netgrif/application/engine/startup/ImportHelper.groovyapplication-engine/src/main/java/com/netgrif/application/engine/petrinet/service/PetriNetService.java
🧬 Code graph analysis (1)
application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/PetriNetService.java (1)
nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/ActorTransformer.java (1)
ActorTransformer(10-131)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: task-list-completed
- GitHub Check: task-list-completed
- GitHub Check: task-list-completed
- GitHub Check: task-list-completed
- GitHub Check: task-list-completed
- GitHub Check: task-list-completed
- GitHub Check: task-list-completed
- GitHub Check: task-list-completed
🔇 Additional comments (36)
nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/petrinet/domain/PetriNet.java (1)
18-62: Verify whether this entity requires active version field mapping.Based on the PR objective (introducing active version semantics across the codebase), this Spring Data MongoDB entity should be reviewed to ensure it includes necessary field mappings for active version support. The AI summary notes that
ElasticPetriNetandVersionclasses were extended to supportversionActive. Please confirm whether thisPetriNetclass should also have an active version field mapped (e.g.,@org.springframework.data.mongodb.core.mapping.Field("versionActive")).application-engine/src/test/resources/petriNets/NAE-1290_Export_actions.xml (1)
220-220: Verify thatgetActiveVersionByIdentifier()contract guarantees non-null and that test setup establishes active versions.The change aligns well with the PR's semantic shift to active versions. However, the direct chain
.stringIdassumes non-null return fromgetActiveVersionByIdentifier().Per the retrieved learnings, existing nets always have versions assigned; confirm that:
getActiveVersionByIdentifier()has a non-null contract (or clarify fallback behavior if no active version exists)- The test setup for NAE-1290_Export_actions properly marks the PetriNet as "active" before this action executes
If the active version may be absent in edge cases, consider adding a null check or handling the scenario explicitly.
application-engine/src/test/groovy/com/netgrif/application/engine/export/service/ExportServiceTest.groovy (2)
131-135: Aligning task search with active PetriNet version looks correctSwitching to
petriNetService.getActiveVersionByIdentifier("export_test").stringIdkeeps the test in sync with the new “active version” semantics and remains safe given the DB is truncated and the net is freshly imported inbefore(), so this call should always resolve to the same net that produced the tasks.
149-156: Consistent use of active version in header test is appropriateUsing
getActiveVersionByIdentifier("export_test")here mirrors the previous change and ensures the repository query targets the active net version whose tasks are being exported; this is consistent with the intended behavior and test setup.application-engine/src/test/groovy/com/netgrif/application/engine/impersonation/ImpersonationServiceTest.groovy (1)
314-314: LGTM! Change aligns with PR objectives.The replacement of
getNewestVersionByIdentifier()withgetActiveVersionByIdentifier()is consistent with the PR's goal of introducing semantic distinction between active and latest versions. The test correctly retrieves the active version of the impersonation config Petri net.Since the entire test class is disabled (line 60), verify that this change works as expected when the impersonation tests are re-enabled and ensure an active version of the config Petri net exists during test execution.
application-engine/src/test/groovy/com/netgrif/application/engine/workflow/NewInitTest.groovy (1)
48-48: Using the active PetriNet version in test setup is consistent with new semanticsSwitching from
getNewestVersionByIdentifier("new_init_test")togetActiveVersionByIdentifier("new_init_test")matches the new “active vs newest” behavior. Given the DB is truncated inbefore()and the net is imported right before case creation, resolving the active version here is unambiguous and correctly exercises the active-version path.Based on learnings, the import flow guarantees nets have a proper version assigned, so relying on an active version here is safe.
application-engine/src/test/resources/petriNets/process_version_1_0_0.xml (1)
1-9: LGTM! Test resource is well-formed.The XML structure is valid and properly defines a PetriNet process version test resource with appropriate schema references.
application-engine/src/test/resources/petriNets/process_version_2_0_0.xml (1)
1-9: LGTM! Test resource is well-formed.The XML structure is valid and properly defines version 2.0.0 of the process version test resource.
application-engine/src/main/groovy/com/netgrif/application/engine/startup/ImportHelper.groovy (2)
131-131: LGTM! Active version retrieval is appropriate here.The change correctly uses the active version to determine if a PetriNet already exists before creating a new one. The null check on line 132 properly handles the case where no active version exists.
252-252: LGTM! Active version check is correct.The change appropriately uses the active version to determine if a process has already been imported. The null check on line 253 properly handles cases where no active version exists.
application-engine/src/test/resources/petriNets/process_version_5_0_0.xml (1)
1-9: LGTM! Test resource is well-formed.The XML structure is valid and properly defines version 5.0.0 of the process version test resource.
application-engine/src/test/resources/petriNets/process_version_3_0_0.xml (1)
1-9: LGTM! Test resource is well-formed.The XML structure is valid and properly defines version 3.0.0 of the process version test resource.
application-engine/src/test/resources/petriNets/process_version_4_0_0.xml (1)
1-9: LGTM! Test resource is well-formed.The XML structure is valid and properly defines version 4.0.0 of the process version test resource.
nae-object-library/src/main/java/com/netgrif/application/engine/objects/petrinet/domain/version/Version.java (1)
55-87: LGTM! Helpful convenience methods added.The new
isHigherThanandisLowerThanmethods provide clear, readable alternatives to directcompareTocalls. The implementation correctly delegates to the existingcompareTomethod, and the Javadoc is well-written.application-engine/src/main/java/com/netgrif/application/engine/workflow/service/FieldActionsCacheService.java (1)
72-75: LGTM! Null handling is present downstream.The change to use
getActiveVersionByIdentifieris correct. ThecachePetriNetFunctionsmethod (line 55) already has a null check, so the flow is safe even if the active version is not found.application-engine/src/main/java/com/netgrif/application/engine/startup/runner/DefaultFiltersRunner.java (1)
427-430: LGTM! Proper null handling in place.The change to
getActiveVersionByIdentifierincludes an appropriate null check with a graceful failure path (returningOptional.empty()). This ensures the filter creation logic is resilient to missing or inactive process definitions.application-engine/src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.java (1)
287-293: LGTM! Null handling is consistent and appropriate.All three
createCaseByIdentifiermethods properly check for null after callinggetActiveVersionByIdentifierand throw descriptiveIllegalArgumentExceptions. This ensures clear error messages when attempting to create cases from inactive or non-existent process definitions.application-engine/src/test/resources/change_caseref_value_action_test.xml (1)
32-37: Switch to active PetriNet versions in test actions is consistentUsing
petriNetService.getActiveVersionByIdentifier(...)here aligns the test with the new active-version semantics and keeps behavior equivalent under the assumption that the referenced nets are active. No additional changes needed.Also applies to: 46-52
nae-object-library/src/main/java/com/netgrif/application/engine/objects/petrinet/domain/PetriNet.java (1)
3-3: versionActive flag and initialization look consistent with active‑version model
- Adding
versionActivewith an index and accessor methods, plusmakeActive()/makeInactive(), cleanly supports the new active‑version concept.- The no‑arg constructor now fully initializes collections and calls
makeInactive(), which is a safe default for newly constructed nets.- The copy constructor copies
versionActivefrom the source net. That’s reasonable for cloning semantics, but any code that uses this copy constructor to create a new version should explicitly reset the flag (e.g., viamakeInactive()) before persisting, if a cloned net must start inactive.Overall the changes are internally consistent; just keep the copy‑semantics in mind at call sites where a “new version” is derived from an existing one.
Also applies to: 72-80, 143-167, 169-204, 441-447
application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/domain/ImporterTest.groovy (1)
132-170: Test now correctly validates active vs historical versionsSwitching to
getActiveVersionByIdentifier("new_model")for both the first and second import assertions matches the new semantics: the active net should move from v1 to v2, whilegetPetriNet(net.stringId)later still validates that v1 remains intact as a historical version. The control flow and assertions remain coherent.Also applies to: 206-232
application-engine/src/main/java/com/netgrif/application/engine/petrinet/domain/repositories/PetriNetRepository.java (1)
36-44: Repository method for active/inactive selection is fine; relies on uniqueness invariant
findByIdentifierAndVersionActive(String identifier, boolean versionActive)is consistent with your existingfindByIdentifierAndVersionmethod and matches the new field onPetriNet. It does rely on there being at most one net per(identifier, versionActive)combination; if multiple active versions could ever exist for a given identifier, callers would get an arbitrary one. As long as the service layer enforces “exactly one active version per identifier”, this is fine.nae-object-library/src/main/java/com/netgrif/application/engine/objects/elastic/domain/ElasticPetriNet.java (1)
27-28: Elastic projection correctly mirrors versionActive stateIntroducing
versionActiveonElasticPetriNetand populating it both in the constructor (fromPetriNet) and inupdate()ensures the search index reflects the active/inactive status of each net version. The change is straightforward and consistent with the domain model.Also applies to: 39-44, 50-53
application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/service/CachePetriNetServiceTest.groovy (1)
70-77: Test correctly validates active version cache behavior.The test properly verifies the cache lifecycle:
- Cache is empty before retrieval (line 70, 75)
- After calling
getActiveVersionByIdentifier, the cache is populated (line 77)Minor observation: Line 70 checks for
"processDeleteTest"as a hardcoded string, while line 75 usestestNet.getIdentifier(). This is intentional as the first check occurs before import, but ensure the identifier in the XML (process_delete_test.xml) matches"processDeleteTest".application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/service/PetriNetServiceTest.groovy (3)
46-46: New constant for version test files.The format string pattern is clear and follows the existing naming convention.
214-241: Test validates active version reassignment on deletion.This test correctly verifies that:
- Deleting an inactive version doesn't change the active version
- Deleting the active version promotes the latest remaining version to active
- All versions can be deleted sequentially
The test complements
testVersionsOnImportby covering the deletion path of the version lifecycle.
303-305: Good extraction of import helper method.The helper method reduces duplication across tests and centralizes the import call pattern.
application-engine/src/main/java/com/netgrif/application/engine/configuration/properties/CacheConfigurationProperties.java (2)
30-37: Clear semantic separation of cache identifiers.The distinction between
petriNetActive(the designated active version) andpetriNetLatest(the highest version number) is well-defined. The documentation comments accurately describe each cache's purpose.
61-66: Both new caches properly included in the aggregate set.The
getAllCaches()method correctly includes bothpetriNetActiveandpetriNetLatestin the returned set, ensuring they are managed alongside other caches.application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/PetriNetService.java (8)
140-146: Cache eviction updated for new cache structure.Both
petriNetActiveandpetriNetLatestcaches are properly cleared, ensuring cache consistency when evicting all caches.
181-184: Transactional annotation added to import methods.Adding
@Transactionalensures atomicity of the import operation. If an exception occurs during import, all database changes (including the deactivation of previous versions) will be rolled back.
243-251: Correct ordering: save inactivated process before new process.Saving the inactivated process first (line 244) before the new process (line 246) ensures that if the new process save fails, the transaction rollback will restore the previous active state. This is the correct order of operations within a transaction.
254-271: Refactored save with internal delegation.The split into public
save()andprotected final doSaveInternal()provides a clear extension point while ensuring consistent persistence behavior. Thefinalmodifier ondoSaveInternalprevents subclasses from bypassing the core save logic.Minor: Line 267 log message uses placeholder correctly. Good error handling that logs but doesn't fail the save operation due to indexing issues.
287-296: Null guard prevents cache key issues.The null check on
identifierandversion(lines 287-289) preventsNullPointerExceptionin the cache key computation (#identifier+#version.toString()in the@Cacheableannotation). Returningnullfor invalid inputs is appropriate since the cache is configured withunless = "#result == null".
310-331: New version retrieval methods with proper caching.Both methods correctly:
- Include null guards to prevent NPE and cache key issues
- Use appropriate cache names (
petriNetActive,petriNetLatest)- Configure
unless = "#result == null"to avoid caching null values
getLatestVersionByIdentifier(lines 321-331) uses descending sort on version components to find the highest version, which is correct.
594-602: Active version reassignment on deletion.When deleting the currently active version, the service correctly promotes the latest remaining version to active. This ensures there's always an active version (if any versions remain) after deletion.
The
self.getLatestVersionByIdentifier()call (line 595) uses the proxy to ensure cache semantics are respected, though note thatevictCache(petriNet)was called just before (line 592), which evicts the latest cache entry. This should still work correctly as the repository query will be executed.
461-464: getReference defaults to active version when version is null.This is the correct semantic change - when no specific version is requested, the active version (not just the newest) should be returned. This aligns with the PR's objective of distinguishing between "active" and "latest" versions.
...vy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/ActionDelegate.groovy
Show resolved
Hide resolved
...f/application/engine/petrinet/domain/dataset/logic/action/delegate/RoleActionDelegate.groovy
Show resolved
Hide resolved
...f/application/engine/petrinet/domain/dataset/logic/action/delegate/RoleActionDelegate.groovy
Show resolved
Hide resolved
...ine/src/main/java/com/netgrif/application/engine/menu/services/DashboardItemServiceImpl.java
Outdated
Show resolved
Hide resolved
...c/main/java/com/netgrif/application/engine/menu/services/DashboardManagementServiceImpl.java
Outdated
Show resolved
Hide resolved
...c/main/java/com/netgrif/application/engine/petrinet/service/interfaces/IPetriNetService.java
Show resolved
Hide resolved
...on-engine/src/main/java/com/netgrif/application/engine/petrinet/service/PetriNetService.java
Show resolved
Hide resolved
...src/main/java/com/netgrif/application/engine/workflow/service/FilterImportExportService.java
Show resolved
Hide resolved
...e/src/test/groovy/com/netgrif/application/engine/petrinet/service/PetriNetServiceTest.groovy
Show resolved
Hide resolved
- add null checks
- add null check
- update javadoc
- add null check
| newProcess.setVersion(existingLatestProcess.getVersion().clone()); | ||
| newProcess.incrementVersion(releaseType); | ||
| } else if (existingLatestProcess != null && newProcess.getVersion().isLowerThan(existingLatestProcess.getVersion())) { | ||
| throw new IllegalArgumentException("Only higher versions of process [%s] are allowed to import. The requested version [%s] cannot be imported because the higher version [%s] already exists." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logic requirements update:
- uploading also lower versions must be allowed (patching older version)
- uploaded process becomes active only if the version is highest
Description
Introduced new petriNet attribute
versionActive. The internal implementation no longer finds petri nets by the latest version, but finds the petri net, that is active. Only one version per identifier can be active.Implements NAE-2266
Dependencies
No new dependencies were introduced
Third party dependencies
No new dependencies were introduced
Blocking Pull requests
There are no dependencies on other PR
How Has Been This Tested?
Manually and by unit tests
PetriNetServiceTest
Test Configuration
Checklist:
Summary by CodeRabbit
Release Notes
New Features
Improvements
Bug Fixes
✏️ Tip: You can customize this high-level summary in your review settings.