Modified the Library to be more friendlier towards the uuid value obtained through... 33/7933/3
authorMadhu Venugopal <mavenugo@gmail.com>
Thu, 12 Jun 2014 07:59:42 +0000 (00:59 -0700)
committerMadhu Venugopal <mavenugo@gmail.com>
Thu, 12 Jun 2014 17:02:41 +0000 (10:02 -0700)
This change involves the following :

- Populated columnschema for internally generated columns(_uuid and version) by default to the TableSchema (Refer RFC 7047 section 3.2)
- Added "uuid" field in TableUpdate, without which the applications were unable to get the Row identifier
- Moved the generic Object in OperationResult to Row<GenericTableSchema>. But this change alone is not enough to make Select operation
  work as expected. We need a more richer way to populate the "columns" in Row class during the Select response (Bug 1190)
- Modified OvsDBClientTestIT.java to use the uuid column obtained from open_vSwitch monitor in order to insert and delete Bridges during
  add and delete operation (Note that the current IT code updates the open_vSwitch row without this where clause).

Change-Id: Ie0a58c6e45be72993a52a93d8c4374eda72fe687
Signed-off-by: Madhu Venugopal <mavenugo@gmail.com>
library/src/main/java/org/opendaylight/ovsdb/lib/OvsDBClientImpl.java
library/src/main/java/org/opendaylight/ovsdb/lib/jsonrpc/JsonRpcEndpoint.java
library/src/main/java/org/opendaylight/ovsdb/lib/message/TableUpdate.java
library/src/main/java/org/opendaylight/ovsdb/lib/message/TableUpdates.java
library/src/main/java/org/opendaylight/ovsdb/lib/notation/Row.java
library/src/main/java/org/opendaylight/ovsdb/lib/operations/OperationResult.java
library/src/main/java/org/opendaylight/ovsdb/lib/schema/DatabaseSchema.java
library/src/main/java/org/opendaylight/ovsdb/lib/schema/TableSchema.java
library/src/test/java/org/opendaylight/ovsdb/lib/OvsDBClientTestIT.java

index fe39faef463adc9874ac485e7a8401489305236a..e8cd5151ff3ca4aadc7da23246280ad5985c106c 100644 (file)
@@ -9,16 +9,14 @@
  */
 package org.opendaylight.ovsdb.lib;
 
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.SettableFuture;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.UUID;
+import java.util.concurrent.ExecutorService;
+
 import org.opendaylight.ovsdb.lib.jsonrpc.Params;
 import org.opendaylight.ovsdb.lib.message.MonitorRequest;
 import org.opendaylight.ovsdb.lib.message.OvsdbRPC;
@@ -34,13 +32,16 @@ import org.opendaylight.ovsdb.lib.schema.TableSchema;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Queue;
-import java.util.UUID;
-import java.util.concurrent.ExecutorService;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
 
 
 public class OvsDBClientImpl implements OvsDBClient {
@@ -230,6 +231,7 @@ public class OvsDBClientImpl implements OvsDBClient {
                         public DatabaseSchema apply(Map<String, DatabaseSchema> result) {
                             if (result.containsKey(database)) {
                                 DatabaseSchema s = result.get(database);
+                                s.populateInternallyGeneratedColumns();
                                 if (cacheResult) {
                                     OvsDBClientImpl.this.schema.put(database, s);
                                 }
index f3ede2f89a231d62452b4b932323095b59ca440f..ce254f5afd41f8cb855744f0d9c9350e163f2222 100644 (file)
@@ -9,7 +9,6 @@
  */
 package org.opendaylight.ovsdb.lib.jsonrpc;
 
-import com.google.common.reflect.Invokable;
 import io.netty.channel.Channel;
 
 import java.lang.reflect.InvocationHandler;
@@ -29,6 +28,7 @@ import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.type.TypeFactory;
 import com.google.common.collect.Maps;
+import com.google.common.reflect.Invokable;
 import com.google.common.reflect.Reflection;
 import com.google.common.reflect.TypeToken;
 import com.google.common.util.concurrent.ListenableFuture;
@@ -130,8 +130,6 @@ public class JsonRpcEndpoint {
             JavaType javaType =  TypeFactory.defaultInstance().constructType (retType.getType());
 
             JsonNode result = response.get("result");
-            logger.trace("Result : {}", result.toString());
-
             Object result1 = objectMapper.convertValue(result, javaType);
             JsonNode error = response.get("error");
             if (error != null && !error.isNull()) {
index 2e2f07d0e9ea6e3edd6f787e26d05ec0ebbdaab0..e27282baa178c3b7783731a19fc2b34795dcdf9d 100644 (file)
 package org.opendaylight.ovsdb.lib.message;
 
 import org.opendaylight.ovsdb.lib.notation.Row;
+import org.opendaylight.ovsdb.lib.notation.UUID;
 import org.opendaylight.ovsdb.lib.schema.TableSchema;
 
 public class TableUpdate<E extends TableSchema<E>> {
 
+    private UUID uuid;
     private Row<E> old;
     private Row<E> new_;
 
+    public TableUpdate(UUID uuid) {
+        super();
+        this.uuid = uuid;
+    }
+
+    public UUID getUuid() {
+        return this.uuid;
+    }
+
     public Row<E> getOld() {
         return old;
     }
index b3d323e2eb88f13f1dcd296e2e2299a320bd1c7b..4b17b1949646511069d727f345dcdb61592d1fef 100644 (file)
  */
 package org.opendaylight.ovsdb.lib.message;
 
-import com.google.common.collect.Maps;
+import java.util.Map;
+
 import org.opendaylight.ovsdb.lib.schema.TableSchema;
 
-import java.util.Map;
+import com.google.common.collect.Maps;
 
 
 public class TableUpdates extends Response {
@@ -32,4 +33,12 @@ public class TableUpdates extends Response {
     public <E extends TableSchema<E>> TableUpdate<E> getUpdate(TableSchema<E> table) {
         return this.map.get(table.getName());
     }
+
+    @Override
+    public String toString() {
+        return "TableUpdates [map=" + map + ", error=" + error + ", details="
+                + details + ", getError()=" + getError() + ", getDetails()="
+                + getDetails() + ", getClass()=" + getClass() + ", hashCode()="
+                + hashCode() + ", toString()=" + super.toString() + "]";
+    }
 }
index fdb8a6683bcfd4a947b4f94b2fd76aad1155d837..c97191d8ee7fdc17d5b14293fcc9ad38cce8721d 100644 (file)
 
 package org.opendaylight.ovsdb.lib.notation;
 
+import java.util.List;
+
 import org.opendaylight.ovsdb.lib.schema.ColumnSchema;
 import org.opendaylight.ovsdb.lib.schema.TableSchema;
 
-import java.util.List;
-
 public class Row<E extends TableSchema<E>> {
     List<Column<E, ?>> columns;
 
+    private Row() { }
 
     public Row(List<Column<E, ?>> columns) {
         this.columns = columns;
index 1c1b98eee7b21a6aa197e38f3cb51dba019dae87..1840e5a662ccfbb705e832f403771bac2a1c0823 100644 (file)
@@ -12,7 +12,9 @@ package org.opendaylight.ovsdb.lib.operations;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.opendaylight.ovsdb.lib.notation.Row;
 import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
@@ -30,7 +32,7 @@ public class OperationResult {
     private int count;
     @JsonIgnore
     private UUID uuid;
-    private ArrayList<Object> rows;
+    private ArrayList<Row<GenericTableSchema>> rows;
     private String error;
     private String details;
 
@@ -47,10 +49,10 @@ public class OperationResult {
     public void setUuid(List<String> uuidList) {
         this.uuid = new UUID(uuidList.get(1));
     }
-    public ArrayList<Object> getRows() {
+    public ArrayList<Row<GenericTableSchema>> getRows() {
         return rows;
     }
-    public void setRows(ArrayList<Object> rows) {
+    public void setRows(ArrayList<Row<GenericTableSchema>> rows) {
         this.rows = rows;
     }
     public String getError() {
index ef0964128d88064c75462555d3ae727be7faf2bf..417dd9ac9e193e6d2c1dcb33268a6aaf7e2b74a4 100644 (file)
@@ -9,19 +9,20 @@
  */
 package org.opendaylight.ovsdb.lib.schema;
 
-import com.fasterxml.jackson.databind.JsonNode;
-import com.google.common.reflect.Invokable;
-import org.opendaylight.ovsdb.lib.ParsingException;
-import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import java.lang.reflect.Constructor;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
 
+import org.opendaylight.ovsdb.lib.ParsingException;
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.reflect.Invokable;
+
 /**
  * Represents an ovsdb database schema, which is comprised of a set of tables.
  */
@@ -107,4 +108,10 @@ public class DatabaseSchema {
     public void setName(String name) {
         this.name = name;
     }
+
+    public void populateInternallyGeneratedColumns() {
+        for (TableSchema tableSchema : tables.values()) {
+            tableSchema.populateInternallyGeneratedColumns();
+        }
+    }
 }
index b20bb6f82f86061ffb741a2d4c6978b2686b3406..26105412a0cdaf81bc8d317f4e2b48305d07bb03 100644 (file)
@@ -9,21 +9,25 @@
  */
 package org.opendaylight.ovsdb.lib.schema;
 
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.google.common.collect.Lists;
+import java.lang.reflect.Constructor;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
 import org.opendaylight.ovsdb.lib.message.TableUpdate;
 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.operations.Insert;
+import org.opendaylight.ovsdb.lib.schema.BaseType.UuidBaseType;
+import org.opendaylight.ovsdb.lib.schema.ColumnType.AtomicColumnType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.lang.reflect.Constructor;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.Lists;
 
 
 public abstract class TableSchema<E extends TableSchema<E>> {
@@ -111,6 +115,7 @@ public abstract class TableSchema<E extends TableSchema<E>> {
     public TableUpdate<E> updatesFromJson(JsonNode value) {
 
         Map.Entry<String, JsonNode> idOldNew = value.fields().next();
+        String uuid = idOldNew.getKey();
 
         ObjectNode new_ = (ObjectNode) idOldNew.getValue().get("new");
         ObjectNode old = (ObjectNode) idOldNew.getValue().get("old");
@@ -118,11 +123,10 @@ public abstract class TableSchema<E extends TableSchema<E>> {
         Row<E> newRow = new_ != null ? createRow(new_) : null;
         Row<E> oldRow = old != null ? createRow(old) : null;
 
-        TableUpdate<E> tableUpdate = new TableUpdate<>();
+        TableUpdate<E> tableUpdate = new TableUpdate<>(new UUID(uuid));
         tableUpdate.setNew(newRow);
         tableUpdate.setOld(oldRow);
 
-
         return tableUpdate;
     }
 
@@ -136,4 +140,19 @@ public abstract class TableSchema<E extends TableSchema<E>> {
         }
         return new Row<>(columns);
     }
+
+    /*
+     * RFC 7047 Section 3.2 specifies 2 internally generated columns in each table
+     * namely _uuid and version which are not exposed in get_schema call.
+     * Since these 2 columns are extremely useful for Mutate, update and select operations,
+     * the ColumnSchema for these 2 columns are manually populated.
+     *
+     * It is to be noted that these 2 columns are specified as part of the RFC7047 and not
+     * a specific Schema implementation detail & hence adding it by default in the Library
+     * for better application experience using the library.
+     */
+    public void populateInternallyGeneratedColumns() {
+        columns.put("_uuid", new ColumnSchema("_uuid", new AtomicColumnType(new UuidBaseType())));
+        columns.put("version", new ColumnSchema("version", new AtomicColumnType(new UuidBaseType())));
+    }
 }
index e26977928011b32a05c8d86e252a5a92bd918fd9..73a89935869c945431ba8dc85c29b3875683fcfe 100644 (file)
@@ -27,6 +27,7 @@ import org.opendaylight.ovsdb.lib.message.MonitorRequest;
 import org.opendaylight.ovsdb.lib.message.MonitorRequestBuilder;
 import org.opendaylight.ovsdb.lib.message.MonitorSelect;
 import org.opendaylight.ovsdb.lib.message.OvsdbRPC;
+import org.opendaylight.ovsdb.lib.message.TableUpdate;
 import org.opendaylight.ovsdb.lib.message.TableUpdates;
 import org.opendaylight.ovsdb.lib.message.UpdateNotification;
 import org.opendaylight.ovsdb.lib.notation.Column;
@@ -99,8 +100,9 @@ public class OvsDBClientTestIT extends OvsdbTestBase {
             }
         });
 
-        for (int i = 0; i < 5 ; i++) { //wait 5 seconds to get a result
-            System.out.println("waiting");
+        for (int i = 0; i < 3 ; i++) { //wait 3 seconds to get a result
+            System.out.println("waiting on monitor response for Bridge Table...");
+            if (!results.isEmpty()) break;
             Thread.sleep(1000);
         }
 
@@ -108,7 +110,7 @@ public class OvsDBClientTestIT extends OvsdbTestBase {
         Object result = results.get(0);
         Assert.assertTrue(result instanceof TableUpdates);
         TableUpdates updates = (TableUpdates) result;
-        org.opendaylight.ovsdb.lib.message.TableUpdate<GenericTableSchema> update = updates.getUpdate(bridge);
+        TableUpdate<GenericTableSchema> update = updates.getUpdate(bridge);
         Row<GenericTableSchema> aNew = update.getNew();
         for (Column<GenericTableSchema, ?> column: aNew.getColumns()) {
             if (column.getSchema().equals(flood_vlans)) {
@@ -118,6 +120,78 @@ public class OvsDBClientTestIT extends OvsdbTestBase {
         }
     }
 
+    /*
+     * Ideally we should be using selectOpenVSwitchTableUuid() instead of this method.
+     * But Row.java needs some Jackson Jitsu to obtain the appropriate Row Json mapped to Java object
+     * for Select operation.
+     * Hence using the Monitor approach to obtain the uuid of the open_vSwitch table entry.
+     * Replace this method with selectOpenVSwitchTableUuid() once it is functional,
+     */
+    private UUID getOpenVSwitchTableUuid() throws ExecutionException, InterruptedException {
+        Assert.assertNotNull(dbSchema);
+        GenericTableSchema ovsTable = dbSchema.table("Open_vSwitch", GenericTableSchema.class);
+        List<MonitorRequest<GenericTableSchema>> monitorRequests = Lists.newArrayList();
+        ColumnSchema<GenericTableSchema, UUID> _uuid = ovsTable.column("_uuid", UUID.class);
+
+        monitorRequests.add(
+                MonitorRequestBuilder.builder(ovsTable)
+                        .addColumn(_uuid)
+                        .with(new MonitorSelect(true, true, true, true))
+                        .build());
+
+        final List<Object> results = Lists.newArrayList();
+
+        MonitorHandle monitor = ovs.monitor(dbSchema, monitorRequests, new MonitorCallBack() {
+            @Override
+            public void update(TableUpdates result) {
+                results.add(result);
+            }
+
+            @Override
+            public void exception(Throwable t) {
+                results.add(t);
+                System.out.println("t = " + t);
+            }
+        });
+
+        for (int i = 0; i < 3 ; i++) { //wait 5 seconds to get a result
+            System.out.println("waiting on monitor response for open_vSwtich Table...");
+            if (!results.isEmpty()) break;
+            Thread.sleep(1000);
+        }
+
+        Assert.assertTrue(!results.isEmpty());
+        Object result = results.get(0); // open_vSwitch table has just 1 row.
+        Assert.assertTrue(result instanceof TableUpdates);
+        TableUpdates updates = (TableUpdates) result;
+        TableUpdate<GenericTableSchema> update = updates.getUpdate(ovsTable);
+        return update.getUuid();
+    }
+
+    /*
+     * TODO : selectOpenVSwitchTableUuid method isn't working as expected due to the Jackson
+     * parsing challenges on the Row object returned by the Select operation.
+     */
+    private UUID selectOpenVSwitchTableUuid() throws ExecutionException, InterruptedException {
+        Assert.assertNotNull(dbSchema);
+        GenericTableSchema ovsTable = dbSchema.table("Open_vSwitch", GenericTableSchema.class);
+
+        List<MonitorRequest<GenericTableSchema>> monitorRequests = Lists.newArrayList();
+        ColumnSchema<GenericTableSchema, UUID> _uuid = ovsTable.column("_uuid", UUID.class);
+
+        List<OperationResult> results = ovs.transactBuilder()
+               .add(op.select(ovsTable)
+                      .column(_uuid))
+                      .execute()
+                      .get();
+
+        Assert.assertTrue(!results.isEmpty());
+        OperationResult result = results.get(0);
+        List<Row<GenericTableSchema>> rows = result.getRows();
+        Row<GenericTableSchema> ovsTableRow = rows.get(0);
+        return (UUID)ovsTableRow.getColumn(_uuid).getData();
+    }
+
     private void createBridgeTransaction() throws IOException, InterruptedException, ExecutionException {
         Assert.assertNotNull(dbSchema);
         TableSchema<GenericTableSchema> bridge = dbSchema.table("Bridge", GenericTableSchema.class);
@@ -127,10 +201,12 @@ public class OvsDBClientTestIT extends OvsdbTestBase {
         ColumnSchema<GenericTableSchema, String> fail_mode = bridge.column("fail_mode", String.class);
         ColumnSchema<GenericTableSchema, Set<Integer>> flood_vlans = bridge.multiValuedColumn("flood_vlans", Integer.class);
         ColumnSchema<GenericTableSchema, Set<UUID>> bridges = ovsTable.multiValuedColumn("bridges", UUID.class);
+        ColumnSchema<GenericTableSchema, UUID> _uuid = ovsTable.column("_uuid", UUID.class);
 
         String namedUuid = "br_test";
         int nOperations = 7;
         int insertOperationIndex = 0;
+        UUID parentTable = getOpenVSwitchTableUuid();
         ListenableFuture<List<OperationResult>> results = ovs.transactBuilder()
                  /*
                   * Make sure that the position of insert operation matches the insertOperationIndex.
@@ -147,6 +223,7 @@ public class OvsDBClientTestIT extends OvsdbTestBase {
                         .build())
                 .add(op.select(bridge)
                         .column(name)
+                        .column(_uuid)
                         .where(name.opEqual(testBridgeName))
                         .build())
                 .add(op.mutate(bridge)
@@ -154,7 +231,9 @@ public class OvsDBClientTestIT extends OvsdbTestBase {
                         .where(name.opEqual(testBridgeName))
                         .build())
                 .add(op.mutate(ovsTable)
-                        .addMutation(bridges, Mutator.INSERT, Sets.newHashSet(new UUID(namedUuid))))
+                        .addMutation(bridges, Mutator.INSERT, Sets.newHashSet(new UUID(namedUuid)))
+                        .where(_uuid.opEqual(parentTable))
+                        .build())
                 .add(op.commit(true))
                 .execute();
 
@@ -247,13 +326,17 @@ public class OvsDBClientTestIT extends OvsdbTestBase {
         ColumnSchema<GenericTableSchema, String> name = bridge.column("name", String.class);
         GenericTableSchema ovsTable = dbSchema.table("Open_vSwitch", GenericTableSchema.class);
         ColumnSchema<GenericTableSchema, Set<UUID>> bridges = ovsTable.multiValuedColumn("bridges", UUID.class);
+        ColumnSchema<GenericTableSchema, UUID> _uuid = ovsTable.column("_uuid", UUID.class);
+        UUID parentTable = getOpenVSwitchTableUuid();
 
         ListenableFuture<List<OperationResult>> results = ovs.transactBuilder()
                 .add(op.delete(bridge)
                         .where(name.opEqual(testBridgeName))
                         .build())
                 .add(op.mutate(ovsTable)
-                        .addMutation(bridges, Mutator.DELETE, Sets.newHashSet(testBridgeUuid)))
+                        .addMutation(bridges, Mutator.DELETE, Sets.newHashSet(testBridgeUuid))
+                        .where(_uuid.opEqual(parentTable))
+                        .build())
                 .add(op.commit(true))
                 .execute();