--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
*/
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);
}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
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));
@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;
}
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<>();
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<>();
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));
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);
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));
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) {
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);
if (mayBeRemoteImpls != null) {
return mayBeRemoteImpls.get(0)
- .invokeRpc(DOMRpcIdentifier.create(entry.getSchemaPath(), iid), input);
+ .invokeRpc(DOMRpcIdentifier.create(entry.getType(), iid), input);
}
} else {
return FluentFutures.immediateFailedFluentFuture(
new DOMRpcImplementationNotAvailableException("No implementation of RPC %s available",
- entry.getSchemaPath()));
+ entry.getType()));
}
private static FluentFuture<DOMRpcResult> invokeGlobalRpc(final GlobalDOMRpcRoutingTableEntry entry,
*/
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;
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) {
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();
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);
- }
}
@Override
protected UnknownDOMRpcRoutingTableEntry newInstance(final Map<YangInstanceIdentifier,
List<DOMRpcImplementation>> impls) {
- return new UnknownDOMRpcRoutingTableEntry(getSchemaPath(), impls);
+ return new UnknownDOMRpcRoutingTableEntry(getType(), impls);
}
}
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));
}
}
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(
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());