From 31de2f97a43518ecc501b8ee0137617baf6f2778 Mon Sep 17 00:00:00 2001 From: Madhu Venugopal Date: Thu, 12 Jun 2014 23:11:47 -0700 Subject: [PATCH] Resolved the Serialization and Deserialization issues for MultiValued Columns with the specialized "set" and "map" indicators. 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 --- .../ovsdb/lib/notation/Column.java | 2 +- .../ovsdb/lib/notation/OvsDBMap.java | 25 +++++-- .../ovsdb/lib/operations/Insert.java | 9 ++- .../ovsdb/lib/schema/ColumnType.java | 71 +++++++++++++++---- .../ovsdb/lib/schema/TableSchema.java | 8 +++ .../ovsdb/lib/OvsDBClientTestIT.java | 19 ++++- 6 files changed, 106 insertions(+), 28 deletions(-) diff --git a/library/src/main/java/org/opendaylight/ovsdb/lib/notation/Column.java b/library/src/main/java/org/opendaylight/ovsdb/lib/notation/Column.java index 57a35c6db..231567a4b 100644 --- a/library/src/main/java/org/opendaylight/ovsdb/lib/notation/Column.java +++ b/library/src/main/java/org/opendaylight/ovsdb/lib/notation/Column.java @@ -31,7 +31,7 @@ public class Column, D> { return schema.validate(data); } - public Object getData() { + public D getData() { return data; } diff --git a/library/src/main/java/org/opendaylight/ovsdb/lib/notation/OvsDBMap.java b/library/src/main/java/org/opendaylight/ovsdb/lib/notation/OvsDBMap.java index c3e1e84c0..c1a436470 100644 --- a/library/src/main/java/org/opendaylight/ovsdb/lib/notation/OvsDBMap.java +++ b/library/src/main/java/org/opendaylight/ovsdb/lib/notation/OvsDBMap.java @@ -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 extends ForwardingMap { - HashMap target = Maps.newHashMap(); + Map target = Maps.newHashMap(); + + public OvsDBMap() { + this(Maps.newHashMap()); + } + + public OvsDBMap(Map value) { + this.target = value; + } @Override public Map delegate() { return target; } + + public static OvsDBMap fromMap(Map value) { + return new OvsDBMap(value); + } } diff --git a/library/src/main/java/org/opendaylight/ovsdb/lib/operations/Insert.java b/library/src/main/java/org/opendaylight/ovsdb/lib/operations/Insert.java index cad870288..b4dc424bc 100644 --- a/library/src/main/java/org/opendaylight/ovsdb/lib/operations/Insert.java +++ b/library/src/main/java/org/opendaylight/ovsdb/lib/operations/Insert.java @@ -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> extends Operation { public > Insert value(ColumnSchema 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; } diff --git a/library/src/main/java/org/opendaylight/ovsdb/lib/schema/ColumnType.java b/library/src/main/java/org/opendaylight/ovsdb/lib/schema/ColumnType.java index 85c11a78f..da967b2d0 100644 --- a/library/src/main/java/org/opendaylight/ovsdb/lib/schema/ColumnType.java +++ b/library/src/main/java/org/opendaylight/ovsdb/lib/schema/ColumnType.java @@ -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 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 map = new OvsDBMap(); + 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); } } } diff --git a/library/src/main/java/org/opendaylight/ovsdb/lib/schema/TableSchema.java b/library/src/main/java/org/opendaylight/ovsdb/lib/schema/TableSchema.java index 26105412a..4215be8a8 100644 --- a/library/src/main/java/org/opendaylight/ovsdb/lib/schema/TableSchema.java +++ b/library/src/main/java/org/opendaylight/ovsdb/lib/schema/TableSchema.java @@ -87,6 +87,14 @@ public abstract class TableSchema> { return columnSchema; } + public ColumnSchema> multiValuedColumn(String column, Class keyType, Class valueType) { + //todo exception handling + + ColumnSchema columnSchema = columns.get(column); + columnSchema.validateType(valueType); + return columnSchema; + } + public ColumnSchema column(String column, Class type) { //todo exception handling diff --git a/library/src/test/java/org/opendaylight/ovsdb/lib/OvsDBClientTestIT.java b/library/src/test/java/org/opendaylight/ovsdb/lib/OvsDBClientTestIT.java index 73a899358..799f04e67 100644 --- a/library/src/test/java/org/opendaylight/ovsdb/lib/OvsDBClientTestIT.java +++ b/library/src/test/java/org/opendaylight/ovsdb/lib/OvsDBClientTestIT.java @@ -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> monitorRequests = Lists.newArrayList(); ColumnSchema> flood_vlans = bridge.multiValuedColumn("flood_vlans", Integer.class); - + ColumnSchema> 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 aNew = update.getNew(); for (Column column: aNew.getColumns()) { if (column.getSchema().equals(flood_vlans)) { + // Test for the 5 flood_vlans inserted in Bridge br-test in createBridgeTransaction Set 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 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> rows = result.getRows(); Row 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 name = bridge.column("name", String.class); ColumnSchema fail_mode = bridge.column("fail_mode", String.class); ColumnSchema> flood_vlans = bridge.multiValuedColumn("flood_vlans", Integer.class); + ColumnSchema> externalIds = bridge.multiValuedColumn("external_ids", String.class, String.class); ColumnSchema> bridges = ovsTable.multiValuedColumn("bridges", UUID.class); ColumnSchema _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") -- 2.36.6