You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by jf...@apache.org on 2018/11/23 10:30:04 UTC
[incubator-plc4x] 01/03: [OPM] Added AliasRegistry and
SimpleAliasRegistry as default impl.
This is an automated email from the ASF dual-hosted git repository.
jfeinauer pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/incubator-plc4x.git
commit e0b067bb2a2460fd8ffbbd8ee6971e9a89049a09
Author: Julian Feinauer <j....@pragmaticminds.de>
AuthorDate: Thu Nov 22 16:41:03 2018 +0100
[OPM] Added AliasRegistry and SimpleAliasRegistry as default impl.
---
.../apache/plc4x/java/mock/PlcMockConnection.java | 19 ++--
.../org/apache/plc4x/java/opm/AliasRegistry.java | 54 +++++++++++
.../java/org/apache/plc4x/java/opm/OpmUtils.java | 46 ++++++++++
.../plc4x/java/opm/PlcEntityInterceptor.java | 38 ++++----
.../apache/plc4x/java/opm/PlcEntityManager.java | 27 ++++--
.../apache/plc4x/java/opm/SimpleAliasRegistry.java | 74 +++++++++++++++
.../org/apache/plc4x/java/opm/OpmUtilsTest.java | 64 +++++++++++++
.../plc4x/java/opm/PlcEntityInterceptorTest.java | 27 ++++--
.../plc4x/java/opm/PlcEntityManagerTest.java | 100 ++++++++++++++++++++-
.../plc4x/java/opm/SimpleAliasRegistryTest.java | 76 ++++++++++++++++
plc4j/utils/opm/src/test/resources/logback.xml | 2 +-
11 files changed, 487 insertions(+), 40 deletions(-)
diff --git a/plc4j/protocols/test/src/main/java/org/apache/plc4x/java/mock/PlcMockConnection.java b/plc4j/protocols/test/src/main/java/org/apache/plc4x/java/mock/PlcMockConnection.java
index 5bf5941..cdd3448 100644
--- a/plc4j/protocols/test/src/main/java/org/apache/plc4x/java/mock/PlcMockConnection.java
+++ b/plc4j/protocols/test/src/main/java/org/apache/plc4x/java/mock/PlcMockConnection.java
@@ -30,6 +30,8 @@ import org.apache.plc4x.java.base.messages.DefaultPlcReadRequest;
import org.apache.plc4x.java.base.messages.DefaultPlcReadResponse;
import org.apache.plc4x.java.base.messages.PlcReader;
import org.apache.plc4x.java.base.messages.items.BaseDefaultFieldItem;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
@@ -39,6 +41,8 @@ import java.util.stream.Collectors;
public class PlcMockConnection implements PlcConnection, PlcReader {
+ private static final Logger logger = LoggerFactory.getLogger(PlcMockConnection.class);
+
private final String name;
private final PlcAuthentication authentication;
@@ -55,6 +59,7 @@ public class PlcMockConnection implements PlcConnection, PlcReader {
}
public void setDevice(MockDevice device) {
+ logger.info("Set Mock Devie on Mock Connection " + this + " with device " + device);
this.device = device;
}
@@ -65,14 +70,12 @@ public class PlcMockConnection implements PlcConnection, PlcReader {
@Override
public boolean isConnected() {
- // is connected if a device is set
- return device != null;
+ return true;
}
@Override
public void close() {
- // unset device
- this.device = null;
+ logger.info("Closing MockConnection with device " + device);
}
@Override
@@ -103,10 +106,16 @@ public class PlcMockConnection implements PlcConnection, PlcReader {
@Override
public CompletableFuture<PlcReadResponse> read(PlcReadRequest readRequest) {
return CompletableFuture.supplyAsync(new Supplier<PlcReadResponse>() {
+
@Override
public PlcReadResponse get() {
+ logger.debug("Sending read request to MockDevice");
Map<String, Pair<PlcResponseCode, BaseDefaultFieldItem>> response = readRequest.getFieldNames().stream()
- .collect(Collectors.toMap(Function.identity(), name -> device.read(((MockField) readRequest.getField(name)).getFieldQuery())));
+ .collect(Collectors.toMap(
+ Function.identity(),
+ name -> device.read(((MockField) readRequest.getField(name)).getFieldQuery())
+ )
+ );
return new DefaultPlcReadResponse((DefaultPlcReadRequest)readRequest, response);
}
});
diff --git a/plc4j/utils/opm/src/main/java/org/apache/plc4x/java/opm/AliasRegistry.java b/plc4j/utils/opm/src/main/java/org/apache/plc4x/java/opm/AliasRegistry.java
new file mode 100644
index 0000000..943a98f
--- /dev/null
+++ b/plc4j/utils/opm/src/main/java/org/apache/plc4x/java/opm/AliasRegistry.java
@@ -0,0 +1,54 @@
+/*
+ * 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.opm;
+
+/**
+ * This interface can be used to give "aliases" for field names in {@link PlcEntity}s {@link PlcField} strings.
+ * These are then resolved.
+ */
+public interface AliasRegistry {
+
+ /**
+ * Checks if this registry can resolve this alias
+ */
+ boolean canResolve(String alias);
+
+ /**
+ * Checks if this registry can resolve this alias for the given connection.
+ */
+ boolean canResolve(String connection, String alias);
+
+ /**
+ * Resolves an alias to a valid PLC Field Adress
+ * @param alias
+ * @return
+ */
+ String resolve(String alias);
+
+ /**
+ * Resolves an alias to a valid PLC Field based on the connection.
+ * This means that the same alias could be resolved to different Addresses for different connections.
+ * @param connection
+ * @param alias
+ * @return
+ */
+ String resolve(String connection, String alias);
+
+}
diff --git a/plc4j/utils/opm/src/main/java/org/apache/plc4x/java/opm/OpmUtils.java b/plc4j/utils/opm/src/main/java/org/apache/plc4x/java/opm/OpmUtils.java
index 29ede9c..0791a93 100644
--- a/plc4j/utils/opm/src/main/java/org/apache/plc4x/java/opm/OpmUtils.java
+++ b/plc4j/utils/opm/src/main/java/org/apache/plc4x/java/opm/OpmUtils.java
@@ -19,11 +19,17 @@
package org.apache.plc4x.java.opm;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
/**
* Utility methods for usage with OPM.
*/
public final class OpmUtils {
+ public static final String ADDRESS = "address";
+ static final Pattern pattern = Pattern.compile("^\\$\\{(?<" + ADDRESS + ">.*)\\}$");
+
private OpmUtils() {
// Util class
}
@@ -42,4 +48,44 @@ public final class OpmUtils {
return annotation;
}
+ static String getOrResolveAddress(AliasRegistry registry, String addressString) {
+ if (!OpmUtils.isValidExpression(addressString)) {
+ throw new IllegalArgumentException("Invalid Syntax, either use field address (no starting $) " +
+ "or an alias with Syntax ${xxx}. But given was '" + addressString + "'");
+ }
+ if (OpmUtils.isAlias(addressString)) {
+ String alias = OpmUtils.getAlias(addressString);
+ if (registry.canResolve(alias)) {
+ return registry.resolve(alias);
+ } else {
+ throw new IllegalArgumentException("Unable to resolve Alias '" + alias + "' in Schema Registry");
+ }
+ } else {
+ return addressString;
+ }
+ }
+
+ /**
+ * Checks whether a given String is a valid OPM Expression, this means
+ * either an Address or an alias ${xxx}.
+ *
+ * @param s
+ * @return
+ */
+ static boolean isValidExpression(String s) {
+ return (s.startsWith("$") && pattern.matcher(s).matches()) || s.startsWith("$") == false;
+ }
+
+ static boolean isAlias(String s) {
+ return s.startsWith("$") && pattern.matcher(s).matches();
+ }
+
+ static String getAlias(String s) {
+ Matcher matcher = pattern.matcher(s);
+ if (matcher.matches() == false) {
+ throw new IllegalArgumentException("Invalid Syntax, no Alias found in String '" + s + "'. Synatx is ${xxx}");
+ }
+ return matcher.group(ADDRESS);
+ }
+
}
diff --git a/plc4j/utils/opm/src/main/java/org/apache/plc4x/java/opm/PlcEntityInterceptor.java b/plc4j/utils/opm/src/main/java/org/apache/plc4x/java/opm/PlcEntityInterceptor.java
index 00c0fe0..2e41155 100644
--- a/plc4j/utils/opm/src/main/java/org/apache/plc4x/java/opm/PlcEntityInterceptor.java
+++ b/plc4j/utils/opm/src/main/java/org/apache/plc4x/java/opm/PlcEntityInterceptor.java
@@ -49,7 +49,7 @@ import java.util.concurrent.TimeoutException;
/**
* Interceptor for dynamic functionality of @{@link PlcEntity}.
- * Basically, its {@link #intercept(Object, Method, Callable, String, PlcDriverManager)} method is called for each
+ * Basically, its {@link #intercept(Object, Method, Callable, String, PlcDriverManager, AliasRegistry)} method is called for each
* invocation of a method on a connected @{@link PlcEntity} and does then the dynamic part.
*
* For those not too familiar with the JVM's dispatch on can roughly imagine the intercept method being a "regular"
@@ -71,9 +71,9 @@ public class PlcEntityInterceptor {
/**
* Basic Intersector for all methods on the proxy object.
* It checks if the invoked method is a getter and if so, only retrieves the requested field, forwarding to
- * the {@link #fetchValueForGetter(Method, PlcDriverManager,String)} method.
+ * the {@link #fetchValueForGetter(Method, PlcDriverManager, String, AliasRegistry)} method.
* <p>
- * If the field is no getter, then all fields are refreshed by calling {@link #refetchAllFields(Object, PlcDriverManager, String)}
+ * If the field is no getter, then all fields are refreshed by calling {@link #refetchAllFields(Object, PlcDriverManager, String, AliasRegistry)}
* and then, the method is invoked.
*
* @param proxy Object to intercept
@@ -87,8 +87,9 @@ public class PlcEntityInterceptor {
@SuppressWarnings("unused")
@RuntimeType
public static Object intercept(@This Object proxy, @Origin Method method, @SuperCall Callable<?> callable,
- @FieldValue(PlcEntityManager.PLC_ADDRESS_FIELD_NAME) String address,
- @FieldValue(PlcEntityManager.DRIVER_MANAGER_FIELD_NAME) PlcDriverManager driverManager) throws OPMException {
+ @FieldValue(PlcEntityManager.PLC_ADDRESS_FIELD_NAME) String address,
+ @FieldValue(PlcEntityManager.DRIVER_MANAGER_FIELD_NAME) PlcDriverManager driverManager,
+ @FieldValue(PlcEntityManager.ALIAS_REGISTRY) AliasRegistry registry) throws OPMException {
LOGGER.trace("Invoked method {} on connected PlcEntity {}", method.getName(), method.getDeclaringClass().getName());
// If "detached" (i.e. _driverManager is null) simply forward the call
@@ -108,7 +109,7 @@ public class PlcEntityInterceptor {
// Fetch single value
LOGGER.trace("Invoked method {} is getter, trying to find annotated field and return requested value",
method.getName());
- return fetchValueForGetter(method, driverManager, address);
+ return fetchValueForGetter(method, driverManager, address, registry);
}
if (method.getName().startsWith("is") && (method.getReturnType() == boolean.class || method.getReturnType() == Boolean.class)) {
@@ -118,13 +119,13 @@ public class PlcEntityInterceptor {
// Fetch single value
LOGGER.trace("Invoked method {} is boolean flag method, trying to find annotated field and return requested value",
method.getName());
- return fetchValueForIsGetter(method, driverManager, address);
+ return fetchValueForIsGetter(method, driverManager, address, registry);
}
// Fetch all values, than invoke method
try {
LOGGER.trace("Invoked method is no getter, refetch all fields and invoke method {} then", method.getName());
- refetchAllFields(proxy, driverManager, address);
+ refetchAllFields(proxy, driverManager, address, registry);
return callable.call();
} catch (Exception e) {
throw new OPMException("Unable to forward invocation " + method.getName() + " on connected PlcEntity", e);
@@ -136,12 +137,14 @@ public class PlcEntityInterceptor {
*
* @param proxy Object to refresh the fields on.
* @param driverManager
+ * @param registry
* @throws OPMException on various errors.
*/
@SuppressWarnings("squid:S1141") // Nested try blocks readability is okay, move to other method makes it imho worse
- static void refetchAllFields(Object proxy, PlcDriverManager driverManager, String address) throws OPMException {
+ static void refetchAllFields(Object proxy, PlcDriverManager driverManager, String address, AliasRegistry registry) throws OPMException {
// Don't log o here as this would cause a second request against a plc so don't touch it, or if you log be aware of that
Class<?> entityClass = proxy.getClass().getSuperclass();
+ LOGGER.trace("Refetching all fields on proxy object of class " + entityClass);
PlcEntity plcEntity = entityClass.getAnnotation(PlcEntity.class);
if (plcEntity == null) {
throw new OPMException("Non PlcEntity supplied");
@@ -157,12 +160,14 @@ public class PlcEntityInterceptor {
.forEach(field ->
requestBuilder.addItem(
field.getDeclaringClass().getName() + "." + field.getName(),
- field.getAnnotation(PlcField.class).value()
+ OpmUtils.getOrResolveAddress(registry, field.getAnnotation(PlcField.class).value())
)
);
PlcReadRequest request = requestBuilder.build();
+ LOGGER.trace("Request for refetch of " + entityClass + " was build and is " + request.toString());
+
PlcReadResponse response = getPlcReadResponse(request);
// Fill all requested fields
@@ -182,15 +187,16 @@ public class PlcEntityInterceptor {
}
}
- private static Object fetchValueForIsGetter(Method m, PlcDriverManager driverManager, String address) throws OPMException {
- return fetchValueForGetter(m, 2, driverManager, address);
+ private static Object fetchValueForIsGetter(Method m, PlcDriverManager driverManager, String address, AliasRegistry registry) throws OPMException {
+ return fetchValueForGetter(m, 2, driverManager, address, registry);
}
- private static Object fetchValueForGetter(Method m, PlcDriverManager driverManager, String address) throws OPMException {
- return fetchValueForGetter(m, 3, driverManager, address);
+ private static Object fetchValueForGetter(Method m, PlcDriverManager driverManager, String address, AliasRegistry registry) throws OPMException {
+ return fetchValueForGetter(m, 3, driverManager, address, registry);
}
- private static Object fetchValueForGetter(Method m, int prefixLength, PlcDriverManager driverManager, String address) throws OPMException {
+ private static Object fetchValueForGetter(Method m, int prefixLength, PlcDriverManager driverManager,
+ String address, AliasRegistry registry) throws OPMException {
String s = m.getName().substring(prefixLength);
// First char to lower
String variable = s.substring(0, 1).toLowerCase().concat(s.substring(1));
@@ -210,7 +216,7 @@ public class PlcEntityInterceptor {
String fqn = field.getDeclaringClass().getName() + "." + field.getName();
PlcReadRequest request = connection.readRequestBuilder()
- .addItem(fqn, annotation.value())
+ .addItem(fqn, OpmUtils.getOrResolveAddress(registry, annotation.value()))
.build();
PlcReadResponse response = getPlcReadResponse(request);
diff --git a/plc4j/utils/opm/src/main/java/org/apache/plc4x/java/opm/PlcEntityManager.java b/plc4j/utils/opm/src/main/java/org/apache/plc4x/java/opm/PlcEntityManager.java
index 0c0b4b2..a27fed7 100644
--- a/plc4j/utils/opm/src/main/java/org/apache/plc4x/java/opm/PlcEntityManager.java
+++ b/plc4j/utils/opm/src/main/java/org/apache/plc4x/java/opm/PlcEntityManager.java
@@ -22,8 +22,6 @@ package org.apache.plc4x.java.opm;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.implementation.MethodDelegation;
-import org.apache.commons.configuration2.Configuration;
-import org.apache.commons.configuration2.SystemConfiguration;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.plc4x.java.PlcDriverManager;
@@ -41,6 +39,8 @@ import java.util.Arrays;
import java.util.concurrent.Callable;
import static net.bytebuddy.matcher.ElementMatchers.any;
+import static net.bytebuddy.matcher.ElementMatchers.isDeclaredBy;
+import static net.bytebuddy.matcher.ElementMatchers.not;
/**
* Plc4x equivalent of Jpas EntityManager for implementing Object-Plc-Mapping.
@@ -74,7 +74,7 @@ import static net.bytebuddy.matcher.ElementMatchers.any;
* A connected @{@link PlcEntity} can be disconnected calling {@link #disconnect(Object)}, then it behaves like the
* regular Pojo it was before.
* <p>
- * All invocations on the getters are forwarded to the {@link PlcEntityInterceptor#intercept(Object, Method, Callable, String, PlcDriverManager)}
+ * All invocations on the getters are forwarded to the {@link PlcEntityInterceptor#intercept(Object, Method, Callable, String, PlcDriverManager, AliasRegistry)}
* method.
*/
public class PlcEntityManager {
@@ -83,15 +83,22 @@ public class PlcEntityManager {
public static final String PLC_ADDRESS_FIELD_NAME = "_plcAddress";
static final String DRIVER_MANAGER_FIELD_NAME = "_driverManager";
+ static final String ALIAS_REGISTRY = "_aliasRegistry";
private final PlcDriverManager driverManager;
+ private final SimpleAliasRegistry registry;
public PlcEntityManager() {
- this.driverManager = new PlcDriverManager();
+ this(new PlcDriverManager());
}
public PlcEntityManager(PlcDriverManager driverManager) {
+ this(driverManager, new SimpleAliasRegistry());
+ }
+
+ public PlcEntityManager(PlcDriverManager driverManager, SimpleAliasRegistry registry) {
this.driverManager = driverManager;
+ this.registry = registry;
}
public <T> T read(Class<T> clazz, String address) throws OPMException {
@@ -109,7 +116,7 @@ public class PlcEntityManager {
.forEach(field ->
requestBuilder.addItem(
field.getDeclaringClass().getName() + "." + field.getName(),
- field.getAnnotation(PlcField.class).value()
+ OpmUtils.getOrResolveAddress(registry, field.getAnnotation(PlcField.class).value())
)
);
@@ -135,7 +142,7 @@ public class PlcEntityManager {
} catch (InstantiationException | InvocationTargetException | NoSuchMethodException | NoSuchFieldException | IllegalAccessException e) {
throw new OPMException("Unable to fetch PlcEntity " + clazz.getName(), e);
} catch (Exception e) {
- throw new OPMException("Unknown Error", e);
+ throw new OPMException("Unexpected Exception: " + e.getMessage(), e);
}
}
@@ -156,7 +163,8 @@ public class PlcEntityManager {
.subclass(clazz)
.defineField(PLC_ADDRESS_FIELD_NAME, String.class, Visibility.PRIVATE)
.defineField(DRIVER_MANAGER_FIELD_NAME, PlcDriverManager.class, Visibility.PRIVATE)
- .method(any()).intercept(MethodDelegation.to(PlcEntityInterceptor.class))
+ .defineField(ALIAS_REGISTRY, AliasRegistry.class, Visibility.PRIVATE)
+ .method(not(isDeclaredBy(Object.class))).intercept(MethodDelegation.to(PlcEntityInterceptor.class))
.make()
.load(Thread.currentThread().getContextClassLoader())
.getLoaded()
@@ -165,9 +173,10 @@ public class PlcEntityManager {
// Set connection value into the private field
FieldUtils.writeDeclaredField(instance, PLC_ADDRESS_FIELD_NAME, address, true);
FieldUtils.writeDeclaredField(instance, DRIVER_MANAGER_FIELD_NAME, driverManager, true);
+ FieldUtils.writeDeclaredField(instance, ALIAS_REGISTRY, registry, true);
// Initially fetch all values
- PlcEntityInterceptor.refetchAllFields(instance, driverManager, address);
+ PlcEntityInterceptor.refetchAllFields(instance, driverManager, address, registry);
return instance;
} catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException | IllegalAccessError e) {
@@ -193,7 +202,7 @@ public class PlcEntityManager {
}
FieldUtils.writeDeclaredField(entity, DRIVER_MANAGER_FIELD_NAME, null, true);
} catch (IllegalAccessException e) {
- throw new OPMException("Unbale to fetch driverManager instance on entity instance", e);
+ throw new OPMException("Unable to fetch driverManager instance on entity instance", e);
}
}
diff --git a/plc4j/utils/opm/src/main/java/org/apache/plc4x/java/opm/SimpleAliasRegistry.java b/plc4j/utils/opm/src/main/java/org/apache/plc4x/java/opm/SimpleAliasRegistry.java
new file mode 100644
index 0000000..10ed5e9
--- /dev/null
+++ b/plc4j/utils/opm/src/main/java/org/apache/plc4x/java/opm/SimpleAliasRegistry.java
@@ -0,0 +1,74 @@
+/*
+ * 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.opm;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+/**
+ * Simple Map Based Implementation of {@link AliasRegistry}.
+ * It is not connection specific and forwards connection aware methods to the "simple" methods.
+ */
+public class SimpleAliasRegistry implements AliasRegistry {
+
+ /**
+ * Map from alias -> plc field address
+ */
+ private final Map<String, String> aliasMap;
+
+ public SimpleAliasRegistry() {
+ this(new HashMap<>());
+ }
+
+ public SimpleAliasRegistry(Map<String, String> aliasMap) {
+ this.aliasMap = aliasMap;
+ }
+
+ /**
+ * Register an Alias in the Registry.
+ */
+ public void register(String alias, String address) {
+ this.aliasMap.put(alias, address);
+ }
+
+ @Override
+ public boolean canResolve(String connection, String alias) {
+ return canResolve(alias);
+ }
+
+ @Override
+ public String resolve(String connection, String alias) {
+ return resolve(alias);
+ }
+
+ @Override
+ public boolean canResolve(String alias) {
+ return aliasMap.containsKey(alias);
+ }
+
+ @Override
+ public String resolve(String alias) {
+ if (!canResolve(alias)) {
+ throw new NoSuchElementException("Unable to resolve '" + alias + "'");
+ }
+ return aliasMap.get(alias);
+ }
+}
diff --git a/plc4j/utils/opm/src/test/java/org/apache/plc4x/java/opm/OpmUtilsTest.java b/plc4j/utils/opm/src/test/java/org/apache/plc4x/java/opm/OpmUtilsTest.java
new file mode 100644
index 0000000..27694d4
--- /dev/null
+++ b/plc4j/utils/opm/src/test/java/org/apache/plc4x/java/opm/OpmUtilsTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.opm;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class OpmUtilsTest {
+
+ @Test
+ public void expression_matches() {
+ assertTrue(OpmUtils.pattern.matcher("${Hallo}").matches());
+ assertTrue(OpmUtils.pattern.matcher("${Hallo:Hallo}").matches());
+ // ...
+ assertTrue(OpmUtils.pattern.matcher("${Ha{}llo}").matches());
+ }
+
+ @Test
+ public void getAlias_matches() {
+ String alias = OpmUtils.getAlias("${hallo}");
+
+ assertEquals("hallo", alias);
+ }
+
+ @Test
+ public void isAlias_bothCases() {
+ // True
+ assertTrue(OpmUtils.isAlias("${hallo}"));
+ assertTrue(OpmUtils.isAlias("${hal{}lo}"));
+ assertTrue(OpmUtils.isAlias("${hallo:hallo}"));
+ // False
+ assertFalse(OpmUtils.isAlias("hallo"));
+ assertFalse(OpmUtils.isAlias("${hallo"));
+ assertFalse(OpmUtils.isAlias("${ha}llo"));
+ }
+
+ @Test
+ public void isValidExpression_startingDollar_false() {
+ assertFalse(OpmUtils.isValidExpression("${hallo"));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void getAlias_illegalString_throws() {
+ OpmUtils.getAlias("hallo");
+ }
+}
\ No newline at end of file
diff --git a/plc4j/utils/opm/src/test/java/org/apache/plc4x/java/opm/PlcEntityInterceptorTest.java b/plc4j/utils/opm/src/test/java/org/apache/plc4x/java/opm/PlcEntityInterceptorTest.java
index 7108474..d508690 100644
--- a/plc4j/utils/opm/src/test/java/org/apache/plc4x/java/opm/PlcEntityInterceptorTest.java
+++ b/plc4j/utils/opm/src/test/java/org/apache/plc4x/java/opm/PlcEntityInterceptorTest.java
@@ -32,8 +32,10 @@ import java.util.Collections;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.when;
@@ -49,12 +51,27 @@ public class PlcEntityInterceptorTest {
PlcEntityInterceptor.getPlcReadResponse(request);
}
- @Test(expected = OPMException.class)
- public void getPlcReadResponse_catchesInterruptedException_rethrows() throws OPMException, InterruptedException, ExecutionException, TimeoutException {
- runGetPlcResponseWIthException(invocation -> {
- throw new InterruptedException();
+ @Test
+ public void getPlcReadResponse_catchesInterruptedException_rethrows() throws InterruptedException {
+ AtomicBoolean exceptionWasThrown = new AtomicBoolean(false);
+ // Run in different Thread
+ Thread thread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ runGetPlcResponseWIthException(invocation -> {
+ throw new InterruptedException();
+ });
+ } catch (InterruptedException | ExecutionException | TimeoutException e) {
+ e.printStackTrace();
+ } catch (OPMException e) {
+ exceptionWasThrown.set(true);
+ }
+ }
});
- return;
+ thread.start();
+ thread.join();
+ assertTrue(exceptionWasThrown.get());
}
@Test(expected = OPMException.class)
diff --git a/plc4j/utils/opm/src/test/java/org/apache/plc4x/java/opm/PlcEntityManagerTest.java b/plc4j/utils/opm/src/test/java/org/apache/plc4x/java/opm/PlcEntityManagerTest.java
index 429b100..e97bf6e 100644
--- a/plc4j/utils/opm/src/test/java/org/apache/plc4x/java/opm/PlcEntityManagerTest.java
+++ b/plc4j/utils/opm/src/test/java/org/apache/plc4x/java/opm/PlcEntityManagerTest.java
@@ -35,13 +35,15 @@ import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
-import java.util.concurrent.CompletableFuture;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
public class PlcEntityManagerTest {
@@ -133,6 +135,66 @@ public class PlcEntityManagerTest {
UninstantiableEntity entity = entityManager.connect(UninstantiableEntity.class, "mock:test");
}
+ @Test
+ public void read_resolveAlias_works() throws OPMException, PlcConnectionException {
+ SimpleAliasRegistry registry = new SimpleAliasRegistry();
+ registry.register("alias", "real_field");
+
+ // Mock
+ PlcDriverManager driverManager = new PlcDriverManager();
+ PlcMockConnection connection = (PlcMockConnection) driverManager.getConnection("mock:test");
+ MockDevice mockDevice = Mockito.mock(MockDevice.class);
+ when(mockDevice.read(any())).thenReturn(Pair.of(PlcResponseCode.OK, new DefaultStringFieldItem("value")));
+ connection.setDevice(mockDevice);
+
+ PlcEntityManager entityManager = new PlcEntityManager(driverManager, registry);
+ entityManager.read(AliasEntity.class, "mock:test");
+
+ // Assert that "field" was queried
+ verify(mockDevice).read(eq("real_field"));
+ }
+
+ @Test
+ public void connect_resolveAlias_works() throws PlcConnectionException, OPMException {
+ SimpleAliasRegistry registry = new SimpleAliasRegistry();
+ registry.register("alias", "real_field");
+
+ // Mock
+ PlcDriverManager driverManager = new PlcDriverManager();
+ PlcMockConnection connection = (PlcMockConnection) driverManager.getConnection("mock:test");
+ MockDevice mockDevice = Mockito.mock(MockDevice.class);
+ when(mockDevice.read(any())).thenReturn(Pair.of(PlcResponseCode.OK, new DefaultStringFieldItem("value")));
+ connection.setDevice(mockDevice);
+
+ PlcEntityManager entityManager = new PlcEntityManager(driverManager, registry);
+ entityManager.connect(AliasEntity.class, "mock:test");
+
+ // Assert that "field" was queried
+ verify(mockDevice, times(1)).read(eq("real_field"));
+ }
+
+ @Test(expected = OPMException.class)
+ public void read_unknownAlias_throws() throws OPMException {
+ PlcEntityManager entityManager = new PlcEntityManager();
+
+ entityManager.read(AliasEntity.class, "mock:test");
+ }
+
+ @Test
+ public void read_badAlias_throws() {
+ PlcEntityManager entityManager = new PlcEntityManager();
+
+ String message = null;
+ try {
+ entityManager.read(BadAliasEntity.class, "mock:test");
+ } catch (OPMException e) {
+ message = e.getMessage();
+ }
+
+ assertNotNull(message);
+ assertTrue(message.contains("Invalid Syntax, either use field address (no starting $) or an alias with Syntax ${xxx}. But given was"));
+ }
+
@PlcEntity
private static class UninstantiableEntity {
@@ -157,4 +219,34 @@ public class PlcEntityManagerTest {
}
}
+ @PlcEntity
+ public static class AliasEntity {
+
+ @PlcField("${alias}")
+ private String aliasedField;
+
+ public AliasEntity() {
+ // for OPM
+ }
+
+ public String getAliasedField() {
+ return aliasedField;
+ }
+ }
+
+ @PlcEntity
+ public static class BadAliasEntity {
+
+ @PlcField("${alias")
+ private String aliasedField;
+
+ public BadAliasEntity() {
+ // for OPM
+ }
+
+ public String getAliasedField() {
+ return aliasedField;
+ }
+ }
+
}
\ No newline at end of file
diff --git a/plc4j/utils/opm/src/test/java/org/apache/plc4x/java/opm/SimpleAliasRegistryTest.java b/plc4j/utils/opm/src/test/java/org/apache/plc4x/java/opm/SimpleAliasRegistryTest.java
new file mode 100644
index 0000000..bc6d8ad
--- /dev/null
+++ b/plc4j/utils/opm/src/test/java/org/apache/plc4x/java/opm/SimpleAliasRegistryTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.opm;
+
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.NoSuchElementException;
+
+import static org.junit.Assert.*;
+
+public class SimpleAliasRegistryTest {
+
+ public static final String ADDRESS = "DB2:1234";
+ public static final String ALIAS = "some_field";
+
+ @Test
+ public void register_containsValue() {
+ SimpleAliasRegistry registry = new SimpleAliasRegistry();
+ registry.register(ALIAS, ADDRESS);
+
+ // Perform checks
+ checkMethods(registry);
+ }
+
+ @Test
+ public void defaultMap_containsValue() {
+ HashMap<String, String> map = new HashMap<>();
+ map.put(ALIAS, ADDRESS);
+ SimpleAliasRegistry registry = new SimpleAliasRegistry(map);
+
+ // Perform checks
+ checkMethods(registry);
+ }
+
+ @Test
+ public void canResolve_unknownAlias_returnFalse() {
+ SimpleAliasRegistry registry = new SimpleAliasRegistry();
+
+ assertFalse(registry.canResolve(ALIAS));
+ }
+
+ @Test(expected = NoSuchElementException.class)
+ public void resolve_unknownAlias_throws() {
+ SimpleAliasRegistry registry = new SimpleAliasRegistry();
+
+ registry.resolve(ALIAS);
+ }
+
+ private void checkMethods(SimpleAliasRegistry registry) {
+ // Can Resolve
+ assertTrue(registry.canResolve(ALIAS));
+ assertTrue(registry.canResolve("unknown_connection", ALIAS));
+
+ // Resolve
+ assertEquals(ADDRESS, registry.resolve(ALIAS));
+ assertEquals(ADDRESS, registry.resolve("unknown_connection", ALIAS));
+ }
+}
\ No newline at end of file
diff --git a/plc4j/utils/opm/src/test/resources/logback.xml b/plc4j/utils/opm/src/test/resources/logback.xml
index 8b49981..74570cd 100644
--- a/plc4j/utils/opm/src/test/resources/logback.xml
+++ b/plc4j/utils/opm/src/test/resources/logback.xml
@@ -29,7 +29,7 @@
</encoder>
</appender>
- <root level="debug">
+ <root level="trace">
<appender-ref ref="STDOUT"/>
</root>