From 1511d7eeb7be3c4cf6be504f4e146cb9ad4a7d3a Mon Sep 17 00:00:00 2001 From: Jie Han Date: Tue, 24 Jul 2018 16:43:55 +0800 Subject: [PATCH] Add DOMActionRoutingTable and DOMActionRoutingTableEntry - Split out AbstractDOMRoutingTable and AbstractDOMRoutingTableEntry - Provide Action routing table and entry Change-Id: I6606b2b280344e52d58fb7b6fbec0e76231c2786 Signed-off-by: Jie Han --- .../dom/broker/AbstractDOMRoutingTable.java | 157 ++++++++++++++++++ .../broker/AbstractDOMRoutingTableEntry.java | 114 +++++++++++++ .../AbstractDOMRpcRoutingTableEntry.java | 96 ++--------- .../dom/broker/DOMActionRoutingTable.java | 85 ++++++++++ .../broker/DOMActionRoutingTableEntry.java | 48 ++++++ .../mdsal/dom/broker/DOMRpcRouter.java | 22 +-- .../mdsal/dom/broker/DOMRpcRoutingTable.java | 151 +++-------------- .../UnknownDOMRpcRoutingTableEntry.java | 2 +- .../mdsal/dom/broker/DOMRpcRouterTest.java | 6 +- .../GlobalDOMRpcRoutingTableEntryTest.java | 2 +- .../UnknownDOMRpcRoutingTableEntryTest.java | 6 +- 11 files changed, 461 insertions(+), 228 deletions(-) create mode 100644 dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/AbstractDOMRoutingTable.java create mode 100644 dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/AbstractDOMRoutingTableEntry.java create mode 100644 dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/DOMActionRoutingTable.java create mode 100644 dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/DOMActionRoutingTableEntry.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 index 0000000000..7a4eb83116 --- /dev/null +++ b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/AbstractDOMRoutingTable.java @@ -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 instance type of RPC or Acton + * @param identifier type of RPC or Acton + * @param implementation type of RPC or Acton + * @param listener type of RPC or Acton + * @param routing entry type of RPC or Acton + */ +@Beta +abstract class AbstractDOMRoutingTable> { + private final Map operations; + private final SchemaContext schemaContext; + + AbstractDOMRoutingTable(final Map operations, + final SchemaContext schemaContext) { + this.operations = Preconditions.checkNotNull(operations); + this.schemaContext = schemaContext; + } + + AbstractDOMRoutingTable setSchemaContext(final SchemaContext context) { + final Builder b = ImmutableMap.builder(); + + for (Entry 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 oprsToAdd) { + if (oprsToAdd.isEmpty()) { + return this; + } + + // First decompose the identifiers to a multimap + final ListMultimap toAdd = decomposeIdentifiers(oprsToAdd); + + // Now iterate over existing entries, modifying them as appropriate... + final Builder mb = ImmutableMap.builder(); + for (Entry re : this.operations.entrySet()) { + List 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> e : toAdd.asMap().entrySet()) { + final Builder> vb = ImmutableMap.builder(); + final List 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 instances) { + if (instances.isEmpty()) { + return this; + } + + // First decompose the identifiers to a multimap + final ListMultimap toRemove = decomposeIdentifiers(instances); + + // Now iterate over existing entries, modifying them as appropriate... + final Builder b = ImmutableMap.builder(); + for (Entry e : this.operations.entrySet()) { + final List 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> getOperations() { + return Maps.transformValues(operations, AbstractDOMRoutingTableEntry::registeredIdentifiers); + } + + Map> getOperations(final L listener) { + final Map> ret = new HashMap<>(operations.size()); + for (Entry e : operations.entrySet()) { + final Set 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 operations, SchemaContext schemaContext); + + abstract ListMultimap decomposeIdentifiers(Set instances); + + abstract E createOperationEntry(SchemaContext context, SchemaPath key, + Map> 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 index 0000000000..b783ab6a04 --- /dev/null +++ b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/AbstractDOMRoutingTableEntry.java @@ -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 identifier type of RPC or Acton + * @param implementation type of RPC or Acton + * @param listener type of RPC or Acton + */ +@Beta +abstract class AbstractDOMRoutingTableEntry { + private final Map> implementations; + private final SchemaPath type; + + AbstractDOMRoutingTableEntry(final SchemaPath type, final Map> implementations) { + this.type = Preconditions.checkNotNull(type); + this.implementations = Preconditions.checkNotNull(implementations); + } + + SchemaPath getType() { + return type; + } + + List getImplementations(final D identifier) { + return implementations.get(identifier); + } + + Map> getImplementations() { + return implementations; + } + + @VisibleForTesting + Set registeredIdentifiers() { + return implementations.keySet(); + } + + protected abstract Set 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 newOprs) { + final Builder> vb = ImmutableMap.builder(); + for (final Entry> ve : implementations.entrySet()) { + if (newOprs.remove(ve.getKey())) { + final List 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 impl = new ArrayList<>(1); + impl.add(implementation); + vb.put(ii, impl); + } + + return newInstance(vb.build()); + } + + AbstractDOMRoutingTableEntry remove(final M implementation, final List removed) { + final Builder> vb = ImmutableMap.builder(); + for (final Entry> ve : implementations.entrySet()) { + if (removed.remove(ve.getKey())) { + final List 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> v = vb.build(); + return v.isEmpty() ? null : newInstance(vb.build()); + } + + protected abstract Comparator implComparator(); + + protected abstract AbstractDOMRoutingTableEntry newInstance(Map> impls); +} diff --git a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/AbstractDOMRpcRoutingTableEntry.java b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/AbstractDOMRpcRoutingTableEntry.java index 32f8ba6053..527f19a935 100644 --- a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/AbstractDOMRpcRoutingTableEntry.java +++ b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/AbstractDOMRpcRoutingTableEntry.java @@ -7,117 +7,43 @@ */ 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> implementations; +abstract class AbstractDOMRpcRoutingTableEntry extends AbstractDOMRoutingTableEntry { private final DOMRpcIdentifier rpcId; AbstractDOMRpcRoutingTableEntry(final DOMRpcIdentifier rpcId, final Map> implementations) { + List> 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 getImplementations(final YangInstanceIdentifier context) { - return implementations.get(context); - } - - final Map> getImplementations() { - return implementations; - } - final boolean containsContext(final YangInstanceIdentifier contextReference) { - return implementations.containsKey(contextReference); + return getImplementations().containsKey(contextReference); } - final Set registeredIdentifiers(final DOMRpcAvailabilityListener listener) { - return Maps.filterValues(implementations, list -> list.stream() + @Override + protected final Set registeredIdentifiers(final DOMRpcAvailabilityListener listener) { + return Maps.filterValues(getImplementations(), list -> list.stream() .anyMatch(listener::acceptsImplementation)).keySet(); } - @VisibleForTesting - final Set 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 newRpcs) { - final Builder> vb = ImmutableMap.builder(); - for (final Entry> ve : implementations.entrySet()) { - if (newRpcs.remove(ve.getKey())) { - final List 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 impl = new ArrayList<>(1); - impl.add(implementation); - vb.put(ii, impl); - } - - return newInstance(vb.build()); + @Override + protected Comparator implComparator() { + return Comparator.comparingLong(DOMRpcImplementation::invocationCost); } - - final AbstractDOMRpcRoutingTableEntry remove( - final DOMRpcImplementation implementation, final List removed) { - final Builder> vb = ImmutableMap.builder(); - for (final Entry> ve : implementations.entrySet()) { - if (removed.remove(ve.getKey())) { - final List 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> v = vb.build(); - return v.isEmpty() ? null : newInstance(v); - } - - protected abstract AbstractDOMRpcRoutingTableEntry newInstance( - Map> 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 index 0000000000..6fdfc124a2 --- /dev/null +++ b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/DOMActionRoutingTable.java @@ -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 { + static final DOMActionRoutingTable EMPTY = new DOMActionRoutingTable(ImmutableMap.of(), null); + + private DOMActionRoutingTable(final Map actions, + final SchemaContext schemaContext) { + super(actions, schemaContext); + } + + @Override + protected DOMActionRoutingTable newInstance(final Map operations, + final SchemaContext schemaContext) { + return new DOMActionRoutingTable(operations, schemaContext); + } + + @Override + protected ListMultimap decomposeIdentifiers( + final Set instances) { + final ListMultimap 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> 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 index 0000000000..f44d884b66 --- /dev/null +++ b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/DOMActionRoutingTableEntry.java @@ -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 { + DOMActionRoutingTableEntry(final SchemaPath type, + final Map> implementations) { + super(type, implementations); + } + + @Override + protected Set registeredIdentifiers(final AvailabilityListener listener) { + return Maps.filterValues(getImplementations(), list -> list.stream() + .anyMatch(listener::acceptsImplementation)).keySet(); + } + + @Override + protected Comparator implComparator() { + return Comparator.comparingLong(DOMActionImplementation::invocationCost); + } + + @Override + protected DOMActionRoutingTableEntry newInstance( + Map> impls) { + return new DOMActionRoutingTableEntry(getType(), impls); + } +} diff --git a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/DOMRpcRouter.java b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/DOMRpcRouter.java index af7a8bf96a..0ddd34259c 100644 --- a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/DOMRpcRouter.java +++ b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/DOMRpcRouter.java @@ -88,7 +88,7 @@ public final class DOMRpcRouter extends AbstractRegistration implements SchemaCo private synchronized void removeRpcImplementation(final DOMRpcImplementation implementation, final Set 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> rpcs = verifyNotNull(newTable.getRpcs(l)); + final Map> rpcs = verifyNotNull(newTable.getOperations(l)); final MapDifference> diff = Maps.difference(prevRpcs, rpcs); final Collection added = new ArrayList<>(); @@ -197,7 +197,7 @@ public final class DOMRpcRouter extends AbstractRegistration implements SchemaCo return; } - final Map> rpcs = verifyNotNull(newTable.getRpcs(l)); + final Map> rpcs = verifyNotNull(newTable.getOperations(l)); final MapDifference> diff = Maps.difference(prevRpcs, rpcs); final Collection removed = new ArrayList<>(); @@ -221,7 +221,7 @@ public final class DOMRpcRouter extends AbstractRegistration implements SchemaCo private final class RpcServiceFacade implements DOMRpcService { @Override public FluentFuture 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 ListenerRegistration registerRpcListener(final T listener) { synchronized (DOMRpcRouter.this) { final Registration ret = new Registration<>(DOMRpcRouter.this, listener, - routingTable.getRpcs(listener)); + routingTable.getOperations(listener)); final Builder> 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 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 invokeGlobalRpc(final GlobalDOMRpcRoutingTableEntry entry, diff --git a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/DOMRpcRoutingTable.java b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/DOMRpcRoutingTable.java index 382e3d2a07..432d3b2aea 100644 --- a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/DOMRpcRoutingTable.java +++ b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/DOMRpcRoutingTable.java @@ -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 { static final DOMRpcRoutingTable EMPTY = new DOMRpcRoutingTable(ImmutableMap.of(), null); - private final Map rpcs; - private final SchemaContext schemaContext; - private DOMRpcRoutingTable(final Map rpcs, final SchemaContext schemaContext) { - this.rpcs = Preconditions.checkNotNull(rpcs); - this.schemaContext = schemaContext; - } - - DOMRpcRoutingTable setSchemaContext(final SchemaContext context) { - final Builder b = ImmutableMap.builder(); - - for (Entry 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 rpcsToAdd) { - if (rpcsToAdd.isEmpty()) { - return this; - } - - // First decompose the identifiers to a multimap - final ListMultimap toAdd = decomposeIdentifiers(rpcsToAdd); - - // Now iterate over existing entries, modifying them as appropriate... - final Builder mb = ImmutableMap.builder(); - for (Entry re : this.rpcs.entrySet()) { - List 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> e : toAdd.asMap().entrySet()) { - final Builder> vb = ImmutableMap.builder(); - final List 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 rpcIds) { - if (rpcIds.isEmpty()) { - return this; - } - - // First decompose the identifiers to a multimap - final ListMultimap toRemove = decomposeIdentifiers(rpcIds); - - // Now iterate over existing entries, modifying them as appropriate... - final Builder b = ImmutableMap.builder(); - for (Entry e : this.rpcs.entrySet()) { - final List 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> getRpcs() { - return Maps.transformValues(rpcs, AbstractDOMRpcRoutingTableEntry::registeredIdentifiers); - } - - Map> getRpcs(final DOMRpcAvailabilityListener listener) { - final Map> ret = new HashMap<>(rpcs.size()); - for (Entry e : rpcs.entrySet()) { - final Set 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 operations, + final SchemaContext schemaContext) { + return new DOMRpcRoutingTable(operations, schemaContext); } - private static ListMultimap decomposeIdentifiers( + @Override + protected ListMultimap decomposeIdentifiers( final Set rpcs) { final ListMultimap 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> 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> 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); - } } diff --git a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/UnknownDOMRpcRoutingTableEntry.java b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/UnknownDOMRpcRoutingTableEntry.java index e830f7a91e..13bd293251 100644 --- a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/UnknownDOMRpcRoutingTableEntry.java +++ b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/UnknownDOMRpcRoutingTableEntry.java @@ -31,6 +31,6 @@ final class UnknownDOMRpcRoutingTableEntry extends AbstractDOMRpcRoutingTableEnt @Override protected UnknownDOMRpcRoutingTableEntry newInstance(final Map> impls) { - return new UnknownDOMRpcRoutingTableEntry(getSchemaPath(), impls); + return new UnknownDOMRpcRoutingTableEntry(getType(), impls); } } diff --git a/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/DOMRpcRouterTest.java b/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/DOMRpcRouterTest.java index 9c62d0daad..fd9461b6d9 100644 --- a/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/DOMRpcRouterTest.java +++ b/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/DOMRpcRouterTest.java @@ -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)); } } diff --git a/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/GlobalDOMRpcRoutingTableEntryTest.java b/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/GlobalDOMRpcRoutingTableEntryTest.java index 83e881e91f..512a7687e4 100644 --- a/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/GlobalDOMRpcRoutingTableEntryTest.java +++ b/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/GlobalDOMRpcRoutingTableEntryTest.java @@ -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( diff --git a/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/UnknownDOMRpcRoutingTableEntryTest.java b/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/UnknownDOMRpcRoutingTableEntryTest.java index 319841a4cf..7e0e829ae6 100644 --- a/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/UnknownDOMRpcRoutingTableEntryTest.java +++ b/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/UnknownDOMRpcRoutingTableEntryTest.java @@ -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()); -- 2.36.6