Skip to content

[NAE-2464] Post release fixes - #464

Open
renczesstefan wants to merge 18 commits into
release/7.0.2from
NAE-2464
Open

[NAE-2464] Post release fixes#464
renczesstefan wants to merge 18 commits into
release/7.0.2from
NAE-2464

Conversation

@renczesstefan

@renczesstefan renczesstefan commented Jul 10, 2026

Copy link
Copy Markdown
Member

Description

Post release fixes after 7.0.1

Implements NAE-2464

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?

This was tested manually and with unit tests.

Test Configuration

Name Tested on
OS macOS Tahoe 26.3
Runtime Java 21
Dependency Manager Maven 3.9.9n
Framework version Spring Boot 3.4.4
Run parameters
Other configuration

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • My changes have been checked, personally or remotely, with @machacjozef
  • I have commented my code, particularly in hard-to-understand areas
  • I have resolved all conflicts with the target branch of the PR
  • I have updated and synced my code with the target branch
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing tests pass locally with my changes:
    • Lint test
    • Unit tests
    • Integration tests
  • I have checked my contribution with code analysis tools:
  • I have made corresponding changes to the documentation:
    • Developer documentation
    • User Guides
    • Migration Guides

Summary by CodeRabbit

  • New Features
    • Improved full-text search with multi-term wildcard handling and relevance weighting.
    • Enhanced Groovy action imports and script capabilities.
    • Added configurable MongoTemplate selection for migrations.
  • Bug Fixes
    • Improved asynchronous action reliability and state cleanup.
    • Corrected migration and deletion lookups.
  • Security
    • Restricted management access to health checks and disabled shutdown.
    • Refined exposed monitoring endpoints.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 33c1e521-feb7-4549-9a81-deb930f7874c

📥 Commits

Reviewing files that changed from the base of the PR and between 359567f and 56fbc83.

📒 Files selected for processing (9)
  • Dockerfile
  • Dockerfile.multi-stage
  • application-engine/pom.xml
  • docker-compose.yml
  • nae-object-library/pom.xml
  • nae-spring-core-adapter/pom.xml
  • nae-user-ce/pom.xml
  • nae-user-common/pom.xml
  • pom.xml

Walkthrough

The PR adds executor-backed asynchronous action execution, defers delegate cleanup across async work, improves Elastic full-text queries and Groovy import discovery, updates MongoDB identifier queries and migration wiring, narrows management endpoint exposure, and updates release version references.

Changes

Asynchronous action execution

Layer / File(s) Summary
Executor-backed action lifecycle
application-engine/src/main/groovy/.../AsyncRunner.groovy, application-engine/src/main/groovy/.../ActionDelegate.groovy, application-engine/src/main/java/.../TaskExecutionConfiguration.java
AsyncRunner submits actions to actionsExecutor, tracks nested delegates, and releases retained state exactly once.
Async action integration coverage
application-engine/src/test/groovy/.../ActionDelegateTest.groovy, application-engine/src/test/resources/petriNets/async_run.xml
Adds an async action Petri-net fixture and an integration test that imports it and creates a case.

Migration dependency wiring

Layer / File(s) Summary
Migration MongoTemplate selection
application-engine/src/main/groovy/.../migration/helpers/*, application-engine/src/main/java/.../MigrationProperties.java, application-engine/src/test/groovy/.../TestHelper.groovy
Migration helpers qualify the MongoTemplate dependency, migration properties use the netgrif.engine.migration prefix, and test cleanup uses the renamed field.

Elastic full-text search

Layer / File(s) Summary
Full-text query construction
application-engine/src/main/java/.../ElasticCaseService.java, application-engine/src/main/java/.../elastic/service/model/FullTextField.java
Search input is normalized into terms and queried with escaped, case-insensitive wildcard clauses using configured field boosts.

Groovy action import discovery

Layer / File(s) Summary
Classpath action-import selection
application-engine/src/main/java/.../GroovyShellFactory.java, application-engine/src/main/java/.../GroovyShellConfiguration.java
Action imports are discovered across configured package patterns and resolved to the most specific matching classes. Groovy scripts receive additional default imports.

Repository identifier migration

Layer / File(s) Summary
Composite identifier query transition
application-engine/src/main/java/.../ProcessRoleRepository.java, application-engine/src/main/java/.../CaseRepository.java, application-engine/src/main/java/.../CaseEventHandler.java
Composite-ID lookup and deletion handling use shortProcessIdentifier. Previous network-ID query methods are deprecated.

Management and release configuration

Layer / File(s) Summary
Actuator and management access settings
application-engine/src/main/resources/application*.properties, application-engine/src/main/resources/application.yaml, application-engine/src/test/resources/application-test.yaml, docker-compose.yml
Management exposure uses explicit allowlists, shutdown is disabled, and unauthenticated management access is narrowed to /manage/health.
Release version references
pom.xml, */pom.xml, Dockerfile*, docker-compose.yml
Maven, Docker, and Compose version references change from 7.0.1 to 7.0.2.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ActionDelegate
  participant AsyncRunner
  participant ActionsExecutor
  ActionDelegate->>AsyncRunner: retainForAsyncExecution()
  AsyncRunner->>ActionsExecutor: submit wrapped action
  ActionsExecutor->>AsyncRunner: execute closure
  AsyncRunner->>ActionDelegate: releaseAfterAsyncExecution()
Loading

Possibly related PRs

Suggested labels: bugfix, improvement, Large, Medium

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.65% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title identifies the work as post-release fixes but does not describe any specific primary change in the broad changeset. Use a concise title that names the main fix, such as asynchronous action execution and 7.0.2 configuration corrections.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@renczesstefan renczesstefan self-assigned this Jul 10, 2026
renczesstefan and others added 14 commits July 15, 2026 15:16
…elpers to use a dedicated MongoTemplate bean (`migrationMongoTemplate`) with fallback logic in multi-database setups.
…Id` and deprecate `findByNetworkIdAndObjectId`.
…te management and enhanced executor configuration.

- Added methods to `ActionDelegate` to manage asynchronous execution lifecycle (`retainForAsyncExecution`, `releaseAfterAsyncExecution`, `clearAfterExecution`).
- Enhanced `AsyncRunner` with delegate state tracking and custom `actionsExecutor`.
- Added `async_run.xml` test Petri net and corresponding test cases to validate asynchronous action handling.
…te management and enhanced executor configuration.

- Added methods to `ActionDelegate` to manage asynchronous execution lifecycle (`retainForAsyncExecution`, `releaseAfterAsyncExecution`, `clearAfterExecution`).
- Enhanced `AsyncRunner` with delegate state tracking and custom `actionsExecutor`.
- Added `async_run.xml` test Petri net and corresponding test cases to validate asynchronous action handling.
- Update `server-patterns` to replace `/manage/**` with `/manage/health`
- Configure `management.endpoint.shutdown.enabled` as `false` across properties
- Expand `management.endpoints.web.exposure.include` for additional actuator endpoints
…logic; consolidate MongoTemplate usage to default bean.
# Conflicts:
#	application-engine/src/test/groovy/com/netgrif/application/engine/TestHelper.groovy
#	application-engine/src/test/groovy/com/netgrif/application/engine/action/ActionDelegateTest.groovy
… and `TestHelper` for consistency and clarity.
…d` and deprecate `findByNetworkIdAndObjectId`; update tests and enums accordingly.
…tringQuery` with `BoolQuery`, introduce `FullTextField` model, and enhance wildcard handling.
…ce static imports with dynamic discovery, introduce `ACTION_IMPORT_PACKAGES`, and optimize class loading.
@machacjozef
machacjozef changed the base branch from release/7.0.0 to release/7.0.2 July 30, 2026 07:42
[NAE-2464] Release 1.0.1 Bugfixes
@machacjozef
machacjozef marked this pull request as ready for review July 30, 2026 08:21
@coderabbitai coderabbitai Bot added breaking change Fix or feature that would cause existing functionality doesn't work as expected bugfix A change that fixes a bug Large labels Jul 30, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@application-engine/src/main/java/com/netgrif/application/engine/configuration/properties/MigrationProperties.java`:
- Around line 24-33: Use MigrationProperties.mongoTemplateBeanName when wiring
the migration helpers instead of hard-coded `@Qualifier`("mongoTemplate")
injection. Update CaseMigrationHelper, PetriNetMigrationHelper, and
TaskMigrationHelper to resolve the configured bean, falling back to the default
mongoTemplate bean when unavailable; update MigrationProperties only as needed
to support this wiring.

In
`@application-engine/src/main/java/com/netgrif/application/engine/configuration/TaskExecutionConfiguration.java`:
- Around line 20-26: Update the actionsExecutor() ThreadPoolTaskExecutor
configuration to set a finite queue capacity, define a maxPoolSize, and
explicitly configure a RejectedExecutionHandler for submissions beyond available
capacity. Preserve the existing core pool size and thread name prefix while
ensuring overload behavior is intentional.

In
`@application-engine/src/main/java/com/netgrif/application/engine/elastic/service/ElasticCaseService.java`:
- Around line 579-585: Update boost parsing in the fulltext field definition
handling to accept the parsed value only when Float.isFinite(boost) and boost >
0. Treat NaN, infinities, zero, and negative values like NumberFormatException,
log the invalid input, and preserve the default 1.0f fallback.
- Around line 559-566: Update the full-text term normalization stream to
preserve backslashes through splitting and trimming, removing the pre-escaping
backslash deletion and the removeDanglingEscapeCharacters mapping. Ensure terms
flow unchanged into escapeWildcardValue so literal backslashes in paths such as
C:\temp are retained.

In
`@application-engine/src/main/java/com/netgrif/application/engine/event/GroovyShellFactory.java`:
- Around line 57-91: Update selectActionImport to emit a warning when multiple
most-specific candidates remain tied, including the conflicting class names in
the diagnostic, before returning Optional.empty(). Preserve the existing
behavior for unique winners and unresolved conflicts, and add focused tests
covering both tie and non-tie specificity resolution.

In `@application-engine/src/test/resources/petriNets/async_run.xml`:
- Around line 16-19: Make the async fixture in
application-engine/src/test/resources/petriNets/async_run.xml lines 16-19
persist a test-observable side effect instead of only printing useCase.stringId.
Update the test in
application-engine/src/test/groovy/com/netgrif/application/engine/action/ActionDelegateTest.groovy
lines 183-197 to await that persisted side effect with a bounded timeout and
assert it occurred, covering submission, execution, and delegate release.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e64b8de1-0138-4bec-ae5b-11a5a2934a26

📥 Commits

Reviewing files that changed from the base of the PR and between f11c250 and 96c7c17.

📒 Files selected for processing (23)
  • application-engine/src/main/groovy/com/netgrif/application/engine/AsyncRunner.groovy
  • application-engine/src/main/groovy/com/netgrif/application/engine/migration/helpers/CaseMigrationHelper.groovy
  • application-engine/src/main/groovy/com/netgrif/application/engine/migration/helpers/PetriNetMigrationHelper.groovy
  • application-engine/src/main/groovy/com/netgrif/application/engine/migration/helpers/TaskMigrationHelper.groovy
  • application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/ActionDelegate.groovy
  • application-engine/src/main/java/com/netgrif/application/engine/configuration/MongoClientConfiguration.java
  • application-engine/src/main/java/com/netgrif/application/engine/configuration/TaskExecutionConfiguration.java
  • application-engine/src/main/java/com/netgrif/application/engine/configuration/properties/MigrationProperties.java
  • application-engine/src/main/java/com/netgrif/application/engine/elastic/service/ElasticCaseService.java
  • application-engine/src/main/java/com/netgrif/application/engine/elastic/service/model/FullTextField.java
  • application-engine/src/main/java/com/netgrif/application/engine/event/GroovyShellFactory.java
  • application-engine/src/main/java/com/netgrif/application/engine/petrinet/domain/roles/ProcessRoleRepository.java
  • application-engine/src/main/java/com/netgrif/application/engine/workflow/domain/repositories/CaseRepository.java
  • application-engine/src/main/java/com/netgrif/application/engine/workflow/service/CaseEventHandler.java
  • application-engine/src/main/resources/application-old-dev.properties
  • application-engine/src/main/resources/application-old.properties
  • application-engine/src/main/resources/application.yaml
  • application-engine/src/test/groovy/com/netgrif/application/engine/TestHelper.groovy
  • application-engine/src/test/groovy/com/netgrif/application/engine/action/ActionDelegateTest.groovy
  • application-engine/src/test/groovy/com/netgrif/application/engine/action/AssignRemoveTest.groovy
  • application-engine/src/test/resources/application-test.yaml
  • application-engine/src/test/resources/petriNets/async_run.xml
  • docker-compose.yml

Comment on lines +20 to +26
@Bean("actionsExecutor")
TaskExecutor actionsExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setThreadNamePrefix("ActionsExecutor-");
return executor;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C3 \
  'actionsExecutor|setQueueCapacity|setMaxPoolSize|setRejectedExecutionHandler|waitForTasksToCompleteOnShutdown' \
  application-engine

fd -a 'pom.xml' . -x grep -nH -E 'spring-boot|spring-context' {}

Repository: netgrif/application-engine

Length of output: 9649


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== TaskExecutionConfiguration.java =="
cat -n application-engine/src/main/java/com/netgrif/application/engine/configuration/TaskExecutionConfiguration.java

echo
echo "== AsyncRunner.groovy =="
cat -n application-engine/src/main/groovy/com/netgrif/application/engine/AsyncRunner.groovy

echo
echo "== pom dependency versions around spring context/core =="
python3 - <<'PY'
from pathlib import Path
p=Path('application-engine/pom.xml')
text=p.read_text()
for needle in ['spring-boot.version','spring-boot-dependencies','spring-boot-parent','spring-context','spring-core','spring-boot-starter']:
    idx=text.find(needle)
    if idx!=-1:
        print(text[max(0,idx-250):idx+len(needle)+250])
PY

echo
echo "== All async executor usage =="
rg -n -C2 'AsyncRunner|actionsExecutor|execute\(\(|TaskExecutor' application-engine/src/main/java application-engine/src/main/groovy | head -200

Repository: netgrif/application-engine

Length of output: 26959


🌐 Web query:

Spring ThreadPoolTaskExecutor default queue capacity infinity unbounded queue rejection policy

💡 Result:

The Spring ThreadPoolTaskExecutor is designed with specific default behaviors regarding task queuing and rejection. Default Queue Capacity The default queue capacity for a ThreadPoolTaskExecutor is Integer.MAX_VALUE [1][2][3]. In practice, this is treated as an unbounded queue [4][5]. Because the queue is effectively infinite, tasks will continue to be added to the queue when the core pool size is reached, preventing the thread pool from ever scaling beyond the core pool size (unless the queue capacity is set to a finite value) [4][5]. Using an unbounded queue is generally discouraged for production applications, as it can lead to OutOfMemoryErrors if task submission outpaces processing [4]. Default Rejection Policy The default rejection policy is the AbortPolicy [6][7]. When the thread pool and its queue are both full (which only occurs if a finite queue capacity is configured), this policy throws a TaskRejectedException [6][8]. Configurable Options You can change these defaults to control how the executor behaves under load: 1. Queue Capacity: You can use setQueueCapacity(int) to define a specific limit [1][3]. Setting this to a positive value uses a LinkedBlockingQueue, while setting it to any other value (like 0) uses a SynchronousQueue [1][3]. A capacity of 0, for instance, forces the pool to create new threads immediately rather than queuing [1][5]. 2. Rejection Policy: You can configure alternatives to the default AbortPolicy, such as: - CallerRunsPolicy: Forces the thread that submitted the task to execute it, providing a natural throttling mechanism [6][7]. - DiscardPolicy: Silently drops the task [6][8]. - DiscardOldestPolicy: Drops the oldest unhandled task to make room for the new one [6][8].

Citations:


Bound the action queue and define overload behavior.

ThreadPoolTaskExecutor defaults to an unbounded queue with CorePoolSize, so async action submissions can accumulate indefinitely behind slow tasks before backpressure occurs. Configure a finite queue, a maxPoolSize, and an explicit rejection policy if that capacity can be reached.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@application-engine/src/main/java/com/netgrif/application/engine/configuration/TaskExecutionConfiguration.java`
around lines 20 - 26, Update the actionsExecutor() ThreadPoolTaskExecutor
configuration to set a finite queue capacity, define a maxPoolSize, and
explicitly configure a RejectedExecutionHandler for submissions beyond available
capacity. Preserve the existing core pool size and thread name prefix while
ensuring overload behavior is intentional.

Comment on lines +559 to +566
return Arrays.stream(fullText
.replaceAll("\\\\", "")
.replaceAll("\\s+", " ")
.trim()
.split("\\s+"))
.map(String::trim)
.map(this::removeDanglingEscapeCharacters)
.filter(term -> !term.isBlank())

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file exists and line count =="
wc -l application-engine/src/main/java/com/netgrif/application/engine/elastic/service/ElasticCaseService.java

echo "== relevant slices =="
sed -n '520,585p' application-engine/src/main/java/com/netgrif/application/engine/elastic/service/ElasticCaseService.java
echo "----"
sed -n '568,578p' application-engine/src/main/java/com/netgrif/application/engine/elastic/service/ElasticCaseService.java

echo "== usages of removeDanglingEscapeCharacters and escapeWildcardValue =="
rg -n "removeDanglingEscapeCharacters|escapeWildcardValue|build.*Search|Query|fullText" application-engine/src/main/java/com/netgrif/application/engine/elastic/service/ElasticCaseService.java

Repository: netgrif/application-engine

Length of output: 11663


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== escapeWildcardValue implementation =="
sed -n '590,610p' application-engine/src/main/java/com/netgrif/application/engine/elastic/service/ElasticCaseService.java

echo "== deterministic Java-like normalization behavior for representative inputs =="
python3 - <<'PY'
import re
def normalize_fulltext_search(full_text):
    return [
        term for term in [
            re.sub(r"[\\\s]+", " ", full_text)  # original .replaceAll("\\\\", "").replaceAll("\\s+", " ")
            .strip()
            .split()
        ] if term.strip()
    ]
def remove_dangling_escape_characters(term):
    return re.sub(r"\\+$", "", term)
def escape_wildcard_value(value):
    return value.replace("[", "\\[").replace(":", "\\:")
for raw in ["C:\\temp", "C:temp", "file:c:\\temp"]:
    terms = normalize_fulltext_search(raw)
    escaped = "*" + escape_wildcard_value(remove_dangling_escape_characters(terms[0] if terms else "" if True else terms[0])) + "*"
    print(f"{raw!r} -> {terms!r}", "-> after removeDangling:", remove_dangling_escape_characters(terms[0]) if terms else "", "-> wildcard:", escaped)

print("\nIf backslashes are kept until wildcard escape:")
for raw in ["C:\\temp", "file:c:\\temp"]:
    parts = re.sub(r"\\s+", " ", raw).strip().split()
    escaped = "*" + escape_wildcard_value(parts[0]) + "*"
    print(f"{raw!r} -> {parts!r} -> wildcard:", escaped)
PY

Repository: netgrif/application-engine

Length of output: 706


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== behavioral probe for normalization flow vs keep-backslash flow =="
python3 - <<'PY'
import re

def normalize_flow(full_text):
    # Model: .replaceAll("\\\\", "") .replaceAll("\\s+", " ") .trim().split("\\s+")
    term = re.sub(r"\\", "", full_text)
    term = re.sub(r"\s+", " ", term)
    term = term.strip()
    terms = term.split()
    return [t for t in terms if t]

def kept_backslash_flow(full_text):
    # Model: .replaceAll("\\s+", " ") .trim().split("\\s+") without removing backslashes
    term = re.sub(r"\s+", " ", full_text)
    term = term.strip()
    terms = term.split()
    return [t for t in terms if t]

def escape_wildcard_value(value):
    return value.replace("\\", "\\\\").replace("*", "\\*").replace("?", "\\?")

raws = ["C:\\temp", "file:c:\\temp", "C:temp"]
print("normalized -> escaped wildcard:")
for raw in raws:
    for term in normalize_flow(raw) or [""]:
        print(repr(raw), "=>", repr(term), "=>", repr("*" + escape_wildcard_value(term) + "*"))

print("\nkept backslashes -> escaped wildcard:")
for raw in raws:
    for term in kept_backslash_flow(raw) or [""]:
        print(repr(raw), "=>", repr(term), "=>", repr("*" + escape_wildcard_value(term) + "*"))
PY

Repository: netgrif/application-engine

Length of output: 564


Preserve literal backslashes in full-text search terms.

C:\\temp is normalized to C:temp before escapeWildcardValue runs, so wildcard searches for Windows paths lose the backslash. Keep backslashes until wildcard escaping, then no longer need removeDanglingEscapeCharacters.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@application-engine/src/main/java/com/netgrif/application/engine/elastic/service/ElasticCaseService.java`
around lines 559 - 566, Update the full-text term normalization stream to
preserve backslashes through splitting and trimming, removing the pre-escaping
backslash deletion and the removeDanglingEscapeCharacters mapping. Ensure terms
flow unchanged into escapeWildcardValue so literal backslashes in paths such as
C:\temp are retained.

Comment on lines +579 to +585
if (parts.length == 2 && !parts[1].isBlank()) {
try {
boost = Float.parseFloat(parts[1].trim());
} catch (NumberFormatException e) {
log.warn("Invalid boost [{}] in fulltext field definition [{}]. Using default boost 1.0.", parts[1], fieldDefinition);
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant service method and nearby boost usage, without running repository code.
file="application-engine/src/main/java/com/netgrif/application/engine/elastic/service/ElasticCaseService.java"
if [ -f "$file" ]; then
  wc -l "$file"
  sed -n '540,610p' "$file"
else
  fd -a 'ElasticCaseService.java' .
fi

# Locate nearby Elasticsearch search source construction involving boosts and fields.
rg -n "boost|Float\.parseFloat|SearchSourceBuilder|fields" application-engine/src/main/java/com/netgrif/application/engine/elastic -S || true

# Behavioral probe: Java parser accepts non-finite/non-positive boosts and ElasticSearch source values are positive-only?
python3 - <<'PY'
values = ['inf', '-inf', 'nan', '-1', '0', '1', '1.5']
for v in values:
    f = float(v)
    print(f"{v!r:8} -> parsed={f}, finite={f==f and abs(f)!=float('inf')}, positive={f>0}")
PY

Repository: netgrif/application-engine

Length of output: 6130


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the call site where parsed boosts are attached to Elasticsearch queries.
sed -n '420,450p' application-engine/src/main/java/com/netgrif/application/engine/elastic/service/ElasticCaseService.java

# Check Java project version/constraints to ground Java 21 parser semantics.
find . -maxdepth 3 \( -name 'pom.xml' -o -name 'build.gradle' -o -name 'gradle.properties' \) -print -exec sh -c 'echo "### $1"; sed -n "/<java.version\\|<java>/,/<\\/java>/p; /targetCompatibility\\|sourceCompatibility/p" "$1" 2>/dev/null || true' sh {} \;

Repository: netgrif/application-engine

Length of output: 11087


Reject non-finite and non-positive boosts.

Float.parseFloat can parse NaN, Infinity, and negative/zero values here, and the parsed boost is applied directly to Elasticsearch wildcard queries. Keep the parsed value only when Float.isFinite(boost) && boost > 0, logging otherwise so the fallback to 1.0f is used consistently for invalid input.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@application-engine/src/main/java/com/netgrif/application/engine/elastic/service/ElasticCaseService.java`
around lines 579 - 585, Update boost parsing in the fulltext field definition
handling to accept the parsed value only when Float.isFinite(boost) and boost >
0. Treat NaN, infinities, zero, and negative values like NumberFormatException,
log the invalid input, and preserve the default 1.0f fallback.

Comment on lines +57 to +91
private Set<String> findAllActionImportClasses() {
Set<Class<?>> classes = ACTION_IMPORT_PACKAGES.stream()
.flatMap(packageName -> findAllClassesUsingClassLoader(packageName).stream())
.map(this::loadClass)
.collect(Collectors.toCollection(HashSet::new));

return classes.stream()
.collect(Collectors.groupingBy(Class::getSimpleName))
.values().stream()
.map(this::selectActionImport)
.flatMap(Optional::stream)
.map(Class::getName)
.collect(Collectors.toSet());
}

private Optional<Class<?>> selectActionImport(List<Class<?>> candidates) {
int highestSpecificity = candidates.stream()
.mapToInt(candidate -> importSpecificity(candidate, candidates))
.max()
.orElseThrow();

List<Class<?>> mostSpecificCandidates = candidates.stream()
.filter(candidate -> importSpecificity(candidate, candidates) == highestSpecificity)
.toList();

return mostSpecificCandidates.size() == 1
? Optional.of(mostSpecificCandidates.getFirst())
: Optional.empty();
}

private int importSpecificity(Class<?> candidate, List<Class<?>> candidates) {
return (int) candidates.stream()
.filter(other -> other != candidate && other.isAssignableFrom(candidate))
.count();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Ambiguous class-name conflicts are silently dropped with no diagnostic signal.

When two unrelated classes across the scanned packages share a simple name (selectActionImport returns Optional.empty() on a specificity tie), both are silently excluded from the import customizer. Since the scan now spans three broad packages instead of the previous single package, name collisions are more likely than before, and a script referencing the dropped short name will fail with an opaque "unable to resolve class" error with no trace back to this resolution step.

Consider logging a warning identifying the colliding candidates when a tie occurs, so operators can diagnose missing imports without reverse-engineering this algorithm.

🪵 Suggested logging addition
     private Optional<Class<?>> selectActionImport(List<Class<?>> candidates) {
         int highestSpecificity = candidates.stream()
                 .mapToInt(candidate -> importSpecificity(candidate, candidates))
                 .max()
                 .orElseThrow();

         List<Class<?>> mostSpecificCandidates = candidates.stream()
                 .filter(candidate -> importSpecificity(candidate, candidates) == highestSpecificity)
                 .toList();

-        return mostSpecificCandidates.size() == 1
-                ? Optional.of(mostSpecificCandidates.getFirst())
-                : Optional.empty();
+        if (mostSpecificCandidates.size() == 1) {
+            return Optional.of(mostSpecificCandidates.getFirst());
+        }
+        log.warn("Ambiguous action-import simple name '{}' resolved among candidates {}; skipping import.",
+                candidates.getFirst().getSimpleName(), mostSpecificCandidates);
+        return Optional.empty();
     }

Separately, this new specificity-based conflict resolution has no dedicated unit test in the provided context (existing GroovyShellFactoryTest only exercises broader role/field action flows). A focused test for selectActionImport/importSpecificity covering the tie/no-tie cases would guard this logic against regressions.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private Set<String> findAllActionImportClasses() {
Set<Class<?>> classes = ACTION_IMPORT_PACKAGES.stream()
.flatMap(packageName -> findAllClassesUsingClassLoader(packageName).stream())
.map(this::loadClass)
.collect(Collectors.toCollection(HashSet::new));
return classes.stream()
.collect(Collectors.groupingBy(Class::getSimpleName))
.values().stream()
.map(this::selectActionImport)
.flatMap(Optional::stream)
.map(Class::getName)
.collect(Collectors.toSet());
}
private Optional<Class<?>> selectActionImport(List<Class<?>> candidates) {
int highestSpecificity = candidates.stream()
.mapToInt(candidate -> importSpecificity(candidate, candidates))
.max()
.orElseThrow();
List<Class<?>> mostSpecificCandidates = candidates.stream()
.filter(candidate -> importSpecificity(candidate, candidates) == highestSpecificity)
.toList();
return mostSpecificCandidates.size() == 1
? Optional.of(mostSpecificCandidates.getFirst())
: Optional.empty();
}
private int importSpecificity(Class<?> candidate, List<Class<?>> candidates) {
return (int) candidates.stream()
.filter(other -> other != candidate && other.isAssignableFrom(candidate))
.count();
}
private Set<String> findAllActionImportClasses() {
Set<Class<?>> classes = ACTION_IMPORT_PACKAGES.stream()
.flatMap(packageName -> findAllClassesUsingClassLoader(packageName).stream())
.map(this::loadClass)
.collect(Collectors.toCollection(HashSet::new));
return classes.stream()
.collect(Collectors.groupingBy(Class::getSimpleName))
.values().stream()
.map(this::selectActionImport)
.flatMap(Optional::stream)
.map(Class::getName)
.collect(Collectors.toSet());
}
private Optional<Class<?>> selectActionImport(List<Class<?>> candidates) {
int highestSpecificity = candidates.stream()
.mapToInt(candidate -> importSpecificity(candidate, candidates))
.max()
.orElseThrow();
List<Class<?>> mostSpecificCandidates = candidates.stream()
.filter(candidate -> importSpecificity(candidate, candidates) == highestSpecificity)
.toList();
if (mostSpecificCandidates.size() == 1) {
return Optional.of(mostSpecificCandidates.getFirst());
}
log.warn("Ambiguous action-import simple name '{}' resolved among candidates {}; skipping import.",
candidates.getFirst().getSimpleName(), mostSpecificCandidates);
return Optional.empty();
}
private int importSpecificity(Class<?> candidate, List<Class<?>> candidates) {
return (int) candidates.stream()
.filter(other -> other != candidate && other.isAssignableFrom(candidate))
.count();
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@application-engine/src/main/java/com/netgrif/application/engine/event/GroovyShellFactory.java`
around lines 57 - 91, Update selectActionImport to emit a warning when multiple
most-specific candidates remain tied, including the conflicting class names in
the diagnostic, before returning Optional.empty(). Preserve the existing
behavior for unique winners and unresolved conflicts, and add focused tests
covering both tie and non-tie specificity resolution.

Comment on lines +16 to +19
async.run {
sleep(2000)
println useCase.stringId
}

@coderabbitai coderabbitai Bot Jul 30, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make the async path observable and await it. The fixture only sleeps and prints, while the test asserts only that import and case creation succeeded; broken submission, execution, or delegate release still passes.

  • application-engine/src/test/resources/petriNets/async_run.xml#L16-L19: replace println with a test-observable persisted side effect.
  • application-engine/src/test/groovy/com/netgrif/application/engine/action/ActionDelegateTest.groovy#L183-L197: await that side effect with a bounded timeout and assert it occurred.
📍 Affects 2 files
  • application-engine/src/test/resources/petriNets/async_run.xml#L16-L19 (this comment)
  • application-engine/src/test/groovy/com/netgrif/application/engine/action/ActionDelegateTest.groovy#L183-L197
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@application-engine/src/test/resources/petriNets/async_run.xml` around lines
16 - 19, Make the async fixture in
application-engine/src/test/resources/petriNets/async_run.xml lines 16-19
persist a test-observable side effect instead of only printing useCase.stringId.
Update the test in
application-engine/src/test/groovy/com/netgrif/application/engine/action/ActionDelegateTest.groovy
lines 183-197 to await that persisted side effect with a bounded timeout and
assert it occurred, covering submission, execution, and delegate release.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ignore /src/test/*

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@machacjozef, acknowledged — I’ll skip review feedback under /src/test/*. For a persistent repository-wide exclusion, add that path to CodeRabbit’s path_filters configuration.

You are interacting with an AI system.

…ce static imports with dynamic discovery, introduce `ACTION_IMPORT_PACKAGES`, and optimize class loading.
@coderabbitai coderabbitai Bot added Medium and removed breaking change Fix or feature that would cause existing functionality doesn't work as expected labels Jul 30, 2026
@coderabbitai coderabbitai Bot removed the Large label Jul 30, 2026
- Update version to 7.0.2 in all affected `pom.xml` files
- Modify `Dockerfile` and `Dockerfile.multi-stage` to use version 7.0.2
- Adjust `docker-compose.yml` to reflect the new image version
@coderabbitai coderabbitai Bot added improvement A change that improves on an existing feature Large labels Jul 31, 2026
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
51.5% Coverage on New Code (required ≥ 60%)

See analysis details on SonarQube Cloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix A change that fixes a bug improvement A change that improves on an existing feature Large Medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants