Adopt odlparent-10.0.0/yangtools-8.0.0-SNAPSHOT
[mdsal.git] / dom / mdsal-dom-broker / src / main / java / org / opendaylight / mdsal / dom / broker / AbstractDOMRoutingTable.java
index dca4a1de7ff160dd6876fd39810fd90e1765a3d9..a1871e8535e49ae3dab24bfbd7da178e711dca28 100644 (file)
@@ -7,14 +7,17 @@
  */
 package org.opendaylight.mdsal.dom.broker;
 
+import static java.util.Objects.requireNonNull;
+
 import com.google.common.annotations.Beta;
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
+import com.google.common.collect.HashMultimap;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableMap.Builder;
 import com.google.common.collect.ListMultimap;
 import com.google.common.collect.Maps;
+import com.google.common.collect.Multimaps;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.EventListener;
@@ -25,35 +28,34 @@ import java.util.Map.Entry;
 import java.util.Set;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 
 /**
  * Abstract routing table definition for Action and RPC.
+ *
  * @param <I> instance type of RPC or Acton
  * @param <D> identifier type of RPC or Acton
  * @param <M> implementation type of RPC or Acton
  * @param <L> listener type of RPC or Acton
  * @param <E> routing entry type of RPC or Acton
+ * @param <K> routing key type
  */
 @Beta
-abstract class AbstractDOMRoutingTable<I, D, M, L extends EventListener,
-        E extends AbstractDOMRoutingTableEntry<D, M, L>> {
-    private final Map<SchemaPath, E> operations;
-    private final SchemaContext schemaContext;
-
-    AbstractDOMRoutingTable(final Map<SchemaPath, E> operations,
-            final SchemaContext schemaContext) {
-        this.operations = Preconditions.checkNotNull(operations);
+abstract class AbstractDOMRoutingTable<I, D, M, L extends EventListener, K,
+        E extends AbstractDOMRoutingTableEntry<D, M, L, K>> {
+    private final Map<K, E> operations;
+    private final EffectiveModelContext schemaContext;
+
+    AbstractDOMRoutingTable(final Map<K, E> operations, final EffectiveModelContext schemaContext) {
+        this.operations = requireNonNull(operations);
         this.schemaContext = schemaContext;
     }
 
-    AbstractDOMRoutingTable<I, D, M, L, E> setSchemaContext(final SchemaContext context) {
-        final Builder<SchemaPath, E> b = ImmutableMap.builder();
+    AbstractDOMRoutingTable<I, D, M, L, K, E> setSchemaContext(final EffectiveModelContext context) {
+        final Builder<K, E> b = ImmutableMap.builder();
 
-        for (Entry<SchemaPath, E> e : operations.entrySet()) {
-            final E entry = createOperationEntry(context, e.getKey(),
-                e.getValue().getImplementations());
+        for (Entry<K, E> e : operations.entrySet()) {
+            final E entry = createOperationEntry(context, e.getKey(), e.getValue().getImplementations());
             if (entry != null) {
                 b.put(e.getKey(), entry);
             }
@@ -62,55 +64,74 @@ abstract class AbstractDOMRoutingTable<I, D, M, L extends EventListener,
         return newInstance(b.build(), context);
     }
 
-    AbstractDOMRoutingTable<I, D, M, L, E> add(final M implementation, final Set<I> oprsToAdd) {
+    AbstractDOMRoutingTable<I, D, M, L, K, E> add(final M implementation, final Set<I> oprsToAdd) {
         if (oprsToAdd.isEmpty()) {
             return this;
         }
 
+        final Builder<K, E> mb = ImmutableMap.builder();
+        add(implementation, oprsToAdd, mb);
+
+        return newInstance(mb.build(), schemaContext);
+    }
+
+    private void add(final M implementation, final Set<I> oprsToAdd,
+            final Builder<K, E> tableInputBuilder) {
         // First decompose the identifiers to a multimap
-        final ListMultimap<SchemaPath, D> toAdd = decomposeIdentifiers(oprsToAdd);
+        final ListMultimap<K, D> toAdd = decomposeIdentifiers(oprsToAdd);
 
         // Now iterate over existing entries, modifying them as appropriate...
-        final Builder<SchemaPath, E> mb = ImmutableMap.builder();
-        for (Entry<SchemaPath, E> re : this.operations.entrySet()) {
+        for (Entry<K, E> re : this.operations.entrySet()) {
             List<D> newOperations = new ArrayList<>(toAdd.removeAll(re.getKey()));
             if (!newOperations.isEmpty()) {
                 final E ne = (E) re.getValue().add(implementation, newOperations);
-                mb.put(re.getKey(), ne);
+                tableInputBuilder.put(re.getKey(), ne);
             } else {
-                mb.put(re);
+                tableInputBuilder.put(re);
             }
         }
 
         // Finally add whatever is left in the decomposed multimap
-        for (Entry<SchemaPath, Collection<D>> e : toAdd.asMap().entrySet()) {
+        for (Entry<K, Collection<D>> e : toAdd.asMap().entrySet()) {
             final Builder<D, List<M>> vb = ImmutableMap.builder();
             final List<M> v = ImmutableList.of(implementation);
             for (D i : e.getValue()) {
                 vb.put(i, v);
             }
 
-            final E entry = createOperationEntry(schemaContext, e.getKey(),
-                vb.build());
+            final E entry = createOperationEntry(schemaContext, e.getKey(), vb.build());
             if (entry != null) {
-                mb.put(e.getKey(), entry);
+                tableInputBuilder.put(e.getKey(), entry);
             }
         }
+    }
 
-        return newInstance(mb.build(), schemaContext);
+    AbstractDOMRoutingTable<I, D, M, L, K, E> addAll(final Map<I, M> map) {
+        if (map.isEmpty()) {
+            return this;
+        }
+
+        HashMultimap<M, I> inverted = invertImplementationsMap(map);
+
+        final Builder<K, E> tableInputBuilder = ImmutableMap.builder();
+        for (M impl : inverted.keySet()) {
+            add(impl, inverted.get(impl), tableInputBuilder);
+        }
+
+        return newInstance(tableInputBuilder.build(), schemaContext);
     }
 
-    AbstractDOMRoutingTable<I, D, M, L, E> remove(final M implementation, final Set<I> instances) {
+    AbstractDOMRoutingTable<I, D, M, L, K, E> remove(final M implementation, final Set<I> instances) {
         if (instances.isEmpty()) {
             return this;
         }
 
         // First decompose the identifiers to a multimap
-        final ListMultimap<SchemaPath, D> toRemove = decomposeIdentifiers(instances);
+        final ListMultimap<K, D> toRemove = decomposeIdentifiers(instances);
 
         // Now iterate over existing entries, modifying them as appropriate...
-        final Builder<SchemaPath, E> b = ImmutableMap.builder();
-        for (Entry<SchemaPath, E> e : this.operations.entrySet()) {
+        final Builder<K, E> b = ImmutableMap.builder();
+        for (Entry<K, E> e : this.operations.entrySet()) {
             final List<D> removed = new ArrayList<>(toRemove.removeAll(e.getKey()));
             if (!removed.isEmpty()) {
                 final E ne = (E) e.getValue().remove(implementation, removed);
@@ -126,14 +147,50 @@ abstract class AbstractDOMRoutingTable<I, D, M, L extends EventListener,
         return newInstance(b.build(), schemaContext);
     }
 
+
+    private void remove(final M implementation, final Set<I> oprsToRemove,
+                        final Builder<K, E> tableInputBuilder) {
+        final ListMultimap<K, D> toRemove = decomposeIdentifiers(oprsToRemove);
+
+        for (Entry<K, E> e : this.operations.entrySet()) {
+            final List<D> removed = new ArrayList<>(toRemove.removeAll(e.getKey()));
+            if (!removed.isEmpty()) {
+                final E ne = (E) e.getValue().remove(implementation, removed);
+                if (ne != null) {
+                    tableInputBuilder.put(e.getKey(), ne);
+                }
+            } else {
+                tableInputBuilder.put(e);
+            }
+        }
+    }
+
+    AbstractDOMRoutingTable<I, D, M, L, K, E> removeAll(final Map<I, M> map) {
+        if (map.isEmpty()) {
+            return this;
+        }
+        HashMultimap<M, I> inverted = invertImplementationsMap(map);
+
+        final Builder<K, E> tableInputBuilder = ImmutableMap.builder();
+        for (M impl : inverted.keySet()) {
+            remove(impl, inverted.get(impl), tableInputBuilder);
+        }
+
+        return newInstance(tableInputBuilder.build(), schemaContext);
+    }
+
+    HashMultimap<M, I> invertImplementationsMap(final Map<I, M> map) {
+        return Multimaps.invertFrom(Multimaps.forMap(map), HashMultimap.create());
+    }
+
     @VisibleForTesting
-    Map<SchemaPath, Set<D>> getOperations() {
+    Map<K, Set<D>> getOperations() {
         return Maps.transformValues(operations, AbstractDOMRoutingTableEntry::registeredIdentifiers);
     }
 
-    Map<SchemaPath, Set<D>> getOperations(final L listener) {
-        final Map<SchemaPath, Set<D>> ret = new HashMap<>(operations.size());
-        for (Entry<SchemaPath, E> e : operations.entrySet()) {
+    Map<K, Set<D>> getOperations(final L listener) {
+        final Map<K, Set<D>> ret = new HashMap<>(operations.size());
+        for (Entry<K, E> e : operations.entrySet()) {
             final Set<D> ids = e.getValue().registeredIdentifiers(listener);
             if (!ids.isEmpty()) {
                 ret.put(e.getKey(), ids);
@@ -143,14 +200,14 @@ abstract class AbstractDOMRoutingTable<I, D, M, L extends EventListener,
         return ret;
     }
 
-    @Nullable AbstractDOMRoutingTableEntry<D, M, L> getEntry(final @NonNull SchemaPath type) {
+    @Nullable AbstractDOMRoutingTableEntry<D, M, L, K> getEntry(final @NonNull K type) {
         return operations.get(type);
     }
 
-    protected abstract AbstractDOMRoutingTable<I, D, M, L, E> newInstance(Map<SchemaPath, E> operations,
-            SchemaContext schemaContext);
+    protected abstract AbstractDOMRoutingTable<I, D, M, L, K, E> newInstance(Map<K, E> operations,
+            EffectiveModelContext schemaContext);
 
-    abstract ListMultimap<SchemaPath, D> decomposeIdentifiers(Set<I> instances);
+    abstract ListMultimap<K, D> decomposeIdentifiers(Set<I> instances);
 
-    abstract E createOperationEntry(SchemaContext context, SchemaPath key, Map<D, List<M>> implementations);
+    abstract @Nullable E createOperationEntry(EffectiveModelContext context, K key, Map<D, List<M>> implementations);
 }