This is an automated email from the ASF dual-hosted git repository. cdutz pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/plc4x.git
commit 05157ad4421a51e1e178bb20f04d28d183553f75 Author: Christofer Dutz <[email protected]> AuthorDate: Tue Sep 24 09:44:44 2019 +0200 - Added a new Udp driver base --- plc4j/protocols/driver-bases/pom.xml | 1 + plc4j/protocols/driver-bases/{ => udp}/pom.xml | 47 ++++++--- .../base/connection/UdpSocketChannelFactory.java | 110 +++++++++++++++++++++ 3 files changed, 143 insertions(+), 15 deletions(-) diff --git a/plc4j/protocols/driver-bases/pom.xml b/plc4j/protocols/driver-bases/pom.xml index 0034532..2895a35 100644 --- a/plc4j/protocols/driver-bases/pom.xml +++ b/plc4j/protocols/driver-bases/pom.xml @@ -39,6 +39,7 @@ <module>raw-socket</module> <module>serial</module> <module>tcp</module> + <module>udp</module> <module>test</module> </modules> diff --git a/plc4j/protocols/driver-bases/pom.xml b/plc4j/protocols/driver-bases/udp/pom.xml similarity index 53% copy from plc4j/protocols/driver-bases/pom.xml copy to plc4j/protocols/driver-bases/udp/pom.xml index 0034532..cb1bc05 100644 --- a/plc4j/protocols/driver-bases/pom.xml +++ b/plc4j/protocols/driver-bases/udp/pom.xml @@ -23,23 +23,40 @@ <parent> <groupId>org.apache.plc4x</groupId> - <artifactId>plc4j-protocols</artifactId> + <artifactId>plc4j-protocols-driver-bases</artifactId> <version>0.5.0-SNAPSHOT</version> </parent> - <artifactId>plc4j-protocols-driver-bases</artifactId> - <packaging>pom</packaging> - - <name>PLC4J: Protocols: Driver-Bases</name> - <description>Collection of base-types for implementing different types of drivers.</description> - - <modules> - <module>base</module> - <module>pcap-socket</module> - <module>raw-socket</module> - <module>serial</module> - <module>tcp</module> - <module>test</module> - </modules> + <artifactId>plc4j-protocol-driver-base-udp</artifactId> + <name>PLC4J: Protocol: Driver-Base: UDP</name> + <description>Base classes needed to implement plc4x drivers based on UDP connections.</description> + + <dependencies> + <dependency> + <groupId>org.apache.plc4x</groupId> + <artifactId>plc4j-protocol-driver-base</artifactId> + <version>0.5.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.plc4x</groupId> + <artifactId>plc4j-api</artifactId> + <version>0.5.0-SNAPSHOT</version> + </dependency> + + <dependency> + <groupId>io.netty</groupId> + <artifactId>netty-transport</artifactId> + </dependency> + <dependency> + <groupId>io.netty</groupId> + <artifactId>netty-common</artifactId> + </dependency> + + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + <scope>test</scope> + </dependency> + </dependencies> </project> \ No newline at end of file diff --git a/plc4j/protocols/driver-bases/udp/src/main/java/org/apache/plc4x/java/base/connection/UdpSocketChannelFactory.java b/plc4j/protocols/driver-bases/udp/src/main/java/org/apache/plc4x/java/base/connection/UdpSocketChannelFactory.java new file mode 100644 index 0000000..942afc4 --- /dev/null +++ b/plc4j/protocols/driver-bases/udp/src/main/java/org/apache/plc4x/java/base/connection/UdpSocketChannelFactory.java @@ -0,0 +1,110 @@ +/* +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.base.connection; + +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandler; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioDatagramChannel; +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.GenericFutureListener; +import org.apache.plc4x.java.api.exceptions.PlcConnectionException; +import org.apache.plc4x.java.api.exceptions.PlcException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; + +public class UdpSocketChannelFactory implements ChannelFactory { + + private static final Logger logger = LoggerFactory.getLogger(UdpSocketChannelFactory.class); + + private static final int PING_TIMEOUT_MS = 1_000; + + private final InetAddress address; + private final int port; + + public UdpSocketChannelFactory(InetAddress address, int port) { + this.address = address; + this.port = port; + } + + @Override + public Channel createChannel(ChannelHandler channelHandler) + throws PlcConnectionException { + try { + final NioEventLoopGroup workerGroup = new NioEventLoopGroup(); + + Bootstrap bootstrap = new Bootstrap(); + bootstrap.group(workerGroup); + bootstrap.channel(NioDatagramChannel.class); + //bootstrap.option(ChannelOption.SO_KEEPALIVE, true); + //bootstrap.option(ChannelOption.TCP_NODELAY, true); + // TODO we should use an explicit (configurable?) timeout here + // bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000); + bootstrap.handler(channelHandler); + // Start the client. + final ChannelFuture f = bootstrap.connect(address, port); + f.addListener(new GenericFutureListener<Future<? super Void>>() { + @Override public void operationComplete(Future<? super Void> future) throws Exception { + if (!future.isSuccess()) { + logger.info("Unable to connect, shutting down worker thread."); + workerGroup.shutdownGracefully(); + } + } + }); + // Wait for sync + f.sync(); + f.awaitUninterruptibly(); // jf: unsure if we need that + // Wait till the session is finished initializing. + return f.channel(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new PlcConnectionException("Error creating channel.", e); + } catch (Exception e) { + throw new PlcConnectionException("Error creating channel.", e); + } + } + + @Override + public void ping() throws PlcException { + // TODO: Replace this check with a more accurate one ... + InetSocketAddress address = new InetSocketAddress(getAddress(), getPort()); + try (Socket s = new Socket()) { + s.connect(address, PING_TIMEOUT_MS); + // TODO keep the address for a (timely) next request??? + s.setReuseAddress(true); + } catch (Exception e) { + throw new PlcConnectionException("Unable to ping remote host"); + } + } + + public InetAddress getAddress() { + return address; + } + + public int getPort() { + return port; + } + +}
