*/
package org.opendaylight.ovsdb.lib;
-import com.fasterxml.jackson.databind.JsonNode;
-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.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.table.Table;
+import org.opendaylight.ovsdb.lib.schema.typed.TypedTable;
+import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.HashMap;
-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 {
private ExecutorService executorService;
private OvsdbRPC rpc;
private Map<String, DatabaseSchema> schema = Maps.newHashMap();
- private HashMap<String, MonitorCallBack> monitorCallbacks = Maps.newHashMap();
+ private HashMap<String, CallbackContext> monitorCallbacks = Maps.newHashMap();
private Queue<Throwable> exceptions;
private OvsdbRPC.Callback rpcCallback;
OvsDBClientImpl() {
}
- void setupUpdateListner() {
+ void setupUpdateListener() {
if (rpcCallback == null) {
OvsdbRPC.Callback temp = new OvsdbRPC.Callback() {
@Override
public void update(Object node, UpdateNotification upadateNotification) {
Object key = upadateNotification.getContext();
- MonitorCallBack monitorCallBack = monitorCallbacks.get(key);
+ CallbackContext callbackContext = monitorCallbacks.get(key);
+ MonitorCallBack monitorCallBack = callbackContext.monitorCallBack;
if (monitorCallBack == null) {
//ignore ?
logger.info("callback received with context {}, but no known handler. Ignoring!", key);
return;
}
- _transformingCallback(upadateNotification.getUpdate(), monitorCallBack);
+ _transformingCallback(upadateNotification.getUpdates(), monitorCallBack, callbackContext.schema);
}
@Override
}
}
- protected void _transformingCallback( org.opendaylight.ovsdb.lib.message.temp.TableUpdates oldUpdate, MonitorCallBack monitorCallBack) {
- //todo(ashwin) : temp kludge to get stuff working while deprecating old stuff
- Map<String, TableUpdate> updateMap = Maps.newHashMap();
- for (Map.Entry<Table.Name, TableUpdate> temp : oldUpdate.map.entrySet()) {
- updateMap.put(temp.getKey().getName(), temp.getValue());
- }
- monitorCallBack.update(new TableUpdates(updateMap));
+ protected void _transformingCallback(JsonNode tableUpdatesJson, MonitorCallBack monitorCallBack, DatabaseSchema dbSchema) {
+ //todo(ashwin): we should move all the JSON parsing logic to a utility class
+ if (tableUpdatesJson instanceof ObjectNode) {
+ Map<String, TableUpdate> tableUpdateMap = Maps.newHashMap();
+ ObjectNode updatesJson = (ObjectNode) tableUpdatesJson;
+ for (Iterator<Map.Entry<String,JsonNode>> itr = updatesJson.fields(); itr.hasNext();){
+ Map.Entry<String, JsonNode> entry = itr.next();
+
+ DatabaseSchema databaseSchema = this.schema.get(dbSchema.getName());
+ TableSchema table = databaseSchema.table(entry.getKey(), TableSchema.class);
+ tableUpdateMap.put(entry.getKey(), table.updatesFromJson(entry.getValue()));
+
+ }
+ TableUpdates updates = new TableUpdates(tableUpdateMap);
+ monitorCallBack.update(updates);
+ }
}
@Override
});
final MonitorHandle monitorHandle = new MonitorHandle(UUID.randomUUID().toString());
- registerCallback(monitorHandle, callback);
+ registerCallback(monitorHandle, callback, dbSchema);
- ListenableFuture<org.opendaylight.ovsdb.lib.message.temp.TableUpdates> monitor = rpc.monitor(new Params() {
+ ListenableFuture<JsonNode> monitor = rpc.monitor(new Params() {
@Override
public List<Object> params() {
return Lists.<Object>newArrayList(dbSchema.getName(), monitorHandle.getId(), reqMap);
}
});
- Futures.addCallback(monitor, new FutureCallback<org.opendaylight.ovsdb.lib.message.temp.TableUpdates>() {
+ Futures.addCallback(monitor, new FutureCallback<JsonNode>() {
@Override
- public void onSuccess(org.opendaylight.ovsdb.lib.message.temp.TableUpdates result) {
- _transformingCallback(result, callback);
+ public void onSuccess(JsonNode result) {
+ _transformingCallback(result, callback, dbSchema);
}
@Override
return monitorHandle;
}
- private void registerCallback(MonitorHandle monitorHandle, MonitorCallBack callback) {
- this.monitorCallbacks.put(monitorHandle.getId(), callback);
- setupUpdateListner();
+ private void registerCallback(MonitorHandle monitorHandle, MonitorCallBack callback, DatabaseSchema schema) {
+ this.monitorCallbacks.put(monitorHandle.getId(), new CallbackContext(callback, schema));
+ setupUpdateListener();
}
@Override
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);
}
return exceptions;
}
+ static class CallbackContext {
+ MonitorCallBack monitorCallBack;
+ DatabaseSchema schema;
+
+ CallbackContext(MonitorCallBack monitorCallBack, DatabaseSchema schema) {
+ this.monitorCallBack = monitorCallBack;
+ 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);
+ }
}