Add TypedDatabaseSchema 76/86076/6
authorRobert Varga <robert.varga@pantheon.tech>
Sat, 30 Nov 2019 11:22:10 +0000 (12:22 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Sun, 1 Dec 2019 11:18:48 +0000 (12:18 +0100)
This adds a new entrypoint for performing typed operations on top
of DatabaseSchema. The implementation fowards to TyperUtils, allowing
transition away from those utilities.

OvsdbClientImpl is update to always return TypedDatabaseSchema and
use it to implement its interface.

Change-Id: I6e31f418b2acdebdca01181522b6bb7966061617
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
library/impl/src/main/java/org/opendaylight/ovsdb/lib/impl/OvsdbClientImpl.java
library/impl/src/main/java/org/opendaylight/ovsdb/lib/schema/ForwardingDatabaseSchema.java [new file with mode: 0644]
library/impl/src/main/java/org/opendaylight/ovsdb/lib/schema/typed/TypedDatabaseSchema.java [new file with mode: 0644]
library/impl/src/main/java/org/opendaylight/ovsdb/lib/schema/typed/TypedDatabaseSchemaImpl.java [new file with mode: 0644]

index 372a6ed56a8418ebe33364c648375e373d5401f5..140830a58cee664627b435d25af43e9a77071261 100644 (file)
@@ -54,8 +54,8 @@ 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.schema.typed.TypedBaseTable;
+import org.opendaylight.ovsdb.lib.schema.typed.TypedDatabaseSchema;
 import org.opendaylight.ovsdb.lib.schema.typed.TypedTable;
-import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -64,7 +64,7 @@ public class OvsdbClientImpl implements OvsdbClient {
     private static final Logger LOG = LoggerFactory.getLogger(OvsdbClientImpl.class);
     private ExecutorService executorService;
     private OvsdbRPC rpc;
-    private final Map<String, DatabaseSchema> schemas = new HashMap<>();
+    private final Map<String, TypedDatabaseSchema> schemas = new HashMap<>();
     private final Map<String, CallbackContext> monitorCallbacks = new HashMap<>();
     private OvsdbRPC.Callback rpcCallback;
     private OvsdbConnectionInfo connectionInfo;
@@ -342,20 +342,20 @@ public class OvsdbClientImpl implements OvsdbClient {
 
     @Override
     public ListenableFuture<DatabaseSchema> getSchema(final String database) {
-        final DatabaseSchema existing = schemas.get(database);
+        final TypedDatabaseSchema existing = schemas.get(database);
         if (existing != null) {
             return Futures.immediateFuture(existing);
         }
 
         return Futures.transform(getSchemaFromDevice(Collections.singletonList(database)), result -> {
-            DatabaseSchema dbSchema = result.get(database);
+            final DatabaseSchema dbSchema = result.get(database);
             if (dbSchema == null) {
                 return null;
             }
 
-            dbSchema = dbSchema.withInternallyGeneratedColumns();
-            final DatabaseSchema raced = schemas.putIfAbsent(database, dbSchema);
-            return raced != null ? raced : dbSchema;
+            final TypedDatabaseSchema typedSchema = TypedDatabaseSchema.of(dbSchema.withInternallyGeneratedColumns());
+            final TypedDatabaseSchema raced = schemas.putIfAbsent(database, typedSchema);
+            return raced != null ? raced : typedSchema;
         }, executorService);
     }
 
@@ -405,7 +405,7 @@ public class OvsdbClientImpl implements OvsdbClient {
     }
 
     @Override
-    public DatabaseSchema getDatabaseSchema(final String dbName) {
+    public TypedDatabaseSchema getDatabaseSchema(final String dbName) {
         return schemas.get(dbName);
     }
 
@@ -417,7 +417,7 @@ public class OvsdbClientImpl implements OvsdbClient {
      * @param klazz Typed Class that represents a Table
      * @return DatabaseSchema that matches a Typed Table Class
      */
-    private <T> DatabaseSchema getDatabaseSchemaForTypedTable(final Class<T> klazz) {
+    private <T> TypedDatabaseSchema getDatabaseSchemaForTypedTable(final Class<T> klazz) {
         TypedTable typedTable = klazz.getAnnotation(TypedTable.class);
         if (typedTable != null) {
             return this.getDatabaseSchema(typedTable.database());
@@ -434,8 +434,7 @@ public class OvsdbClientImpl implements OvsdbClient {
      */
     @Override
     public <T extends TypedBaseTable<?>> T createTypedRowWrapper(final Class<T> klazz) {
-        DatabaseSchema dbSchema = getDatabaseSchemaForTypedTable(klazz);
-        return this.createTypedRowWrapper(dbSchema, klazz);
+        return getTypedRowWrapper(klazz, new Row<>());
     }
 
     /**
@@ -448,7 +447,7 @@ public class OvsdbClientImpl implements OvsdbClient {
      */
     @Override
     public <T extends TypedBaseTable<?>> T createTypedRowWrapper(final DatabaseSchema dbSchema, final Class<T> klazz) {
-        return TyperUtils.getTypedRowWrapper(dbSchema, klazz, new Row<>());
+        return dbSchema == null ? null : TypedDatabaseSchema.of(dbSchema).getTypedRowWrapper(klazz, new Row<>());
     }
 
     /**
@@ -462,8 +461,8 @@ public class OvsdbClientImpl implements OvsdbClient {
     @Override
 
     public <T extends TypedBaseTable<?>> T getTypedRowWrapper(final Class<T> klazz, final Row<GenericTableSchema> row) {
-        DatabaseSchema dbSchema = getDatabaseSchemaForTypedTable(klazz);
-        return TyperUtils.getTypedRowWrapper(dbSchema, klazz, row);
+        final TypedDatabaseSchema dbSchema = getDatabaseSchemaForTypedTable(klazz);
+        return dbSchema == null ? null : dbSchema.getTypedRowWrapper(klazz, row);
     }
 
     @Override
diff --git a/library/impl/src/main/java/org/opendaylight/ovsdb/lib/schema/ForwardingDatabaseSchema.java b/library/impl/src/main/java/org/opendaylight/ovsdb/lib/schema/ForwardingDatabaseSchema.java
new file mode 100644 (file)
index 0000000..6ebc6c8
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright © 2019 PANTHEON.tech, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.ovsdb.lib.schema;
+
+import com.google.common.collect.ForwardingObject;
+import java.util.Set;
+import org.opendaylight.ovsdb.lib.notation.Version;
+
+public abstract class ForwardingDatabaseSchema extends ForwardingObject implements DatabaseSchema {
+    @Override
+    protected abstract DatabaseSchema delegate();
+
+    @Override
+    public Set<String> getTables() {
+        return delegate().getTables();
+    }
+
+    @Override
+    public boolean hasTable(final String table) {
+        return delegate().hasTable(table);
+    }
+
+    @Override
+    public <E extends TableSchema<E>> E table(final String tableName, final Class<E> clazz) {
+        return delegate().table(tableName, clazz);
+    }
+
+    @Override
+    public String getName() {
+        return delegate().getName();
+    }
+
+    @Override
+    public Version getVersion() {
+        return delegate().getVersion();
+    }
+}
diff --git a/library/impl/src/main/java/org/opendaylight/ovsdb/lib/schema/typed/TypedDatabaseSchema.java b/library/impl/src/main/java/org/opendaylight/ovsdb/lib/schema/typed/TypedDatabaseSchema.java
new file mode 100644 (file)
index 0000000..d3da2d1
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright © 2019 PANTHEON.tech, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.ovsdb.lib.schema.typed;
+
+import java.util.Map;
+import org.opendaylight.ovsdb.lib.message.TableUpdates;
+import org.opendaylight.ovsdb.lib.notation.Row;
+import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
+
+public interface TypedDatabaseSchema extends DatabaseSchema {
+
+    static TypedDatabaseSchema of(final DatabaseSchema delegate) {
+        return delegate instanceof TypedDatabaseSchema ? (TypedDatabaseSchema) delegate
+                : new TypedDatabaseSchemaImpl(delegate);
+    }
+
+    @Override
+    TypedDatabaseSchema withInternallyGeneratedColumns();
+
+    /**
+     * Retrieve the table schema for the given table in the given database schema.
+     *
+     * @param klazz The class whose table schema should be retrieved. Classes are matched in the database schema either
+     *              using their {@link TypedTable} annotation, if they have one, or by name.
+     * @return the table schema.
+     */
+    GenericTableSchema getTableSchema(Class<?> klazz);
+
+    /**
+     * Returns a Typed Proxy implementation for the klazz passed as a parameter.
+     * Per design choice, the Typed Proxy implementation is just a Wrapper on top of the actual
+     * Row which is untyped.
+     *
+     * <p>Being just a wrapper, it is state-less and more of a convenience functionality to
+     * provide a type-safe infrastructure for the applications to built on top of.
+     * And this Typed infra is completely optional.
+     *
+     * <p>It is the applications responsibility to pass on the raw Row parameter and this method will
+     * return the appropriate Proxy wrapper for the passed klazz Type.
+     * The raw Row parameter may be null if the caller is interested in just the ColumnSchema.
+     * But that is not a very common use-case.
+     *
+     * @param klazz Typed Class that represents a Table
+     */
+    <T> T getTypedRowWrapper(Class<T> klazz);
+
+    /**
+     * Returns a Typed Proxy implementation for the klazz passed as a parameter.
+     * Per design choice, the Typed Proxy implementation is just a Wrapper on top of the actual
+     * Row which is untyped.
+     *
+     * <p>Being just a wrapper, it is state-less and more of a convenience functionality
+     * to provide a type-safe infrastructure for the applications to built on top of.
+     * And this Typed infra is completely optional.
+     *
+     * <p>It is the applications responsibility to pass on the raw Row parameter and this method
+     * will return the appropriate Proxy wrapper for the passed klazz Type.
+     * The raw Row parameter may be null if the caller is interested in just the
+     * ColumnSchema. But that is not a very common use-case.
+     *
+     * @param klazz Typed Class that represents a Table
+     * @param row The actual Row that the wrapper is operating on. It can be null if the caller
+     *            is just interested in getting ColumnSchema.
+     */
+    <T> T getTypedRowWrapper(Class<T> klazz, Row<GenericTableSchema> row);
+
+    /**
+     * This method extracts all row updates of Class&lt;T&gt; klazz from a TableUpdates
+     * that correspond to old version of rows of type klazz that have been updated.
+     * Example:
+     * <code>
+     * Map&lt;UUID,Bridge&gt; oldBridges = extractRowsOld(Bridge.class,updates,dbSchema)
+     * </code>
+     *
+     * @param klazz Class for row type to be extracted
+     * @param updates TableUpdates from which to extract rowUpdates
+     * @return Map&lt;UUID,T&gt; for the type of things being sought
+     */
+    <T> Map<UUID, T> extractRowsOld(Class<T> klazz, TableUpdates updates);
+
+    /**
+     * This method extracts all row updates of Class&lt;T&gt; klazz from a TableUpdates
+     * that correspond to removal of rows of type klazz.
+     * Example:
+     * <code>
+     * Map&lt;UUID,Bridge&gt; updatedBridges = extractRowsRemoved(Bridge.class,updates,dbSchema)
+     * </code>
+     *
+     * @param klazz Class for row type to be extracted
+     * @param updates TableUpdates from which to extract rowUpdates
+     * @return Map&lt;UUID,T&gt; for the type of things being sought
+     */
+    <T> Map<UUID,T> extractRowsRemoved(Class<T> klazz, TableUpdates updates);
+
+    /**
+     * This method extracts all row updates of Class&lt;T&gt; klazz from a TableUpdates
+     * that correspond to insertion or updates of rows of type klazz.
+     * Example:
+     * <code>
+     * Map&lt;UUID,Bridge&gt; updatedBridges = extractRowsUpdated(Bridge.class,updates,dbSchema)
+     * </code>
+     *
+     * @param klazz Class for row type to be extracted
+     * @param updates TableUpdates from which to extract rowUpdates
+     * @return Map&lt;UUID,T&gt; for the type of things being sought
+     */
+    <T> Map<UUID, T> extractRowsUpdated(Class<T> klazz, TableUpdates updates);
+}
diff --git a/library/impl/src/main/java/org/opendaylight/ovsdb/lib/schema/typed/TypedDatabaseSchemaImpl.java b/library/impl/src/main/java/org/opendaylight/ovsdb/lib/schema/typed/TypedDatabaseSchemaImpl.java
new file mode 100644 (file)
index 0000000..0cfee20
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright © 2019 PANTHEON.tech, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.ovsdb.lib.schema.typed;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.Map;
+import org.opendaylight.ovsdb.lib.message.TableUpdates;
+import org.opendaylight.ovsdb.lib.notation.Row;
+import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.ForwardingDatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
+
+final class TypedDatabaseSchemaImpl extends ForwardingDatabaseSchema implements TypedDatabaseSchema {
+    private final DatabaseSchema delegate;
+
+    TypedDatabaseSchemaImpl(final DatabaseSchema delegate) {
+        this.delegate = requireNonNull(delegate);
+    }
+
+    @Override
+    protected DatabaseSchema delegate() {
+        return delegate;
+    }
+
+    @Override
+    public TypedDatabaseSchema withInternallyGeneratedColumns() {
+        final DatabaseSchema newDelegate = delegate.withInternallyGeneratedColumns();
+        return newDelegate == delegate ? this : new TypedDatabaseSchemaImpl(newDelegate);
+    }
+
+    @Override
+    public GenericTableSchema getTableSchema(final Class<?> klazz) {
+        return TyperUtils.getTableSchema(this, klazz);
+    }
+
+    @Override
+    public <T> T getTypedRowWrapper(final Class<T> klazz) {
+        return TyperUtils.getTypedRowWrapper(this, klazz);
+    }
+
+    @Override
+    public <T> T getTypedRowWrapper(final Class<T> klazz, final Row<GenericTableSchema> row) {
+        return TyperUtils.getTypedRowWrapper(this, klazz, row);
+    }
+
+    @Override
+    public <T> Map<UUID, T> extractRowsOld(final Class<T> klazz, final TableUpdates updates) {
+        return TyperUtils.extractRowsOld(klazz, updates, this);
+    }
+
+    @Override
+    public <T> Map<UUID, T> extractRowsUpdated(final Class<T> klazz, final TableUpdates updates) {
+        return TyperUtils.extractRowsUpdated(klazz, updates, this);
+    }
+
+    @Override
+    public <T> Map<UUID, T> extractRowsRemoved(final Class<T> klazz, final TableUpdates updates) {
+        return TyperUtils.extractRowsRemoved(klazz, updates, this);
+    }
+}