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.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
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.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
+import javax.annotation.PreDestroy;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.checkerframework.checker.lock.qual.GuardedBy;
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.DOMActionProviderServiceExtension;
import org.opendaylight.mdsal.dom.api.DOMActionResult;
import org.opendaylight.mdsal.dom.api.DOMActionService;
import org.opendaylight.mdsal.dom.api.DOMActionServiceExtension;
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 @NonNull DOMRpcService rpcService = new RpcServiceFacade();
@GuardedBy("this")
- private Collection<Registration<?>> listeners = Collections.emptyList();
+ private ImmutableList<Registration<?>> listeners = ImmutableList.of();
@GuardedBy("this")
- private Collection<ActionRegistration<?>> actionListeners = Collections.emptyList();
+ private ImmutableList<ActionRegistration<?>> actionListeners = ImmutableList.of();
private volatile DOMRpcRoutingTable routingTable = DOMRpcRoutingTable.EMPTY;
private ListenerRegistration<?> 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
return rpcProviderService;
}
- @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
- justification = "https://github.com/spotbugs/spotbugs/issues/811")
private synchronized void removeRpcImplementation(final DOMRpcImplementation implementation,
final Set<DOMRpcIdentifier> rpcs) {
final DOMRpcRoutingTable oldTable = routingTable;
listenerNotifier.execute(() -> notifyRemoved(newTable, implementation));
}
- @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
- justification = "https://github.com/spotbugs/spotbugs/issues/811")
private synchronized void removeRpcImplementations(final Map<DOMRpcIdentifier, DOMRpcImplementation> map) {
final DOMRpcRoutingTable oldTable = routingTable;
final DOMRpcRoutingTable newTable = (DOMRpcRoutingTable) oldTable.removeAll(map);
listenerNotifier.execute(() -> notifyRemoved(newTable, map.values()));
}
- @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
- justification = "https://github.com/spotbugs/spotbugs/issues/811")
private synchronized void removeActionImplementation(final DOMActionImplementation implementation,
final Set<DOMActionInstance> actions) {
final DOMActionRoutingTable oldTable = actionRoutingTable;
listenerNotifier.execute(() -> notifyActionChanged(newTable, implementation));
}
- @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
- justification = "https://github.com/spotbugs/spotbugs/issues/811")
private synchronized void removeListener(final ListenerRegistration<? extends DOMRpcAvailabilityListener> reg) {
listeners = ImmutableList.copyOf(Collections2.filter(listeners, input -> !reg.equals(input)));
}
- @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
- justification = "https://github.com/spotbugs/spotbugs/issues/811")
private synchronized void removeActionListener(final ListenerRegistration<? extends AvailabilityListener> reg) {
actionListeners = ImmutableList.copyOf(Collections2.filter(actionListeners, input -> !reg.equals(input)));
}
- @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
- justification = "https://github.com/spotbugs/spotbugs/issues/811")
private synchronized void notifyAdded(final DOMRpcRoutingTable newTable, final DOMRpcImplementation impl) {
for (Registration<?> l : listeners) {
l.addRpc(newTable, impl);
}
}
- @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
- justification = "https://github.com/spotbugs/spotbugs/issues/811")
private synchronized void notifyAdded(final DOMRpcRoutingTable newTable,
final Collection<? extends DOMRpcImplementation> impls) {
for (Registration<?> l : listeners) {
}
}
- @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
- justification = "https://github.com/spotbugs/spotbugs/issues/811")
private synchronized void notifyRemoved(final DOMRpcRoutingTable newTable, final DOMRpcImplementation impl) {
for (Registration<?> l : listeners) {
l.removeRpc(newTable, impl);
}
}
- @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
- justification = "https://github.com/spotbugs/spotbugs/issues/811")
private synchronized void notifyRemoved(final DOMRpcRoutingTable newTable,
final Collection<? extends DOMRpcImplementation> impls) {
for (Registration<?> l : listeners) {
listenerRegistration = null;
}
listenerNotifier.shutdown();
+ LOG.info("DOM RPC/Action router stopped");
}
@VisibleForTesting
- synchronized Collection<?> listeners() {
+ synchronized List<?> listeners() {
return listeners;
}
+ @VisibleForTesting
+ synchronized List<?> actionListeners() {
+ return actionListeners;
+ }
+
@VisibleForTesting
DOMRpcRoutingTable routingTable() {
return routingTable;
}
void initialTable() {
- final Collection<DOMRpcIdentifier> added = new ArrayList<>();
+ final List<DOMRpcIdentifier> added = new ArrayList<>();
for (Entry<QName, Set<YangInstanceIdentifier>> e : prevRpcs.entrySet()) {
added.addAll(Collections2.transform(e.getValue(), i -> DOMRpcIdentifier.create(e.getKey(), i)));
}
final Map<QName, Set<YangInstanceIdentifier>> rpcs = verifyNotNull(newTable.getOperations(l));
final MapDifference<QName, Set<YangInstanceIdentifier>> diff = Maps.difference(prevRpcs, rpcs);
- final Collection<DOMRpcIdentifier> added = new ArrayList<>();
+ final List<DOMRpcIdentifier> added = new ArrayList<>();
for (Entry<QName, Set<YangInstanceIdentifier>> e : diff.entriesOnlyOnRight().entrySet()) {
added.addAll(Collections2.transform(e.getValue(), i -> DOMRpcIdentifier.create(e.getKey(), i)));
}
final Map<QName, Set<YangInstanceIdentifier>> rpcs = verifyNotNull(newTable.getOperations(l));
final MapDifference<QName, Set<YangInstanceIdentifier>> diff = Maps.difference(prevRpcs, rpcs);
- final Collection<DOMRpcIdentifier> removed = new ArrayList<>();
+ final List<DOMRpcIdentifier> removed = new ArrayList<>();
for (Entry<QName, Set<YangInstanceIdentifier>> e : diff.entriesOnlyOnLeft().entrySet()) {
removed.addAll(Collections2.transform(e.getValue(), i -> DOMRpcIdentifier.create(e.getKey(), i)));
}
}
void initialTable() {
- final Collection<DOMActionInstance> added = new ArrayList<>();
+ final List<DOMActionInstance> added = new ArrayList<>();
for (Entry<Absolute, Set<DOMDataTreeIdentifier>> e : prevActions.entrySet()) {
added.addAll(Collections2.transform(e.getValue(), i -> DOMActionInstance.of(e.getKey(), i)));
}
@Override
public <T extends AvailabilityListener> ListenerRegistration<T> registerAvailabilityListener(final T listener) {
synchronized (DOMRpcRouter.this) {
- final ActionRegistration<T> ret = new ActionRegistration<>(DOMRpcRouter.this,
- listener, actionRoutingTable.getOperations(listener));
- final Builder<ActionRegistration<?>> b = ImmutableList.builder();
- b.addAll(actionListeners);
- b.add(ret);
- actionListeners = b.build();
+ final ActionRegistration<T> ret = new ActionRegistration<>(DOMRpcRouter.this, listener,
+ actionRoutingTable.getOperations(listener));
+ actionListeners = ImmutableList.<ActionRegistration<?>>builder()
+ .addAll(actionListeners)
+ .add(ret)
+ .build();
listenerNotifier.execute(ret::initialTable);
return ret;
@Override
public ListenableFuture<? extends DOMActionResult> 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);
- if (entry == null) {
- return Futures.immediateFailedFuture(
+ return entry != null ? OperationInvocation.invoke(entry, type, path, requireNonNull(input))
+ : Futures.immediateFailedFuture(
new DOMActionNotAvailableException("No implementation of Action %s available", type));
- }
-
- return OperationInvocation.invoke(entry, type, path, requireNonNull(input));
}
}
@NonNullByDefault
private final class ActionProviderServiceFacade implements DOMActionProviderService {
- @Override
- public ClassToInstanceMap<DOMActionProviderServiceExtension> getExtensions() {
- return ImmutableClassToInstanceMap.of();
- }
-
@Override
public <T extends DOMActionImplementation> ObjectRegistration<T> registerActionImplementation(
- final T implementation, final Set<DOMActionInstance> instances) {
+ final T implementation, final Set<DOMActionInstance> instances) {
synchronized (DOMRpcRouter.this) {
final DOMActionRoutingTable oldTable = actionRoutingTable;
private final class RpcServiceFacade implements DOMRpcService {
@Override
- public ListenableFuture<? extends DOMRpcResult> invokeRpc(final QName type, final NormalizedNode<?, ?> input) {
+ public ListenableFuture<? extends DOMRpcResult> invokeRpc(final QName type, final NormalizedNode input) {
final AbstractDOMRpcRoutingTableEntry entry = (AbstractDOMRpcRoutingTableEntry) routingTable.getEntry(type);
if (entry == null) {
return Futures.immediateFailedFuture(
synchronized (DOMRpcRouter.this) {
final Registration<T> ret = new Registration<>(DOMRpcRouter.this, listener,
routingTable.getOperations(listener));
- final Builder<Registration<?>> b = ImmutableList.builder();
- b.addAll(listeners);
- b.add(ret);
- listeners = b.build();
+ listeners = ImmutableList.<Registration<?>>builder().addAll(listeners).add(ret).build();
listenerNotifier.execute(ret::initialTable);
return ret;
static ListenableFuture<? extends DOMActionResult> invoke(final DOMActionRoutingTableEntry entry,
final Absolute type, final DOMDataTreeIdentifier path, final ContainerNode input) {
- return entry.getImplementations(path).get(0).invokeAction(type, path, input);
+ List<DOMActionImplementation> 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<? extends DOMRpcResult> invoke(final AbstractDOMRpcRoutingTableEntry entry,
- final NormalizedNode<?, ?> input) {
+ final NormalizedNode input) {
if (entry instanceof UnknownDOMRpcRoutingTableEntry) {
return Futures.immediateFailedFuture(
new DOMRpcImplementationNotAvailableException("%s is not resolved to an RPC", entry.getType()));
}
private static ListenableFuture<? extends DOMRpcResult> invokeRoutedRpc(
- final RoutedDOMRpcRoutingTableEntry entry, final NormalizedNode<?, ?> input) {
- final Optional<NormalizedNode<?, ?>> maybeKey = NormalizedNodes.findNode(input,
+ final RoutedDOMRpcRoutingTableEntry entry, final NormalizedNode input) {
+ final Optional<NormalizedNode> 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.getValue();
+ final NormalizedNode key = maybeKey.get();
+ final Object value = key.body();
if (value instanceof YangInstanceIdentifier) {
final YangInstanceIdentifier iid = (YangInstanceIdentifier) value;
}
private static ListenableFuture<? extends DOMRpcResult> invokeGlobalRpc(
- final GlobalDOMRpcRoutingTableEntry entry, final NormalizedNode<?, ?> input) {
+ final GlobalDOMRpcRoutingTableEntry entry, final NormalizedNode input) {
return entry.getImplementations(YangInstanceIdentifier.empty()).get(0).invokeRpc(entry.getRpcId(), input);
}
}