Make TableSchema/DatabaseSchema immutable 74/86074/2
authorRobert Varga <robert.varga@pantheon.tech>
Sat, 30 Nov 2019 08:26:00 +0000 (09:26 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Sat, 30 Nov 2019 11:15:44 +0000 (12:15 +0100)
Having schemas completely immutable is beneficial, as we can
propagate invariants properly. This patch makes TableSchema
and DatabaseSchema use immutable maps internally, making sure
the final bit is achieved.

Change-Id: Ie7c9fd4aa9cba7f0af88c8886400e8e5c804d6af
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/DatabaseSchema.java
library/impl/src/main/java/org/opendaylight/ovsdb/lib/schema/GenericTableSchema.java
library/impl/src/main/java/org/opendaylight/ovsdb/lib/schema/TableSchema.java

index 72afec33459c88cecb16158d1242f00ed6a34f5f..372a6ed56a8418ebe33364c648375e373d5401f5 100644 (file)
@@ -348,12 +348,12 @@ public class OvsdbClientImpl implements OvsdbClient {
         }
 
         return Futures.transform(getSchemaFromDevice(Collections.singletonList(database)), result -> {
-            final DatabaseSchema dbSchema = result.get(database);
+            DatabaseSchema dbSchema = result.get(database);
             if (dbSchema == null) {
                 return null;
             }
 
-            dbSchema.populateInternallyGeneratedColumns();
+            dbSchema = dbSchema.withInternallyGeneratedColumns();
             final DatabaseSchema raced = schemas.putIfAbsent(database, dbSchema);
             return raced != null ? raced : dbSchema;
         }, executorService);
index ccf43d13a1ff7dc8f47e7e6541350531d0d43a1d..a80d653d0962eaa8dc942c2c7721ae43dec587cd 100644 (file)
@@ -8,7 +8,11 @@
 
 package org.opendaylight.ovsdb.lib.schema;
 
+import static java.util.Objects.requireNonNull;
+
 import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
 import com.google.common.reflect.Invokable;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
@@ -29,20 +33,20 @@ public class DatabaseSchema {
 
     private final String name;
     private final Version version;
-    private final Map<String, TableSchema> tables;
+    private final ImmutableMap<String, TableSchema> tables;
 
     public DatabaseSchema(final String name, final Version version, final Map<String, TableSchema> tables) {
-        this.name = name;
-        this.version = version;
-        this.tables = tables;
+        this.name = requireNonNull(name);
+        this.version = requireNonNull(version);
+        this.tables = ImmutableMap.copyOf(tables);
     }
 
     public Set<String> getTables() {
-        return this.tables.keySet();
+        return tables.keySet();
     }
 
     public boolean hasTable(final String table) {
-        return this.getTables().contains(table);
+        return tables.containsKey(table);
     }
 
     public <E extends TableSchema<E>> E table(final String tableName, final Class<E> clazz) {
@@ -105,9 +109,17 @@ public class DatabaseSchema {
         return version;
     }
 
-    public void populateInternallyGeneratedColumns() {
+    public DatabaseSchema withInternallyGeneratedColumns() {
+        return haveInternallyGeneratedColumns() ? this : new DatabaseSchema(name, version,
+            Maps.transformValues(tables, TableSchema::withInternallyGeneratedColumns));
+    }
+
+    protected final boolean haveInternallyGeneratedColumns() {
         for (TableSchema tableSchema : tables.values()) {
-            tableSchema.populateInternallyGeneratedColumns();
+            if (!tableSchema.haveInternallyGeneratedColumns()) {
+                return false;
+            }
         }
+        return true;
     }
 }
index 47a0d9a12c833a52cde700ac71053055629b4cf2..576073f6be3b95e9dbf49901f49c8d473d51f0df 100644 (file)
@@ -44,4 +44,16 @@ public class GenericTableSchema extends TableSchema<GenericTableSchema> {
 
         return new GenericTableSchema(tableName, columns);
     }
+
+    @Override
+    public GenericTableSchema withInternallyGeneratedColumns() {
+        if (haveInternallyGeneratedColumns()) {
+            return this;
+        }
+
+        final Map<String, ColumnSchema> columns = new HashMap<>(getColumnSchemas());
+        columns.put(UUID_COLUMN_SCHMEMA.getName(), UUID_COLUMN_SCHMEMA);
+        columns.put(VERSION_COLUMN_SCHMEMA.getName(), VERSION_COLUMN_SCHMEMA);
+        return new GenericTableSchema(getName(), columns);
+    }
 }
index 15efee38000768327c23784adc777c6eaae87286..e63ecef6b5c815b3a12c7e9e9ec1fb3162e2b796 100644 (file)
@@ -7,12 +7,14 @@
  */
 package org.opendaylight.ovsdb.lib.schema;
 
+import static java.util.Objects.requireNonNull;
+
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.ImmutableMap;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -26,24 +28,23 @@ import org.opendaylight.ovsdb.lib.operations.Insert;
 
 public abstract class TableSchema<E extends TableSchema<E>> {
     private static final AtomicColumnType UUID_COLUMN_TYPE = new AtomicColumnType(UuidBaseType.SINGLETON);
-    private static final ColumnSchema UUID_COLUMN_SCHMEMA = new ColumnSchema("_uuid", UUID_COLUMN_TYPE);
-    private static final ColumnSchema VERSION_COLUMN_SCHMEMA = new ColumnSchema("_version", UUID_COLUMN_TYPE);
+    protected static final ColumnSchema UUID_COLUMN_SCHMEMA = new ColumnSchema("_uuid", UUID_COLUMN_TYPE);
+    protected static final ColumnSchema VERSION_COLUMN_SCHMEMA = new ColumnSchema("_version", UUID_COLUMN_TYPE);
 
     private final String name;
-    private final Map<String, ColumnSchema> columns;
+    private final ImmutableMap<String, ColumnSchema> columns;
 
     protected TableSchema(final String name) {
-        this.name = name;
-        this.columns = new HashMap<>();
+        this(name, ImmutableMap.of());
     }
 
     protected TableSchema(final String name, final Map<String, ColumnSchema> columns) {
-        this.name = name;
-        this.columns = columns;
+        this.name = requireNonNull(name);
+        this.columns = ImmutableMap.copyOf(columns);
     }
 
     public Set<String> getColumns() {
-        return this.columns.keySet();
+        return columns.keySet();
     }
 
     public Map<String, ColumnSchema> getColumnSchemas() {
@@ -51,11 +52,11 @@ public abstract class TableSchema<E extends TableSchema<E>> {
     }
 
     public boolean hasColumn(final String column) {
-        return this.getColumns().contains(column);
+        return columns.containsKey(column);
     }
 
     public ColumnType getColumnType(final String column) {
-        return this.columns.get(column).getType();
+        return columns.get(column).getType();
     }
 
     public <E extends TableSchema<E>> E as(final Class<E> clazz) {
@@ -100,7 +101,7 @@ public abstract class TableSchema<E extends TableSchema<E>> {
     }
 
     public ColumnSchema column(final String column) {
-        return this.columns.get(column);
+        return columns.get(column);
     }
 
     public String getName() {
@@ -163,8 +164,9 @@ public abstract class TableSchema<E extends TableSchema<E>> {
      * 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", UUID_COLUMN_SCHMEMA);
-        columns.put("_version", VERSION_COLUMN_SCHMEMA);
+    public abstract E withInternallyGeneratedColumns();
+
+    protected final boolean haveInternallyGeneratedColumns() {
+        return hasColumn(UUID_COLUMN_SCHMEMA.getName()) && hasColumn(VERSION_COLUMN_SCHMEMA.getName());
     }
 }