Skip to content

Comments

Add service level monitoring support#1539

Merged
niveathika merged 5 commits intomasterfrom
service-attach
Feb 10, 2026
Merged

Add service level monitoring support#1539
niveathika merged 5 commits intomasterfrom
service-attach

Conversation

@niveathika
Copy link
Contributor

@niveathika niveathika commented Feb 5, 2026

Purpose

Fixes ballerina-platform/ballerina-library#8606

Examples

Checklist

  • Linked to an issue
  • Updated the changelog
  • Added tests
  • Updated the spec
  • Checked native-image compatibility

Summary by CodeRabbit

  • New Features

    • Service-level monitoring config: per-service path routing, filename patterns, age filters, and dependency rules.
    • Multi-path connector to route events to specific service paths while preserving legacy single-path behavior.
    • Events now include source-path metadata.
  • Deprecations

    • Listener-level fields for path, filename pattern, age filter, and dependency conditions marked deprecated—migrate to service-level config.
  • Documentation

    • Spec updated with migration guidance, examples, and validation rules.
  • Tests

    • Extensive tests added for service configs, routing, and error scenarios.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds service-level monitoring support to the FTP module, enabling multiple services attached to a single listener to monitor different paths independently through the @ftp:ServiceConfig annotation. This is a significant architectural enhancement that improves flexibility and modularity.

Changes:

  • Introduces @ftp:ServiceConfig annotation for service-level path configuration
  • Implements multi-path routing with MultiPathServerConnector and PathSpecificListener
  • Deprecates listener-level path, fileNamePattern, fileAgeFilter, and fileDependencyConditions fields in favor of service-level configuration

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
native/src/main/java/io/ballerina/stdlib/ftp/util/FtpConstants.java Adds constants for service-level configuration annotation
native/src/main/java/io/ballerina/stdlib/ftp/transport/server/connector/contractimpl/PathSpecificListener.java New wrapper class that adds path context to events for routing
native/src/main/java/io/ballerina/stdlib/ftp/transport/server/connector/contractimpl/MultiPathServerConnector.java New connector implementation supporting multiple path consumers
native/src/main/java/io/ballerina/stdlib/ftp/transport/message/RemoteFileSystemEvent.java Adds sourcePath field for routing events to correct service
native/src/main/java/io/ballerina/stdlib/ftp/server/ServiceConfiguration.java New immutable configuration class using builder pattern
native/src/main/java/io/ballerina/stdlib/ftp/server/FtpListenerHelper.java Extends registration logic to handle service-level configs, validates consistency, switches connectors
native/src/main/java/io/ballerina/stdlib/ftp/server/FtpListener.java Implements path-based routing logic and maintains service configurations
ballerina/tests/service_config_test.bal Comprehensive tests for multi-path routing, single service, backward compatibility
ballerina/listener_endpoint.bal Deprecates listener-level configuration fields
ballerina/annotations.bal Defines ServiceConfiguration record and ServiceConfig annotation

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@niveathika
Copy link
Contributor Author

@copilot open a new pull request to apply changes based on the unresolved comments in this thread

Copy link
Contributor

Copilot AI commented Feb 5, 2026

@niveathika I've opened a new pull request, #1540, to work on those changes. Once the pull request is ready, I'll request review from you.

@niveathika niveathika added the Skip GraalVM Check This will skip the GraalVM compatibility check label Feb 5, 2026
@niveathika niveathika force-pushed the service-attach branch 2 times, most recently from 626e1c9 to 0a033e0 Compare February 6, 2026 07:44
@niveathika niveathika requested a review from Copilot February 6, 2026 07:44
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 21 out of 21 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@codecov
Copy link

codecov bot commented Feb 6, 2026

Codecov Report

❌ Patch coverage is 67.02128% with 124 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.52%. Comparing base (0ea7960) to head (c55a1c2).
⚠️ Report is 6 commits behind head on master.

Files with missing lines Patch % Lines
...ballerina/stdlib/ftp/server/FtpListenerHelper.java 66.96% 51 Missing and 22 partials ⚠️
...nnector/contractimpl/MultiPathServerConnector.java 58.53% 19 Missing and 15 partials ⚠️
...lerina/stdlib/ftp/server/ServiceConfiguration.java 75.00% 8 Missing ⚠️
...va/io/ballerina/stdlib/ftp/server/FtpListener.java 80.00% 3 Missing and 2 partials ⚠️
...r/connector/contractimpl/PathSpecificListener.java 66.66% 3 Missing and 1 partial ⚠️

❌ Your project status has failed because the head coverage (77.52%) is below the target coverage (80.00%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files
@@             Coverage Diff              @@
##             master    #1539      +/-   ##
============================================
- Coverage     77.83%   77.52%   -0.31%     
- Complexity      718      989     +271     
============================================
  Files            55       74      +19     
  Lines          3582     4583    +1001     
  Branches        599      789     +190     
============================================
+ Hits           2788     3553     +765     
- Misses          552      686     +134     
- Partials        242      344     +102     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@niveathika
Copy link
Contributor Author

@copilot open a new pull request to apply changes based on the comments in this thread

Copy link
Contributor

Copilot AI commented Feb 6, 2026

@niveathika I've opened a new pull request, #1542, to work on those changes. Once the pull request is ready, I'll request review from you.

@coderabbitai
Copy link

coderabbitai bot commented Feb 9, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds service-level FTP monitoring via a new ServiceConfiguration type and @ServiceConfig annotation, implements multi-path routing and per-path consumers in native transport and listener layers, deprecates listener-level path fields, updates tests and docs, and propagates event sourcePath for routing.

Changes

Cohort / File(s) Summary
Public API & Docs
ballerina/annotations.bal, docs/spec/spec.md, changelog.md
Add ServiceConfiguration record and @ServiceConfig annotation; document service-level config, migration guidance, and add changelog entry.
Listener Configuration (Deprecation)
ballerina/listener_endpoint.bal
Mark listener-level fields (path, fileNamePattern, fileAgeFilter, fileDependencyConditions) deprecated and point to @ftp:ServiceConfig.
ServiceConfig Java Model
native/src/main/java/.../server/ServiceConfiguration.java
New immutable Java ServiceConfiguration with Builder (path, fileNamePattern, min/max age, ageCalculationMode, dependency conditions).
Listener Runtime & API
native/src/main/java/.../server/FtpListener.java, native/src/main/java/.../server/FtpListenerHelper.java
Defer connector creation; add concurrent maps for service configs and path→service mapping; parse/validate @ServiceConfig; support multi-path vs legacy single-path flows; add public query APIs; adjust lifecycle/poll/cleanup logic.
Multi-Path Connector & Path Listener
native/src/main/java/.../transport/server/connector/contractimpl/MultiPathServerConnector.java, .../PathSpecificListener.java
New MultiPathServerConnector managing per-path consumers and guarded poll/stop; PathSpecificListener tags events with sourcePath before delegating to FtpListener.
Connector Factory
native/src/main/java/.../transport/RemoteFileSystemConnectorFactory.java, .../impl/RemoteFileSystemConnectorFactoryImpl.java
Add factory method to create MultiPathServerConnector with FtpListener and implementation.
Event & Constants
native/src/main/java/.../transport/message/RemoteFileSystemEvent.java, native/src/main/java/.../util/FtpConstants.java
Add sourcePath field + accessors to events; add SERVICE_CONFIG_ANNOTATION and SERVICE_CONFIG_PATH constants.
Transport Integration
native/src/main/java/.../transport/...
Integrate MultiPathServerConnector with per-path property building and URI path replacement logic for per-path consumers.
Tests & Test Utilities
ballerina/tests/*, test-utils/src/main/java/.../MockFtpServer.java, compiler-plugin-tests/.../FtpServiceValidationTest.java
Add extensive service_config_test.bal; refactor many tests to use attach-based error checks; adjust client/listener tests and mock server dirs; narrow deprecation diagnostic filter.
Client/Listener Tests
ballerina/tests/client_endpoint_test.bal, .../client_endpoint_negative_test.bal, .../listener_endpoint_test.bal, .../secure_*_listener_endpoint_test.bal
Shift error surface to attach flow (attachResult) and restructure assertions; switch file-list verification to map-based checks.
Test Utilities
test-utils/src/.../MockFtpServer.java
Add directories used by new service-config tests (sc-route-a, sc-route-b, sc-single, sc-legacy, duplicate-test, mixed-test-annotated).
Misc
ballerina/Dependencies.toml
Bump ballerina/os dependency from 1.10.0 to 1.10.1.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Listener
    participant FtpListenerHelper
    participant MultiPathConnector
    participant PathListener
    participant RemoteFS

    Client->>Listener: new Listener(baseConfig)
    Listener->>FtpListenerHelper: init(baseConfig)
    FtpListenerHelper->>FtpListenerHelper: store base params, defer connector creation

    Client->>Listener: attach(service with `@ServiceConfig` path="/route-a")
    Listener->>FtpListenerHelper: register(service)
    FtpListenerHelper->>FtpListenerHelper: parse ServiceConfig, validate
    FtpListenerHelper->>MultiPathConnector: create(baseParams, ftpListener)
    FtpListenerHelper->>MultiPathConnector: addPathConsumer("/route-a", patterns, filters)
    MultiPathConnector->>PathListener: create(listener, "/route-a")
    MultiPathConnector->>RemoteFS: create consumer for /route-a

    RemoteFS->>MultiPathConnector: poll()
    MultiPathConnector->>PathListener: notify consumer
    PathListener->>PathListener: setSourcePath("/route-a")
    PathListener->>Listener: onMessage(event with sourcePath)
    Listener->>Listener: route event to service bound to "/route-a"
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Poem

🐰 I tunneled new paths for files to meet,
I taught each service where its route should be,
Annotations point the way, listeners lean in,
Events wear their source like a tiny pin,
Tests hop around — all green and glee!

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.30% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add service level monitoring support' clearly and concisely describes the primary change—introducing service-level configuration for FTP file monitoring.
Description check ✅ Passed The PR description includes the required sections: purpose (linked to issue #8606), checklist with all items checked, but lacks detailed examples or technical explanation of the implementation.
Linked Issues check ✅ Passed The PR implements service-level annotation (@ftp:ServiceConfig) with required fields (path, fileNamePattern) and optional fields (fileAgeFilter, fileDependencyConditions), enabling per-service configuration. Listener-level fields are properly deprecated, and comprehensive tests validate multi-path routing, backward compatibility, and error handling.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing service-level monitoring: new annotation, configuration deprecations, native connector refactoring, comprehensive tests, and documentation updates. A minor dependency version bump (os: 1.10.0→1.10.1) appears incidental.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch service-attach

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ballerina/tests/client_endpoint_test.bal (1)

1203-1249: ⚠️ Potential issue | 🟠 Major

Fix resourceNames/fileSizes length mismatch (and duplicate entry).
resourceNames has 23 entries while fileSizes has 22, so fileSizes[i] will throw out-of-bounds when i reaches the extra entry. There’s also a duplicate "onerror-tests" which likely caused the mismatch.

🛠️ Possible fix (remove the duplicate entry)
-        "test3.txt",
-        "onerror-tests",
+        "test3.txt",
         "sc-route-a",
If the duplicate is intentional, add the missing size entry instead.
🤖 Fix all issues with AI agents
In `@ballerina/tests/service_config_test.bal`:
- Around line 107-155: The testMultiPathRouting function uses module-level state
(routeAEventCount, routeBEventCount, routeALastFileName, routeBLastFileName)
which can leak between tests; reset those variables at the start of
testMultiPathRouting by setting routeAEventCount = 0, routeBEventCount = 0 and
clearing routeALastFileName/routeBLastFileName (empty string or nil as
appropriate) before creating the Listener and attaching services so each run
starts with clean state.

In `@changelog.md`:
- Line 10: Update the changelog entry text "- [Add service level monitoring
config](https://github.com/ballerina-platform/ballerina-library/issues/8606)" to
hyphenate "service-level" (i.e., change "service level monitoring config" to
"service-level monitoring config") so the markdown entry reads "- [Add
service-level monitoring
config](https://github.com/ballerina-platform/ballerina-library/issues/8606)".

In `@native/src/main/java/io/ballerina/stdlib/ftp/server/FtpListener.java`:
- Around line 574-578: The cleanup method currently clears registeredServices,
serviceConfigurations, pathToService and resets caller but leaves the
usesServiceLevelConfig flag set; update the cleanup() method in FtpListener to
also reset the usesServiceLevelConfig field (set it back to false) so that when
the listener is reused legacy services are not incorrectly rejected; locate the
usesServiceLevelConfig variable in the FtpListener class and ensure cleanup()
assigns it false alongside the other clears.
- Around line 518-526: The addServiceConfiguration method currently uses
containsKey + put on pathToService which is racy; replace that logic with an
atomic putIfAbsent on pathToService (call pathToService.putIfAbsent(path,
service) and check the return value) and only when putIfAbsent returns null
(meaning we successfully inserted) should you add the entry into
serviceConfigurations and set usesServiceLevelConfig.set(true); if putIfAbsent
indicates a preexisting entry, return false without modifying
serviceConfigurations or usesServiceLevelConfig.

In `@native/src/main/java/io/ballerina/stdlib/ftp/server/FtpListenerHelper.java`:
- Around line 134-165: Defer registering the service-level config so stale
mappings aren't left if connector creation fails: move the call to
listener.addServiceConfiguration(service, config) (and any listener flag like
usesServiceLevelConfig) to after createMultiPathConnector(...) has successfully
completed and ftpConnector is obtained, then proceed with casting to
MultiPathServerConnector and calling multiPathConnector.addPathConsumer(...),
listener.setFileSystemManager(...), and setFileSystemOptions(...);
alternatively, if you must call addServiceConfiguration before
createMultiPathConnector, wrap createMultiPathConnector in a try/catch and on
any failure remove the previously added config (e.g.,
listener.removeServiceConfiguration or equivalent) so the listener state is not
left with stale mappings.

In
`@native/src/main/java/io/ballerina/stdlib/ftp/server/ServiceConfiguration.java`:
- Around line 37-113: Ensure ServiceConfiguration enforces a non-null required
path and preserves immutability of dependencyConditions: in Builder.build()
(and/or the ServiceConfiguration(Builder) ctor) validate that Builder.path is
not null/empty and throw an IllegalStateException with a clear message if
missing, and defensively copy the dependencyConditions (e.g., use
List.copyOf(...) or Collections.unmodifiableList(new ArrayList<>(...))) instead
of assigning the builder list reference so the internal
List<FileDependencyCondition> cannot be mutated by callers; update assignments
in ServiceConfiguration(Builder) and/or Builder.dependencyConditions to perform
the immutable copy.
🧹 Nitpick comments (3)
docs/spec/spec.md (1)

1249-1249: Minor: Use hyphenated compound adjective.

"high availability" should be hyphenated when used as a compound adjective modifying "deployments".

📝 Suggested fix
-The FTP listener supports distributed coordination for high availability deployments.
+The FTP listener supports distributed coordination for high-availability deployments.
native/src/main/java/io/ballerina/stdlib/ftp/server/FtpListener.java (1)

557-563: Javadoc key mismatch (path vs service name).
The map is keyed by path, but the comment says “service name.” Consider aligning the Javadoc to avoid confusion.

native/src/main/java/io/ballerina/stdlib/ftp/server/FtpListenerHelper.java (1)

351-369: Prefer exact annotation-key matching to avoid false positives.
Using endsWith can match unrelated annotations from other modules with the same suffix.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@ballerina/tests/service_config_test.bal`:
- Around line 479-505: The test creates a Listener (ftpListener) but never stops
it, causing resource leaks if assertions fail; update
testServiceConfigInvalidFileNamePattern to ensure ftpListener is cleaned up by
calling ftpListener.stop() (or the listener's proper shutdown method) in a
finally block or a try/finally around the attach/assert logic, and apply the
same cleanup pattern to testServiceConfigInvalidTargetPattern and
testServiceConfigInvalidRequiredFilesPattern so the listener is always stopped
regardless of test outcome.
🧹 Nitpick comments (4)
native/src/main/java/io/ballerina/stdlib/ftp/server/FtpListenerHelper.java (1)

141-143: Consider using log.info instead of log.warn for expected behavior.

This log message describes normal, expected behavior when a service uses @ftp:ServiceConfig. Using warn level suggests something is wrong, but this is simply informational about which configuration takes precedence.

♻️ Suggested change
-                    log.warn("Creating multi-path connector for service with `@ftp`:ServiceConfig annotation " +
+                    log.info("Creating multi-path connector for service with `@ftp`:ServiceConfig annotation " +
                             "and path '{}'. The listener-level 'path' configuration will be ignored.",
                             config.getPath());
native/src/main/java/io/ballerina/stdlib/ftp/transport/server/connector/contractimpl/MultiPathServerConnector.java (3)

49-51: Consider making isPollOperationOccupied final.

The AtomicBoolean is never reassigned, so it should be final for clarity and to prevent accidental reassignment.

♻️ Suggested fix
-    private AtomicBoolean isPollOperationOccupied = new AtomicBoolean(false);
+    private final AtomicBoolean isPollOperationOccupied = new AtomicBoolean(false);

94-98: Potential race condition when initializing shared FileSystemManager.

If addPathConsumer is called concurrently from multiple threads, both could pass the fileSystemManager == null check and overwrite the field. While the effect is likely benign (same manager type), this is a subtle thread-safety issue.

Consider synchronizing initialization or using a more defensive pattern if concurrent registration is expected.

♻️ Suggested fix using synchronized block
         pathConsumers.put(path, consumer);
 
         // Store FileSystemManager and options from first consumer
-        if (fileSystemManager == null) {
-            fileSystemManager = consumer.getFileSystemManager();
-            fileSystemOptions = consumer.getFileSystemOptions();
+        synchronized (this) {
+            if (fileSystemManager == null) {
+                fileSystemManager = consumer.getFileSystemManager();
+                fileSystemOptions = consumer.getFileSystemOptions();
+            }
         }

Is addPathConsumer called concurrently during service attachment, or is it guaranteed to be single-threaded during listener startup?


194-209: Consider logging all errors, not just returning the last one.

The stop() method returns only the last error encountered, meaning earlier errors are silently lost. While the interface may constrain the return type, logging all errors would aid debugging.

♻️ Suggested enhancement
     `@Override`
     public Object stop() {
         Object lastError = null;
         for (Map.Entry<String, RemoteFileSystemConsumer> entry : pathConsumers.entrySet()) {
             try {
                 Object error = entry.getValue().close();
                 if (error != null) {
+                    log.warn("Error closing consumer for path {}: {}", entry.getKey(), error);
                     lastError = error;
                 }
             } catch (Exception e) {
                 log.error("Error stopping consumer for path: " + entry.getKey(), e);
             }
         }
         pathConsumers.clear();
         return lastError;
     }

coderabbitai bot added a commit that referenced this pull request Feb 9, 2026
Docstrings generation was requested by @niveathika.

* #1539 (comment)

The following files were modified:

* `native/src/main/java/io/ballerina/stdlib/ftp/server/FtpListener.java`
* `native/src/main/java/io/ballerina/stdlib/ftp/server/FtpListenerHelper.java`
* `native/src/main/java/io/ballerina/stdlib/ftp/server/ServiceConfiguration.java`
* `native/src/main/java/io/ballerina/stdlib/ftp/transport/RemoteFileSystemConnectorFactory.java`
* `native/src/main/java/io/ballerina/stdlib/ftp/transport/impl/RemoteFileSystemConnectorFactoryImpl.java`
* `native/src/main/java/io/ballerina/stdlib/ftp/transport/message/RemoteFileSystemEvent.java`
* `native/src/main/java/io/ballerina/stdlib/ftp/transport/server/connector/contractimpl/MultiPathServerConnector.java`
* `native/src/main/java/io/ballerina/stdlib/ftp/transport/server/connector/contractimpl/PathSpecificListener.java`
* `test-utils/src/main/java/io/ballerina/stdlib/ftp/testutils/mockServerUtils/MockFtpServer.java`
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@docs/spec/spec.md`:
- Around line 919-920: The sentence in the spec misleadingly states that
ftp:ListenerConfiguration requires a listener-level path; update it to say that
ftp:ListenerConfiguration requires protocol and host, and that the path should
be supplied via the `@ftp`:ServiceConfig annotation (listener-level path fields
are deprecated). Reference ftp:ListenerConfiguration, the deprecated
listener-level path field, and `@ftp`:ServiceConfig in the revised sentence.
- Around line 879-881: The spec currently states that `@ftp`:ServiceConfig.path
"must be an absolute path starting with '/'", but the runtime accepts and
normalizes relative paths; update the table row for "Invalid path pattern" to
reflect that relative paths are accepted and normalized (or remove the hard
requirement). Specifically, change the error message string for the "Invalid
path pattern" entry (the cell currently containing "Invalid path '{path}' in
`@ftp`:ServiceConfig. Path must be an absolute path starting with '/'." ) to
indicate that paths may be relative and will be normalized (e.g., "Invalid path
'{path}' in `@ftp`:ServiceConfig. Paths may be relative; runtime normalizes them
to an absolute path starting with '/'.") or otherwise document the automatic
normalization behavior for `@ftp`:ServiceConfig.path.
🧹 Nitpick comments (2)
ballerina/tests/secure_ftps_listener_endpoint_test.bal (1)

243-276: Consider consistency in error verification patterns across tests.

Some tests use Listener|Error with constructor-time error checks (e.g., testFtpsConnectToFTPServerWithFTPProtocol at line 319), while others use check new with attach-based error verification. This inconsistency may be intentional if certain errors are expected at construction time vs. attach time, but documenting this distinction would improve maintainability.

The attach-based pattern with inline attachService definitions works correctly for the intended test scenarios.

native/src/main/java/io/ballerina/stdlib/ftp/server/FtpListener.java (1)

124-135: Log when a source path has no registered service.
When usesServiceLevelConfig is enabled and no service matches event.getSourcePath(), the event is dropped silently. A warning would make misconfigurations far easier to debug.

💡 Suggested tweak
                 if (usesServiceLevelConfig.get() && event.getSourcePath() != null) {
                     // Path-keyed routing: dispatch only to the service monitoring this path
                     BObject service = pathToService.get(event.getSourcePath());
                     if (service != null) {
                         dispatchFileEventToService(this.environment, service, event);
+                    } else {
+                        log.warn("No service registered for source path: {}", event.getSourcePath());
                     }
                 } else {

@sonarqubecloud
Copy link

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@ballerina/tests/secure_ftps_listener_endpoint_test.bal`:
- Around line 306-309: The assertion is checking for "Failed to load KeyStore
from path" while the test is validating an invalid truststore, which is
confusing; update the test assertion or add a clarifying comment near the
ftpsServer.attach call and the test:assertTrue usage to explicitly state that
KeyStore is the Java class used for both keystore and truststore, or change the
test assertion message to mention "truststore" (e.g., include "truststore
(KeyStore) failed to load from path") so the failure message and the test name
align with attachResult, ftpsServer.attach, and test:assertTrue.
🧹 Nitpick comments (1)
ballerina/tests/secure_ftps_listener_endpoint_test.bal (1)

265-268: Extract duplicate attachService to a shared constant.

The identical attachService definition is repeated 6 times across the negative test cases (lines 265-268, 302-305, 360-363, 396-399, 472-475, 513-516). Consider extracting this to a file-level constant to reduce duplication and simplify maintenance.

♻️ Suggested refactor

Add a shared constant at the top of the file (e.g., near line 28):

// Minimal service for error-path testing
final Service noOpAttachService = service object {
    remote function onFileChange(WatchEvent & readonly event) {
    }
};

Then replace all inline attachService definitions with:

-    Service attachService = service object {
-        remote function onFileChange(WatchEvent & readonly event) {
-        }
-    };
-    error? attachResult = ftpsServer.attach(attachService);
+    error? attachResult = ftpsServer.attach(noOpAttachService);

Copy link
Contributor

@Nuvindu Nuvindu left a comment

Choose a reason for hiding this comment

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

LGTM

@niveathika niveathika merged commit 238b5fd into master Feb 10, 2026
7 of 9 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Feb 10, 2026
5 tasks
@niveathika niveathika deleted the service-attach branch February 12, 2026 12:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Skip GraalVM Check This will skip the GraalVM compatibility check

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Streamline service configuration via Annotations

3 participants