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/10/27 11:48:18 UTC

[incubator-plc4x] 01/02: [OPM] Refactoring. Added PlcEntityInterceptor.

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

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

commit 29c83a29ff9ebdb124ea10e469d876dede412f26
Author: Julian Feinauer <j....@pragmaticminds.de>
AuthorDate: Sat Oct 27 11:56:11 2018 +0200

    [OPM] Refactoring. Added PlcEntityInterceptor.
---
 .../java/org/apache/plc4x/java/opm/OpmUtils.java   |  12 -
 ...ntityManager.java => PlcEntityInterceptor.java} | 229 ++++-------------
 .../apache/plc4x/java/opm/PlcEntityManager.java    | 282 +--------------------
 3 files changed, 67 insertions(+), 456 deletions(-)

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 39f447d..604866d 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
@@ -44,16 +44,4 @@ public final class OpmUtils {
         return annotation;
     }
 
-    static String extractAddress(Object proxy) throws OPMException {
-        String address;
-        try {
-            Field field = proxy.getClass().getDeclaredField(PlcEntityManager.PLC_ADDRESS_FIELD_NAME);
-            field.setAccessible(true);
-            address = (String) field.get(proxy);
-        } catch (IllegalAccessException | NoSuchFieldException e) {
-            throw new OPMException("Problem with accessing internal plc address", e);
-        }
-        return address;
-    }
-
 }
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/PlcEntityInterceptor.java
similarity index 56%
copy from plc4j/utils/opm/src/main/java/org/apache/plc4x/java/opm/PlcEntityManager.java
copy to plc4j/utils/opm/src/main/java/org/apache/plc4x/java/opm/PlcEntityInterceptor.java
index d6d6de6..48df70e 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/PlcEntityInterceptor.java
@@ -1,36 +1,33 @@
 /*
- 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.
+ * 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 net.bytebuddy.ByteBuddy;
-import net.bytebuddy.description.modifier.Visibility;
-import net.bytebuddy.implementation.MethodDelegation;
 import net.bytebuddy.implementation.bind.annotation.*;
 import org.apache.commons.configuration2.Configuration;
 import org.apache.commons.configuration2.SystemConfiguration;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.reflect.FieldUtils;
 import org.apache.plc4x.java.PlcDriverManager;
 import org.apache.plc4x.java.api.PlcConnection;
 import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
-import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
 import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.api.messages.PlcReadRequest;
 import org.apache.plc4x.java.api.messages.PlcReadResponse;
@@ -38,7 +35,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.math.BigDecimal;
 import java.math.BigInteger;
@@ -51,164 +47,52 @@ import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
-import static net.bytebuddy.matcher.ElementMatchers.any;
-
 /**
- * Plc4x equivalent of Jpas EntityManager for implementing Object-Plc-Mapping.
- * This means that calls to a plc can be done by using plain POJOs with Annotations.
- * <p>
- * First, the necessary annotations are {@link PlcEntity} and {@link PlcField}.
- * For a class to be usable as PlcEntity it needs
- * <ul>
- * <li>be non-final (as proxiing has to be used in case of {@link #connect(Class, String)}</li>
- * <li>a public no args constructor for instanciation</li>
- * <li>Needs to be annotated with {@link PlcEntity} and has a valid value which is the connection string</li>
- * </ul>
- * <p>
- * Basically, the {@link PlcEntityManager} has to operation "modes" represented by the methods {@link #read(Class,String)} and
- * {@link #connect(Class,String)}.
- * <p>
- * For a field to get Values from the Plc Injected it needs to be annotated with the {@link PlcField} annotation.
- * The value has to be the plc fields string (which is inserted in the {@link PlcReadRequest}).
- * The connection string is taken from the value of the {@link PlcEntity} annotation on the class.
- * <p>
- * The {@link #read(Class,String)} method has no direkt equivalent in JPA (as far as I know) as it only returns a "detached"
- * entity. This means it fetches all values from the plc that are annotated wiht the {@link PlcField} annotations.
- * <p>
- * The {@link #connect(Class,String)} method is more JPA-like as it returns a "connected" entity. This means, that each
- * time one of the getters on the returned entity is called a call is made to the plc (and the field value is changed
- * for this specific field).
- * Furthermore, if a method which is no getter is called, then all {@link PlcField}s are refreshed before doing the call.
- * Thus, all operations on fields that are annotated with {@link PlcField} are always done against the "live" values
- * from the PLC.
- * <p>
- * // TODO Add detach method
+ * Interceptor for dynamic functionality of @{@link PlcEntity}.
+ * Basically, its {@link #intercept(Object, Method, Callable, String, PlcDriverManager)} 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"
+ * method on the "proxied" entity and all parameters of the intercept method could then be access to local fields.
+ *
+ * @author julian
  */
-public class PlcEntityManager {
+public class PlcEntityInterceptor {
 
-    public static final String PLC_ADDRESS_FIELD_NAME = "_plcAddress";
-    private static final Logger LOGGER = LoggerFactory.getLogger(PlcEntityManager.class);
+    private static final Logger LOGGER = LoggerFactory.getLogger(PlcEntityInterceptor.class);
 
     private static final Configuration CONF = new SystemConfiguration();
     private static final long READ_TIMEOUT = CONF.getLong("org.apache.plc4x.java.opm.entity_manager.read_timeout", 1_000);
-
-    private final PlcDriverManager driverManager;
-
-    public PlcEntityManager() {
-        this.driverManager = new PlcDriverManager();
-    }
-
-    public PlcEntityManager(PlcDriverManager driverManager) {
-        this.driverManager = driverManager;
-    }
-
-    public <T> T read(Class<T> clazz, String address) throws OPMException {
-        PlcEntity annotation = OpmUtils.getPlcEntityAndCheckPreconditions(clazz);
-
-        try (PlcConnection connection = driverManager.getConnection(address)) {
-            if (!connection.getMetadata().canRead()) {
-                throw new OPMException("Unable to get Reader for connection with url '" + address + "'");
-            }
-
-            PlcReadRequest.Builder requestBuilder = connection.readRequestBuilder();
-
-            Arrays.stream(clazz.getDeclaredFields())
-                .filter(field -> field.isAnnotationPresent(PlcField.class))
-                .forEach(field ->
-                    requestBuilder.addItem(
-                        field.getDeclaringClass().getName() + "." + field.getName(),
-                        field.getAnnotation(PlcField.class).value()
-                    )
-                );
-
-            // Build the request
-            PlcReadRequest request = requestBuilder.build();
-
-            // Perform the request
-            PlcReadResponse response = getPlcReadResponse(request);
-
-            // Construct the Object
-            T instance = clazz.getConstructor().newInstance();
-
-            // Fill all requested fields
-            for (String fieldName : response.getFieldNames()) {
-                String targetFieldName = StringUtils.substringAfterLast(fieldName, ".");
-                setField(clazz, instance, response, targetFieldName, fieldName);
-            }
-            return instance;
-        } catch (PlcInvalidFieldException e) {
-            throw new OPMException("Unable to parse one field request", e);
-        } catch (PlcConnectionException e) {
-            throw new OPMException("Unable to get connection with url '" + address + "'", e);
-        } 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);
-        }
-    }
-
-    /**
-     * Returns a connected proxy.
-     *
-     * @param clazz clazz to be connected.
-     * @param <T>   type of param {@code clazz}.
-     * @return a connected entity.
-     * @throws OPMException when proxy can't be build.
-     */
-    public <T> T connect(Class<T> clazz, String address) throws OPMException {
-        OpmUtils.getPlcEntityAndCheckPreconditions(clazz);
-        try {
-            // Use Byte Buddy to generate a subclassed proxy that delegates all PlcField Methods
-            // to the intercept method
-            T instance = new ByteBuddy()
-                .subclass(clazz)
-                .defineField(PLC_ADDRESS_FIELD_NAME, String.class, Visibility.PRIVATE)
-                .method(any()).intercept(MethodDelegation.to(this))
-                .make()
-                .load(Thread.currentThread().getContextClassLoader())
-                .getLoaded()
-                .getConstructor()
-                .newInstance();
-            // Set connection value into the private field
-            Field plcAddress = instance.getClass().getDeclaredField(PLC_ADDRESS_FIELD_NAME);
-            plcAddress.setAccessible(true);
-            plcAddress.set(instance, address);
-            return instance;
-        } catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
-            throw new OPMException("Unable to instantiate Proxy", e);
-        } catch (NoSuchFieldException e) {
-            throw new IllegalStateException("Problem with field injection during proxy generation", e);
-        }
-    }
-
-    //------------------------------------------------------------------------------------------------
-    //
-    //  Methods for interception for the proxy object
-    //
-    //------------------------------------------------------------------------------------------------
-
     /**
      * 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, String)} method.
+     * the {@link #fetchValueForGetter(Method, PlcDriverManager,String)} method.
      * <p>
-     * If the field is no getter, then all fields are refreshed by calling {@link #refetchAllFields(Object,String)}
+     * If the field is no getter, then all fields are refreshed by calling {@link #refetchAllFields(Object, PlcDriverManager, String)}
      * and then, the method is invoked.
      *
      * @param proxy    Object to intercept
      * @param method   Method that was intercepted
      * @param callable Callable to call the method after fetching the values
-     * @param entity   Reference to the PlcEntity
      * @return possible result of the original methods invocation
      * @throws OPMException Problems with plc / proxying
      */
     @SuppressWarnings("unused")
     @RuntimeType
-    public Object intercept(@This Object proxy, @Origin Method method, @SuperCall Callable<?> callable, @Super Object entity) throws OPMException {
-        LOGGER.trace("Invoked method {} on connected PlcEntity {}", method.getName(), entity);
-
-        // Fetch connection from internal variable
-        String address = OpmUtils.extractAddress(proxy);
+    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 {
+        LOGGER.trace("Invoked method {} on connected PlcEntity {}", method.getName(), method.getDeclaringClass().getName());
+
+        // If "detached" (i.e. _driverManager is null) simply forward the call
+        if (driverManager == null) {
+            LOGGER.trace("Entity not connected, simply fowarding call");
+            try {
+                return callable.call();
+            } catch (Exception e) {
+                throw new OPMException("Exception during forwarding call", e);
+            }
+        }
 
         if (method.getName().startsWith("get")) {
             if (method.getParameterCount() > 0) {
@@ -217,7 +101,7 @@ public class PlcEntityManager {
             // Fetch single value
             LOGGER.trace("Invoked method {} is getter, trying to find annotated field and return requested value",
                 method.getName());
-            return fetchValueForGetter(method, address);
+            return fetchValueForGetter(method, driverManager, address);
         }
 
         if (method.getName().startsWith("is") && (method.getReturnType() == boolean.class || method.getReturnType() == Boolean.class)) {
@@ -227,13 +111,13 @@ public class PlcEntityManager {
             // 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, address);
+            return fetchValueForIsGetter(method, driverManager, address);
         }
 
         // 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, address);
+            refetchAllFields(proxy, driverManager, address);
             return callable.call();
         } catch (Exception e) {
             throw new OPMException("Unable to forward invocation " + method.getName() + " on connected PlcEntity", e);
@@ -244,9 +128,10 @@ public class PlcEntityManager {
      * Renews all values of all Fields that are annotated with {@link PlcEntity}.
      *
      * @param proxy Object to refresh the fields on.
+     * @param driverManager
      * @throws OPMException on various errors.
      */
-    private void refetchAllFields(Object proxy, String address) throws OPMException {
+    private static void refetchAllFields(Object proxy, PlcDriverManager driverManager, String address) 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();
         PlcEntity plcEntity = entityClass.getAnnotation(PlcEntity.class);
@@ -289,16 +174,15 @@ public class PlcEntityManager {
         }
     }
 
-
-    private Object fetchValueForIsGetter(Method m, String address) throws OPMException {
-        return fetchValueForGetter(m, 2, address);
+    private static Object fetchValueForIsGetter(Method m, PlcDriverManager driverManager, String address) throws OPMException {
+        return fetchValueForGetter(m, 2, driverManager, address);
     }
 
-    private Object fetchValueForGetter(Method m, String address) throws OPMException {
-        return fetchValueForGetter(m, 3, address);
+    private static Object fetchValueForGetter(Method m, PlcDriverManager driverManager, String address) throws OPMException {
+        return fetchValueForGetter(m, 3, driverManager, address);
     }
 
-    private Object fetchValueForGetter(Method m, int prefixLength, String address) throws OPMException {
+    private static Object fetchValueForGetter(Method m, int prefixLength, PlcDriverManager driverManager, String address) throws OPMException {
         String s = m.getName().substring(prefixLength);
         // First char to lower
         String variable = s.substring(0, 1).toLowerCase().concat(s.substring(1));
@@ -339,7 +223,7 @@ public class PlcEntityManager {
      * @throws NoSuchFieldException
      * @throws IllegalAccessException
      */
-    private void setField(Class<?> clazz, Object o, PlcReadResponse response, String targetFieldName, String sourceFieldName) throws NoSuchFieldException, IllegalAccessException {
+    static void setField(Class<?> clazz, Object o, PlcReadResponse response, String targetFieldName, String sourceFieldName) throws NoSuchFieldException, IllegalAccessException {
         LOGGER.debug("setField on clazz: {}, Object: {}, response: {}, targetFieldName: {}, sourceFieldName:{} ", clazz, o, response, targetFieldName, sourceFieldName);
         Field field = clazz.getDeclaredField(targetFieldName);
         field.setAccessible(true);
@@ -351,7 +235,7 @@ public class PlcEntityManager {
         }
     }
 
-    private Object getTyped(Class<?> clazz, PlcReadResponse response, String sourceFieldName) {
+    private static Object getTyped(Class<?> clazz, PlcReadResponse response, String sourceFieldName) {
         LOGGER.debug("getTyped clazz: {}, response: {}, fieldName: {}", clazz, response, sourceFieldName);
         if (clazz.isPrimitive()) {
             if (clazz == boolean.class) {
@@ -416,7 +300,7 @@ public class PlcEntityManager {
      * @return the response from the exception.
      * @throws OPMException on {@link InterruptedException} or {@link ExecutionException} or {@link TimeoutException}
      */
-    private PlcReadResponse getPlcReadResponse(PlcReadRequest request) throws OPMException {
+    static PlcReadResponse getPlcReadResponse(PlcReadRequest request) throws OPMException {
         try {
             return request.execute().get(READ_TIMEOUT, TimeUnit.MILLISECONDS);
         } catch (InterruptedException e) {
@@ -428,5 +312,4 @@ public class PlcEntityManager {
             throw new OPMException("Timeout during fetching values", e);
         }
     }
-
 }
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 d6d6de6..aeb7fa2 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,34 +22,23 @@ package org.apache.plc4x.java.opm;
 import net.bytebuddy.ByteBuddy;
 import net.bytebuddy.description.modifier.Visibility;
 import net.bytebuddy.implementation.MethodDelegation;
-import net.bytebuddy.implementation.bind.annotation.*;
 import org.apache.commons.configuration2.Configuration;
 import org.apache.commons.configuration2.SystemConfiguration;
-import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.reflect.FieldUtils;
 import org.apache.plc4x.java.PlcDriverManager;
 import org.apache.plc4x.java.api.PlcConnection;
 import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
 import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
-import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.api.messages.PlcReadRequest;
 import org.apache.plc4x.java.api.messages.PlcReadResponse;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
 import java.util.Arrays;
 import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
 
 import static net.bytebuddy.matcher.ElementMatchers.any;
 
@@ -82,15 +71,16 @@ import static net.bytebuddy.matcher.ElementMatchers.any;
  * Thus, all operations on fields that are annotated with {@link PlcField} are always done against the "live" values
  * from the PLC.
  * <p>
+ * All invocations on the getters are forwarded to the {@link PlcEntityInterceptor#intercept(Object, Method, Callable, Object)}
+ * method.
  * // TODO Add detach method
  */
 public class PlcEntityManager {
 
-    public static final String PLC_ADDRESS_FIELD_NAME = "_plcAddress";
     private static final Logger LOGGER = LoggerFactory.getLogger(PlcEntityManager.class);
 
-    private static final Configuration CONF = new SystemConfiguration();
-    private static final long READ_TIMEOUT = CONF.getLong("org.apache.plc4x.java.opm.entity_manager.read_timeout", 1_000);
+    public static final String PLC_ADDRESS_FIELD_NAME = "_plcAddress";
+    static final String DRIVER_MANAGER_FIELD_NAME = "_driverManager";
 
     private final PlcDriverManager driverManager;
 
@@ -125,7 +115,7 @@ public class PlcEntityManager {
             PlcReadRequest request = requestBuilder.build();
 
             // Perform the request
-            PlcReadResponse response = getPlcReadResponse(request);
+            PlcReadResponse response = PlcEntityInterceptor.getPlcReadResponse(request);
 
             // Construct the Object
             T instance = clazz.getConstructor().newInstance();
@@ -133,7 +123,7 @@ public class PlcEntityManager {
             // Fill all requested fields
             for (String fieldName : response.getFieldNames()) {
                 String targetFieldName = StringUtils.substringAfterLast(fieldName, ".");
-                setField(clazz, instance, response, targetFieldName, fieldName);
+                PlcEntityInterceptor.setField(clazz, instance, response, targetFieldName, fieldName);
             }
             return instance;
         } catch (PlcInvalidFieldException e) {
@@ -163,269 +153,19 @@ public class PlcEntityManager {
             T instance = new ByteBuddy()
                 .subclass(clazz)
                 .defineField(PLC_ADDRESS_FIELD_NAME, String.class, Visibility.PRIVATE)
-                .method(any()).intercept(MethodDelegation.to(this))
+                .defineField(DRIVER_MANAGER_FIELD_NAME, PlcDriverManager.class, Visibility.PRIVATE)
+                .method(any()).intercept(MethodDelegation.to(PlcEntityInterceptor.class))
                 .make()
                 .load(Thread.currentThread().getContextClassLoader())
                 .getLoaded()
                 .getConstructor()
                 .newInstance();
             // Set connection value into the private field
-            Field plcAddress = instance.getClass().getDeclaredField(PLC_ADDRESS_FIELD_NAME);
-            plcAddress.setAccessible(true);
-            plcAddress.set(instance, address);
+            FieldUtils.writeDeclaredField(instance, PLC_ADDRESS_FIELD_NAME, address, true);
+            FieldUtils.writeDeclaredField(instance, DRIVER_MANAGER_FIELD_NAME, driverManager, true);
             return instance;
         } catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
             throw new OPMException("Unable to instantiate Proxy", e);
-        } catch (NoSuchFieldException e) {
-            throw new IllegalStateException("Problem with field injection during proxy generation", e);
-        }
-    }
-
-    //------------------------------------------------------------------------------------------------
-    //
-    //  Methods for interception for the proxy object
-    //
-    //------------------------------------------------------------------------------------------------
-
-    /**
-     * 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, String)} method.
-     * <p>
-     * If the field is no getter, then all fields are refreshed by calling {@link #refetchAllFields(Object,String)}
-     * and then, the method is invoked.
-     *
-     * @param proxy    Object to intercept
-     * @param method   Method that was intercepted
-     * @param callable Callable to call the method after fetching the values
-     * @param entity   Reference to the PlcEntity
-     * @return possible result of the original methods invocation
-     * @throws OPMException Problems with plc / proxying
-     */
-    @SuppressWarnings("unused")
-    @RuntimeType
-    public Object intercept(@This Object proxy, @Origin Method method, @SuperCall Callable<?> callable, @Super Object entity) throws OPMException {
-        LOGGER.trace("Invoked method {} on connected PlcEntity {}", method.getName(), entity);
-
-        // Fetch connection from internal variable
-        String address = OpmUtils.extractAddress(proxy);
-
-        if (method.getName().startsWith("get")) {
-            if (method.getParameterCount() > 0) {
-                throw new OPMException("Only getter with no arguments are supported");
-            }
-            // Fetch single value
-            LOGGER.trace("Invoked method {} is getter, trying to find annotated field and return requested value",
-                method.getName());
-            return fetchValueForGetter(method, address);
-        }
-
-        if (method.getName().startsWith("is") && (method.getReturnType() == boolean.class || method.getReturnType() == Boolean.class)) {
-            if (method.getParameterCount() > 0) {
-                throw new OPMException("Only getter with no arguments are supported");
-            }
-            // 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, address);
-        }
-
-        // 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, address);
-            return callable.call();
-        } catch (Exception e) {
-            throw new OPMException("Unable to forward invocation " + method.getName() + " on connected PlcEntity", e);
-        }
-    }
-
-    /**
-     * Renews all values of all Fields that are annotated with {@link PlcEntity}.
-     *
-     * @param proxy Object to refresh the fields on.
-     * @throws OPMException on various errors.
-     */
-    private void refetchAllFields(Object proxy, String address) 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();
-        PlcEntity plcEntity = entityClass.getAnnotation(PlcEntity.class);
-        if (plcEntity == null) {
-            throw new OPMException("Non PlcEntity supplied");
-        }
-
-        try (PlcConnection connection = driverManager.getConnection(address)) {
-            // Catch the exception, if no reader present (see below)
-            // Build the query
-            PlcReadRequest.Builder requestBuilder = connection.readRequestBuilder();
-
-            Arrays.stream(entityClass.getDeclaredFields())
-                .filter(field -> field.isAnnotationPresent(PlcField.class))
-                .forEach(field ->
-                    requestBuilder.addItem(
-                        field.getDeclaringClass().getName() + "." + field.getName(),
-                        field.getAnnotation(PlcField.class).value()
-                    )
-                );
-
-            PlcReadRequest request = requestBuilder.build();
-
-            PlcReadResponse response = getPlcReadResponse(request);
-
-            // Fill all requested fields
-            for (String fieldName : response.getFieldNames()) {
-                LOGGER.trace("Value for field " + fieldName + " is " + response.getObject(fieldName));
-                String clazzFieldName = StringUtils.substringAfterLast(fieldName, ".");
-                try {
-                    setField(entityClass, proxy, response, clazzFieldName, fieldName);
-                } catch (NoSuchFieldException | IllegalAccessException e) {
-                    throw new PlcRuntimeException(e);
-                }
-            }
-        } catch (PlcConnectionException e) {
-            throw new OPMException("Problem during processing", e);
-        } catch (Exception e) {
-            throw new OPMException("Unknown Error", e);
-        }
-    }
-
-
-    private Object fetchValueForIsGetter(Method m, String address) throws OPMException {
-        return fetchValueForGetter(m, 2, address);
-    }
-
-    private Object fetchValueForGetter(Method m, String address) throws OPMException {
-        return fetchValueForGetter(m, 3, address);
-    }
-
-    private Object fetchValueForGetter(Method m, int prefixLength, String address) throws OPMException {
-        String s = m.getName().substring(prefixLength);
-        // First char to lower
-        String variable = s.substring(0, 1).toLowerCase().concat(s.substring(1));
-        LOGGER.trace("Looking for field with name {} after invokation of getter {}", variable, m.getName());
-        PlcField annotation;
-        try {
-            annotation = m.getDeclaringClass().getDeclaredField(variable).getDeclaredAnnotation(PlcField.class);
-        } catch (NoSuchFieldException e) {
-            throw new OPMException("Unable to identify field annotated field for call to " + m.getName(), e);
-        }
-        try (PlcConnection connection = driverManager.getConnection(address)) {
-            // Catch the exception, if no reader present (see below)
-
-            // Assume to do the query here...
-            PlcReadRequest request = connection.readRequestBuilder()
-                .addItem(m.getName(), annotation.value())
-                .build();
-
-            PlcReadResponse response = getPlcReadResponse(request);
-
-            return getTyped(m.getReturnType(), response, m.getName());
-        } catch (ClassCastException e) {
-            throw new OPMException("Unable to return response as suitable type", e);
-        } catch (Exception e) {
-            throw new OPMException("Problem during processing", e);
-        }
-    }
-
-    /**
-     * Tries to set a response Item to a field in the given object.
-     * This is one by looking for a field in the class and a response item
-     * which is equal to the given fieldName parameter.
-     *
-     * @param o               Object to set the value on
-     * @param response        Response to fetch the response from
-     * @param targetFieldName Name of the field in the object
-     * @param sourceFieldName Name of the field in the response
-     * @throws NoSuchFieldException
-     * @throws IllegalAccessException
-     */
-    private void setField(Class<?> clazz, Object o, PlcReadResponse response, String targetFieldName, String sourceFieldName) throws NoSuchFieldException, IllegalAccessException {
-        LOGGER.debug("setField on clazz: {}, Object: {}, response: {}, targetFieldName: {}, sourceFieldName:{} ", clazz, o, response, targetFieldName, sourceFieldName);
-        Field field = clazz.getDeclaredField(targetFieldName);
-        field.setAccessible(true);
-        try {
-            field.set(o, getTyped(field.getType(), response, sourceFieldName));
-        } catch (ClassCastException e) {
-            // TODO should we simply fail here?
-            LOGGER.warn("Unable to assign return value {} to field {} with type {}", response.getObject(sourceFieldName), targetFieldName, field.getType(), e);
-        }
-    }
-
-    private Object getTyped(Class<?> clazz, PlcReadResponse response, String sourceFieldName) {
-        LOGGER.debug("getTyped clazz: {}, response: {}, fieldName: {}", clazz, response, sourceFieldName);
-        if (clazz.isPrimitive()) {
-            if (clazz == boolean.class) {
-                return response.getBoolean(sourceFieldName);
-            } else if (clazz == byte.class) {
-                return response.getByte(sourceFieldName);
-            } else if (clazz == short.class) {
-                return response.getShort(sourceFieldName);
-            } else if (clazz == int.class) {
-                return response.getInteger(sourceFieldName);
-            } else if (clazz == long.class) {
-                return response.getLong(sourceFieldName);
-            }
-        }
-
-        if (clazz == Boolean.class) {
-            return response.getBoolean(sourceFieldName);
-        } else if (clazz == Byte.class) {
-            return response.getByte(sourceFieldName);
-        } else if (clazz == Short.class) {
-            return response.getShort(sourceFieldName);
-        } else if (clazz == Integer.class) {
-            return response.getInteger(sourceFieldName);
-        } else if (clazz == Long.class) {
-            return response.getLong(sourceFieldName);
-        } else if (clazz == BigInteger.class) {
-            return response.getBigInteger(sourceFieldName);
-        } else if (clazz == Float.class) {
-            return response.getFloat(sourceFieldName);
-        } else if (clazz == Double.class) {
-            return response.getDouble(sourceFieldName);
-        } else if (clazz == BigDecimal.class) {
-            return response.getBigDecimal(sourceFieldName);
-        } else if (clazz == String.class) {
-            return response.getString(sourceFieldName);
-        } else if (clazz == LocalTime.class) {
-            return response.getTime(sourceFieldName);
-        } else if (clazz == LocalDate.class) {
-            return response.getDate(sourceFieldName);
-        } else if (clazz == LocalDateTime.class) {
-            return response.getDateTime(sourceFieldName);
-        } else if (clazz == byte[].class) {
-            return ArrayUtils.toPrimitive(response.getByteArray(sourceFieldName));
-        } else if (clazz == Byte[].class) {
-            return response.getByteArray(sourceFieldName);
-        }
-
-        // Fallback
-        Object responseObject = response.getObject(sourceFieldName);
-        if (clazz.isAssignableFrom(responseObject.getClass())) {
-            return responseObject;
-        }
-
-        // If nothing matched, throw
-        throw new ClassCastException("Unable to return response item " + responseObject + "(" + responseObject.getClass() + ") as instance of " + clazz);
-    }
-
-    /**
-     * Fetch the request and do appropriate error handling
-     *
-     * @param request the request to get the exception from
-     * @return the response from the exception.
-     * @throws OPMException on {@link InterruptedException} or {@link ExecutionException} or {@link TimeoutException}
-     */
-    private PlcReadResponse getPlcReadResponse(PlcReadRequest request) throws OPMException {
-        try {
-            return request.execute().get(READ_TIMEOUT, TimeUnit.MILLISECONDS);
-        } catch (InterruptedException e) {
-            Thread.currentThread().interrupt();
-            throw new OPMException("Exception during execution", e);
-        } catch (ExecutionException e) {
-            throw new OPMException("Exception during execution", e);
-        } catch (TimeoutException e) {
-            throw new OPMException("Timeout during fetching values", e);
         }
     }