Add DOMActionRoutingTable and DOMActionRoutingTableEntry 74/74374/13
authorJie Han <han.jie@zte.com.cn>
Tue, 24 Jul 2018 08:43:55 +0000 (16:43 +0800)
committerRobert Varga <nite@hq.sk>
Tue, 31 Jul 2018 22:19:02 +0000 (22:19 +0000)
- Split out AbstractDOMRoutingTable and AbstractDOMRoutingTableEntry
- Provide Action routing table and entry

Change-Id: I6606b2b280344e52d58fb7b6fbec0e76231c2786
Signed-off-by: Jie Han <han.jie@zte.com.cn>
dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/AbstractDOMRoutingTable.java [new file with mode: 0644]
dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/AbstractDOMRoutingTableEntry.java [new file with mode: 0644]
dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/AbstractDOMRpcRoutingTableEntry.java
dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/DOMActionRoutingTable.java [new file with mode: 0644]
dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/DOMActionRoutingTableEntry.java [new file with mode: 0644]
dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/DOMRpcRouter.java
dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/DOMRpcRoutingTable.java
dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/UnknownDOMRpcRoutingTableEntry.java
dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/DOMRpcRouterTest.java
dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/GlobalDOMRpcRoutingTableEntryTest.java
dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/UnknownDOMRpcRoutingTableEntryTest.java

diff --git a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/AbstractDOMRoutingTable.java b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/AbstractDOMRoutingTable.java
new file mode 100644 (file)
index 0000000..7a4eb83
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2018 ZTE Corp. 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.mdsal.dom.broker;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+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 java.util.ArrayList;
+import java.util.Collection;
+import java.util.EventListener;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+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;
+
+/**
+ * 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
+ */
+@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);
+        this.schemaContext = schemaContext;
+    }
+
+    AbstractDOMRoutingTable setSchemaContext(final SchemaContext context) {
+        final Builder<SchemaPath, E> b = ImmutableMap.builder();
+
+        for (Entry<SchemaPath, E> e : operations.entrySet()) {
+            final E entry = createOperationEntry(context, e.getKey(),
+                e.getValue().getImplementations());
+            if (entry != null) {
+                b.put(e.getKey(), entry);
+            }
+        }
+
+        return newInstance(b.build(), context);
+    }
+
+    AbstractDOMRoutingTable add(final M implementation, final Set<I> oprsToAdd) {
+        if (oprsToAdd.isEmpty()) {
+            return this;
+        }
+
+        // First decompose the identifiers to a multimap
+        final ListMultimap<SchemaPath, 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()) {
+            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);
+            } else {
+                mb.put(re);
+            }
+        }
+
+        // Finally add whatever is left in the decomposed multimap
+        for (Entry<SchemaPath, 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());
+            if (entry != null) {
+                mb.put(e.getKey(), entry);
+            }
+        }
+
+        return newInstance(mb.build(), schemaContext);
+    }
+
+    AbstractDOMRoutingTable 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);
+
+        // 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 List<D> removed = new ArrayList<>(toRemove.removeAll(e.getKey()));
+            if (!removed.isEmpty()) {
+                final E ne = (E) e.getValue().remove(implementation, removed);
+                if (ne != null) {
+                    b.put(e.getKey(), ne);
+                }
+            } else {
+                b.put(e);
+            }
+        }
+
+        // All done, whatever is in toRemove, was not there in the first place
+        return newInstance(b.build(), schemaContext);
+    }
+
+    @VisibleForTesting
+    Map<SchemaPath, 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()) {
+            final Set<D> ids = e.getValue().registeredIdentifiers(listener);
+            if (!ids.isEmpty()) {
+                ret.put(e.getKey(), ids);
+            }
+        }
+
+        return ret;
+    }
+
+    @Nullable AbstractDOMRoutingTableEntry getEntry(final @NonNull SchemaPath type) {
+        return operations.get(type);
+    }
+
+    protected abstract AbstractDOMRoutingTable newInstance(
+        Map<SchemaPath, E> operations, SchemaContext schemaContext);
+
+    abstract ListMultimap<SchemaPath, D> decomposeIdentifiers(Set<I> instances);
+
+    abstract E createOperationEntry(SchemaContext context, SchemaPath key,
+        Map<D, List<M>> implementations);
+}
diff --git a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/AbstractDOMRoutingTableEntry.java b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/AbstractDOMRoutingTableEntry.java
new file mode 100644 (file)
index 0000000..b783ab6
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2018 ZTE Corp. 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.mdsal.dom.broker;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMap.Builder;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.EventListener;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+/**
+ * Abstract routing table entry definition for Action and RPC.
+ * @param <D> identifier type of RPC or Acton
+ * @param <M> implementation type of RPC or Acton
+ * @param <L> listener type of RPC or Acton
+ */
+@Beta
+abstract class AbstractDOMRoutingTableEntry<D, M, L extends EventListener> {
+    private final Map<D, List<M>> implementations;
+    private final SchemaPath type;
+
+    AbstractDOMRoutingTableEntry(final SchemaPath type, final Map<D, List<M>> implementations) {
+        this.type = Preconditions.checkNotNull(type);
+        this.implementations = Preconditions.checkNotNull(implementations);
+    }
+
+    SchemaPath getType() {
+        return type;
+    }
+
+    List<M> getImplementations(final D identifier) {
+        return implementations.get(identifier);
+    }
+
+    Map<D, List<M>> getImplementations() {
+        return implementations;
+    }
+
+    @VisibleForTesting
+    Set<D> registeredIdentifiers() {
+        return implementations.keySet();
+    }
+
+    protected abstract Set<D> registeredIdentifiers(L listener);
+
+    /**
+     * This method adds the given DOMOperationImplementation instance for the given list operation identifiers.
+     *
+     * @param implementation the DOMOperationImplementation instance to add
+     * @param newOprs  the List of new RPCs/Actions that the DOMOperationImplementation provides, must be mutable
+     * @return a new instance of DOMActionRoutingTableEntry with the additions
+     */
+    AbstractDOMRoutingTableEntry add(final M implementation, final List<D> newOprs) {
+        final Builder<D, List<M>> vb = ImmutableMap.builder();
+        for (final Entry<D, List<M>> ve : implementations.entrySet()) {
+            if (newOprs.remove(ve.getKey())) {
+                final List<M> i = new ArrayList<>(ve.getValue().size() + 1);
+                i.addAll(ve.getValue());
+                i.add(implementation);
+
+                // New implementation is at the end, this will move it to be the last among implementations
+                // with equal cost -- relying on sort() being stable.
+                i.sort(implComparator());
+                vb.put(ve.getKey(), i);
+            } else {
+                vb.put(ve);
+            }
+        }
+        for (final D ii : newOprs) {
+            final List<M> impl = new ArrayList<>(1);
+            impl.add(implementation);
+            vb.put(ii, impl);
+        }
+
+        return newInstance(vb.build());
+    }
+
+    AbstractDOMRoutingTableEntry remove(final M implementation, final List<D> removed) {
+        final Builder<D, List<M>> vb = ImmutableMap.builder();
+        for (final Entry<D, List<M>> ve : implementations.entrySet()) {
+            if (removed.remove(ve.getKey())) {
+                final List<M> i = new ArrayList<>(ve.getValue());
+                i.remove(implementation);
+                // We could trimToSize(), but that may perform another copy just to get rid
+                // of a single element. That is probably not worth the trouble.
+                if (!i.isEmpty()) {
+                    vb.put(ve.getKey(), i);
+                }
+            } else {
+                vb.put(ve);
+            }
+        }
+
+        final Map<D, List<M>> v = vb.build();
+        return v.isEmpty() ? null : newInstance(vb.build());
+    }
+
+    protected abstract Comparator<M> implComparator();
+
+    protected abstract AbstractDOMRoutingTableEntry newInstance(Map<D, List<M>> impls);
+}
index 32f8ba6053d1e1895111d800abd8c5e8b6bf348a..527f19a93562ee057ce76a45e70eaea086ec2f1a 100644 (file)
  */
 package org.opendaylight.mdsal.dom.broker;
 
-import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableMap.Builder;
 import com.google.common.collect.Maps;
-import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Set;
 import org.opendaylight.mdsal.dom.api.DOMRpcAvailabilityListener;
 import org.opendaylight.mdsal.dom.api.DOMRpcIdentifier;
 import org.opendaylight.mdsal.dom.api.DOMRpcImplementation;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 
-abstract class AbstractDOMRpcRoutingTableEntry {
-    private final Map<YangInstanceIdentifier, List<DOMRpcImplementation>> implementations;
+abstract class AbstractDOMRpcRoutingTableEntry extends AbstractDOMRoutingTableEntry<YangInstanceIdentifier,
+        DOMRpcImplementation, DOMRpcAvailabilityListener> {
     private final DOMRpcIdentifier rpcId;
 
     AbstractDOMRpcRoutingTableEntry(final DOMRpcIdentifier rpcId, final Map<YangInstanceIdentifier,
-            List<DOMRpcImplementation>> implementations) {
+        List<DOMRpcImplementation>> implementations) {
+        super(rpcId.getType(), implementations);
         this.rpcId = Preconditions.checkNotNull(rpcId);
-        this.implementations = Preconditions.checkNotNull(implementations);
-    }
-
-    final SchemaPath getSchemaPath() {
-        return rpcId.getType();
     }
 
     final DOMRpcIdentifier getRpcId() {
         return rpcId;
     }
 
-    final List<DOMRpcImplementation> getImplementations(final YangInstanceIdentifier context) {
-        return implementations.get(context);
-    }
-
-    final Map<YangInstanceIdentifier, List<DOMRpcImplementation>> getImplementations() {
-        return implementations;
-    }
-
     final boolean containsContext(final YangInstanceIdentifier contextReference) {
-        return implementations.containsKey(contextReference);
+        return getImplementations().containsKey(contextReference);
     }
 
-    final Set<YangInstanceIdentifier> registeredIdentifiers(final DOMRpcAvailabilityListener listener) {
-        return Maps.filterValues(implementations, list -> list.stream()
+    @Override
+    protected final Set<YangInstanceIdentifier> registeredIdentifiers(final DOMRpcAvailabilityListener listener) {
+        return Maps.filterValues(getImplementations(), list -> list.stream()
             .anyMatch(listener::acceptsImplementation)).keySet();
     }
 
-    @VisibleForTesting
-    final Set<YangInstanceIdentifier> registeredIdentifiers() {
-        return implementations.keySet();
-    }
-
-    /**
-     * This method adds the given DOMRpcImplementation instance for the given list RPC identifiers.
-     *
-     * @param implementation the DOMRpcImplementation instance to add
-     * @param newRpcs the List of new RPCs that the DOMRpcImplementation provides, must be mutable
-     * @return a new instance of AbstractDOMRpcRoutingTableEntry with the additions
-     */
-    final AbstractDOMRpcRoutingTableEntry add(
-            final DOMRpcImplementation implementation, final List<YangInstanceIdentifier> newRpcs) {
-        final Builder<YangInstanceIdentifier, List<DOMRpcImplementation>> vb = ImmutableMap.builder();
-        for (final Entry<YangInstanceIdentifier, List<DOMRpcImplementation>> ve : implementations.entrySet()) {
-            if (newRpcs.remove(ve.getKey())) {
-                final List<DOMRpcImplementation> i = new ArrayList<>(ve.getValue().size() + 1);
-                i.addAll(ve.getValue());
-                i.add(implementation);
-
-                // New implementation is at the end, this will move it to be the last among implementations
-                // with equal cost -- relying on sort() being stable.
-                i.sort(Comparator.comparingLong(DOMRpcImplementation::invocationCost));
-                vb.put(ve.getKey(), i);
-            } else {
-                vb.put(ve);
-            }
-        }
-        for (final YangInstanceIdentifier ii : newRpcs) {
-            final List<DOMRpcImplementation> impl = new ArrayList<>(1);
-            impl.add(implementation);
-            vb.put(ii, impl);
-        }
-
-        return newInstance(vb.build());
+    @Override
+    protected Comparator<DOMRpcImplementation> implComparator() {
+        return Comparator.comparingLong(DOMRpcImplementation::invocationCost);
     }
-
-    final AbstractDOMRpcRoutingTableEntry remove(
-            final DOMRpcImplementation implementation, final List<YangInstanceIdentifier> removed) {
-        final Builder<YangInstanceIdentifier, List<DOMRpcImplementation>> vb = ImmutableMap.builder();
-        for (final Entry<YangInstanceIdentifier, List<DOMRpcImplementation>> ve : implementations.entrySet()) {
-            if (removed.remove(ve.getKey())) {
-                final List<DOMRpcImplementation> i = new ArrayList<>(ve.getValue());
-                i.remove(implementation);
-                // We could trimToSize(), but that may perform another copy just to get rid
-                // of a single element. That is probably not worth the trouble.
-                if (!i.isEmpty()) {
-                    vb.put(ve.getKey(), i);
-                }
-            } else {
-                vb.put(ve);
-            }
-        }
-
-        final Map<YangInstanceIdentifier, List<DOMRpcImplementation>> v = vb.build();
-        return v.isEmpty() ? null : newInstance(v);
-    }
-
-    protected abstract AbstractDOMRpcRoutingTableEntry newInstance(
-            Map<YangInstanceIdentifier, List<DOMRpcImplementation>> impls);
 }
diff --git a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/DOMActionRoutingTable.java b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/DOMActionRoutingTable.java
new file mode 100644 (file)
index 0000000..6fdfc12
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2018 ZTE Corp. 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.mdsal.dom.broker;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.LinkedListMultimap;
+import com.google.common.collect.ListMultimap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.opendaylight.mdsal.dom.api.DOMActionAvailabilityExtension.AvailabilityListener;
+import org.opendaylight.mdsal.dom.api.DOMActionImplementation;
+import org.opendaylight.mdsal.dom.api.DOMActionInstance;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
+import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
+import org.opendaylight.yangtools.yang.model.api.ActionNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
+
+
+/**
+ * Definition of Action routing table.
+ */
+@Beta
+@NonNullByDefault
+final class DOMActionRoutingTable extends AbstractDOMRoutingTable<DOMActionInstance, DOMDataTreeIdentifier,
+        DOMActionImplementation, AvailabilityListener, DOMActionRoutingTableEntry> {
+    static final DOMActionRoutingTable EMPTY = new DOMActionRoutingTable(ImmutableMap.of(), null);
+
+    private DOMActionRoutingTable(final Map<SchemaPath, DOMActionRoutingTableEntry> actions,
+            final SchemaContext schemaContext) {
+        super(actions, schemaContext);
+    }
+
+    @Override
+    protected DOMActionRoutingTable newInstance(final Map<SchemaPath, DOMActionRoutingTableEntry> operations,
+            final SchemaContext schemaContext) {
+        return new DOMActionRoutingTable(operations, schemaContext);
+    }
+
+    @Override
+    protected ListMultimap<SchemaPath, DOMDataTreeIdentifier> decomposeIdentifiers(
+            final Set<DOMActionInstance> instances) {
+        final ListMultimap<SchemaPath, DOMDataTreeIdentifier> ret = LinkedListMultimap.create();
+        for (DOMActionInstance instance : instances) {
+            instance.getDataTrees().forEach(id -> ret.put(instance.getType(), id));
+        }
+        return ret;
+    }
+
+    @Override
+    protected DOMActionRoutingTableEntry createOperationEntry(final SchemaContext context, final SchemaPath type,
+            final Map<DOMDataTreeIdentifier, List<DOMActionImplementation>> implementations) {
+        final ActionDefinition actionDef = findActionDefinition(context, type);
+        if (actionDef == null) {
+            //FIXME: return null directly instead of providing kind of unknown entry.
+            return null;
+        }
+
+        return new DOMActionRoutingTableEntry(type, implementations);
+    }
+
+    private static ActionDefinition findActionDefinition(final SchemaContext context, final SchemaPath path) {
+        final SchemaNode node = SchemaContextUtil.findDataSchemaNode(context, path.getParent());
+        if (node != null) {
+            if (node instanceof ActionNodeContainer) {
+                for (ActionDefinition action : ((ActionNodeContainer) node).getActions()) {
+                    if (action.getQName().equals(path.getLastComponent())) {
+                        return action;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+}
diff --git a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/DOMActionRoutingTableEntry.java b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/DOMActionRoutingTableEntry.java
new file mode 100644 (file)
index 0000000..f44d884
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2018 ZTE Corp. 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.mdsal.dom.broker;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.Maps;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.opendaylight.mdsal.dom.api.DOMActionAvailabilityExtension.AvailabilityListener;
+import org.opendaylight.mdsal.dom.api.DOMActionImplementation;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+/**
+ * Definition of Action routing table entry.
+ */
+@Beta
+final class DOMActionRoutingTableEntry extends AbstractDOMRoutingTableEntry<DOMDataTreeIdentifier,
+        DOMActionImplementation, AvailabilityListener> {
+    DOMActionRoutingTableEntry(final SchemaPath type,
+            final Map<DOMDataTreeIdentifier, List<DOMActionImplementation>> implementations) {
+        super(type, implementations);
+    }
+
+    @Override
+    protected Set<DOMDataTreeIdentifier> registeredIdentifiers(final AvailabilityListener listener) {
+        return Maps.filterValues(getImplementations(), list -> list.stream()
+            .anyMatch(listener::acceptsImplementation)).keySet();
+    }
+
+    @Override
+    protected Comparator<DOMActionImplementation> implComparator() {
+        return Comparator.comparingLong(DOMActionImplementation::invocationCost);
+    }
+
+    @Override
+    protected DOMActionRoutingTableEntry newInstance(
+        Map<DOMDataTreeIdentifier, List<DOMActionImplementation>> impls) {
+        return new DOMActionRoutingTableEntry(getType(), impls);
+    }
+}
index af7a8bf96aad8cc54e3e7a39f7925252e92bd685..0ddd34259c7c825442b8549c8404f9ef31c33784 100644 (file)
@@ -88,7 +88,7 @@ public final class DOMRpcRouter extends AbstractRegistration implements SchemaCo
     private synchronized void removeRpcImplementation(final DOMRpcImplementation implementation,
             final Set<DOMRpcIdentifier> rpcs) {
         final DOMRpcRoutingTable oldTable = routingTable;
-        final DOMRpcRoutingTable newTable = oldTable.remove(implementation, rpcs);
+        final DOMRpcRoutingTable newTable = (DOMRpcRoutingTable) oldTable.remove(implementation, rpcs);
         routingTable = newTable;
 
         listenerNotifier.execute(() -> notifyRemoved(newTable, implementation));
@@ -113,7 +113,7 @@ public final class DOMRpcRouter extends AbstractRegistration implements SchemaCo
     @Override
     public synchronized void onGlobalContextUpdated(final SchemaContext context) {
         final DOMRpcRoutingTable oldTable = routingTable;
-        final DOMRpcRoutingTable newTable = oldTable.setSchemaContext(context);
+        final DOMRpcRoutingTable newTable = (DOMRpcRoutingTable) oldTable.setSchemaContext(context);
         routingTable = newTable;
     }
 
@@ -171,7 +171,7 @@ public final class DOMRpcRouter extends AbstractRegistration implements SchemaCo
                 return;
             }
 
-            final Map<SchemaPath, Set<YangInstanceIdentifier>> rpcs = verifyNotNull(newTable.getRpcs(l));
+            final Map<SchemaPath, Set<YangInstanceIdentifier>> rpcs = verifyNotNull(newTable.getOperations(l));
             final MapDifference<SchemaPath, Set<YangInstanceIdentifier>> diff = Maps.difference(prevRpcs, rpcs);
 
             final Collection<DOMRpcIdentifier> added = new ArrayList<>();
@@ -197,7 +197,7 @@ public final class DOMRpcRouter extends AbstractRegistration implements SchemaCo
                 return;
             }
 
-            final Map<SchemaPath, Set<YangInstanceIdentifier>> rpcs = verifyNotNull(newTable.getRpcs(l));
+            final Map<SchemaPath, Set<YangInstanceIdentifier>> rpcs = verifyNotNull(newTable.getOperations(l));
             final MapDifference<SchemaPath, Set<YangInstanceIdentifier>> diff = Maps.difference(prevRpcs, rpcs);
 
             final Collection<DOMRpcIdentifier> removed = new ArrayList<>();
@@ -221,7 +221,7 @@ public final class DOMRpcRouter extends AbstractRegistration implements SchemaCo
     private final class RpcServiceFacade implements DOMRpcService {
         @Override
         public FluentFuture<DOMRpcResult> invokeRpc(final SchemaPath type, final NormalizedNode<?, ?> input) {
-            final AbstractDOMRpcRoutingTableEntry entry = routingTable.getEntry(type);
+            final AbstractDOMRpcRoutingTableEntry entry = (AbstractDOMRpcRoutingTableEntry) routingTable.getEntry(type);
             if (entry == null) {
                 return FluentFutures.immediateFailedFluentFuture(
                     new DOMRpcImplementationNotAvailableException("No implementation of RPC %s available", type));
@@ -234,7 +234,7 @@ public final class DOMRpcRouter extends AbstractRegistration implements SchemaCo
         public <T extends DOMRpcAvailabilityListener> ListenerRegistration<T> registerRpcListener(final T listener) {
             synchronized (DOMRpcRouter.this) {
                 final Registration<T> ret = new Registration<>(DOMRpcRouter.this, listener,
-                        routingTable.getRpcs(listener));
+                        routingTable.getOperations(listener));
                 final Builder<Registration<?>> b = ImmutableList.builder();
                 b.addAll(listeners);
                 b.add(ret);
@@ -259,7 +259,7 @@ public final class DOMRpcRouter extends AbstractRegistration implements SchemaCo
 
             synchronized (DOMRpcRouter.this) {
                 final DOMRpcRoutingTable oldTable = routingTable;
-                final DOMRpcRoutingTable newTable = oldTable.add(implementation, rpcs);
+                final DOMRpcRoutingTable newTable = (DOMRpcRoutingTable) oldTable.add(implementation, rpcs);
                 routingTable = newTable;
 
                 listenerNotifier.execute(() -> notifyAdded(newTable, implementation));
@@ -282,7 +282,7 @@ public final class DOMRpcRouter extends AbstractRegistration implements SchemaCo
             if (entry instanceof UnknownDOMRpcRoutingTableEntry) {
                 return FluentFutures.immediateFailedFluentFuture(
                     new DOMRpcImplementationNotAvailableException("SchemaPath %s is not resolved to an RPC",
-                        entry.getSchemaPath()));
+                        entry.getType()));
             } else if (entry instanceof RoutedDOMRpcRoutingTableEntry) {
                 return invokeRoutedRpc((RoutedDOMRpcRoutingTableEntry) entry, input);
             } else if (entry instanceof GlobalDOMRpcRoutingTableEntry) {
@@ -309,7 +309,7 @@ public final class DOMRpcRouter extends AbstractRegistration implements SchemaCo
                     final List<DOMRpcImplementation> specificImpls = entry.getImplementations(iid);
                     if (specificImpls != null) {
                         return specificImpls.get(0)
-                            .invokeRpc(DOMRpcIdentifier.create(entry.getSchemaPath(), iid), input);
+                            .invokeRpc(DOMRpcIdentifier.create(entry.getType(), iid), input);
                     }
 
                     LOG.debug("No implementation for context {} found will now look for wildcard id", iid);
@@ -321,7 +321,7 @@ public final class DOMRpcRouter extends AbstractRegistration implements SchemaCo
 
                     if (mayBeRemoteImpls != null) {
                         return mayBeRemoteImpls.get(0)
-                            .invokeRpc(DOMRpcIdentifier.create(entry.getSchemaPath(), iid), input);
+                            .invokeRpc(DOMRpcIdentifier.create(entry.getType(), iid), input);
                     }
 
                 } else {
@@ -336,7 +336,7 @@ public final class DOMRpcRouter extends AbstractRegistration implements SchemaCo
 
             return FluentFutures.immediateFailedFluentFuture(
                 new DOMRpcImplementationNotAvailableException("No implementation of RPC %s available",
-                    entry.getSchemaPath()));
+                    entry.getType()));
         }
 
         private static FluentFuture<DOMRpcResult> invokeGlobalRpc(final GlobalDOMRpcRoutingTableEntry entry,
index 382e3d2a070ce171fb841c26ac04a3f82b8b2424..432d3b2aeaa7cddaf4d09a8ffb1f59d0f2af6cb6 100644 (file)
@@ -7,23 +7,12 @@
  */
 package org.opendaylight.mdsal.dom.broker;
 
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableMap.Builder;
 import com.google.common.collect.LinkedListMultimap;
 import com.google.common.collect.ListMultimap;
-import com.google.common.collect.Maps;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Set;
-import org.eclipse.jdt.annotation.NonNull;
-import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.mdsal.dom.api.DOMRpcAvailabilityListener;
 import org.opendaylight.mdsal.dom.api.DOMRpcIdentifier;
 import org.opendaylight.mdsal.dom.api.DOMRpcImplementation;
@@ -35,115 +24,28 @@ import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 
-final class DOMRpcRoutingTable {
+final class DOMRpcRoutingTable extends AbstractDOMRoutingTable<DOMRpcIdentifier, YangInstanceIdentifier,
+        DOMRpcImplementation, DOMRpcAvailabilityListener, AbstractDOMRpcRoutingTableEntry> {
     static final DOMRpcRoutingTable EMPTY = new DOMRpcRoutingTable(ImmutableMap.of(), null);
 
-    private final Map<SchemaPath, AbstractDOMRpcRoutingTableEntry> rpcs;
-    private final SchemaContext schemaContext;
-
     private DOMRpcRoutingTable(final Map<SchemaPath, AbstractDOMRpcRoutingTableEntry> rpcs,
             final SchemaContext schemaContext) {
-        this.rpcs = Preconditions.checkNotNull(rpcs);
-        this.schemaContext = schemaContext;
-    }
-
-    DOMRpcRoutingTable setSchemaContext(final SchemaContext context) {
-        final Builder<SchemaPath, AbstractDOMRpcRoutingTableEntry> b = ImmutableMap.builder();
-
-        for (Entry<SchemaPath, AbstractDOMRpcRoutingTableEntry> e : rpcs.entrySet()) {
-            b.put(e.getKey(), createRpcEntry(context, e.getKey(), e.getValue().getImplementations()));
-        }
-
-        return new DOMRpcRoutingTable(b.build(), context);
-    }
-
-    DOMRpcRoutingTable add(final DOMRpcImplementation implementation, final Set<DOMRpcIdentifier> rpcsToAdd) {
-        if (rpcsToAdd.isEmpty()) {
-            return this;
-        }
-
-        // First decompose the identifiers to a multimap
-        final ListMultimap<SchemaPath, YangInstanceIdentifier> toAdd = decomposeIdentifiers(rpcsToAdd);
-
-        // Now iterate over existing entries, modifying them as appropriate...
-        final Builder<SchemaPath, AbstractDOMRpcRoutingTableEntry> mb = ImmutableMap.builder();
-        for (Entry<SchemaPath, AbstractDOMRpcRoutingTableEntry> re : this.rpcs.entrySet()) {
-            List<YangInstanceIdentifier> newRpcs = new ArrayList<>(toAdd.removeAll(re.getKey()));
-            if (!newRpcs.isEmpty()) {
-                final AbstractDOMRpcRoutingTableEntry ne = re.getValue().add(implementation, newRpcs);
-                mb.put(re.getKey(), ne);
-            } else {
-                mb.put(re);
-            }
-        }
-
-        // Finally add whatever is left in the decomposed multimap
-        for (Entry<SchemaPath, Collection<YangInstanceIdentifier>> e : toAdd.asMap().entrySet()) {
-            final Builder<YangInstanceIdentifier, List<DOMRpcImplementation>> vb = ImmutableMap.builder();
-            final List<DOMRpcImplementation> v = ImmutableList.of(implementation);
-            for (YangInstanceIdentifier i : e.getValue()) {
-                vb.put(i, v);
-            }
-
-            mb.put(e.getKey(), createRpcEntry(schemaContext, e.getKey(), vb.build()));
-        }
-
-        return new DOMRpcRoutingTable(mb.build(), schemaContext);
-    }
-
-    DOMRpcRoutingTable remove(final DOMRpcImplementation implementation, final Set<DOMRpcIdentifier> rpcIds) {
-        if (rpcIds.isEmpty()) {
-            return this;
-        }
-
-        // First decompose the identifiers to a multimap
-        final ListMultimap<SchemaPath, YangInstanceIdentifier> toRemove = decomposeIdentifiers(rpcIds);
-
-        // Now iterate over existing entries, modifying them as appropriate...
-        final Builder<SchemaPath, AbstractDOMRpcRoutingTableEntry> b = ImmutableMap.builder();
-        for (Entry<SchemaPath, AbstractDOMRpcRoutingTableEntry> e : this.rpcs.entrySet()) {
-            final List<YangInstanceIdentifier> removed = new ArrayList<>(toRemove.removeAll(e.getKey()));
-            if (!removed.isEmpty()) {
-                final AbstractDOMRpcRoutingTableEntry ne = e.getValue().remove(implementation, removed);
-                if (ne != null) {
-                    b.put(e.getKey(), ne);
-                }
-            } else {
-                b.put(e);
-            }
-        }
-
-        // All done, whatever is in toRemove, was not there in the first place
-        return new DOMRpcRoutingTable(b.build(), schemaContext);
+        super(rpcs, schemaContext);
     }
 
     boolean contains(final DOMRpcIdentifier input) {
-        final AbstractDOMRpcRoutingTableEntry contexts = rpcs.get(input.getType());
+        final AbstractDOMRpcRoutingTableEntry contexts = (AbstractDOMRpcRoutingTableEntry) getEntry(input.getType());
         return contexts != null && contexts.containsContext(input.getContextReference());
     }
 
-    @VisibleForTesting
-    Map<SchemaPath, Set<YangInstanceIdentifier>> getRpcs() {
-        return Maps.transformValues(rpcs, AbstractDOMRpcRoutingTableEntry::registeredIdentifiers);
-    }
-
-    Map<SchemaPath, Set<YangInstanceIdentifier>> getRpcs(final DOMRpcAvailabilityListener listener) {
-        final Map<SchemaPath, Set<YangInstanceIdentifier>> ret = new HashMap<>(rpcs.size());
-        for (Entry<SchemaPath, AbstractDOMRpcRoutingTableEntry> e : rpcs.entrySet()) {
-            final Set<YangInstanceIdentifier> ids = e.getValue().registeredIdentifiers(listener);
-            if (!ids.isEmpty()) {
-                ret.put(e.getKey(), ids);
-            }
-        }
-
-        return ret;
-    }
-
-    @Nullable AbstractDOMRpcRoutingTableEntry getEntry(final @NonNull SchemaPath type) {
-        return rpcs.get(type);
+    @Override
+    protected AbstractDOMRoutingTable newInstance(final Map<SchemaPath, AbstractDOMRpcRoutingTableEntry> operations,
+            final SchemaContext schemaContext) {
+        return new DOMRpcRoutingTable(operations, schemaContext);
     }
 
-    private static ListMultimap<SchemaPath, YangInstanceIdentifier> decomposeIdentifiers(
+    @Override
+    protected ListMultimap<SchemaPath, YangInstanceIdentifier> decomposeIdentifiers(
             final Set<DOMRpcIdentifier> rpcs) {
         final ListMultimap<SchemaPath, YangInstanceIdentifier> ret = LinkedListMultimap.create();
         for (DOMRpcIdentifier i : rpcs) {
@@ -152,6 +54,23 @@ final class DOMRpcRoutingTable {
         return ret;
     }
 
+    @Override
+    AbstractDOMRpcRoutingTableEntry createOperationEntry(final SchemaContext context, final SchemaPath key,
+            final Map<YangInstanceIdentifier, List<DOMRpcImplementation>> implementations) {
+        final RpcDefinition rpcDef = findRpcDefinition(context, key);
+        if (rpcDef == null) {
+            return new UnknownDOMRpcRoutingTableEntry(key, implementations);
+        }
+
+        final RpcRoutingStrategy strategy = RpcRoutingStrategy.from(rpcDef);
+        if (strategy.isContextBasedRouted()) {
+            return new RoutedDOMRpcRoutingTableEntry(rpcDef, YangInstanceIdentifier.of(strategy.getLeaf()),
+                implementations);
+        }
+
+        return new GlobalDOMRpcRoutingTableEntry(rpcDef, implementations);
+    }
+
     private static RpcDefinition findRpcDefinition(final SchemaContext context, final SchemaPath schemaPath) {
         if (context != null) {
             final QName qname = schemaPath.getPathFromRoot().iterator().next();
@@ -167,20 +86,4 @@ final class DOMRpcRoutingTable {
 
         return null;
     }
-
-    private static AbstractDOMRpcRoutingTableEntry createRpcEntry(final SchemaContext context, final SchemaPath key,
-            final Map<YangInstanceIdentifier, List<DOMRpcImplementation>> implementations) {
-        final RpcDefinition rpcDef = findRpcDefinition(context, key);
-        if (rpcDef == null) {
-            return new UnknownDOMRpcRoutingTableEntry(key, implementations);
-        }
-
-        final RpcRoutingStrategy strategy = RpcRoutingStrategy.from(rpcDef);
-        if (strategy.isContextBasedRouted()) {
-            return new RoutedDOMRpcRoutingTableEntry(rpcDef, YangInstanceIdentifier.of(strategy.getLeaf()),
-                implementations);
-        }
-
-        return new GlobalDOMRpcRoutingTableEntry(rpcDef, implementations);
-    }
 }
index e830f7a91e739bcc1eb254ff35e1336a681d4919..13bd2932516763e5a4b3c3cced5ad74d9d5b12b6 100644 (file)
@@ -31,6 +31,6 @@ final class UnknownDOMRpcRoutingTableEntry extends AbstractDOMRpcRoutingTableEnt
     @Override
     protected UnknownDOMRpcRoutingTableEntry newInstance(final Map<YangInstanceIdentifier,
             List<DOMRpcImplementation>> impls) {
-        return new UnknownDOMRpcRoutingTableEntry(getSchemaPath(), impls);
+        return new UnknownDOMRpcRoutingTableEntry(getType(), impls);
     }
 }
index 9c62d0daad69f2d23706954336d46394a842cf47..fd9461b6d90a295be48299274736a144d7cf4aff 100644 (file)
@@ -27,17 +27,17 @@ public class DOMRpcRouterTest extends TestUtils {
     public void registerRpcImplementation() {
         try (DOMRpcRouter rpcRouter = new DOMRpcRouter()) {
             DOMRpcRoutingTable routingTable = rpcRouter.routingTable();
-            assertFalse(routingTable.getRpcs().containsKey(SchemaPath.ROOT));
+            assertFalse(routingTable.getOperations().containsKey(SchemaPath.ROOT));
 
             rpcRouter.getRpcProviderService().registerRpcImplementation(getTestRpcImplementation(),
                 DOMRpcIdentifier.create(SchemaPath.ROOT, null));
             routingTable = rpcRouter.routingTable();
-            assertTrue(routingTable.getRpcs().containsKey(SchemaPath.ROOT));
+            assertTrue(routingTable.getOperations().containsKey(SchemaPath.ROOT));
 
             rpcRouter.getRpcProviderService().registerRpcImplementation(getTestRpcImplementation(),
                 DOMRpcIdentifier.create(SchemaPath.SAME, null));
             routingTable = rpcRouter.routingTable();
-            assertTrue(routingTable.getRpcs().containsKey(SchemaPath.SAME));
+            assertTrue(routingTable.getOperations().containsKey(SchemaPath.SAME));
         }
     }
 
index 83e881e91fea7fb2ff257091577b061935719800..512a7687e489902e89f11bb17ebfba3d190e4dd7 100644 (file)
@@ -43,7 +43,7 @@ public class GlobalDOMRpcRoutingTableEntryTest extends TestUtils {
         rpcImplementation.add(getTestRpcImplementation());
         rpcImplementations.put(yangInstanceIdentifier, rpcImplementation);
 
-        assertTrue(globalDOMRpcRoutingTableEntry.getSchemaPath().equals(SchemaPath.ROOT));
+        assertTrue(globalDOMRpcRoutingTableEntry.getType().equals(SchemaPath.ROOT));
         assertTrue(globalDOMRpcRoutingTableEntry.getImplementations().isEmpty());
         assertFalse(globalDOMRpcRoutingTableEntry.newInstance(rpcImplementations).getImplementations().isEmpty());
         assertTrue(globalDOMRpcRoutingTableEntry.newInstance(rpcImplementations).getImplementations().containsValue(
index 319841a4cf0d37ea0efb37c41efa6ec2539a22ad..7e0e829ae6d61fb9de83f0756e9a0cc697554d94 100644 (file)
@@ -48,9 +48,9 @@ public class UnknownDOMRpcRoutingTableEntryTest extends TestUtils {
         addList1.add(YangInstanceIdentifier.of(TestModel.TEST_QNAME));
         addList2.add(YangInstanceIdentifier.of(TestModel.TEST2_QNAME));
 
-        final AbstractDOMRpcRoutingTableEntry tst = test.add(testClass, addList1);
-        final AbstractDOMRpcRoutingTableEntry tst1 = tst.add(testClass, addList2);
-        final AbstractDOMRpcRoutingTableEntry tst2 = tst1.remove(testClass, addList1);
+        final AbstractDOMRpcRoutingTableEntry tst = (AbstractDOMRpcRoutingTableEntry) test.add(testClass, addList1);
+        final AbstractDOMRpcRoutingTableEntry tst1 = (AbstractDOMRpcRoutingTableEntry) tst.add(testClass, addList2);
+        final AbstractDOMRpcRoutingTableEntry tst2 = (AbstractDOMRpcRoutingTableEntry) tst1.remove(testClass, addList1);
 
         assertEquals(1, test.getImplementations().size());
         assertEquals(2, tst.getImplementations().size());