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

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

commit ce8cff4d2f71d47771aebcd0ea0c26b2b6ae10eb
Author: Sebastian Rühl <[email protected]>
AuthorDate: Mon Jul 6 15:24:24 2026 +0200

    fix(plc4j): align serial transport options with the plc4go vocabulary
    
    Remove the unused break-enabled, receive-buffer-size and send-buffer-size
    options, drop the RTS_CTS_XON_XOFF combined flow-control mode, and reject
    invalid parity/flow-control values with a TransportException naming the
    option instead of silently falling back to defaults. Values are now
    case-insensitive with "-"/"_" interchangeable (canonical: none, odd,
    even, mark, space; none, rts-cts, xon-xoff). Website config-doc partials
    regenerate from the updated annotations at the next site build.
---
 RELEASE_NOTES                                      |  7 +++
 .../transport/serial/SerialTransportInstance.java  | 51 +++++++--------
 .../config/SerialTransportConfiguration.java       | 36 ++---------
 .../serial/SerialTransportInstanceTest.java        | 72 ++++++++++++++++------
 .../java/transport/serial/SerialTransportTest.java |  2 +-
 .../config/SerialTransportConfigurationTest.java   | 40 ------------
 6 files changed, 93 insertions(+), 115 deletions(-)

diff --git a/RELEASE_NOTES b/RELEASE_NOTES
index 8278a7be72..dffd8b8e0e 100644
--- a/RELEASE_NOTES
+++ b/RELEASE_NOTES
@@ -34,6 +34,13 @@ Incompatible changes
   (default 1000 ms; set to 0 for the previous blocking behavior),
   and invalid serial option values now fail connection creation
   instead of being silently ignored.
+- The Java serial transport removed the unused options
+  "break-enabled", "receive-buffer-size" and "send-buffer-size",
+  removed the combined "RTS_CTS_XON_XOFF" flow-control mode, and now
+  rejects invalid parity/flow-control values instead of silently
+  falling back to defaults. Option values are case-insensitive and
+  accept "-" or "_" as separator (canonical forms: none, odd, even,
+  mark, space; none, rts-cts, xon-xoff).
 - The 'plc4x' proxy driver now defaults to the TLS transport
   instead of plaintext TCP. Existing plaintext connections must
   switch to an explicit transport prefix (e.g. "plc4x:tcp://...").
diff --git 
a/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialTransportInstance.java
 
b/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialTransportInstance.java
index 961a46fffb..05422834a7 100644
--- 
a/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialTransportInstance.java
+++ 
b/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialTransportInstance.java
@@ -33,6 +33,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.OutputStream;
+import java.util.Locale;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.Consumer;
@@ -187,39 +188,41 @@ public class SerialTransportInstance extends 
BaseTransportInstance<SerialTranspo
     }
 
     /**
-     * Converts parity string to jSerialComm constant.
+     * Converts a parity option value to the matching jSerialComm constant.
+     * Values are case-insensitive and accept "-" or "_" as separator.
      */
-    private int parseParity(String parity) {
-        return switch (parity.toUpperCase()) {
-            case "NONE" -> SerialPort.NO_PARITY;
-            case "ODD" -> SerialPort.ODD_PARITY;
-            case "EVEN" -> SerialPort.EVEN_PARITY;
-            case "MARK" -> SerialPort.MARK_PARITY;
-            case "SPACE" -> SerialPort.SPACE_PARITY;
-            default -> {
-                LOGGER.warn("Unknown parity '{}', using NONE", parity);
-                yield SerialPort.NO_PARITY;
-            }
+    static int parseParity(String parity) throws TransportException {
+        return switch (normalizeOptionValue(parity)) {
+            case "none" -> SerialPort.NO_PARITY;
+            case "odd" -> SerialPort.ODD_PARITY;
+            case "even" -> SerialPort.EVEN_PARITY;
+            case "mark" -> SerialPort.MARK_PARITY;
+            case "space" -> SerialPort.SPACE_PARITY;
+            default -> throw new TransportException(
+                "Invalid value '" + parity + "' for option 'parity' (must be 
one of: none, odd, even, mark, space)");
         };
     }
 
     /**
-     * Converts flow control string to jSerialComm constant.
+     * Converts a flow-control option value to the matching jSerialComm
+     * constant. Values are case-insensitive and accept "-" or "_" as
+     * separator. Combining hardware and software flow control is not
+     * supported (matching the plc4go serial transport).
      */
-    private int parseFlowControl(String flowControl) {
-        return switch (flowControl.toUpperCase()) {
-            case "NONE" -> SerialPort.FLOW_CONTROL_DISABLED;
-            case "RTS_CTS", "RTSCTS" -> SerialPort.FLOW_CONTROL_RTS_ENABLED | 
SerialPort.FLOW_CONTROL_CTS_ENABLED;
-            case "XON_XOFF", "XONXOFF" -> 
SerialPort.FLOW_CONTROL_XONXOFF_IN_ENABLED | 
SerialPort.FLOW_CONTROL_XONXOFF_OUT_ENABLED;
-            case "RTS_CTS_XON_XOFF" -> SerialPort.FLOW_CONTROL_RTS_ENABLED | 
SerialPort.FLOW_CONTROL_CTS_ENABLED |
-                    SerialPort.FLOW_CONTROL_XONXOFF_IN_ENABLED | 
SerialPort.FLOW_CONTROL_XONXOFF_OUT_ENABLED;
-            default -> {
-                LOGGER.warn("Unknown flow control '{}', using NONE", 
flowControl);
-                yield SerialPort.FLOW_CONTROL_DISABLED;
-            }
+    static int parseFlowControl(String flowControl) throws TransportException {
+        return switch (normalizeOptionValue(flowControl)) {
+            case "none" -> SerialPort.FLOW_CONTROL_DISABLED;
+            case "rts-cts", "rtscts" -> SerialPort.FLOW_CONTROL_RTS_ENABLED | 
SerialPort.FLOW_CONTROL_CTS_ENABLED;
+            case "xon-xoff", "xonxoff" -> 
SerialPort.FLOW_CONTROL_XONXOFF_IN_ENABLED | 
SerialPort.FLOW_CONTROL_XONXOFF_OUT_ENABLED;
+            default -> throw new TransportException(
+                "Invalid value '" + flowControl + "' for option 'flow-control' 
(must be one of: none, rts-cts, xon-xoff)");
         };
     }
 
+    private static String normalizeOptionValue(String value) {
+        return value.toLowerCase(Locale.ROOT).replace('_', '-');
+    }
+
     @Override
     public boolean isOpen() {
         return open && port.isOpen();
diff --git 
a/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/config/SerialTransportConfiguration.java
 
b/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/config/SerialTransportConfiguration.java
index 475456a1f8..41d4c6cafe 100644
--- 
a/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/config/SerialTransportConfiguration.java
+++ 
b/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/config/SerialTransportConfiguration.java
@@ -52,19 +52,19 @@ public class SerialTransportConfiguration implements 
TransportConfiguration {
     public int stopBits;
 
     /**
-     * Parity: NONE, ODD, EVEN, MARK, SPACE
+     * Parity: none, odd, even, mark, space (case-insensitive)
      */
     @ConfigurationParameter( "parity")
-    @Description( "Parity: NONE, ODD, EVEN, MARK, SPACE")
-    @StringDefaultValue("NONE")
+    @Description( "Parity: none, odd, even, mark, space (case-insensitive)")
+    @StringDefaultValue("none")
     public String parity;
 
     /**
-     * Flow control: NONE, RTS_CTS, XON_XOFF, RTS_CTS_XON_XOFF
+     * Flow control: none, rts-cts, xon-xoff (case-insensitive)
      */
     @ConfigurationParameter( "flow-control")
-    @Description( "Flow control: NONE, RTS_CTS, XON_XOFF, RTS_CTS_XON_XOFF")
-    @StringDefaultValue("NONE")
+    @Description( "Flow control: none, rts-cts, xon-xoff (case-insensitive)")
+    @StringDefaultValue("none")
     public String flowControl;
 
     /**
@@ -110,30 +110,6 @@ public class SerialTransportConfiguration implements 
TransportConfiguration {
     @BooleanDefaultValue(false)
     public boolean reusePort;
 
-    /**
-     * Receive buffer size in bytes. 0 uses system default.
-     */
-    @ConfigurationParameter( "receive-buffer-size")
-    @Description( "Receive buffer size in bytes. 0 uses system default.")
-    @IntDefaultValue(4096)
-    public int receiveBufferSize;
-
-    /**
-     * Send buffer size in bytes. 0 uses system default.
-     */
-    @ConfigurationParameter( "send-buffer-size")
-    @Description( "Send buffer size in bytes. 0 uses system default.")
-    @IntDefaultValue(4096)
-    public int sendBufferSize;
-
-    /**
-     * Enable break signal
-     */
-    @ConfigurationParameter( "break-enabled")
-    @Description( "Enable break signal")
-    @BooleanDefaultValue(false)
-    public boolean breakEnabled;
-
     /**
      * Interframe delay in milliseconds for protocols that need spacing 
between messages.
      * Only applies when reusePort is true.
diff --git 
a/plc4j/transports/serial/src/test/java/org/apache/plc4x/java/transport/serial/SerialTransportInstanceTest.java
 
b/plc4j/transports/serial/src/test/java/org/apache/plc4x/java/transport/serial/SerialTransportInstanceTest.java
index 8fc4cce0e7..5ad458f4b1 100644
--- 
a/plc4j/transports/serial/src/test/java/org/apache/plc4x/java/transport/serial/SerialTransportInstanceTest.java
+++ 
b/plc4j/transports/serial/src/test/java/org/apache/plc4x/java/transport/serial/SerialTransportInstanceTest.java
@@ -69,8 +69,6 @@ class SerialTransportInstanceTest {
         config.stopBits = 1;
         config.parity = "NONE";
         config.flowControl = "NONE";
-        config.receiveBufferSize = 4096;
-        config.sendBufferSize = 4096;
 
         transportInstance = new SerialTransportInstance(new 
SharedSerialPortManager(), "/tmp/ttyV0"/*port.getSystemPortName()*/, config, 
AuditLog.builder().build());
     }
@@ -314,7 +312,7 @@ class SerialTransportInstanceTest {
             transportInstance.close();
         }
 
-        // Create config with unknown parity - should default to NONE
+        // Create config with unknown parity - should now fail fast
         SerialTransportConfiguration configWithUnknownParity = new 
SerialTransportConfiguration();
         configWithUnknownParity.baudRate = 9600;
         configWithUnknownParity.dataBits = 8;
@@ -323,11 +321,8 @@ class SerialTransportInstanceTest {
         configWithUnknownParity.flowControl = "NONE";
         configWithUnknownParity.reusePort = false;
 
-        SerialTransportInstance instanceWithUnknownParity = new 
SerialTransportInstance(
-            new SharedSerialPortManager(), "/tmp/ttyV0", 
configWithUnknownParity, AuditLog.builder().build());
-
-        assertTrue(instanceWithUnknownParity.isOpen());
-        instanceWithUnknownParity.close();
+        assertThrows(TransportException.class, () -> new 
SerialTransportInstance(
+            new SharedSerialPortManager(), "/tmp/ttyV0", 
configWithUnknownParity, AuditLog.builder().build()));
     }
 
     @Test
@@ -337,7 +332,7 @@ class SerialTransportInstanceTest {
             transportInstance.close();
         }
 
-        // Create config with unknown flow control - should default to NONE
+        // Create config with unknown flow control - should now fail fast
         SerialTransportConfiguration configWithUnknownFlowControl = new 
SerialTransportConfiguration();
         configWithUnknownFlowControl.baudRate = 9600;
         configWithUnknownFlowControl.dataBits = 8;
@@ -346,11 +341,8 @@ class SerialTransportInstanceTest {
         configWithUnknownFlowControl.flowControl = "UNKNOWN_FLOW_CONTROL";  // 
Unknown flow control
         configWithUnknownFlowControl.reusePort = false;
 
-        SerialTransportInstance instanceWithUnknownFlowControl = new 
SerialTransportInstance(
-            new SharedSerialPortManager(), "/tmp/ttyV0", 
configWithUnknownFlowControl, AuditLog.builder().build());
-
-        assertTrue(instanceWithUnknownFlowControl.isOpen());
-        instanceWithUnknownFlowControl.close();
+        assertThrows(TransportException.class, () -> new 
SerialTransportInstance(
+            new SharedSerialPortManager(), "/tmp/ttyV0", 
configWithUnknownFlowControl, AuditLog.builder().build()));
     }
 
     @Test
@@ -383,7 +375,7 @@ class SerialTransportInstanceTest {
             transportInstance.close();
         }
 
-        // Create config with RTS_CTS_XON_XOFF flow control
+        // Create config with RTS_CTS_XON_XOFF flow control - combined mode is 
no longer supported
         SerialTransportConfiguration configWithCombinedFlowControl = new 
SerialTransportConfiguration();
         configWithCombinedFlowControl.baudRate = 9600;
         configWithCombinedFlowControl.dataBits = 8;
@@ -392,11 +384,8 @@ class SerialTransportInstanceTest {
         configWithCombinedFlowControl.flowControl = "RTS_CTS_XON_XOFF";
         configWithCombinedFlowControl.reusePort = false;
 
-        SerialTransportInstance instanceWithCombinedFlowControl = new 
SerialTransportInstance(
-            new SharedSerialPortManager(), "/tmp/ttyV0", 
configWithCombinedFlowControl, AuditLog.builder().build());
-
-        assertTrue(instanceWithCombinedFlowControl.isOpen());
-        instanceWithCombinedFlowControl.close();
+        assertThrows(TransportException.class, () -> new 
SerialTransportInstance(
+            new SharedSerialPortManager(), "/tmp/ttyV0", 
configWithCombinedFlowControl, AuditLog.builder().build()));
     }
 
     @Test
@@ -424,4 +413,47 @@ class SerialTransportInstanceTest {
             instanceWithParity.close();
         }
     }
+
+    @Test
+    void parseParityAcceptsCaseInsensitiveForms() throws Exception {
+        assertEquals(SerialPort.NO_PARITY, 
SerialTransportInstance.parseParity("none"));
+        assertEquals(SerialPort.EVEN_PARITY, 
SerialTransportInstance.parseParity("even"));
+        assertEquals(SerialPort.EVEN_PARITY, 
SerialTransportInstance.parseParity("EVEN"));
+        assertEquals(SerialPort.ODD_PARITY, 
SerialTransportInstance.parseParity("Odd"));
+        assertEquals(SerialPort.MARK_PARITY, 
SerialTransportInstance.parseParity("MARK"));
+        assertEquals(SerialPort.SPACE_PARITY, 
SerialTransportInstance.parseParity("space"));
+    }
+
+    @Test
+    void parseParityRejectsUnknownValues() {
+        TransportException e = assertThrows(TransportException.class,
+            () -> SerialTransportInstance.parseParity("strong"));
+        assertTrue(e.getMessage().contains("parity"));
+        assertTrue(e.getMessage().contains("strong"));
+    }
+
+    @Test
+    void parseFlowControlAcceptsCanonicalAndLegacyForms() throws Exception {
+        int rtsCts = SerialPort.FLOW_CONTROL_RTS_ENABLED | 
SerialPort.FLOW_CONTROL_CTS_ENABLED;
+        assertEquals(rtsCts, 
SerialTransportInstance.parseFlowControl("rts-cts"));
+        assertEquals(rtsCts, 
SerialTransportInstance.parseFlowControl("RTS_CTS"));
+        assertEquals(rtsCts, 
SerialTransportInstance.parseFlowControl("RTSCTS"));
+        int xonXoff = SerialPort.FLOW_CONTROL_XONXOFF_IN_ENABLED | 
SerialPort.FLOW_CONTROL_XONXOFF_OUT_ENABLED;
+        assertEquals(xonXoff, 
SerialTransportInstance.parseFlowControl("xon-xoff"));
+        assertEquals(xonXoff, 
SerialTransportInstance.parseFlowControl("XON_XOFF"));
+        assertEquals(SerialPort.FLOW_CONTROL_DISABLED, 
SerialTransportInstance.parseFlowControl("NONE"));
+    }
+
+    @Test
+    void parseFlowControlRejectsCombinedMode() {
+        TransportException e = assertThrows(TransportException.class,
+            () -> 
SerialTransportInstance.parseFlowControl("RTS_CTS_XON_XOFF"));
+        assertTrue(e.getMessage().contains("flow-control"));
+    }
+
+    @Test
+    void parseFlowControlRejectsUnknownValues() {
+        assertThrows(TransportException.class,
+            () -> SerialTransportInstance.parseFlowControl("magic"));
+    }
 }
diff --git 
a/plc4j/transports/serial/src/test/java/org/apache/plc4x/java/transport/serial/SerialTransportTest.java
 
b/plc4j/transports/serial/src/test/java/org/apache/plc4x/java/transport/serial/SerialTransportTest.java
index 5021b41b3d..155169baf6 100644
--- 
a/plc4j/transports/serial/src/test/java/org/apache/plc4x/java/transport/serial/SerialTransportTest.java
+++ 
b/plc4j/transports/serial/src/test/java/org/apache/plc4x/java/transport/serial/SerialTransportTest.java
@@ -214,7 +214,7 @@ class SerialTransportTest {
         SerialPort[] ports = SerialPort.getCommPorts();
         assumeTrue(ports.length > 0, "No serial ports available for testing");
 
-        String[] flowControlOptions = {"NONE", "RTS_CTS", "XON_XOFF", 
"RTS_CTS_XON_XOFF"};
+        String[] flowControlOptions = {"NONE", "RTS_CTS", "XON_XOFF"};
 
         for (String flowControl : flowControlOptions) {
             SerialTransportConfiguration config = new 
SerialTransportConfiguration();
diff --git 
a/plc4j/transports/serial/src/test/java/org/apache/plc4x/java/transport/serial/config/SerialTransportConfigurationTest.java
 
b/plc4j/transports/serial/src/test/java/org/apache/plc4x/java/transport/serial/config/SerialTransportConfigurationTest.java
index d485b0a9f5..9dbfe9a774 100644
--- 
a/plc4j/transports/serial/src/test/java/org/apache/plc4x/java/transport/serial/config/SerialTransportConfigurationTest.java
+++ 
b/plc4j/transports/serial/src/test/java/org/apache/plc4x/java/transport/serial/config/SerialTransportConfigurationTest.java
@@ -119,30 +119,6 @@ class SerialTransportConfigurationTest {
         assertTrue(config.reusePort);
     }
 
-    @Test
-    void testReceiveBufferSizeField() {
-        SerialTransportConfiguration config = new 
SerialTransportConfiguration();
-        config.receiveBufferSize = 65536;
-        assertEquals(65536, config.receiveBufferSize);
-    }
-
-    @Test
-    void testSendBufferSizeField() {
-        SerialTransportConfiguration config = new 
SerialTransportConfiguration();
-        config.sendBufferSize = 32768;
-        assertEquals(32768, config.sendBufferSize);
-    }
-
-    @Test
-    void testBreakEnabledField() {
-        SerialTransportConfiguration config = new 
SerialTransportConfiguration();
-        config.breakEnabled = false;
-        assertFalse(config.breakEnabled);
-
-        config.breakEnabled = true;
-        assertTrue(config.breakEnabled);
-    }
-
     @Test
     void testInterframeDelayField() {
         SerialTransportConfiguration config = new 
SerialTransportConfiguration();
@@ -164,9 +140,6 @@ class SerialTransportConfigurationTest {
         config.dtr = true;
         config.rts = true;
         config.reusePort = true;
-        config.receiveBufferSize = 8192;
-        config.sendBufferSize = 8192;
-        config.breakEnabled = true;
         config.interframeDelay = 10;
 
         assertEquals(115200, config.baudRate);
@@ -179,9 +152,6 @@ class SerialTransportConfigurationTest {
         assertTrue(config.dtr);
         assertTrue(config.rts);
         assertTrue(config.reusePort);
-        assertEquals(8192, config.receiveBufferSize);
-        assertEquals(8192, config.sendBufferSize);
-        assertTrue(config.breakEnabled);
         assertEquals(10, config.interframeDelay);
     }
 
@@ -195,16 +165,6 @@ class SerialTransportConfigurationTest {
         assertEquals(0, config.writeTimeout);
     }
 
-    @Test
-    void testZeroBufferSizes() {
-        SerialTransportConfiguration config = new 
SerialTransportConfiguration();
-        config.sendBufferSize = 0;
-        config.receiveBufferSize = 0;
-
-        assertEquals(0, config.sendBufferSize);
-        assertEquals(0, config.receiveBufferSize);
-    }
-
     @Test
     void testZeroInterframeDelay() {
         SerialTransportConfiguration config = new 
SerialTransportConfiguration();

Reply via email to