X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=dom%2Fmdsal-dom-broker%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fmdsal%2Fdom%2Fbroker%2FDOMRpcRouter.java;h=ef656b8634277e7749db92e32a32abff0255c954;hb=refs%2Fchanges%2F16%2F97116%2F5;hp=48c8525ba056e7e64e272277d1e6a8df2df38a20;hpb=4b652dbcfd5878cb0aace36780bbc7a1ee8dd025;p=mdsal.git 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 48c8525ba0..ef656b8634 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 @@ -7,33 +7,52 @@ */ package org.opendaylight.mdsal.dom.broker; +import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Verify.verifyNotNull; import static java.util.Objects.requireNonNull; import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ClassToInstanceMap; import com.google.common.collect.Collections2; +import com.google.common.collect.ImmutableClassToInstanceMap; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableList.Builder; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.MapDifference; import com.google.common.collect.MapDifference.ValueDifference; import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; +import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Optional; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; -import javax.annotation.concurrent.GuardedBy; +import javax.annotation.PreDestroy; +import javax.inject.Inject; +import javax.inject.Singleton; +import org.checkerframework.checker.lock.qual.GuardedBy; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.opendaylight.mdsal.dom.api.DOMActionAvailabilityExtension; +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.DOMActionNotAvailableException; +import org.opendaylight.mdsal.dom.api.DOMActionProviderService; +import org.opendaylight.mdsal.dom.api.DOMActionResult; +import org.opendaylight.mdsal.dom.api.DOMActionService; +import org.opendaylight.mdsal.dom.api.DOMActionServiceExtension; +import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier; import org.opendaylight.mdsal.dom.api.DOMRpcAvailabilityListener; -import org.opendaylight.mdsal.dom.api.DOMRpcException; import org.opendaylight.mdsal.dom.api.DOMRpcIdentifier; import org.opendaylight.mdsal.dom.api.DOMRpcImplementation; import org.opendaylight.mdsal.dom.api.DOMRpcImplementationNotAvailableException; @@ -44,39 +63,95 @@ import org.opendaylight.mdsal.dom.api.DOMRpcService; import org.opendaylight.mdsal.dom.api.DOMSchemaService; import org.opendaylight.mdsal.dom.spi.AbstractDOMRpcImplementationRegistration; import org.opendaylight.yangtools.concepts.AbstractListenerRegistration; +import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; import org.opendaylight.yangtools.concepts.AbstractRegistration; import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.concepts.ObjectRegistration; +import org.opendaylight.yangtools.concepts.Registration; +import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; -import org.opendaylight.yangtools.yang.model.api.SchemaPath; - -public final class DOMRpcRouter extends AbstractRegistration implements SchemaContextListener { +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes; +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContextListener; +import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.RequireServiceComponentRuntime; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Singleton +@Component(immediate = true, service = DOMRpcRouterServices.class) +@RequireServiceComponentRuntime +public final class DOMRpcRouter extends AbstractRegistration + implements DOMRpcRouterServices, EffectiveModelContextListener { + private static final Logger LOG = LoggerFactory.getLogger(DOMRpcRouter.class); private static final ThreadFactory THREAD_FACTORY = new ThreadFactoryBuilder().setNameFormat( "DOMRpcRouter-listener-%s").setDaemon(true).build(); private final ExecutorService listenerNotifier = Executors.newSingleThreadExecutor(THREAD_FACTORY); - private final DOMRpcProviderService rpcProviderService = new RpcProviderServiceFacade(); - private final DOMRpcService rpcService = new RpcServiceFacade(); + private final @NonNull DOMActionProviderService actionProviderService = new ActionProviderServiceFacade(); + private final @NonNull DOMActionService actionService = new ActionServiceFacade(); + private final @NonNull DOMRpcProviderService rpcProviderService = new RpcProviderServiceFacade(); + private final @NonNull DOMRpcService rpcService = new RpcServiceFacade(); + + @GuardedBy("this") + private ImmutableList> listeners = ImmutableList.of(); @GuardedBy("this") - private Collection> listeners = Collections.emptyList(); + private ImmutableList> actionListeners = ImmutableList.of(); private volatile DOMRpcRoutingTable routingTable = DOMRpcRoutingTable.EMPTY; - private ListenerRegistration listenerRegistration; + private volatile DOMActionRoutingTable actionRoutingTable = DOMActionRoutingTable.EMPTY; + + private Registration listenerRegistration; + + @Deprecated + @VisibleForTesting + // FIXME: 9.0.0: make this constructor package-private + public DOMRpcRouter() { + + } + + @Inject + @Activate + public DOMRpcRouter(@Reference final DOMSchemaService schemaService) { + listenerRegistration = schemaService.registerSchemaContextListener(this); + LOG.info("DOM RPC/Action router started"); + } + @Deprecated(forRemoval = true) public static DOMRpcRouter newInstance(final DOMSchemaService schemaService) { - final DOMRpcRouter rpcRouter = new DOMRpcRouter(); - rpcRouter.listenerRegistration = schemaService.registerSchemaContextListener(rpcRouter); - return rpcRouter; + return new DOMRpcRouter(schemaService); } + @PreDestroy + @Deactivate + public void shutdown() { + close(); + } + + @Override + public DOMActionService getActionService() { + return actionService; + } + + @Override + public DOMActionProviderService getActionProviderService() { + return actionProviderService; + } + + @Override public DOMRpcService getRpcService() { return rpcService; } + @Override public DOMRpcProviderService getRpcProviderService() { return rpcProviderService; } @@ -84,33 +159,84 @@ 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)); } + private synchronized void removeRpcImplementations(final Map map) { + final DOMRpcRoutingTable oldTable = routingTable; + final DOMRpcRoutingTable newTable = (DOMRpcRoutingTable) oldTable.removeAll(map); + routingTable = newTable; + + listenerNotifier.execute(() -> notifyRemoved(newTable, map.values())); + } + + private synchronized void removeActionImplementation(final DOMActionImplementation implementation, + final Set actions) { + final DOMActionRoutingTable oldTable = actionRoutingTable; + final DOMActionRoutingTable newTable = (DOMActionRoutingTable) oldTable.remove(implementation, actions); + actionRoutingTable = newTable; + + listenerNotifier.execute(() -> notifyActionChanged(newTable, implementation)); + } + private synchronized void removeListener(final ListenerRegistration reg) { listeners = ImmutableList.copyOf(Collections2.filter(listeners, input -> !reg.equals(input))); } + private synchronized void removeActionListener(final ListenerRegistration reg) { + actionListeners = ImmutableList.copyOf(Collections2.filter(actionListeners, input -> !reg.equals(input))); + } + private synchronized void notifyAdded(final DOMRpcRoutingTable newTable, final DOMRpcImplementation impl) { - for (Registration l : listeners) { + for (RegImpl l : listeners) { l.addRpc(newTable, impl); } } + private synchronized void notifyAdded(final DOMRpcRoutingTable newTable, + final Collection impls) { + for (RegImpl l : listeners) { + for (DOMRpcImplementation impl : impls) { + l.addRpc(newTable, impl); + } + } + } + private synchronized void notifyRemoved(final DOMRpcRoutingTable newTable, final DOMRpcImplementation impl) { - for (Registration l : listeners) { + for (RegImpl l : listeners) { l.removeRpc(newTable, impl); } } + private synchronized void notifyRemoved(final DOMRpcRoutingTable newTable, + final Collection impls) { + for (RegImpl l : listeners) { + for (DOMRpcImplementation impl : impls) { + l.removeRpc(newTable, impl); + } + } + } + + private synchronized void notifyActionChanged(final DOMActionRoutingTable newTable, + final DOMActionImplementation impl) { + for (ActionRegistration l : actionListeners) { + l.actionChanged(newTable, impl); + } + } + @Override - public synchronized void onGlobalContextUpdated(final SchemaContext context) { + public synchronized void onModelContextUpdated(final EffectiveModelContext newModelContext) { final DOMRpcRoutingTable oldTable = routingTable; - final DOMRpcRoutingTable newTable = oldTable.setSchemaContext(context); + final DOMRpcRoutingTable newTable = (DOMRpcRoutingTable) oldTable.setSchemaContext(newModelContext); routingTable = newTable; + + final DOMActionRoutingTable oldActionTable = actionRoutingTable; + final DOMActionRoutingTable newActionTable = + (DOMActionRoutingTable) oldActionTable.setSchemaContext(newModelContext); + actionRoutingTable = newActionTable; } @Override @@ -120,26 +246,29 @@ public final class DOMRpcRouter extends AbstractRegistration implements SchemaCo listenerRegistration = null; } listenerNotifier.shutdown(); + LOG.info("DOM RPC/Action router stopped"); } @VisibleForTesting - Collection listeners() { + synchronized List listeners() { return listeners; } + @VisibleForTesting + synchronized List actionListeners() { + return actionListeners; + } + @VisibleForTesting DOMRpcRoutingTable routingTable() { return routingTable; } - private static final class Registration - extends AbstractListenerRegistration { - - private Map> prevRpcs; + private static final class RegImpl extends AbstractListenerRegistration { + private Map> prevRpcs; private DOMRpcRouter router; - Registration(final DOMRpcRouter router, final T listener, - final Map> rpcs) { + RegImpl(final DOMRpcRouter router, final T listener, final Map> rpcs) { super(listener); this.router = requireNonNull(router); this.prevRpcs = requireNonNull(rpcs); @@ -152,8 +281,8 @@ public final class DOMRpcRouter extends AbstractRegistration implements SchemaCo } void initialTable() { - final Collection added = new ArrayList<>(); - for (Entry> e : prevRpcs.entrySet()) { + final List added = new ArrayList<>(); + for (Entry> e : prevRpcs.entrySet()) { added.addAll(Collections2.transform(e.getValue(), i -> DOMRpcIdentifier.create(e.getKey(), i))); } if (!added.isEmpty()) { @@ -167,15 +296,14 @@ public final class DOMRpcRouter extends AbstractRegistration implements SchemaCo return; } - final Map> rpcs = verifyNotNull(newTable.getRpcs(l)); - final MapDifference> diff = Maps.difference(prevRpcs, rpcs); + final Map> rpcs = verifyNotNull(newTable.getOperations(l)); + final MapDifference> diff = Maps.difference(prevRpcs, rpcs); - final Collection added = new ArrayList<>(); - for (Entry> e : diff.entriesOnlyOnRight().entrySet()) { + final List added = new ArrayList<>(); + for (Entry> e : diff.entriesOnlyOnRight().entrySet()) { added.addAll(Collections2.transform(e.getValue(), i -> DOMRpcIdentifier.create(e.getKey(), i))); } - for (Entry>> e : - diff.entriesDiffering().entrySet()) { + for (Entry>> e : diff.entriesDiffering().entrySet()) { for (YangInstanceIdentifier i : Sets.difference(e.getValue().rightValue(), e.getValue().leftValue())) { added.add(DOMRpcIdentifier.create(e.getKey(), i)); } @@ -193,15 +321,14 @@ public final class DOMRpcRouter extends AbstractRegistration implements SchemaCo return; } - final Map> rpcs = verifyNotNull(newTable.getRpcs(l)); - final MapDifference> diff = Maps.difference(prevRpcs, rpcs); + final Map> rpcs = verifyNotNull(newTable.getOperations(l)); + final MapDifference> diff = Maps.difference(prevRpcs, rpcs); - final Collection removed = new ArrayList<>(); - for (Entry> e : diff.entriesOnlyOnLeft().entrySet()) { + final List removed = new ArrayList<>(); + for (Entry> e : diff.entriesOnlyOnLeft().entrySet()) { removed.addAll(Collections2.transform(e.getValue(), i -> DOMRpcIdentifier.create(e.getKey(), i))); } - for (Entry>> e : - diff.entriesDiffering().entrySet()) { + for (Entry>> e : diff.entriesDiffering().entrySet()) { for (YangInstanceIdentifier i : Sets.difference(e.getValue().leftValue(), e.getValue().rightValue())) { removed.add(DOMRpcIdentifier.create(e.getKey(), i)); } @@ -214,30 +341,156 @@ public final class DOMRpcRouter extends AbstractRegistration implements SchemaCo } } + private static final class ActionRegistration + extends AbstractListenerRegistration { + + private Map> prevActions; + private DOMRpcRouter router; + + ActionRegistration(final DOMRpcRouter router, final T listener, + final Map> actions) { + super(listener); + this.router = requireNonNull(router); + this.prevActions = requireNonNull(actions); + } + + @Override + protected void removeRegistration() { + router.removeActionListener(this); + router = null; + } + + void initialTable() { + final List added = new ArrayList<>(); + for (Entry> e : prevActions.entrySet()) { + added.addAll(Collections2.transform(e.getValue(), i -> DOMActionInstance.of(e.getKey(), i))); + } + if (!added.isEmpty()) { + getInstance().onActionsChanged(ImmutableSet.of(), ImmutableSet.copyOf(added)); + } + } + + void actionChanged(final DOMActionRoutingTable newTable, final DOMActionImplementation impl) { + final T l = getInstance(); + if (!l.acceptsImplementation(impl)) { + return; + } + + final Map> actions = verifyNotNull(newTable.getOperations(l)); + final MapDifference> diff = Maps.difference(prevActions, actions); + + final Set removed = new HashSet<>(); + final Set added = new HashSet<>(); + + for (Entry> e : diff.entriesOnlyOnLeft().entrySet()) { + removed.addAll(Collections2.transform(e.getValue(), i -> DOMActionInstance.of(e.getKey(), i))); + } + + for (Entry> e : diff.entriesOnlyOnRight().entrySet()) { + added.addAll(Collections2.transform(e.getValue(), i -> DOMActionInstance.of(e.getKey(), i))); + } + + for (Entry>> e : diff.entriesDiffering().entrySet()) { + for (DOMDataTreeIdentifier i : Sets.difference(e.getValue().leftValue(), e.getValue().rightValue())) { + removed.add(DOMActionInstance.of(e.getKey(), i)); + } + + for (DOMDataTreeIdentifier i : Sets.difference(e.getValue().rightValue(), e.getValue().leftValue())) { + added.add(DOMActionInstance.of(e.getKey(), i)); + } + } + + prevActions = actions; + if (!removed.isEmpty() || !added.isEmpty()) { + l.onActionsChanged(removed, added); + } + } + } + + @NonNullByDefault + private final class ActionAvailabilityFacade implements DOMActionAvailabilityExtension { + @Override + public ListenerRegistration registerAvailabilityListener(final T listener) { + synchronized (DOMRpcRouter.this) { + final ActionRegistration ret = new ActionRegistration<>(DOMRpcRouter.this, listener, + actionRoutingTable.getOperations(listener)); + actionListeners = ImmutableList.>builder() + .addAll(actionListeners) + .add(ret) + .build(); + + listenerNotifier.execute(ret::initialTable); + return ret; + } + } + } + + @NonNullByDefault + private final class ActionServiceFacade implements DOMActionService { + private final ClassToInstanceMap extensions = ImmutableClassToInstanceMap.of( + DOMActionAvailabilityExtension.class, new ActionAvailabilityFacade()); + + @Override + public ClassToInstanceMap getExtensions() { + return extensions; + } + + @Override + public ListenableFuture invokeAction(final Absolute type, + final DOMDataTreeIdentifier path, final ContainerNode input) { + final YangInstanceIdentifier pathRoot = path.getRootIdentifier(); + checkArgument(!pathRoot.isEmpty(), "Action path must not be empty"); + + final DOMActionRoutingTableEntry entry = (DOMActionRoutingTableEntry) actionRoutingTable.getEntry(type); + return entry != null ? OperationInvocation.invoke(entry, type, path, requireNonNull(input)) + : Futures.immediateFailedFuture( + new DOMActionNotAvailableException("No implementation of Action %s available", type)); + } + } + + @NonNullByDefault + private final class ActionProviderServiceFacade implements DOMActionProviderService { + @Override + public ObjectRegistration registerActionImplementation( + final T implementation, final Set instances) { + checkArgument(!instances.isEmpty(), "Instances must not be empty"); + + synchronized (DOMRpcRouter.this) { + final DOMActionRoutingTable oldTable = actionRoutingTable; + final DOMActionRoutingTable newTable = (DOMActionRoutingTable) oldTable.add(implementation, instances); + actionRoutingTable = newTable; + + listenerNotifier.execute(() -> notifyActionChanged(newTable, implementation)); + } + + return new AbstractObjectRegistration<>(implementation) { + @Override + protected void removeRegistration() { + removeActionImplementation(getInstance(), instances); + } + }; + } + } + private final class RpcServiceFacade implements DOMRpcService { @Override - public CheckedFuture invokeRpc(final SchemaPath type, - final NormalizedNode input) { - final AbstractDOMRpcRoutingTableEntry entry = routingTable.getEntry(type); + public ListenableFuture invokeRpc(final QName type, final NormalizedNode input) { + final AbstractDOMRpcRoutingTableEntry entry = (AbstractDOMRpcRoutingTableEntry) routingTable.getEntry(type); if (entry == null) { - return Futures.immediateFailedCheckedFuture( + return Futures.immediateFailedFuture( new DOMRpcImplementationNotAvailableException("No implementation of RPC %s available", type)); } - return entry.invokeRpc(input); + return OperationInvocation.invoke(entry, requireNonNull(input)); } @Override public ListenerRegistration registerRpcListener(final T listener) { synchronized (DOMRpcRouter.this) { - final Registration ret = new Registration<>(DOMRpcRouter.this, listener, - routingTable.getRpcs(listener)); - final Builder> b = ImmutableList.builder(); - b.addAll(listeners); - b.add(ret); - listeners = b.build(); - - listenerNotifier.execute(() -> ret.initialTable()); + final RegImpl ret = new RegImpl<>(DOMRpcRouter.this, listener, routingTable.getOperations(listener)); + listeners = ImmutableList.>builder().addAll(listeners).add(ret).build(); + + listenerNotifier.execute(ret::initialTable); return ret; } } @@ -256,18 +509,123 @@ 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)); } - return new AbstractDOMRpcImplementationRegistration(implementation) { + return new AbstractDOMRpcImplementationRegistration<>(implementation) { @Override protected void removeRegistration() { removeRpcImplementation(getInstance(), rpcs); } }; } + + @Override + public org.opendaylight.yangtools.concepts.Registration registerRpcImplementations( + final Map map) { + final ImmutableMap defensive = ImmutableMap.copyOf(map); + checkArgument(!map.isEmpty()); + + synchronized (DOMRpcRouter.this) { + final DOMRpcRoutingTable oldTable = routingTable; + final DOMRpcRoutingTable newTable = (DOMRpcRoutingTable) oldTable.addAll(defensive); + routingTable = newTable; + + listenerNotifier.execute(() -> notifyAdded(newTable, defensive.values())); + } + + return new AbstractRegistration() { + @Override + protected void removeRegistration() { + removeRpcImplementations(defensive); + } + }; + } + } + + static final class OperationInvocation { + private static final Logger LOG = LoggerFactory.getLogger(OperationInvocation.class); + + static ListenableFuture invoke(final DOMActionRoutingTableEntry entry, + final Absolute type, final DOMDataTreeIdentifier path, final ContainerNode input) { + List impls = entry.getImplementations(path); + if (impls == null) { + impls = entry.getImplementations( + new DOMDataTreeIdentifier(path.getDatastoreType(), YangInstanceIdentifier.empty())); + if (impls == null) { + return Futures.immediateFailedFuture(new DOMActionNotAvailableException( + "No implementation of Action %s available for %s", type, path)); + } + } + + return impls.get(0).invokeAction(type, path, input); + } + + static ListenableFuture invoke(final AbstractDOMRpcRoutingTableEntry entry, + final NormalizedNode input) { + if (entry instanceof UnknownDOMRpcRoutingTableEntry) { + return Futures.immediateFailedFuture( + new DOMRpcImplementationNotAvailableException("%s is not resolved to an RPC", entry.getType())); + } else if (entry instanceof RoutedDOMRpcRoutingTableEntry routed) { + return invokeRoutedRpc(routed, input); + } else if (entry instanceof GlobalDOMRpcRoutingTableEntry global) { + return invokeGlobalRpc(global, input); + } + + return Futures.immediateFailedFuture( + new DOMRpcImplementationNotAvailableException("Unsupported RPC entry.")); + } + + private static ListenableFuture invokeRoutedRpc( + final RoutedDOMRpcRoutingTableEntry entry, final NormalizedNode input) { + final Optional maybeKey = NormalizedNodes.findNode(input, + entry.getRpcId().getContextReference()); + + // Routing key is present, attempt to deliver as a routed RPC + if (maybeKey.isPresent()) { + final NormalizedNode key = maybeKey.get(); + final Object value = key.body(); + if (value instanceof YangInstanceIdentifier iid) { + // Find a DOMRpcImplementation for a specific iid + final List specificImpls = entry.getImplementations(iid); + if (specificImpls != null) { + return specificImpls.get(0) + .invokeRpc(DOMRpcIdentifier.create(entry.getType(), iid), input); + } + + LOG.debug("No implementation for context {} found will now look for wildcard id", iid); + + // Find a DOMRpcImplementation for a wild card. Usually remote-rpc-connector would register an + // implementation this way + final List mayBeRemoteImpls = + entry.getImplementations(YangInstanceIdentifier.empty()); + + if (mayBeRemoteImpls != null) { + return mayBeRemoteImpls.get(0) + .invokeRpc(DOMRpcIdentifier.create(entry.getType(), iid), input); + } + + } else { + LOG.warn("Ignoring wrong context value {}", value); + } + } + + final List impls = entry.getImplementations(null); + if (impls != null) { + return impls.get(0).invokeRpc(entry.getRpcId(), input); + } + + return Futures.immediateFailedFuture( + new DOMRpcImplementationNotAvailableException("No implementation of RPC %s available", + entry.getType())); + } + + private static ListenableFuture invokeGlobalRpc( + final GlobalDOMRpcRoutingTableEntry entry, final NormalizedNode input) { + return entry.getImplementations(YangInstanceIdentifier.empty()).get(0).invokeRpc(entry.getRpcId(), input); + } } }