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

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

commit fa2688a617713e62a194be45d0ae1acecac628de
Author: Sebastian Rühl <sru...@apache.org>
AuthorDate: Thu Nov 1 17:49:32 2018 +0100

    [plc4j-pool] added PoolKeyFactory to produce different keys for different 
protocols.
---
 .../plc4x/java/utils/connectionpool/PoolKey.java   |  21 ++---
 .../java/utils/connectionpool/PoolKeyFactory.java  | 103 +++++++++++++++++++++
 .../connectionpool/PooledPlcDriverManager.java     |  19 +++-
 .../utils/connectionpool/PoolKeyFactoryTest.java   |  93 +++++++++++++++++++
 4 files changed, 224 insertions(+), 12 deletions(-)

diff --git 
a/plc4j/utils/connection-pool/src/main/java/org/apache/plc4x/java/utils/connectionpool/PoolKey.java
 
b/plc4j/utils/connection-pool/src/main/java/org/apache/plc4x/java/utils/connectionpool/PoolKey.java
index 166589c..7cd719a 100644
--- 
a/plc4j/utils/connection-pool/src/main/java/org/apache/plc4x/java/utils/connectionpool/PoolKey.java
+++ 
b/plc4j/utils/connection-pool/src/main/java/org/apache/plc4x/java/utils/connectionpool/PoolKey.java
@@ -23,21 +23,15 @@ import 
org.apache.plc4x.java.api.authentication.PlcAuthentication;
 
 import java.util.Objects;
 
-public class PoolKey {
-    final String url;
-    final PlcAuthentication plcAuthentication;
+public abstract class PoolKey {
+    protected final String url;
+    protected final PlcAuthentication plcAuthentication;
 
-    // TODO: we need to extract relevant parts of the url as key as we don't 
want many connections for different racks in s7 for example.
-    // TODO: So we might end up need a generic key and special keys for all 
known protocols which parses the relevant portions.
     public PoolKey(String url, PlcAuthentication plcAuthentication) {
         this.url = url;
         this.plcAuthentication = plcAuthentication;
     }
 
-    public static PoolKey of(String host, PlcAuthentication plcAuthentication) 
{
-        return new PoolKey(host, plcAuthentication);
-    }
-
     public String getUrl() {
         return url;
     }
@@ -46,6 +40,11 @@ public class PoolKey {
         return plcAuthentication;
     }
 
+    /**
+     * @return the part of the url that should be pooled.
+     */
+    public abstract String getPoolableKey();
+
     @Override
     public boolean equals(Object o) {
         if (this == o) {
@@ -55,13 +54,13 @@ public class PoolKey {
             return false;
         }
         PoolKey poolKey = (PoolKey) o;
-        return Objects.equals(url, poolKey.url) &&
+        return Objects.equals(getPoolableKey(), poolKey.getPoolableKey()) &&
             Objects.equals(plcAuthentication, poolKey.plcAuthentication);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(url, plcAuthentication);
+        return Objects.hash(getPoolableKey(), plcAuthentication);
     }
 
     @Override
diff --git 
a/plc4j/utils/connection-pool/src/main/java/org/apache/plc4x/java/utils/connectionpool/PoolKeyFactory.java
 
b/plc4j/utils/connection-pool/src/main/java/org/apache/plc4x/java/utils/connectionpool/PoolKeyFactory.java
new file mode 100644
index 0000000..e5d73c1
--- /dev/null
+++ 
b/plc4j/utils/connection-pool/src/main/java/org/apache/plc4x/java/utils/connectionpool/PoolKeyFactory.java
@@ -0,0 +1,103 @@
+/*
+ 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.utils.connectionpool;
+
+import org.apache.plc4x.java.api.authentication.PlcAuthentication;
+import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class PoolKeyFactory {
+
+    public PoolKey getPoolKey(String url, PlcAuthentication plcAuthentication) 
throws PlcConnectionException {
+        Objects.requireNonNull(url);
+        URI connectionUri;
+        try {
+            connectionUri = new URI(url);
+        } catch (URISyntaxException e) {
+            throw new PlcConnectionException("Invalid plc4j connection string 
'" + url + "'", e);
+        }
+        String protocol = connectionUri.getScheme().toLowerCase();
+        switch (protocol) {
+            case "s7":
+                return new PoolKey(url, plcAuthentication) {
+                    private final Pattern s7URIPattern = 
Pattern.compile("^(?<poolablePart>s7://(?<host>.*)/(?<rack>\\d{1,4})/(?<slot>\\d{1,4}))(?<params>\\?.*)?");
+
+                    @Override
+                    public String getPoolableKey() {
+                        Matcher matcher = s7URIPattern.matcher(url);
+                        if (!matcher.matches()) {
+                            throw new IllegalArgumentException(url + " doesn't 
match " + s7URIPattern);
+                        }
+                        return 
Objects.requireNonNull(matcher.group("poolablePart"));
+                    }
+                };
+            case "ads":
+                return new PoolKey(url, plcAuthentication) {
+                    private final Pattern amsPortPattern = 
Pattern.compile("\\d+");
+                    private final Pattern amsNetIdPattern = 
Pattern.compile("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}");
+                    private final Pattern adsAddressPattern =
+                        Pattern.compile("(?<targetAmsNetId>" + amsNetIdPattern 
+ "):(?<targetAmsPort>" + amsPortPattern + ")"
+                            + "(/"
+                            + "(?<sourceAmsNetId>" + amsNetIdPattern + 
"):(?<sourceAmsPort>" + amsPortPattern + ")"
+                            + ")?");
+                    private final Pattern inetAddressPattern = 
Pattern.compile("tcp://(?<host>[\\w.]+)(:(?<port>\\d*))?");
+                    private final Pattern serialPattern = 
Pattern.compile("serial://(?<serialDefinition>((?!/\\d).)*)");
+                    private final Pattern adsUriPattern = 
Pattern.compile("^(?<poolablePart>ads:(" + inetAddressPattern + "|" + 
serialPattern + "))/" + adsAddressPattern + "(\\?.*)?");
+
+                    @Override
+                    public String getPoolableKey() {
+                        Matcher matcher =
+                            adsUriPattern.matcher(url);
+                        if (!matcher.matches()) {
+                            throw new IllegalArgumentException(url + " doesn't 
match " + adsUriPattern);
+                        }
+                        return 
Objects.requireNonNull(matcher.group("poolablePart"));
+                    }
+                };
+            case "modbus":
+                return new PoolKey(url, plcAuthentication) {
+                    private final Pattern inetAddressPattern = 
Pattern.compile("tcp://(?<host>[\\w.]+)(:(?<port>\\d*))?");
+                    private final Pattern serialPattern = 
Pattern.compile("serial://(?<serialDefinition>((?!/\\d).)*)");
+                    private final Pattern modbusUriPattern = 
Pattern.compile("^(?<poolablePart>modbus:(" + inetAddressPattern + "|" + 
serialPattern + "))/?" + "(?<params>\\?.*)?");
+
+                    @Override
+                    public String getPoolableKey() {
+                        Matcher matcher = modbusUriPattern.matcher(url);
+                        if (!matcher.matches()) {
+                            throw new IllegalArgumentException(url + " doesn't 
match " + modbusUriPattern);
+                        }
+                        return 
Objects.requireNonNull(matcher.group("poolablePart"));
+                    }
+                };
+            default:
+                return new PoolKey(url, plcAuthentication) {
+                    @Override
+                    public String getPoolableKey() {
+                        return url;
+                    }
+                };
+        }
+    }
+}
diff --git 
a/plc4j/utils/connection-pool/src/main/java/org/apache/plc4x/java/utils/connectionpool/PooledPlcDriverManager.java
 
b/plc4j/utils/connection-pool/src/main/java/org/apache/plc4x/java/utils/connectionpool/PooledPlcDriverManager.java
index d10dc20..9a7e5d7 100644
--- 
a/plc4j/utils/connection-pool/src/main/java/org/apache/plc4x/java/utils/connectionpool/PooledPlcDriverManager.java
+++ 
b/plc4j/utils/connection-pool/src/main/java/org/apache/plc4x/java/utils/connectionpool/PooledPlcDriverManager.java
@@ -43,22 +43,39 @@ public class PooledPlcDriverManager extends 
PlcDriverManager {
     // Marker class do detected a non null value
     static final NoPlcAuthentication noPlcAuthentication = new 
NoPlcAuthentication();
 
+    private final PoolKeyFactory poolKeyFactory;
+
     public PooledPlcDriverManager() {
         this(GenericKeyedObjectPool::new);
     }
 
+    public PooledPlcDriverManager(PoolKeyFactory poolKeyFactory) {
+        this(GenericKeyedObjectPool::new, poolKeyFactory);
+    }
+
     public PooledPlcDriverManager(ClassLoader classLoader) {
+        this(classLoader, new PoolKeyFactory());
+    }
+
+    public PooledPlcDriverManager(ClassLoader classLoader, PoolKeyFactory 
poolKeyFactory) {
         super(classLoader);
         setFromPoolCreator(GenericKeyedObjectPool::new);
+        this.poolKeyFactory = poolKeyFactory;
     }
 
     public PooledPlcDriverManager(PoolCreator poolCreator) {
+        this(poolCreator, new PoolKeyFactory());
+    }
+
+    public PooledPlcDriverManager(PoolCreator poolCreator, PoolKeyFactory 
poolKeyFactory) {
         setFromPoolCreator(poolCreator);
+        this.poolKeyFactory = poolKeyFactory;
     }
 
     public PooledPlcDriverManager(ClassLoader classLoader, PoolCreator 
poolCreator) {
         super(classLoader);
         setFromPoolCreator(poolCreator);
+        poolKeyFactory = new PoolKeyFactory();
     }
 
     private void setFromPoolCreator(PoolCreator poolCreator) {
@@ -85,7 +102,7 @@ public class PooledPlcDriverManager extends PlcDriverManager 
{
 
     @Override
     public PlcConnection getConnection(String url, PlcAuthentication 
authentication) throws PlcConnectionException {
-        PoolKey poolKey = PoolKey.of(url, authentication);
+        PoolKey poolKey = poolKeyFactory.getPoolKey(url, authentication);
         if (LOGGER.isDebugEnabled()) {
             if (authentication != noPlcAuthentication) {
                 LOGGER.debug("Try to borrow an object for url {} and 
authentication {}", url, authentication);
diff --git 
a/plc4j/utils/connection-pool/src/test/java/org/apache/plc4x/java/utils/connectionpool/PoolKeyFactoryTest.java
 
b/plc4j/utils/connection-pool/src/test/java/org/apache/plc4x/java/utils/connectionpool/PoolKeyFactoryTest.java
new file mode 100644
index 0000000..a73f9c7
--- /dev/null
+++ 
b/plc4j/utils/connection-pool/src/test/java/org/apache/plc4x/java/utils/connectionpool/PoolKeyFactoryTest.java
@@ -0,0 +1,93 @@
+/*
+ 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.utils.connectionpool;
+
+import org.assertj.core.api.WithAssertions;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+class PoolKeyFactoryTest implements WithAssertions {
+
+    private PoolKeyFactory SUT = new PoolKeyFactory();
+
+    @Nested
+    class Generic {
+        @Test
+        void getPoolKey() throws Exception {
+            PoolKey poolKey = 
SUT.getPoolKey("randomProtocol://randomHost/1/1?someOptions", 
PooledPlcDriverManager.noPlcAuthentication);
+            
assertThat(poolKey.getUrl()).isEqualTo("randomProtocol://randomHost/1/1?someOptions");
+            
assertThat(poolKey.getPlcAuthentication()).isEqualTo(PooledPlcDriverManager.noPlcAuthentication);
+            
assertThat(poolKey.getPoolableKey()).isEqualTo("randomProtocol://randomHost/1/1?someOptions");
+        }
+    }
+
+    @Nested
+    class S7 {
+        @Test
+        void getPoolKey() throws Exception {
+            PoolKey poolKey = 
SUT.getPoolKey("s7://localhost/1/2?randomOption=true", 
PooledPlcDriverManager.noPlcAuthentication);
+            
assertThat(poolKey.getUrl()).isEqualTo("s7://localhost/1/2?randomOption=true");
+            
assertThat(poolKey.getPlcAuthentication()).isEqualTo(PooledPlcDriverManager.noPlcAuthentication);
+            
assertThat(poolKey.getPoolableKey()).isEqualTo("s7://localhost/1/2");
+        }
+    }
+
+    @Nested
+    class ADS {
+        @Test
+        void getPoolKey_TCP() throws Exception {
+            PoolKey poolKey = 
SUT.getPoolKey("ads:tcp://10.10.64.40/10.10.64.40.1.1:851/10.10.56.23.1.1:30000",
 PooledPlcDriverManager.noPlcAuthentication);
+            
assertThat(poolKey.getUrl()).isEqualTo("ads:tcp://10.10.64.40/10.10.64.40.1.1:851/10.10.56.23.1.1:30000");
+            
assertThat(poolKey.getPlcAuthentication()).isEqualTo(PooledPlcDriverManager.noPlcAuthentication);
+            
assertThat(poolKey.getPoolableKey()).isEqualTo("ads:tcp://10.10.64.40");
+        }
+
+        @Test
+        void getPoolKey_SERIAL() throws Exception {
+            PoolKey poolKey = 
SUT.getPoolKey("ads:serial:///dev/ttys003/10.10.64.40.1.1:851/10.10.56.23.1.1:30000",
 PooledPlcDriverManager.noPlcAuthentication);
+            
assertThat(poolKey.getUrl()).isEqualTo("ads:serial:///dev/ttys003/10.10.64.40.1.1:851/10.10.56.23.1.1:30000");
+            
assertThat(poolKey.getPlcAuthentication()).isEqualTo(PooledPlcDriverManager.noPlcAuthentication);
+            
assertThat(poolKey.getPoolableKey()).isEqualTo("ads:serial:///dev/ttys003");
+        }
+    }
+
+    @Nested
+    class Modbus {
+        @Test
+        void getPoolKey_TCP() throws Exception {
+            PoolKey poolKey = 
SUT.getPoolKey("modbus:tcp://10.10.64.40?someRandomOption=true", 
PooledPlcDriverManager.noPlcAuthentication);
+            
assertThat(poolKey.getUrl()).isEqualTo("modbus:tcp://10.10.64.40?someRandomOption=true");
+            
assertThat(poolKey.getPlcAuthentication()).isEqualTo(PooledPlcDriverManager.noPlcAuthentication);
+            
assertThat(poolKey.getPoolableKey()).isEqualTo("modbus:tcp://10.10.64.40");
+        }
+
+        @Disabled("Modbus serial pooling doesn't work right now as intended")
+        @Test
+        void getPoolKey_SERIAL() throws Exception {
+            PoolKey poolKey = 
SUT.getPoolKey("modbus:serial:///dev/ttys003?someRandomOption=true", 
PooledPlcDriverManager.noPlcAuthentication);
+            
assertThat(poolKey.getUrl()).isEqualTo("modbus:serial:///dev/ttys003?someRandomOption=true");
+            
assertThat(poolKey.getPlcAuthentication()).isEqualTo(PooledPlcDriverManager.noPlcAuthentication);
+            
assertThat(poolKey.getPoolableKey()).isEqualTo("modbus:serial:///dev/ttys003");
+        }
+    }
+
+
+}
\ No newline at end of file

Reply via email to