Simplifying the User facing APIs in TyperUtils. 60/8160/7
authorMadhu Venugopal <mavenugo@gmail.com>
Fri, 20 Jun 2014 08:41:33 +0000 (01:41 -0700)
committerMadhu Venugopal <mavenugo@gmail.com>
Fri, 20 Jun 2014 17:10:14 +0000 (10:10 -0700)
Based on Ashwin's comment to the library infra gerrit (8104), more simplified User Facing APIs are introduced :
1. Bridge rBridge = ovs.createTypedRowWrapper(TestBridge.class);
   replaces
   TestBridge rBridge = TyperUtils.getTypedRowWrapper(dbSchema, TestBridge.class, new Row<GenericTableSchema>());

2. rBridge.getSchema()
   replaces
   GenericTableSchema rBridgeSchema = TyperUtils.getTableSchema(dbSchema, TestBridge.class);

More such Simplified alternative APIs will be added based on usage.

Change-Id: Ibdee07b308145bf792c9309d7095a94aac2d23b3
Signed-off-by: Madhu Venugopal <mavenugo@gmail.com>
library/src/main/java/org/opendaylight/ovsdb/lib/OvsDBClient.java
library/src/main/java/org/opendaylight/ovsdb/lib/OvsDBClientImpl.java
library/src/main/java/org/opendaylight/ovsdb/lib/schema/typed/MethodType.java
library/src/main/java/org/opendaylight/ovsdb/lib/schema/typed/TypedBaseTable.java
library/src/main/java/org/opendaylight/ovsdb/lib/schema/typed/TyperUtils.java
library/src/test/java/org/opendaylight/ovsdb/lib/OvsDBClientTestITTyped.java
library/src/test/java/org/opendaylight/ovsdb/lib/VersionIncompatibleBridge.java [new file with mode: 0644]
schemas/Open_vSwitch/src/test/java/org/opendaylight/ovsdb/schema/openvswitch/TypedVSwitchdSchemaIT.java

index 1ae226184afcb97911f90829f1633cf203bcd8eb..7ad3a30852d5c2e3b22b1a43e8f7270f75d81bb2 100644 (file)
@@ -15,10 +15,12 @@ package org.opendaylight.ovsdb.lib;
 import java.util.List;
 
 import org.opendaylight.ovsdb.lib.message.MonitorRequest;
+import org.opendaylight.ovsdb.lib.notation.Row;
 import org.opendaylight.ovsdb.lib.operations.Operation;
 import org.opendaylight.ovsdb.lib.operations.OperationResult;
 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
 import org.opendaylight.ovsdb.lib.schema.TableSchema;
 
 import com.google.common.util.concurrent.ListenableFuture;
@@ -109,4 +111,33 @@ public interface OvsDBClient {
      */
     public void stopEchoService();
 
+    public DatabaseSchema getDatabaseSchema (String dbName);
+
+    /**
+     * User friendly convenient methods that make use of TyperUtils.getTypedRowWrapper to create a Typed Row Proxy
+     * given the Typed Table Class
+     *
+     * @param klazz Typed Interface
+     * @return Proxy wrapper for the actual raw Row class.
+     */
+    public <T> T createTypedRowWrapper(Class<T> klazz);
+    /**
+     * User friendly convenient methods that make use of getTypedRowWrapper to create a Typed Row Proxy given
+     * DatabaseSchema and Typed Table Class.
+     *
+     * @param dbSchema Database Schema of interest
+     * @param klazz Typed Interface
+     * @return Proxy wrapper for the actual raw Row class.
+     */
+    public <T> T createTypedRowWrapper(DatabaseSchema dbSchema, Class<T> klazz);
+
+    /**
+     * User friendly convenient method to get a Typed Row Proxy given a Typed Table Class and the Row to be wrapped.
+     *
+     * @param klazz Typed Interface
+     * @param row The actual Row that the wrapper is operating on. It can be null if the caller is just interested in getting ColumnSchema.
+     * @return Proxy wrapper for the actual raw Row class.
+     */
+    public <T> T getTypedRowWrapper(final Class<T> klazz, final Row<GenericTableSchema> row);
+
 }
index e8cd5151ff3ca4aadc7da23246280ad5985c106c..5cdd2bdc6775344b347d0a80adce754ea2dc7b24 100644 (file)
@@ -24,11 +24,15 @@ import org.opendaylight.ovsdb.lib.message.TableUpdate;
 import org.opendaylight.ovsdb.lib.message.TableUpdates;
 import org.opendaylight.ovsdb.lib.message.TransactBuilder;
 import org.opendaylight.ovsdb.lib.message.UpdateNotification;
+import org.opendaylight.ovsdb.lib.notation.Row;
 import org.opendaylight.ovsdb.lib.operations.Operation;
 import org.opendaylight.ovsdb.lib.operations.OperationResult;
 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
 import org.opendaylight.ovsdb.lib.schema.TableSchema;
+import org.opendaylight.ovsdb.lib.schema.typed.TypedTable;
+import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -299,4 +303,64 @@ public class OvsDBClientImpl implements OvsDBClient {
             this.schema = schema;
         }
     }
+
+    @Override
+    public DatabaseSchema getDatabaseSchema (String dbName) {
+        return schema.get(dbName);
+    }
+
+    /**
+     * This method finds the DatabaseSchema that matches a given Typed Table Class.
+     * With the introduction of TypedTable and TypedColumn annotations, it is possible to express
+     * the Database Name, Table Name & the Database Versions within which the Table is defined and maintained.
+     *
+     * @param klazz Typed Class that represents a Table
+     * @return DatabaseSchema that matches a Typed Table Class
+     */
+    private <T> DatabaseSchema getDatabaseSchemaForTypedTable (Class <T> klazz) {
+        TypedTable typedTable = klazz.getAnnotation(TypedTable.class);
+        if (typedTable != null) {
+            return this.getDatabaseSchema(typedTable.database());
+        }
+        return null;
+    }
+
+    /**
+     * User friendly convenient method that make use of TyperUtils.getTypedRowWrapper to create a Typed Row Proxy
+     * given the Typed Table Class
+     *
+     * @param klazz Typed Interface
+     * @return Proxy wrapper for the actual raw Row class.
+     */
+    @Override
+    public <T> T createTypedRowWrapper(Class<T> klazz) {
+        DatabaseSchema dbSchema = getDatabaseSchemaForTypedTable(klazz);
+        return this.createTypedRowWrapper(dbSchema, klazz);
+    }
+
+    /**
+     * User friendly convenient method that make use of getTypedRowWrapper to create a Typed Row Proxy given
+     * DatabaseSchema and Typed Table Class.
+     *
+     * @param dbSchema Database Schema of interest
+     * @param klazz Typed Interface
+     * @return Proxy wrapper for the actual raw Row class.
+     */
+    @Override
+    public <T> T createTypedRowWrapper(DatabaseSchema dbSchema, Class<T> klazz) {
+        return TyperUtils.getTypedRowWrapper(dbSchema, klazz, new Row<GenericTableSchema>());
+    }
+
+    /**
+     * User friendly convenient method to get a Typed Row Proxy given a Typed Table Class and the Row to be wrapped.
+     *
+     * @param klazz Typed Interface
+     * @param row The actual Row that the wrapper is operating on. It can be null if the caller is just interested in getting ColumnSchema.
+     * @return Proxy wrapper for the actual raw Row class.
+     */
+    @Override
+    public <T> T getTypedRowWrapper(final Class<T> klazz, final Row<GenericTableSchema> row) {
+        DatabaseSchema dbSchema = getDatabaseSchemaForTypedTable(klazz);
+        return TyperUtils.getTypedRowWrapper(dbSchema, klazz, row);
+    }
 }
index bcb0ea1794c026a2910d26c2f11fc43a6abca02a..8ba7f6837543e984c1646fcb758469da6430dfcf 100644 (file)
@@ -11,5 +11,5 @@
 package org.opendaylight.ovsdb.lib.schema.typed;
 
 public enum MethodType {
-    GETCOLUMN, GETDATA, SETDATA
+    GETCOLUMN, GETDATA, SETDATA, GETTABLESCHEMA
 }
index fc0fa59a2354c867571855053b501c9996f7018c..19e1dc17be795e69d243a7f27c86377fc9028948 100644 (file)
@@ -9,5 +9,9 @@
  */
 package org.opendaylight.ovsdb.lib.schema.typed;
 
+import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
+
 public interface TypedBaseTable {
+    @TypedColumn(name="", method=MethodType.GETTABLESCHEMA)
+    GenericTableSchema getSchema();
 }
index 6a03ab13c23f3ca4f61e66357f2360f80849e52b..25e2868aedd48a247ae62a758c9b58305151f2e8 100644 (file)
@@ -67,6 +67,14 @@ public class TyperUtils {
         return null;
     }
 
+    private static boolean isGetTableSchema (Method method) {
+        TypedColumn typedColumn = method.getAnnotation(TypedColumn.class);
+        if (typedColumn != null) {
+            return typedColumn.method().equals(MethodType.GETTABLESCHEMA) ? true : false;
+        }
+        return false;
+    }
+
     private static boolean isGetColumn (Method method) {
         TypedColumn typedColumn = method.getAnnotation(TypedColumn.class);
         if (typedColumn != null) {
@@ -137,6 +145,10 @@ public class TyperUtils {
      * @return true if valid, false otherwise
      */
     private static <T> boolean isValid (DatabaseSchema dbSchema, final Class<T> klazz) {
+        if (dbSchema == null) {
+            return false;
+        }
+
         TypedTable typedTable = klazz.getAnnotation(TypedTable.class);
         if (typedTable != null) {
             if (!dbSchema.getName().equalsIgnoreCase(typedTable.database())) {
@@ -245,16 +257,28 @@ public class TyperUtils {
                 return proxy;
             }
 
+            private Object processGetTableSchema() throws Throwable {
+                if (dbSchema == null) return null;
+                return getTableSchema(dbSchema, klazz);
+            }
+
             @Override
             public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
-                if (isSetData(method)) {
+                if (isGetTableSchema(method)) {
+                    return processGetTableSchema();
+                } else if (isSetData(method)) {
                     return processSetData(proxy, method, args);
                 } else if(isGetData(method)) {
                     return processGetData(method);
                 } else if(isGetColumn(method)) {
                     return processGetColumn(method);
                 } else {
-                    throw new RuntimeException("Unsupported method : "+method.getName());
+                    /*
+                     *  TODO : Handle the methods provided by Object class (such as toString, hashCode, equals, etc.).
+                     *  Reintroduce throwing RuntimeException("Unsupported method : "+method.getName()); after these methods
+                     *  are handled
+                     */
+                    return null;
                 }
             }
         }
index 3e3a2326749a2cc8de98137691cfec3320c984ed..04fd3a299156fe29198e1c2669b68c6abe763d91 100644 (file)
@@ -28,7 +28,6 @@ import org.junit.Test;
 import org.opendaylight.ovsdb.lib.message.OvsdbRPC;
 import org.opendaylight.ovsdb.lib.message.UpdateNotification;
 import org.opendaylight.ovsdb.lib.notation.Mutator;
-import org.opendaylight.ovsdb.lib.notation.Row;
 import org.opendaylight.ovsdb.lib.notation.UUID;
 import org.opendaylight.ovsdb.lib.operations.OperationResult;
 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
@@ -36,7 +35,6 @@ import org.opendaylight.ovsdb.lib.schema.ColumnSchema;
 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
 import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
 import org.opendaylight.ovsdb.lib.schema.TableSchema;
-import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -55,8 +53,7 @@ public class OvsDBClientTestITTyped extends OvsdbTestBase {
 
     @Test
     public void testTypedBridgeCreate() throws IOException, InterruptedException, ExecutionException, NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
-        GenericTableSchema rBridgeSchema = TyperUtils.getTableSchema(dbSchema, TestBridge.class);
-        TestBridge rBridge = TyperUtils.getTypedRowWrapper(dbSchema, TestBridge.class, new Row<GenericTableSchema>());
+        TestBridge rBridge = ovs.createTypedRowWrapper(TestBridge.class);
         rBridge.setName(testBridgeName);
         rBridge.setStatus(Maps.newHashMap(ImmutableMap.of("key","value")));
         rBridge.setFloodVlans(Sets.newHashSet(34));
@@ -68,10 +65,10 @@ public class OvsDBClientTestITTyped extends OvsdbTestBase {
         int insertOperationIndex = 0;
 
         TransactionBuilder transactionBuilder = ovs.transactBuilder()
-                .add(op.insert(rBridgeSchema)
+                .add(op.insert(rBridge.getSchema())
                         .withId(namedUuid)
                         .value(rBridge.getNameColumn()))
-                .add(op.update(rBridgeSchema)
+                .add(op.update(rBridge.getSchema())
                         .set(rBridge.getStatusColumn())
                         .set(rBridge.getFloodVlansColumn())
                         .where(rBridge.getNameColumn().getSchema().opEqual(rBridge.getName()))
diff --git a/library/src/test/java/org/opendaylight/ovsdb/lib/VersionIncompatibleBridge.java b/library/src/test/java/org/opendaylight/ovsdb/lib/VersionIncompatibleBridge.java
new file mode 100644 (file)
index 0000000..949c917
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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
+ *
+ * Authors : Madhu Venugopal
+ */
+
+package org.opendaylight.ovsdb.lib;
+import org.opendaylight.ovsdb.lib.schema.typed.TypedBaseTable;
+import org.opendaylight.ovsdb.lib.schema.typed.TypedTable;
+
+/**
+ * VersionIncompatibleBridge is used to test the Version Compatibility logic in the Library
+ * with an absurdly low fromVersion and untilVersion which will fail for all the OVS versions.
+ */
+@TypedTable(name="Bridge", database="Open_vSwitch", fromVersion="0.0.1", untilVersion="0.0.2")
+public interface VersionIncompatibleBridge extends TypedBaseTable {
+}
index eca74105a4babfe027b917cc5f91d0ebacc9c838..c7dac1ea5ae757c17df0fe80744a296702349557 100644 (file)
@@ -27,13 +27,10 @@ import org.opendaylight.ovsdb.lib.OvsDBClientImpl;
 import org.opendaylight.ovsdb.lib.message.OvsdbRPC;
 import org.opendaylight.ovsdb.lib.message.UpdateNotification;
 import org.opendaylight.ovsdb.lib.notation.Mutator;
-import org.opendaylight.ovsdb.lib.notation.Row;
 import org.opendaylight.ovsdb.lib.notation.UUID;
 import org.opendaylight.ovsdb.lib.operations.OperationResult;
 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
-import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
-import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -56,28 +53,26 @@ public class TypedVSwitchdSchemaIT extends OvsdbTestBase {
     }
 
     private void createTypedBridge() throws IOException, InterruptedException, ExecutionException, NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
-        GenericTableSchema bridgeSchema = TyperUtils.getTableSchema(dbSchema, Bridge.class);
-        Bridge bridge = TyperUtils.getTypedRowWrapper(dbSchema, Bridge.class, new Row<GenericTableSchema>());
+        Bridge bridge = ovs.createTypedRowWrapper(Bridge.class);
         bridge.setName(testBridgeName);
         bridge.setStatus(Maps.newHashMap(ImmutableMap.of("key","value")));
         bridge.setFloodVlans(Sets.newHashSet(34));
 
-        GenericTableSchema ovsTable = TyperUtils.getTableSchema(dbSchema, OpenVSwitch.class);
-        OpenVSwitch openVSwitch = TyperUtils.getTypedRowWrapper(dbSchema, OpenVSwitch.class, new Row<GenericTableSchema>());
+        OpenVSwitch openVSwitch = ovs.createTypedRowWrapper(OpenVSwitch.class);
         openVSwitch.setBridges(Sets.newHashSet(new UUID(testBridgeName)));
 
         int insertOperationIndex = 0;
 
         TransactionBuilder transactionBuilder = ovs.transactBuilder()
-                .add(op.insert(bridgeSchema)
+                .add(op.insert(bridge.getSchema())
                         .withId(testBridgeName)
                         .value(bridge.getNameColumn()))
-                .add(op.update(bridgeSchema)
+                .add(op.update(bridge.getSchema())
                         .set(bridge.getStatusColumn())
                         .set(bridge.getFloodVlansColumn())
                         .where(bridge.getNameColumn().getSchema().opEqual(bridge.getName()))
                         .and(bridge.getNameColumn().getSchema().opEqual(bridge.getName())).build())
-                .add(op.mutate(ovsTable)
+                .add(op.mutate(openVSwitch.getSchema())
                         .addMutation(openVSwitch.getBridgesColumn().getSchema(), Mutator.INSERT,
                                      openVSwitch.getBridgesColumn().getData()));
 
@@ -120,17 +115,14 @@ public class TypedVSwitchdSchemaIT extends OvsdbTestBase {
 
     @After
     public void tearDown() throws InterruptedException, ExecutionException {
-        GenericTableSchema bridgeSchema = TyperUtils.getTableSchema(dbSchema, Bridge.class);
-        Bridge bridge = TyperUtils.getTypedRowWrapper(dbSchema, Bridge.class, null);
-
-        GenericTableSchema ovsTable = TyperUtils.getTableSchema(dbSchema, OpenVSwitch.class);
-        OpenVSwitch openVSwitch = TyperUtils.getTypedRowWrapper(dbSchema, OpenVSwitch.class, null);
+        Bridge bridge = ovs.getTypedRowWrapper(Bridge.class, null);
+        OpenVSwitch openVSwitch = ovs.getTypedRowWrapper(OpenVSwitch.class, null);
 
         ListenableFuture<List<OperationResult>> results = ovs.transactBuilder()
-                .add(op.delete(bridgeSchema)
+                .add(op.delete(bridge.getSchema())
                         .where(bridge.getNameColumn().getSchema().opEqual(testBridgeName))
                         .build())
-                .add(op.mutate(ovsTable)
+                .add(op.mutate(openVSwitch.getSchema())
                         .addMutation(openVSwitch.getBridgesColumn().getSchema(), Mutator.DELETE, Sets.newHashSet(testBridgeUuid)))
                 .add(op.commit(true))
                 .execute();