This is an automated email from the ASF dual-hosted git repository.

chrisdutz pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x-extras.git


The following commit(s) were added to refs/heads/develop by this push:
     new 2092725b fix(plc4j/nifi): Repair the connection string validator
2092725b is described below

commit 2092725b71698262498665e78088a67890059cca
Author: Christofer Dutz <[email protected]>
AuthorDate: Sat Aug 15 12:18:58 2026 +0200

    fix(plc4j/nifi): Repair the connection string validator
    
    The validator opened a connection to check a connection string and then
    dropped it on the floor:
    
        driver.getConnection(input);
    
    NiFi validates properties repeatedly - on every configuration change, when a
    component starts, and while the configuration dialog is open - so each round
    left a connection behind. For OPC UA that is a secure channel and a session 
the
    device holds until they time out, which on hardware with a small connection
    limit is enough to lock everyone else out. The connection is now closed 
again.
    
    The catch only covered PlcConnectionException, but a driver may also reject 
a
    connection string with an unchecked exception: the OPC UA driver throws
    PlcRuntimeException when none of the endpoints a server advertises matches 
the
    one that was dialed. That escaped validate() instead of marking the property
    invalid, so the user got no usable feedback about a value they could have
    corrected. Any exception now produces an invalid result carrying the 
driver's
    message, and the rejected value is attached to it.
    
    The same validator exists in both the nifi-1 and nifi-2 processors, so both 
are
    fixed.
    
    Relates to: #2302
---
 .../org/apache/plc4x/nifi/BasePlc4xProcessor.java    | 20 +++++++++++++++-----
 .../org/apache/plc4x/nifi/BasePlc4xProcessor.java    | 20 +++++++++++++++-----
 2 files changed, 30 insertions(+), 10 deletions(-)

diff --git 
a/plc4j/integrations/apache-nifi/nifi-1/nifi-plc4x-processors/src/main/java/org/apache/plc4x/nifi/BasePlc4xProcessor.java
 
b/plc4j/integrations/apache-nifi/nifi-1/nifi-plc4x-processors/src/main/java/org/apache/plc4x/nifi/BasePlc4xProcessor.java
index 52cc63f4..a56c6835 100644
--- 
a/plc4j/integrations/apache-nifi/nifi-1/nifi-plc4x-processors/src/main/java/org/apache/plc4x/nifi/BasePlc4xProcessor.java
+++ 
b/plc4j/integrations/apache-nifi/nifi-1/nifi-plc4x-processors/src/main/java/org/apache/plc4x/nifi/BasePlc4xProcessor.java
@@ -48,7 +48,6 @@ import org.apache.nifi.serialization.record.RecordSchema;
 import org.apache.plc4x.java.DefaultPlcDriverManager;
 import org.apache.plc4x.java.api.PlcConnection;
 import org.apache.plc4x.java.api.PlcDriver;
-import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
 import org.apache.plc4x.java.api.messages.PlcReadRequest;
 import org.apache.plc4x.java.api.messages.PlcReadResponse;
 import org.apache.plc4x.java.api.messages.PlcWriteRequest;
@@ -341,12 +340,23 @@ public abstract class BasePlc4xProcessor extends 
AbstractProcessor {
             if (context.isExpressionLanguageSupported(subject) && 
context.isExpressionLanguagePresent(input)) {
                 return new 
ValidationResult.Builder().subject(subject).input(input).explanation("Expression
 Language Present").valid(true).build();
             }
+            // Validation opens a real connection, so it has to close it 
again: NiFi validates
+            // properties repeatedly and every leaked connection leaves a 
session behind on the
+            // device until it times out.
             try {
-                PlcDriver driver =  
AddressesAccessUtils.getManager().getDriverForUrl(input);
-                driver.getConnection(input);
-            } catch (PlcConnectionException e) {
+                PlcDriver driver = 
AddressesAccessUtils.getManager().getDriverForUrl(input);
+                try (PlcConnection connection = driver.getConnection(input)) {
+                    // Opening and closing is the check; nothing to do with 
the connection itself.
+                }
+            } catch (Exception e) {
+                // Not just PlcConnectionException: a driver may reject a 
connection string with an
+                // unchecked exception (the OPC UA driver throws 
PlcRuntimeException when no
+                // endpoint matches, for instance). Letting that escape turns 
a property the user
+                // can fix into a failing validator.
+                String explanation = e.getMessage() == null ? 
e.getClass().getName() : e.getMessage();
                 return new ValidationResult.Builder().subject(subject)
-                    .explanation(e.getMessage())
+                    .input(input)
+                    .explanation(explanation)
                     .valid(false)
                     .build();
             }
diff --git 
a/plc4j/integrations/apache-nifi/nifi-2/nifi-2-plc4x-processors/src/main/java/org/apache/plc4x/nifi/BasePlc4xProcessor.java
 
b/plc4j/integrations/apache-nifi/nifi-2/nifi-2-plc4x-processors/src/main/java/org/apache/plc4x/nifi/BasePlc4xProcessor.java
index 4f2a3991..70f3675d 100644
--- 
a/plc4j/integrations/apache-nifi/nifi-2/nifi-2-plc4x-processors/src/main/java/org/apache/plc4x/nifi/BasePlc4xProcessor.java
+++ 
b/plc4j/integrations/apache-nifi/nifi-2/nifi-2-plc4x-processors/src/main/java/org/apache/plc4x/nifi/BasePlc4xProcessor.java
@@ -48,7 +48,6 @@ import org.apache.nifi.serialization.record.RecordSchema;
 import org.apache.plc4x.java.DefaultPlcDriverManager;
 import org.apache.plc4x.java.api.PlcConnection;
 import org.apache.plc4x.java.api.PlcDriver;
-import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
 import org.apache.plc4x.java.api.messages.PlcReadRequest;
 import org.apache.plc4x.java.api.messages.PlcReadResponse;
 import org.apache.plc4x.java.api.messages.PlcWriteRequest;
@@ -341,12 +340,23 @@ public abstract class BasePlc4xProcessor extends 
AbstractProcessor {
             if (context.isExpressionLanguageSupported(subject) && 
context.isExpressionLanguagePresent(input)) {
                 return new 
ValidationResult.Builder().subject(subject).input(input).explanation("Expression
 Language Present").valid(true).build();
             }
+            // Validation opens a real connection, so it has to close it 
again: NiFi validates
+            // properties repeatedly and every leaked connection leaves a 
session behind on the
+            // device until it times out.
             try {
-                PlcDriver driver =  
AddressesAccessUtils.getManager().getDriverForUrl(input);
-                driver.getConnection(input);
-            } catch (PlcConnectionException e) {
+                PlcDriver driver = 
AddressesAccessUtils.getManager().getDriverForUrl(input);
+                try (PlcConnection connection = driver.getConnection(input)) {
+                    // Opening and closing is the check; nothing to do with 
the connection itself.
+                }
+            } catch (Exception e) {
+                // Not just PlcConnectionException: a driver may reject a 
connection string with an
+                // unchecked exception (the OPC UA driver throws 
PlcRuntimeException when no
+                // endpoint matches, for instance). Letting that escape turns 
a property the user
+                // can fix into a failing validator.
+                String explanation = e.getMessage() == null ? 
e.getClass().getName() : e.getMessage();
                 return new ValidationResult.Builder().subject(subject)
-                    .explanation(e.getMessage())
+                    .input(input)
+                    .explanation(explanation)
                     .valid(false)
                     .build();
             }

Reply via email to