Resolved the Serialization and Deserialization issues for MultiValued Columns with... 70/7970/1
authorMadhu Venugopal <mavenugo@gmail.com>
Fri, 13 Jun 2014 06:11:47 +0000 (23:11 -0700)
committerMadhu Venugopal <mavenugo@gmail.com>
Fri, 13 Jun 2014 06:11:47 +0000 (23:11 -0700)
Fixed various classes where the KeyValue ColumnType is not handled.
Also added IT tests to cover both Serialization and Deserialization aspects of KeyValue ColumntType by using the external_ids column of Bridge table.

Change-Id: I067bba372da8c02b0befbdb5210dda9068ea397f
Signed-off-by: Madhu Venugopal <mavenugo@gmail.com>
library/src/main/java/org/opendaylight/ovsdb/lib/notation/Column.java
library/src/main/java/org/opendaylight/ovsdb/lib/notation/OvsDBMap.java
library/src/main/java/org/opendaylight/ovsdb/lib/operations/Insert.java
library/src/main/java/org/opendaylight/ovsdb/lib/schema/ColumnType.java
library/src/main/java/org/opendaylight/ovsdb/lib/schema/TableSchema.java
library/src/test/java/org/opendaylight/ovsdb/lib/OvsDBClientTestIT.java

index 57a35c6db1430e30e5bd6aa01e04c11cf6b72328..231567a4b2bfe85e3592a752efa1cb48cbf34877 100644 (file)
@@ -31,7 +31,7 @@ public class Column<E extends TableSchema<E>, D> {
         return schema.validate(data);
     }
 
-    public Object getData() {
+    public D getData() {
         return data;
     }
 
index c3e1e84c00ecffe11a33fcaa707a8e6ba57f78ca..c1a43647012a18be85b0a52a2e15b85fbbc8c9ad 100644 (file)
@@ -9,25 +9,36 @@
  */
 package org.opendaylight.ovsdb.lib.notation;
 
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-import com.google.common.collect.ForwardingMap;
-import com.google.common.collect.Maps;
+import java.util.Map;
 
 import org.opendaylight.ovsdb.lib.notation.json.Converter;
 import org.opendaylight.ovsdb.lib.notation.json.OvsDBMapSerializer;
 
-import java.util.HashMap;
-import java.util.Map;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.google.common.collect.ForwardingMap;
+import com.google.common.collect.Maps;
 
 @JsonDeserialize(converter = Converter.MapConverter.class)
 @JsonSerialize(using = OvsDBMapSerializer.class)
 public class OvsDBMap<K, V> extends ForwardingMap<K, V> {
 
-    HashMap<K, V> target = Maps.newHashMap();
+    Map<K, V> target = Maps.newHashMap();
+
+    public OvsDBMap() {
+        this(Maps.<K,V>newHashMap());
+    }
+
+    public OvsDBMap(Map<K, V> value) {
+        this.target = value;
+    }
 
     @Override
     public Map<K, V> delegate() {
         return target;
     }
+
+    public static<K,V> OvsDBMap<K,V> fromMap(Map<K, V> value) {
+        return new OvsDBMap<K,V>(value);
+    }
 }
index cad8702888703a53bdd9dbfc78c07e4c07962bf2..b4dc424bc76f248a7eb4291ffb2b71a72b692d21 100644 (file)
@@ -12,12 +12,12 @@ package org.opendaylight.ovsdb.lib.operations;
 import java.util.Map;
 import java.util.Set;
 
+import org.opendaylight.ovsdb.lib.notation.OvsDBMap;
 import org.opendaylight.ovsdb.lib.notation.OvsDBSet;
 import org.opendaylight.ovsdb.lib.schema.ColumnSchema;
 import org.opendaylight.ovsdb.lib.schema.TableSchema;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.Preconditions;
 import com.google.common.collect.Maps;
 
 
@@ -51,8 +51,11 @@ public class Insert<E extends TableSchema<E>> extends Operation<E> {
     public <D, C extends TableSchema<C>> Insert<E> value(ColumnSchema<C, D> columnSchema, D value) {
         Object untypedValue = null;
         if (columnSchema.getType().isMultiValued()) {
-            Preconditions.checkArgument((value instanceof Set),"expected a set for multivalued item") ;
-            untypedValue = OvsDBSet.fromSet((Set) value);
+            if (value instanceof Set) {
+                untypedValue = OvsDBSet.fromSet((Set) value);
+            } else if (value instanceof Map) {
+                untypedValue = OvsDBMap.fromMap((Map)value);
+            }
         } else {
             untypedValue = value;
         }
index 85c11a78f57a68a16d4136ed2b4fe0afcd5c5764..da967b2d0352f092c21cd73cbddd46994d139278 100644 (file)
@@ -9,11 +9,13 @@
  */
 package org.opendaylight.ovsdb.lib.schema;
 
-import com.fasterxml.jackson.databind.JsonNode;
-import com.google.common.collect.Sets;
+import java.util.Set;
+
 import org.opendaylight.ovsdb.lib.jsonrpc.JsonUtils;
+import org.opendaylight.ovsdb.lib.notation.OvsDBMap;
 
-import java.util.Set;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.collect.Sets;
 
 
 public abstract class ColumnType {
@@ -121,6 +123,7 @@ public abstract class ColumnType {
             super(baseType1);
         }
 
+        @Override
         public AtomicColumnType fromJsonNode(JsonNode json) {
             if (json.isObject() && json.has("value")) {
                 return null;
@@ -153,10 +156,14 @@ public abstract class ColumnType {
         public Object valueFromJson(JsonNode value) {
             if (isMultiValued()) {
                 Set<Object> result = Sets.newHashSet();
-               if(value.isContainerNode()) {
-                  for(JsonNode node: value) {
-                     result.add(getBaseType().toValue(node));
-                  }
+               if(value.isArray()) {
+                     if (value.size() == 2) {
+                         if (value.get(0).isTextual() && "set".equals(value.get(0).asText())) {
+                              for(JsonNode node: value.get(1)) {
+                                 result.add(getBaseType().toValue(node));
+                              }
+                         }
+                     }
                } else {
                    result.add(getBaseType().toValue(value));
                }
@@ -174,16 +181,21 @@ public abstract class ColumnType {
     }
 
     public static class KeyValuedColumnType extends ColumnType {
+        BaseType keyType;
 
-        BaseType valueType;
+        public BaseType getKeyType() {
+            return keyType;
+        }
 
         public KeyValuedColumnType() {
         }
 
-        public KeyValuedColumnType(BaseType baseType, BaseType valueType) {
-            super(baseType);
+        public KeyValuedColumnType(BaseType keyType, BaseType valueType) {
+            super(valueType);
+            this.keyType = keyType;
         }
 
+        @Override
         public KeyValuedColumnType fromJsonNode(JsonNode json) {
             if (json.isValueNode() || !json.has("value")) {
                 return null;
@@ -191,17 +203,48 @@ public abstract class ColumnType {
             BaseType keyType = BaseType.fromJson(json, "key");
             BaseType valueType = BaseType.fromJson(json, "value");
 
-            return new KeyValuedColumnType(keyType, valueType);
+            KeyValuedColumnType keyValueColumnType = new KeyValuedColumnType(keyType, valueType);
+            JsonNode node = null;
+            if ((node = json.get("min")) != null) {
+                keyValueColumnType.setMin(node.asLong());
+            }
+
+            if ((node = json.get("max")) != null) {
+                if (node.isLong()){
+                    keyValueColumnType.setMax(node.asLong());
+                } else if (node.isTextual() && "unlimited".equals(node.asText())) {
+                    max = Long.MAX_VALUE;
+                }
+            }
+
+            return keyValueColumnType;
         }
 
         @Override
-        public Object valueFromJson(JsonNode value) {
-            throw new UnsupportedOperationException("needs to be implemented");
+        public Object valueFromJson(JsonNode node) {
+            if (node.isArray()) {
+                if (node.size() == 2) {
+                    if (node.get(0).isTextual() && "map".equals(node.get(0).asText())) {
+                        OvsDBMap<Object, Object> map = new OvsDBMap<Object, Object>();
+                        for (JsonNode pairNode : node.get(1)) {
+                            if (pairNode.isArray() && node.size() == 2) {
+                                Object key = getKeyType().toValue(pairNode.get(0));
+                                Object value = getBaseType().toValue(pairNode.get(1));
+                                map.put(key, value);
+                            }
+                        }
+                        return map;
+                    } else if (node.size() == 0) {
+                        return null;
+                    }
+                }
+            }
+            return null;
         }
 
         @Override
         public void validate(Object value) {
-            throw new UnsupportedOperationException("not implemented yet");
+            this.baseType.validate(value);
         }
     }
 }
index 26105412a0cdaf81bc8d317f4e2b48305d07bb03..4215be8a87b5f5405dae6004aac41a69c12e07d7 100644 (file)
@@ -87,6 +87,14 @@ public abstract class TableSchema<E extends TableSchema<E>> {
         return columnSchema;
     }
 
+    public <K,V> ColumnSchema<E, Map<K,V>> multiValuedColumn(String column, Class<K> keyType, Class<V> valueType) {
+        //todo exception handling
+
+        ColumnSchema columnSchema = columns.get(column);
+        columnSchema.validateType(valueType);
+        return columnSchema;
+    }
+
     public <D> ColumnSchema<E, D> column(String column, Class<D> type) {
         //todo exception handling
 
index 73a89935869c945431ba8dc85c29b3875683fcfe..799f04e6766abc904de95314f0db4e45d23666f7 100644 (file)
@@ -13,6 +13,7 @@ import static org.opendaylight.ovsdb.lib.operations.Operations.op;
 
 import java.io.IOException;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
@@ -42,7 +43,9 @@ import org.opendaylight.ovsdb.lib.schema.TableSchema;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import com.google.common.util.concurrent.ListenableFuture;
 
@@ -75,12 +78,13 @@ public class OvsDBClientTestIT extends OvsdbTestBase {
 
         List<MonitorRequest<GenericTableSchema>> monitorRequests = Lists.newArrayList();
         ColumnSchema<GenericTableSchema, Set<Integer>> flood_vlans = bridge.multiValuedColumn("flood_vlans", Integer.class);
-
+        ColumnSchema<GenericTableSchema, Map<String, String>> externalIds = bridge.multiValuedColumn("external_ids", String.class, String.class);
         monitorRequests.add(
                 MonitorRequestBuilder.builder(bridge)
                         .addColumn(bridge.column("name"))
                         .addColumn(bridge.column("fail_mode", String.class))
                         .addColumn(flood_vlans)
+                        .addColumn(externalIds)
                         .with(new MonitorSelect(true, true, true, true))
                         .build());
 
@@ -114,8 +118,15 @@ public class OvsDBClientTestIT extends OvsdbTestBase {
         Row<GenericTableSchema> aNew = update.getNew();
         for (Column<GenericTableSchema, ?> column: aNew.getColumns()) {
             if (column.getSchema().equals(flood_vlans)) {
+                // Test for the 5 flood_vlans inserted in Bridge br-test in createBridgeTransaction
                 Set<Integer> data = column.getData(flood_vlans);
                 Assert.assertTrue(!data.isEmpty());
+                Assert.assertEquals(5, data.size());
+            } else if (column.getSchema().equals(externalIds)) {
+                // Test for the {"key", "value"} external_ids inserted in Bridge br-test in createBridgeTransaction
+                Map<String, String> data = column.getData(externalIds);
+                Assert.assertNotNull(data.get("key"));
+                Assert.assertEquals("value", data.get("key"));
             }
         }
     }
@@ -189,7 +200,7 @@ public class OvsDBClientTestIT extends OvsdbTestBase {
         OperationResult result = results.get(0);
         List<Row<GenericTableSchema>> rows = result.getRows();
         Row<GenericTableSchema> ovsTableRow = rows.get(0);
-        return (UUID)ovsTableRow.getColumn(_uuid).getData();
+        return ovsTableRow.getColumn(_uuid).getData();
     }
 
     private void createBridgeTransaction() throws IOException, InterruptedException, ExecutionException {
@@ -200,6 +211,7 @@ public class OvsDBClientTestIT extends OvsdbTestBase {
         ColumnSchema<GenericTableSchema, String> name = bridge.column("name", String.class);
         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, Map<String, String>> externalIds = bridge.multiValuedColumn("external_ids", String.class, String.class);
         ColumnSchema<GenericTableSchema, Set<UUID>> bridges = ovsTable.multiValuedColumn("bridges", UUID.class);
         ColumnSchema<GenericTableSchema, UUID> _uuid = ovsTable.column("_uuid", UUID.class);
 
@@ -215,7 +227,8 @@ public class OvsDBClientTestIT extends OvsdbTestBase {
                 .add(op.insert(bridge)
                         .withId(namedUuid)
                         .value(name, testBridgeName)
-                        .value(flood_vlans, Sets.newHashSet(100, 101, 4001)))
+                        .value(flood_vlans, Sets.newHashSet(100, 101, 4001))
+                        .value(externalIds, Maps.newHashMap(ImmutableMap.of("key","value"))))
                 .add(op.comment("Inserting Bridge br-int"))
                 .add(op.update(bridge)
                         .set(fail_mode, "secure")