*/
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;
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 {
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);
}
*/
package org.opendaylight.ovsdb.lib.jsonrpc;
-import com.google.common.reflect.Invokable;
import io.netty.channel.Channel;
import java.lang.reflect.InvocationHandler;
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;
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()) {
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;
}
*/
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 {
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() + "]";
+ }
}
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;
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;
private int count;
@JsonIgnore
private UUID uuid;
- private ArrayList<Object> rows;
+ private ArrayList<Row<GenericTableSchema>> rows;
private String error;
private String details;
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() {
*/
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.
*/
public void setName(String name) {
this.name = name;
}
+
+ public void populateInternallyGeneratedColumns() {
+ for (TableSchema tableSchema : tables.values()) {
+ tableSchema.populateInternallyGeneratedColumns();
+ }
+ }
}
*/
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>> {
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");
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;
}
}
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())));
+ }
}
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;
}
});
- 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);
}
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)) {
}
}
+ /*
+ * 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);
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.
.build())
.add(op.select(bridge)
.column(name)
+ .column(_uuid)
.where(name.opEqual(testBridgeName))
.build())
.add(op.mutate(bridge)
.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();
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();