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

cdutz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-plc4x.git


The following commit(s) were added to refs/heads/master by this push:
     new f80c9ef  Made the disconnect for S7 respect the ISO TP protocol.
f80c9ef is described below

commit f80c9ef8be8d163e0702f77b028977d310978606
Author: Christofer Dutz <christofer.d...@c-ware.de>
AuthorDate: Fri Aug 3 09:27:08 2018 +0200

    Made the disconnect for S7 respect the ISO TP protocol.
---
 .../ads/connection/AdsAbstractPlcConnection.java   |  3 +-
 .../apache/plc4x/java/ads/adslib/AmsRouter.java    |  6 +++-
 .../base/connection/AbstractPlcConnection.java     |  2 +-
 plc4j/protocols/s7/pom.xml                         |  4 +++
 .../plc4x/java/s7/connection/S7PlcConnection.java  | 38 +++++++++++++++++++---
 .../java/s7/connection/S7PlcConnectionIT.java      |  4 +--
 6 files changed, 47 insertions(+), 10 deletions(-)

diff --git 
a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/connection/AdsAbstractPlcConnection.java
 
b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/connection/AdsAbstractPlcConnection.java
index cf1b8d9..125d012 100644
--- 
a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/connection/AdsAbstractPlcConnection.java
+++ 
b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/connection/AdsAbstractPlcConnection.java
@@ -33,6 +33,7 @@ import org.apache.plc4x.java.ads.model.SymbolicAdsAddress;
 import org.apache.plc4x.java.api.connection.PlcProprietarySender;
 import org.apache.plc4x.java.api.connection.PlcReader;
 import org.apache.plc4x.java.api.connection.PlcWriter;
+import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
 import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.api.messages.*;
 import org.apache.plc4x.java.api.messages.items.RequestItem;
@@ -189,7 +190,7 @@ public abstract class AdsAbstractPlcConnection extends 
AbstractPlcConnection imp
     }
 
     @Override
-    public void close() {
+    public void close() throws PlcConnectionException {
         addressMapping.values().stream()
             .parallel()
             .map(adsAddress -> AdsWriteRequest.of(
diff --git 
a/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/adslib/AmsRouter.java
 
b/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/adslib/AmsRouter.java
index ba0bf79..06786af 100644
--- 
a/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/adslib/AmsRouter.java
+++ 
b/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/adslib/AmsRouter.java
@@ -107,7 +107,11 @@ public class AmsRouter {
         AdsTcpPlcConnection route = mapping.get(ams);
         if (route != null) {
             AdsTcpPlcConnection conn = route;
-            conn.close();
+            try {
+                conn.close();
+            } catch (PlcConnectionException e) {
+                throw new RuntimeException(e);
+            }
             MutableInt refCounter = refCounts.getOrDefault(conn, new 
MutableInt());
             if (0 == refCounter.decrementAndGet()) {
                 mapping.remove(ams);
diff --git 
a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/connection/AbstractPlcConnection.java
 
b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/connection/AbstractPlcConnection.java
index 83f1540..c679915 100644
--- 
a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/connection/AbstractPlcConnection.java
+++ 
b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/connection/AbstractPlcConnection.java
@@ -80,7 +80,7 @@ public abstract class AbstractPlcConnection implements 
PlcConnection {
     }
 
     @Override
-    public void close() {
+    public void close() throws PlcConnectionException {
         channel = null;
         connected = false;
     }
diff --git a/plc4j/protocols/s7/pom.xml b/plc4j/protocols/s7/pom.xml
index 75dec71..9ea4e45 100644
--- a/plc4j/protocols/s7/pom.xml
+++ b/plc4j/protocols/s7/pom.xml
@@ -76,6 +76,10 @@
       <groupId>org.apache.commons</groupId>
       <artifactId>commons-lang3</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-configuration2</artifactId>
+    </dependency>
 
     <dependency>
       <groupId>ch.qos.logback</groupId>
diff --git 
a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java
 
b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java
index fd8c98d..9b80741 100644
--- 
a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java
+++ 
b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java
@@ -19,6 +19,8 @@ under the License.
 package org.apache.plc4x.java.s7.connection;
 
 import io.netty.channel.*;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.SystemConfiguration;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.plc4x.java.api.connection.PlcReader;
 import org.apache.plc4x.java.api.connection.PlcWriter;
@@ -50,6 +52,9 @@ import org.slf4j.LoggerFactory;
 import java.net.InetAddress;
 import java.util.Collections;
 import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -75,6 +80,10 @@ public class S7PlcConnection extends AbstractPlcConnection 
implements PlcReader,
 
     private static final int ISO_ON_TCP_PORT = 102;
 
+    // Fetch values from configuration
+    private static final Configuration CONF = new SystemConfiguration();
+    private static final long CLOSE_DEVICE_TIMEOUT_MS = 
CONF.getLong("plc4x.s7connection.close.device,timeout", 1_000);
+
     private static final Pattern S7_DATABLOCK_ADDRESS_PATTERN =
         
Pattern.compile("^DATA_BLOCKS/(?<blockNumber>\\d{1,4})/(?<byteOffset>\\d{1,4})");
     private static final Pattern S7_ADDRESS_PATTERN =
@@ -194,19 +203,38 @@ public class S7PlcConnection extends 
AbstractPlcConnection implements PlcReader,
     }
 
     @Override
-    public void close() {
+    public void close() throws PlcConnectionException {
         if ((channel != null) && channel.isOpen()) {
             // Send the PLC a message that the connection is being closed.
             DisconnectRequestTpdu disconnectRequest = new 
DisconnectRequestTpdu(
                 (short) 0x0000, (short) 0x000F, DisconnectReason.NORMAL, 
Collections.emptyList(),
                 null);
-            channel.writeAndFlush(disconnectRequest).awaitUninterruptibly();
 
             // In case of an ISO TP Class 0 connection, the remote is usually 
expected to actively
-            // close the connection. We are simplifying things by doing it 
ourselves immediately.
-            // TODO: It would probably be more spec-conform to wait for the 
remote to disconnect and to only do it actively if it doesn't happen within a 
certain time. But this solution is good enough for now.
-            channel.close();
+            // close the connection. So we add a listener waiting for this to 
happen.
+            CompletableFuture<Void> disconnectFuture = new 
CompletableFuture<>();
+            channel.closeFuture().addListener(
+                (ChannelFutureListener) future -> 
disconnectFuture.complete(null));
+
+            // Send the disconnect request.
+            channel.writeAndFlush(disconnectRequest);
+            // Wait for the configured time for the remote to close the 
session.
+            try {
+                disconnectFuture.get(CLOSE_DEVICE_TIMEOUT_MS, 
TimeUnit.MILLISECONDS);
+            }
+            // If the remote didn't close the connection within the given 
time-frame, we have to take
+            // care of closing the connection.
+            catch (TimeoutException e) {
+                logger.info("Remote didn't close connection within the 
configured timeout of " +
+                    CLOSE_DEVICE_TIMEOUT_MS + "ms, shutting down actively.");
+                channel.close();
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+            } catch (ExecutionException e) {
+                throw new PlcConnectionException(e);
+            }
 
+            // Do some additional cleanup operations ...
             // In normal operation, the channels event loop has a parent, 
however when running with
             // the embedded channel for unit tests, parent is null.
             if(channel.eventLoop().parent() != null) {
diff --git 
a/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/s7/connection/S7PlcConnectionIT.java
 
b/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/s7/connection/S7PlcConnectionIT.java
index c9c4b94..324ee0a 100644
--- 
a/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/s7/connection/S7PlcConnectionIT.java
+++ 
b/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/s7/connection/S7PlcConnectionIT.java
@@ -56,7 +56,7 @@ public class S7PlcConnectionIT {
     }
 
     @After
-    public void tearDown() {
+    public void tearDown() throws PlcConnectionException{
         if(s7PlcConnection.isConnected()) {
             s7PlcConnection.close();
         }
@@ -71,7 +71,7 @@ public class S7PlcConnectionIT {
     }
 
     @Test
-    public void testDisconnect() {
+    public void testDisconnect() throws PlcConnectionException {
         assertThat(s7PlcConnection, notNullValue());
         assertThat("The connection should be 'connected'", 
s7PlcConnection.isConnected(), is( true) );
         s7PlcConnection.close();

Reply via email to