You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by sr...@apache.org on 2018/02/02 09:07:16 UTC
[incubator-plc4x] branch feature/Beckhoff_ADS_protocol updated:
added some basic tests and commited the missing parts
This is an automated email from the ASF dual-hosted git repository.
sruehl pushed a commit to branch feature/Beckhoff_ADS_protocol
in repository https://gitbox.apache.org/repos/asf/incubator-plc4x.git
The following commit(s) were added to refs/heads/feature/Beckhoff_ADS_protocol by this push:
new 813415f added some basic tests and commited the missing parts
813415f is described below
commit 813415f32f73124b7b54fc2f7a87e7bf92e3acc6
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Fri Feb 2 10:07:11 2018 +0100
added some basic tests and commited the missing parts
---
plc4j/protocols/ads/pom.xml | 6 ++
.../org/apache/plc4x/java/ads/ADSPlcDriver.java | 15 +--
.../plc4x/java/ads/api/generic/types/AMSNetId.java | 6 ++
.../plc4x/java/ads/api/generic/types/AMSPort.java | 9 +-
.../java/ads/connection/ADSPlcConnection.java | 26 +++++-
.../plc4x/java/ads/netty/Plc4XADSProtocol.java | 85 +++++++++++++++++
.../services/org.apache.plc4x.java.api.PlcDriver | 19 ++++
plc4j/protocols/ads/src/site/asciidoc/index.adoc | 101 +++++++++++++++++++++
.../apache/plc4x/java/ads/ADSPlcDriverTest.java | 56 ++++++++++++
.../java/ads/connection/ADSPlcConnectionTests.java | 72 +++++++++++++++
plc4j/protocols/ads/src/test/resources/logback.xml | 36 ++++++++
11 files changed, 418 insertions(+), 13 deletions(-)
diff --git a/plc4j/protocols/ads/pom.xml b/plc4j/protocols/ads/pom.xml
index 273084c..2eb013e 100644
--- a/plc4j/protocols/ads/pom.xml
+++ b/plc4j/protocols/ads/pom.xml
@@ -68,6 +68,12 @@
</dependency>
<dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ <version>3.7</version>
+ </dependency>
+
+ <dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<scope>test</scope>
diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/ADSPlcDriver.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/ADSPlcDriver.java
index d1bcd0d..2b9b3b6 100644
--- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/ADSPlcDriver.java
+++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/ADSPlcDriver.java
@@ -37,9 +37,10 @@ import java.util.regex.Pattern;
public class ADSPlcDriver implements PlcDriver {
private static final Pattern ADS_ADDRESS_PATTERN =
- Pattern.compile("^(?<targetAmsNetId>" + AMSNetId.AMS_NET_ID_PATTERN + "):(?<targetAmsPort>" + AMSPort.AMS_PORT_PATTERN + ")"
- + "/"
- + "(?<sourceAmsNetId>" + AMSNetId.AMS_NET_ID_PATTERN + "):(?<sourceAmsPort>" + AMSPort.AMS_PORT_PATTERN + ")");
+ Pattern.compile("(?<targetAmsNetId>" + AMSNetId.AMS_NET_ID_PATTERN + "):(?<targetAmsPort>" + AMSPort.AMS_PORT_PATTERN + ")"
+ + "(/"
+ + "(?<sourceAmsNetId>" + AMSNetId.AMS_NET_ID_PATTERN + "):(?<sourceAmsPort>" + AMSPort.AMS_PORT_PATTERN + ")"
+ + ")?");
private static final Pattern ADS_URI_PATTERN = Pattern.compile("^ads://(?<host>\\w+)/" + ADS_ADDRESS_PATTERN);
@Override
@@ -57,13 +58,15 @@ public class ADSPlcDriver implements PlcDriver {
Matcher matcher = ADS_URI_PATTERN.matcher(url);
if (!matcher.matches()) {
throw new PlcConnectionException(
- "Connection url doesn't match the format 'ads://{host|ip}/{targetAmsNetId}:{targetAmsPort}/{sourceAmsNetId}:{sourceAmsPort}'");
+ "Connection url " + url + " doesn't match 'ads://{host|ip}/{targetAmsNetId}:{targetAmsPort}/{sourceAmsNetId}:{sourceAmsPort}' RAW:" + ADS_URI_PATTERN);
}
String host = matcher.group("host");
AMSNetId targetAmsNetId = AMSNetId.of(matcher.group("targetAmsNetId"));
AMSPort targetAmsPort = AMSPort.of(matcher.group("targetAmsPort"));
- AMSNetId sourceAmsNetId = AMSNetId.of(matcher.group("sourceAmsNetId"));
- AMSPort sourceAmsPort = AMSPort.of(matcher.group("sourceAmsPort"));
+ String sourceAmsNetIdString = matcher.group("sourceAmsNetId");
+ AMSNetId sourceAmsNetId = sourceAmsNetIdString != null ? AMSNetId.of(sourceAmsNetIdString) : null;
+ String sourceAmsPortString = matcher.group("sourceAmsPort");
+ AMSPort sourceAmsPort = sourceAmsPortString != null ? AMSPort.of(sourceAmsPortString) : null;
return new ADSPlcConnection(host, targetAmsNetId, targetAmsPort, sourceAmsNetId, sourceAmsPort);
}
diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AMSNetId.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AMSNetId.java
index 73fc07d..0c5917f 100644
--- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AMSNetId.java
+++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AMSNetId.java
@@ -63,4 +63,10 @@ public class AMSNetId extends ByteValue {
byte[] bytes = ArrayUtils.toPrimitive(Stream.of(split).map(Integer::parseInt).map(Integer::byteValue).toArray(Byte[]::new));
return new AMSNetId(bytes);
}
+
+ @Override
+ public String toString() {
+ byte[] bytes = getBytes();
+ return bytes[0] + "." + bytes[1] + "." + bytes[2] + "." + bytes[3] + "." + bytes[4] + "." + bytes[5];
+ }
}
diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AMSPort.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AMSPort.java
index e5e9c28..ab8a1c1 100644
--- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AMSPort.java
+++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AMSPort.java
@@ -39,13 +39,18 @@ public class AMSPort extends ByteValue {
}
public static AMSPort of(int port) {
- return new AMSPort(ByteBuffer.allocate(NUM_BYTES).putInt(port).array());
+ return new AMSPort(ByteBuffer.allocate(NUM_BYTES).put((byte) (port & 0xff)).array());
}
public static AMSPort of(String port) {
if (!AMS_PORT_PATTERN.matcher(port).matches()) {
throw new IllegalArgumentException(port + " must match " + AMS_PORT_PATTERN);
}
- return new AMSPort(ByteBuffer.allocate(NUM_BYTES).putInt(Integer.parseInt(port)).array());
+ return of(Integer.parseInt(port));
+ }
+
+ @Override
+ public String toString() {
+ return "" + getBytes()[0];
}
}
diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/connection/ADSPlcConnection.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/connection/ADSPlcConnection.java
index a6b7ba6..92ae31f 100644
--- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/connection/ADSPlcConnection.java
+++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/connection/ADSPlcConnection.java
@@ -47,19 +47,23 @@ public class ADSPlcConnection extends AbstractPlcConnection implements PlcReader
private final String hostName;
- private final int pduSize;
-
private final AMSNetId targetAmsNetId;
+
private final AMSPort targetAmsPort;
+
private final AMSNetId sourceAmsNetId;
+
private final AMSPort sourceAmsPort;
private EventLoopGroup workerGroup;
private Channel channel;
+ public ADSPlcConnection(String hostName, AMSNetId targetAmsNetId, AMSPort targetAmsPort) {
+ this(hostName, targetAmsNetId, targetAmsPort, null, null);
+ }
+
public ADSPlcConnection(String hostName, AMSNetId targetAmsNetId, AMSPort targetAmsPort, AMSNetId sourceAmsNetId, AMSPort sourceAmsPort) {
this.hostName = hostName;
- this.pduSize = 1024;
this.targetAmsNetId = targetAmsNetId;
this.targetAmsPort = targetAmsPort;
this.sourceAmsNetId = sourceAmsNetId;
@@ -70,8 +74,20 @@ public class ADSPlcConnection extends AbstractPlcConnection implements PlcReader
return hostName;
}
- public int getPduSize() {
- return pduSize;
+ public AMSNetId getTargetAmsNetId() {
+ return targetAmsNetId;
+ }
+
+ public AMSPort getTargetAmsPort() {
+ return targetAmsPort;
+ }
+
+ public AMSNetId getSourceAmsNetId() {
+ return sourceAmsNetId;
+ }
+
+ public AMSPort getSourceAmsPort() {
+ return sourceAmsPort;
}
@Override
diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/netty/Plc4XADSProtocol.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/netty/Plc4XADSProtocol.java
new file mode 100644
index 0000000..358e33b
--- /dev/null
+++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/netty/Plc4XADSProtocol.java
@@ -0,0 +1,85 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+package org.apache.plc4x.java.ads.netty;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.MessageToMessageCodec;
+import org.apache.plc4x.java.api.exceptions.PlcException;
+import org.apache.plc4x.java.api.exceptions.PlcProtocolException;
+import org.apache.plc4x.java.api.messages.PlcReadRequest;
+import org.apache.plc4x.java.api.messages.PlcRequest;
+import org.apache.plc4x.java.api.messages.PlcRequestContainer;
+import org.apache.plc4x.java.api.messages.PlcWriteRequest;
+import org.apache.plc4x.java.api.messages.items.ReadRequestItem;
+import org.apache.plc4x.java.api.messages.items.WriteRequestItem;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class Plc4XADSProtocol extends MessageToMessageCodec<ByteBuf, PlcRequestContainer> {
+
+ private static final AtomicInteger tpduGenerator = new AtomicInteger(1);
+
+ private Map<Short, PlcRequestContainer> requests;
+
+ public Plc4XADSProtocol() {
+ this.requests = new HashMap<>();
+ }
+
+ @Override
+ protected void encode(ChannelHandlerContext ctx, PlcRequestContainer msg, List<Object> out) throws Exception {
+ PlcRequest request = msg.getRequest();
+ if (request instanceof PlcReadRequest) {
+ encodeReadRequest(msg, out);
+ } else if (request instanceof PlcWriteRequest) {
+ encodeWriteRequest(msg, out);
+ }
+ }
+
+ private void encodeWriteRequest(PlcRequestContainer msg, List<Object> out) throws PlcException {
+ PlcWriteRequest writeRequest = (PlcWriteRequest) msg.getRequest();
+ if (writeRequest.getRequestItems().size() != 1) {
+ throw new PlcProtocolException("Only one item supported");
+ }
+ WriteRequestItem<?> writeRequestItem = writeRequest.getRequestItems().get(0);
+
+ out.add(Unpooled.buffer());
+ }
+
+ private void encodeReadRequest(PlcRequestContainer msg, List<Object> out) throws PlcException {
+ PlcReadRequest readRequest = (PlcReadRequest) msg.getRequest();
+
+ if (readRequest.getRequestItems().size() != 1) {
+ throw new PlcProtocolException("Only one item supported");
+ }
+ ReadRequestItem<?> readRequestItem = readRequest.getRequestItems().get(0);
+ out.add(Unpooled.buffer());
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
+
+ }
+
+}
diff --git a/plc4j/protocols/ads/src/main/resources/META-INF/services/org.apache.plc4x.java.api.PlcDriver b/plc4j/protocols/ads/src/main/resources/META-INF/services/org.apache.plc4x.java.api.PlcDriver
new file mode 100644
index 0000000..0cdd1b3
--- /dev/null
+++ b/plc4j/protocols/ads/src/main/resources/META-INF/services/org.apache.plc4x.java.api.PlcDriver
@@ -0,0 +1,19 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+org.apache.plc4x.java.ads.ADSPlcDriver
diff --git a/plc4j/protocols/ads/src/site/asciidoc/index.adoc b/plc4j/protocols/ads/src/site/asciidoc/index.adoc
new file mode 100644
index 0000000..1f37781
--- /dev/null
+++ b/plc4j/protocols/ads/src/site/asciidoc/index.adoc
@@ -0,0 +1,101 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+:imagesdir: ./img/
+
+== ADS Protocol Java Implementation
+
+The current version of the ADS protocol java driver is based upon Netty 4 (http://netty.io/).
+
+As the ADS protocol running on TCP is a hierarchy of protocols, the ADS driver is implemented by providing several Protocol implementations, each encoding one layer of the protocol stack.
+
+The complete pipeline for the ADS protocol looks like this:
+
+[blockdiag,ads-netty-pipeline]
+....
+{
+ Application -> ADSPlcConnection;
+ Socket -> PLC;
+
+ group {
+ label = "PLC4X ADS Driver"
+ color = "#77FF77";
+
+ ADSPlcConnection -> Plc4XADSProtocol -> ADSProtocol -> IsoTPProtocol -> IsoOnTcpProtocol -> Socket
+
+ group {
+ Plc4XADSProtocol; ADSProtocol; IsoTPProtocol; IsoOnTcpProtocol;
+ }
+ }
+}
+....
+
+Each protocol layer implementation extends the class `MessageToMessageCodec` and is configured to consume/encode messages in the current format into messages of the next lower layer.
+
+The highest layer hereby consumes PLC4X messages, which are defined in the `plc4j-api` module, and the lowest layer produces a simple byte output.
+
+In order to implement the ADS Protocol as described in link:../../../protocols/ads/index.html[ADS Protocol] internally this is what happens inside the driver as soon as a connection is requested:
+
+[seqdiag,ads-netty-setup-communication]
+....
+{
+ Application; ADSPlcConnection; Plc4XADSProtocol; ADSProtocol; IsoTPProtocol; IsoOnTcpProtocol; Socket; PLC;
+
+ group Pipeline {
+ "Plc4XADSProtocol";
+ "ADSProtocol";
+ "IsoTPProtocol";
+ "IsoOnTcpProtocol";
+ }
+
+ Application -> ADSPlcConnection [label = "Calls 'connect'"]
+ ADSPlcConnection --> IsoTPProtocol [label = "Fires ADSConnectionEvent(INITIAL) event to the pipeline", note = "IsoTPProtocol listens for ADSConnectionEvent(INITIAL) events"]
+ IsoTPProtocol -> IsoOnTcpProtocol [label = "Creates new IsoOnTcp\nconnection request message"]
+ IsoOnTcpProtocol -> Socket [label = "Creates the byte array\ncontaining the TCP on ISO\nmessage"]
+ Socket -> PLC [label = "Sends the raw byte data to\nthe PLC"]
+
+ Socket <- PLC [label = "Sends the response to the\nSocket"]
+ IsoOnTcpProtocol <- Socket [label = "Passes the binary data to\nthe pipeline"]
+ IsoTPProtocol <- IsoOnTcpProtocol [label = "Creates new IsoOnTcp message containing binary user data"]
+
+ IsoTPProtocol --> ADSProtocol [label = "Sends ADSConnectionEvent(\nISO_TP_CONNECTION_RESPONSE_\nRECEIVED) event to the\npipeline", note = "ADSProtocol listens for ADSConnectionEvent(ISO_TP_CONNECTION_RESPONSE_RECEIVED) events"]
+
+ IsoTPProtocol <- ADSProtocol [label = "Creates new ISO TP Data\nmessage containing an\n ADS SetupCommunictaion\nmessage"]
+ IsoTPProtocol -> IsoOnTcpProtocol [label = "Creates new IsoOnTcp message"]
+ IsoOnTcpProtocol -> Socket [label = "Creates the byte array\ncontaining the TCP on ISO\nmessage"]
+ Socket -> PLC [label = "Sends the raw byte data to\nthe PLC"]
+
+ Socket <-- PLC [label = "Sends the response to the\nSocket"]
+ IsoOnTcpProtocol <- Socket [label = "Passes the binary data to\nthe pipeline"]
+ IsoTPProtocol <- IsoOnTcpProtocol [label = "Creates new IsoOnTcp message containing binary user data"]
+ IsoTPProtocol -> ADSProtocol
+ ADSPlcConnection <- ADSProtocol [label = "Sends ADSConnectionEvent(SETUP_COMPLETE) event to the\npipeline", note = "ADSPlcConnection listens for ADSConnectionEvent(SETUP_COMPLETE) events"]
+
+}
+....
+
+Above picture is a simplification. The communication of the outside with the pipeline is not implemented in a way that one component directly addresses the other.
+It is more that all communication is done with the `pipeline` and Netty then takes care of calling the right component at the right time.
+
+When writing to the pipeline from an application Netty starts at the `top` of the pipeline and asks each pipeline level if it is able and willing to handle the current message.
+If it does, the message is passed in to the `encode` method and the next component is supplied with the output of this.
+If the component can't process the message the next level is checked with the unmodified message.
+
+When reading from the Socket the Netty processes the pipeline elements the same way, but in the opposite direction and a pipeline elements `decode` method is called instead of `encode`.
+
+In addition to the normal flow of messages, a Netty pipeline also provides a messaging system. Every component can fire so-called `user events` and every component can react on them by implementing a `userEventTriggered` method.
+
+This functionality is mainly used during connection setup to synchronize the sending of messages on the different layers of the protocol stack.
\ No newline at end of file
diff --git a/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/ADSPlcDriverTest.java b/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/ADSPlcDriverTest.java
new file mode 100644
index 0000000..49585d4
--- /dev/null
+++ b/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/ADSPlcDriverTest.java
@@ -0,0 +1,56 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+package org.apache.plc4x.java.ads;
+
+
+import org.apache.plc4x.java.PlcDriverManager;
+import org.apache.plc4x.java.ads.connection.ADSPlcConnection;
+import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
+import org.apache.plc4x.java.api.exceptions.PlcException;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+
+public class ADSPlcDriverTest {
+
+ @Disabled("We first have to find/build some tool to help test these connections.")
+ @Test
+ @Tag("fast")
+ void getConnection() throws PlcException {
+ ADSPlcConnection adsConnection = (ADSPlcConnection)
+ new PlcDriverManager().getConnection("ads://localhost/0.0.0.0.0.0:13");
+ Assertions.assertEquals(adsConnection.getHostName(), "localhost");
+ Assertions.assertEquals(adsConnection.getTargetAmsNetId().toString(), "0.0.0.0.0.0");
+ Assertions.assertEquals(adsConnection.getTargetAmsPort().toString(), "13");
+ }
+
+ /**
+ * In this test case the 'ads' driver should report an invalid url format.
+ *
+ * @throws PlcException something went wrong
+ */
+ @Test
+ @Tag("fast")
+ void getConnectionInvalidUrl() throws PlcException {
+ Assertions.assertThrows(PlcConnectionException.class,
+ () -> new PlcDriverManager().getConnection("ads://localhost/hurz/2"));
+ }
+
+}
diff --git a/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/connection/ADSPlcConnectionTests.java b/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/connection/ADSPlcConnectionTests.java
new file mode 100644
index 0000000..8bb0d73
--- /dev/null
+++ b/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/connection/ADSPlcConnectionTests.java
@@ -0,0 +1,72 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+package org.apache.plc4x.java.ads.connection;
+
+import org.apache.plc4x.java.ads.api.generic.types.AMSNetId;
+import org.apache.plc4x.java.ads.api.generic.types.AMSPort;
+import org.apache.plc4x.java.ads.model.ADSAddress;
+import org.apache.plc4x.java.api.exceptions.PlcException;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class ADSPlcConnectionTests {
+
+ private ADSPlcConnection adsPlcConnection;
+
+ @BeforeEach
+ void setUp() {
+ adsPlcConnection = new ADSPlcConnection("localhost", AMSNetId.of("0.0.0.0.0.0"), AMSPort.of(13));
+ }
+
+ @AfterEach
+ void tearDown() {
+ adsPlcConnection = null;
+ }
+
+ @Test
+ void initialState() {
+ assertTrue(adsPlcConnection.getHostName().equalsIgnoreCase("localhost"), "Hostname is incorrect");
+ assertEquals(adsPlcConnection.getTargetAmsNetId().toString(), "0.0.0.0.0.0");
+ assertEquals(adsPlcConnection.getTargetAmsPort().toString(), "13");
+ }
+
+ @Test
+ void emptyParseAddress() {
+ try {
+ adsPlcConnection.parseAddress("");
+ } catch (PlcException exception) {
+ assertTrue(exception.getMessage().startsWith("Address string doesn't match"), "Unexpected exception");
+ }
+ }
+
+ @Test
+ void parseAddress() {
+ try {
+ ADSAddress address = (ADSAddress) adsPlcConnection.parseAddress("0.0.0.0.0.0:13");
+ assertEquals(address.targetAmsNetId.toString(), "0.0.0.0.0.0");
+ assertEquals(address.targetAmsPort.toString(), "13");
+ } catch (PlcException exception) {
+ fail("valid data block address");
+ }
+ }
+}
\ No newline at end of file
diff --git a/plc4j/protocols/ads/src/test/resources/logback.xml b/plc4j/protocols/ads/src/test/resources/logback.xml
new file mode 100644
index 0000000..bba8e02
--- /dev/null
+++ b/plc4j/protocols/ads/src/test/resources/logback.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<configuration xmlns="http://ch.qos.logback/xml/ns/logback"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://ch.qos.logback/xml/ns/logback https://raw.githubusercontent.com/enricopulatzo/logback-XSD/master/src/main/xsd/logback.xsd">
+
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <!-- encoders are assigned the type
+ ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
+ <encoder>
+ <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
+ </encoder>
+ </appender>
+
+ <root level="warn">
+ <appender-ref ref="STDOUT" />
+ </root>
+
+</configuration>
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
sruehl@apache.org.