Extract TypedRowInvocationHandler 81/86081/12
authorRobert Varga <robert.varga@pantheon.tech>
Sun, 1 Dec 2019 10:33:02 +0000 (11:33 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Mon, 2 Dec 2019 11:20:08 +0000 (12:20 +0100)
The InvocationHandler used in TyperUtils has significant
functionality, which we want to further extend/optimize. Split it
out into its own class.

Change-Id: I6406150799d805b2c2e0867a37205f54ec1c10bd
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
library/impl/src/main/java/org/opendaylight/ovsdb/lib/schema/typed/TypedRowInvocationHandler.java [new file with mode: 0644]
library/impl/src/main/java/org/opendaylight/ovsdb/lib/schema/typed/TyperUtils.java

diff --git a/library/impl/src/main/java/org/opendaylight/ovsdb/lib/schema/typed/TypedRowInvocationHandler.java b/library/impl/src/main/java/org/opendaylight/ovsdb/lib/schema/typed/TypedRowInvocationHandler.java
new file mode 100644 (file)
index 0000000..27f1d4f
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * Copyright © 2014, 2017 Red Hat, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.ovsdb.lib.schema.typed;
+
+import static java.util.Objects.requireNonNull;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.Locale;
+import java.util.Objects;
+import org.opendaylight.ovsdb.lib.error.ColumnSchemaNotFoundException;
+import org.opendaylight.ovsdb.lib.error.TableSchemaNotFoundException;
+import org.opendaylight.ovsdb.lib.error.TyperException;
+import org.opendaylight.ovsdb.lib.error.UnsupportedMethodException;
+import org.opendaylight.ovsdb.lib.notation.Column;
+import org.opendaylight.ovsdb.lib.notation.Row;
+import org.opendaylight.ovsdb.lib.schema.ColumnSchema;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
+
+final class TypedRowInvocationHandler implements InvocationHandler {
+    private static final String GET_STARTS_WITH = "get";
+    private static final String SET_STARTS_WITH = "set";
+    private static final String GETCOLUMN_ENDS_WITH = "Column";
+    private static final String GETROW_ENDS_WITH = "Row";
+
+    private final Class<?> target;
+    private final DatabaseSchema dbSchema;
+    private final Row<GenericTableSchema> row;
+
+    TypedRowInvocationHandler(final Class<?> target, final DatabaseSchema dbSchema,
+            final Row<GenericTableSchema> row) {
+        this.target = requireNonNull(target);
+        this.dbSchema = requireNonNull(dbSchema);
+        this.row = row;
+    }
+
+    private Object processGetData(final Method method) {
+        String columnName = getColumnName(method);
+        checkColumnSchemaVersion(dbSchema, method);
+        if (columnName == null) {
+            throw new TyperException("Error processing Getter : " + method.getName());
+        }
+        GenericTableSchema tableSchema = TyperUtils.getTableSchema(dbSchema, target);
+        if (tableSchema == null) {
+            String message = TableSchemaNotFoundException.createMessage(TypedReflections.getTableName(target),
+                        dbSchema.getName());
+            throw new TableSchemaNotFoundException(message);
+        }
+        ColumnSchema<GenericTableSchema, Object> columnSchema =
+                TyperUtils.getColumnSchema(tableSchema, columnName, (Class<Object>) method.getReturnType());
+        if (columnSchema == null) {
+            String message = ColumnSchemaNotFoundException.createMessage(columnName, tableSchema.getName());
+            throw new ColumnSchemaNotFoundException(message);
+        }
+        if (row == null || row.getColumn(columnSchema) == null) {
+            return null;
+        }
+        return row.getColumn(columnSchema).getData();
+    }
+
+    private Object processGetRow() {
+        return row;
+    }
+
+    private Object processGetColumn(final Method method) {
+        String columnName = getColumnName(method);
+        checkColumnSchemaVersion(dbSchema, method);
+        if (columnName == null) {
+            throw new TyperException("Error processing GetColumn : " + method.getName());
+        }
+        GenericTableSchema tableSchema = TyperUtils.getTableSchema(dbSchema, target);
+        if (tableSchema == null) {
+            String message = TableSchemaNotFoundException.createMessage(TypedReflections.getTableName(target),
+                dbSchema.getName());
+            throw new TableSchemaNotFoundException(message);
+        }
+        ColumnSchema<GenericTableSchema, Object> columnSchema =
+                TyperUtils.getColumnSchema(tableSchema, columnName, (Class<Object>) method.getReturnType());
+        if (columnSchema == null) {
+            String message = ColumnSchemaNotFoundException.createMessage(columnName, tableSchema.getName());
+            throw new ColumnSchemaNotFoundException(message);
+        }
+        // When the row is null, that might indicate that the user maybe interested
+        // only in the ColumnSchema and not on the Data.
+        if (row == null) {
+            return new Column<>(columnSchema, null);
+        }
+        return row.getColumn(columnSchema);
+    }
+
+    private Object processSetData(final Object proxy, final Method method, final Object[] args) {
+        if (args == null || args.length != 1) {
+            throw new TyperException("Setter method : " + method.getName() + " requires 1 argument");
+        }
+        checkColumnSchemaVersion(dbSchema, method);
+        String columnName = getColumnName(method);
+        if (columnName == null) {
+            throw new TyperException("Unable to locate Column Name for " + method.getName());
+        }
+        GenericTableSchema tableSchema = TyperUtils.getTableSchema(dbSchema, target);
+        ColumnSchema<GenericTableSchema, Object> columnSchema =
+                TyperUtils.getColumnSchema(tableSchema, columnName, (Class<Object>) args[0].getClass());
+        Column<GenericTableSchema, Object> column =
+                new Column<>(columnSchema, args[0]);
+        row.addColumn(columnName, column);
+        return proxy;
+    }
+
+    private GenericTableSchema processGetTableSchema() {
+        return TyperUtils.getTableSchema(dbSchema, target);
+    }
+
+    private static Boolean isHashCodeMethod(final Method method, final Object[] args) {
+        return (args == null || args.length == 0) && method.getName().equals("hashCode");
+    }
+
+    private static Boolean isEqualsMethod(final Method method, final Object[] args) {
+        return args != null
+                && args.length == 1
+                && method.getName().equals("equals")
+                && Object.class.equals(method.getParameterTypes()[0]);
+    }
+
+    private static Boolean isToStringMethod(final Method method, final Object[] args) {
+        return (args == null || args.length == 0) && method.getName().equals("toString");
+    }
+
+    @Override
+    public Object invoke(final Object proxy, final Method method, final Object[] args) throws Exception {
+        if (isGetTableSchema(method)) {
+            return processGetTableSchema();
+        } else if (isGetRow(method)) {
+            return processGetRow();
+        } else if (isSetData(method)) {
+            return processSetData(proxy, method, args);
+        } else if (isGetData(method)) {
+            return processGetData(method);
+        } else if (isGetColumn(method)) {
+            return processGetColumn(method);
+        } else if (isHashCodeMethod(method, args)) {
+            return processHashCode();
+        } else if (isEqualsMethod(method, args)) {
+            return proxy.getClass().isInstance(args[0]) && processEquals(args[0]);
+        } else if (isToStringMethod(method, args)) {
+            return processToString();
+        }
+        throw new UnsupportedMethodException("Method not supported " + method.toString());
+    }
+
+    private boolean processEquals(final Object obj) {
+        return obj instanceof TypedBaseTable && Objects.equals(row, ((TypedBaseTable<?>)obj).getRow());
+    }
+
+    private int processHashCode() {
+        return row == null ? 0 : row.hashCode();
+    }
+
+    private String processToString() {
+        final GenericTableSchema schema = processGetTableSchema();
+        final String tableName = schema != null ? schema.getName() : "";
+        return row == null ? tableName : tableName + " : " + row.toString();
+    }
+
+    private static boolean isGetColumn(final Method method) {
+        TypedColumn typedColumn = method.getAnnotation(TypedColumn.class);
+        if (typedColumn != null) {
+            return typedColumn.method().equals(MethodType.GETCOLUMN);
+        }
+
+        return method.getName().startsWith(GET_STARTS_WITH) && method.getName().endsWith(GETCOLUMN_ENDS_WITH);
+    }
+
+    private static boolean isGetData(final Method method) {
+        TypedColumn typedColumn = method.getAnnotation(TypedColumn.class);
+        if (typedColumn != null) {
+            return typedColumn.method().equals(MethodType.GETDATA);
+        }
+
+        return method.getName().startsWith(GET_STARTS_WITH) && !method.getName().endsWith(GETCOLUMN_ENDS_WITH);
+    }
+
+    private static boolean isGetRow(final Method method) {
+        TypedColumn typedColumn = method.getAnnotation(TypedColumn.class);
+        if (typedColumn != null) {
+            return typedColumn.method().equals(MethodType.GETROW);
+        }
+
+        return method.getName().startsWith(GET_STARTS_WITH) && method.getName().endsWith(GETROW_ENDS_WITH);
+    }
+
+    private static boolean isGetTableSchema(final Method method) {
+        TypedColumn typedColumn = method.getAnnotation(TypedColumn.class);
+        return typedColumn != null && typedColumn.method().equals(MethodType.GETTABLESCHEMA);
+    }
+
+    private static boolean isSetData(final Method method) {
+        TypedColumn typedColumn = method.getAnnotation(TypedColumn.class);
+        if (typedColumn != null) {
+            return typedColumn.method().equals(MethodType.SETDATA);
+        }
+
+        return method.getName().startsWith(SET_STARTS_WITH);
+    }
+
+    private static void checkColumnSchemaVersion(final DatabaseSchema dbSchema, final Method method) {
+        TyperUtils.checkVersion(dbSchema.getVersion(), TypedReflections.getColumnVersionRange(method));
+    }
+
+    private static String getColumnName(final Method method) {
+        TypedColumn typedColumn = method.getAnnotation(TypedColumn.class);
+        if (typedColumn != null) {
+            return typedColumn.name();
+        }
+
+        /*
+         * Attempting to get the column name by parsing the method name with a following convention :
+         * 1. GETDATA : get<ColumnName>
+         * 2. SETDATA : set<ColumnName>
+         * 3. GETCOLUMN : get<ColumnName>Column
+         * where <ColumnName> is the name of the column that we are interested in.
+         */
+        int index = GET_STARTS_WITH.length();
+        if (isGetData(method) || isSetData(method)) {
+            return method.getName().substring(index, method.getName().length()).toLowerCase(Locale.ROOT);
+        } else if (isGetColumn(method)) {
+            return method.getName().substring(index, method.getName().indexOf(GETCOLUMN_ENDS_WITH,
+                    index)).toLowerCase(Locale.ROOT);
+        }
+
+        return null;
+    }
+}
index 284e3c6769007e70dd77618419c83b97a44348eb..0e2029c3a2c51ad75c15f0948318a5a265f4e46b 100644 (file)
@@ -5,28 +5,16 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
-
 package org.opendaylight.ovsdb.lib.schema.typed;
 
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Objects;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Range;
 import com.google.common.reflect.Reflection;
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
 import java.util.HashMap;
-import java.util.Locale;
 import java.util.Map;
-import org.opendaylight.ovsdb.lib.error.ColumnSchemaNotFoundException;
 import org.opendaylight.ovsdb.lib.error.SchemaVersionMismatchException;
-import org.opendaylight.ovsdb.lib.error.TableSchemaNotFoundException;
-import org.opendaylight.ovsdb.lib.error.TyperException;
-import org.opendaylight.ovsdb.lib.error.UnsupportedMethodException;
 import org.opendaylight.ovsdb.lib.message.TableUpdate;
 import org.opendaylight.ovsdb.lib.message.TableUpdates;
-import org.opendaylight.ovsdb.lib.notation.Column;
 import org.opendaylight.ovsdb.lib.notation.Row;
 import org.opendaylight.ovsdb.lib.notation.UUID;
 import org.opendaylight.ovsdb.lib.notation.Version;
@@ -38,12 +26,6 @@ import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
  * Utility methods for typed OVSDB schema data.
  */
 public final class TyperUtils {
-
-    private static final String GET_STARTS_WITH = "get";
-    private static final String SET_STARTS_WITH = "set";
-    private static final String GETCOLUMN_ENDS_WITH = "Column";
-    private static final String GETROW_ENDS_WITH = "Row";
-
     private TyperUtils() {
         // Prevent instantiating a utility class
     }
@@ -65,77 +47,6 @@ public final class TyperUtils {
         return tableSchema.column(columnName, metaClass);
     }
 
-    @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
-            justification = "https://github.com/spotbugs/spotbugs/issues/811")
-    private static String getColumnName(final Method method) {
-        TypedColumn typedColumn = method.getAnnotation(TypedColumn.class);
-        if (typedColumn != null) {
-            return typedColumn.name();
-        }
-
-        /*
-         * Attempting to get the column name by parsing the method name with a following convention :
-         * 1. GETDATA : get<ColumnName>
-         * 2. SETDATA : set<ColumnName>
-         * 3. GETCOLUMN : get<ColumnName>Column
-         * where <ColumnName> is the name of the column that we are interested in.
-         */
-        int index = GET_STARTS_WITH.length();
-        if (isGetData(method) || isSetData(method)) {
-            return method.getName().substring(index, method.getName().length()).toLowerCase(Locale.ROOT);
-        } else if (isGetColumn(method)) {
-            return method.getName().substring(index, method.getName().indexOf(GETCOLUMN_ENDS_WITH,
-                    index)).toLowerCase(Locale.ROOT);
-        }
-
-        return null;
-    }
-
-    @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
-            justification = "https://github.com/spotbugs/spotbugs/issues/811")
-    private static boolean isGetTableSchema(final Method method) {
-        TypedColumn typedColumn = method.getAnnotation(TypedColumn.class);
-        return typedColumn != null && typedColumn.method().equals(MethodType.GETTABLESCHEMA);
-    }
-
-    @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
-            justification = "https://github.com/spotbugs/spotbugs/issues/811")
-    private static boolean isGetRow(final Method method) {
-        TypedColumn typedColumn = method.getAnnotation(TypedColumn.class);
-        if (typedColumn != null) {
-            return typedColumn.method().equals(MethodType.GETROW);
-        }
-
-        return method.getName().startsWith(GET_STARTS_WITH) && method.getName().endsWith(GETROW_ENDS_WITH);
-    }
-
-    private static boolean isGetColumn(final Method method) {
-        TypedColumn typedColumn = method.getAnnotation(TypedColumn.class);
-        if (typedColumn != null) {
-            return typedColumn.method().equals(MethodType.GETCOLUMN);
-        }
-
-        return method.getName().startsWith(GET_STARTS_WITH) && method.getName().endsWith(GETCOLUMN_ENDS_WITH);
-    }
-
-    private static boolean isGetData(final Method method) {
-        TypedColumn typedColumn = method.getAnnotation(TypedColumn.class);
-        if (typedColumn != null) {
-            return typedColumn.method().equals(MethodType.GETDATA);
-        }
-
-        return method.getName().startsWith(GET_STARTS_WITH) && !method.getName().endsWith(GETCOLUMN_ENDS_WITH);
-    }
-
-    private static boolean isSetData(final Method method) {
-        TypedColumn typedColumn = method.getAnnotation(TypedColumn.class);
-        if (typedColumn != null) {
-            return typedColumn.method().equals(MethodType.SETDATA);
-        }
-
-        return method.getName().startsWith(SET_STARTS_WITH);
-    }
-
     /**
      * Method that checks validity of the parameter passed to getTypedRowWrapper.
      * This method checks for a valid Database Schema matching the expected Database for a given table
@@ -146,31 +57,15 @@ public final class TyperUtils {
      * @return true if valid, false otherwise
      */
     private static <T> boolean isValid(final DatabaseSchema dbSchema, final Class<T> klazz) {
-        if (dbSchema == null) {
-            return false;
-        }
-
         final String dbName = TypedReflections.getTableDatabase(klazz);
         if (dbName != null && !dbSchema.getName().equalsIgnoreCase(dbName)) {
             return false;
         }
 
-        checkTableSchemaVersion(dbSchema, klazz);
-
-        return true;
-    }
-
-    @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
-            justification = "https://github.com/spotbugs/spotbugs/issues/811")
-    private static void checkColumnSchemaVersion(final DatabaseSchema dbSchema, final Method method) {
-        checkVersion(dbSchema.getVersion(), TypedReflections.getColumnVersionRange(method));
-    }
-
-    private static <T> void checkTableSchemaVersion(final DatabaseSchema dbSchema, final Class<T> klazz) {
         checkVersion(dbSchema.getVersion(), TypedReflections.getTableVersionRange(klazz));
+        return true;
     }
 
-    @VisibleForTesting
     static void checkVersion(final Version schemaVersion, final Range<Version> range) {
         if (!range.contains(schemaVersion)) {
             throw new SchemaVersionMismatchException(schemaVersion,
@@ -221,140 +116,13 @@ public final class TyperUtils {
      */
     public static <T> T getTypedRowWrapper(final DatabaseSchema dbSchema, final Class<T> klazz,
                                            final Row<GenericTableSchema> row) {
-        if (!isValid(dbSchema, klazz)) {
+        if (dbSchema == null || !isValid(dbSchema, klazz)) {
             return null;
         }
         if (row != null) {
             row.setTableSchema(getTableSchema(dbSchema, klazz));
         }
-        return Reflection.newProxy(klazz, new InvocationHandler() {
-            private Object processGetData(final Method method) {
-                String columnName = getColumnName(method);
-                checkColumnSchemaVersion(dbSchema, method);
-                if (columnName == null) {
-                    throw new TyperException("Error processing Getter : " + method.getName());
-                }
-                GenericTableSchema tableSchema = getTableSchema(dbSchema, klazz);
-                if (tableSchema == null) {
-                    String message = TableSchemaNotFoundException.createMessage(TypedReflections.getTableName(klazz),
-                                dbSchema.getName());
-                    throw new TableSchemaNotFoundException(message);
-                }
-                ColumnSchema<GenericTableSchema, Object> columnSchema =
-                        getColumnSchema(tableSchema, columnName, (Class<Object>) method.getReturnType());
-                if (columnSchema == null) {
-                    String message = ColumnSchemaNotFoundException.createMessage(columnName, tableSchema.getName());
-                    throw new ColumnSchemaNotFoundException(message);
-                }
-                if (row == null || row.getColumn(columnSchema) == null) {
-                    return null;
-                }
-                return row.getColumn(columnSchema).getData();
-            }
-
-            private Object processGetRow() {
-                return row;
-            }
-
-            private Object processGetColumn(final Method method) {
-                String columnName = getColumnName(method);
-                checkColumnSchemaVersion(dbSchema, method);
-                if (columnName == null) {
-                    throw new TyperException("Error processing GetColumn : " + method.getName());
-                }
-                GenericTableSchema tableSchema = getTableSchema(dbSchema, klazz);
-                if (tableSchema == null) {
-                    String message = TableSchemaNotFoundException.createMessage(TypedReflections.getTableName(klazz),
-                        dbSchema.getName());
-                    throw new TableSchemaNotFoundException(message);
-                }
-                ColumnSchema<GenericTableSchema, Object> columnSchema =
-                        getColumnSchema(tableSchema, columnName, (Class<Object>) method.getReturnType());
-                if (columnSchema == null) {
-                    String message = ColumnSchemaNotFoundException.createMessage(columnName, tableSchema.getName());
-                    throw new ColumnSchemaNotFoundException(message);
-                }
-                // When the row is null, that might indicate that the user maybe interested
-                // only in the ColumnSchema and not on the Data.
-                if (row == null) {
-                    return new Column<>(columnSchema, null);
-                }
-                return row.getColumn(columnSchema);
-            }
-
-            private Object processSetData(final Object proxy, final Method method, final Object[] args) {
-                if (args == null || args.length != 1) {
-                    throw new TyperException("Setter method : " + method.getName() + " requires 1 argument");
-                }
-                checkColumnSchemaVersion(dbSchema, method);
-                String columnName = getColumnName(method);
-                if (columnName == null) {
-                    throw new TyperException("Unable to locate Column Name for " + method.getName());
-                }
-                GenericTableSchema tableSchema = getTableSchema(dbSchema, klazz);
-                ColumnSchema<GenericTableSchema, Object> columnSchema =
-                        getColumnSchema(tableSchema, columnName, (Class<Object>) args[0].getClass());
-                Column<GenericTableSchema, Object> column =
-                        new Column<>(columnSchema, args[0]);
-                row.addColumn(columnName, column);
-                return proxy;
-            }
-
-            private GenericTableSchema processGetTableSchema() {
-                return dbSchema == null ? null : getTableSchema(dbSchema, klazz);
-            }
-
-            private Boolean isHashCodeMethod(final Method method, final Object[] args) {
-                return (args == null || args.length == 0) && method.getName().equals("hashCode");
-            }
-
-            private Boolean isEqualsMethod(final Method method, final Object[] args) {
-                return args != null
-                        && args.length == 1
-                        && method.getName().equals("equals")
-                        && Object.class.equals(method.getParameterTypes()[0]);
-            }
-
-            private Boolean isToStringMethod(final Method method, final Object[] args) {
-                return (args == null || args.length == 0) && method.getName().equals("toString");
-            }
-
-            @Override
-            public Object invoke(final Object proxy, final Method method, final Object[] args) throws Exception {
-                if (isGetTableSchema(method)) {
-                    return processGetTableSchema();
-                } else if (isGetRow(method)) {
-                    return processGetRow();
-                } else if (isSetData(method)) {
-                    return processSetData(proxy, method, args);
-                } else if (isGetData(method)) {
-                    return processGetData(method);
-                } else if (isGetColumn(method)) {
-                    return processGetColumn(method);
-                } else if (isHashCodeMethod(method, args)) {
-                    return processHashCode();
-                } else if (isEqualsMethod(method, args)) {
-                    return proxy.getClass().isInstance(args[0]) && processEquals(args[0]);
-                } else if (isToStringMethod(method, args)) {
-                    return processToString();
-                }
-                throw new UnsupportedMethodException("Method not supported " + method.toString());
-            }
-
-            private boolean processEquals(final Object obj) {
-                return obj instanceof TypedBaseTable && Objects.equal(row, ((TypedBaseTable<?>)obj).getRow());
-            }
-
-            private int processHashCode() {
-                return row == null ? 0 : row.hashCode();
-            }
-
-            private String processToString() {
-                final GenericTableSchema schema = processGetTableSchema();
-                final String tableName = schema != null ? schema.getName() : "";
-                return row == null ? tableName : tableName + " : " + row.toString();
-            }
-        });
+        return Reflection.newProxy(klazz, new TypedRowInvocationHandler(klazz, dbSchema, row));
     }
 
     /**