+ listener.onRpcUnavailable(removed);
+ }
+ }
+ }
+
+ private static final class ActionAvailReg extends AbstractRegistration {
+ private final AvailabilityListener listener;
+
+ private Map<Absolute, Set<DOMDataTreeIdentifier>> prevActions;
+ private DOMRpcRouter router;
+
+ ActionAvailReg(final DOMRpcRouter router, final AvailabilityListener listener,
+ final Map<Absolute, Set<DOMDataTreeIdentifier>> actions) {
+ this.listener = requireNonNull(listener);
+ this.router = requireNonNull(router);
+ prevActions = requireNonNull(actions);
+ }
+
+ @Override
+ protected void removeRegistration() {
+ router.removeActionListener(this);
+ router = null;
+ }
+
+ void initialTable() {
+ final var added = new ArrayList<DOMActionInstance>();
+ for (var e : prevActions.entrySet()) {
+ added.addAll(Collections2.transform(e.getValue(), i -> DOMActionInstance.of(e.getKey(), i)));
+ }
+ if (!added.isEmpty()) {
+ listener.onActionsChanged(ImmutableSet.of(), ImmutableSet.copyOf(added));
+ }
+ }
+
+ void actionChanged(final DOMActionRoutingTable newTable, final DOMActionImplementation impl) {
+ if (!listener.acceptsImplementation(impl)) {
+ return;
+ }
+
+ final Map<Absolute, Set<DOMDataTreeIdentifier>> actions = verifyNotNull(newTable.getOperations(listener));
+ final MapDifference<Absolute, Set<DOMDataTreeIdentifier>> diff = Maps.difference(prevActions, actions);
+
+ final Set<DOMActionInstance> removed = new HashSet<>();
+ final Set<DOMActionInstance> added = new HashSet<>();
+
+ for (Entry<Absolute, Set<DOMDataTreeIdentifier>> e : diff.entriesOnlyOnLeft().entrySet()) {
+ removed.addAll(Collections2.transform(e.getValue(), i -> DOMActionInstance.of(e.getKey(), i)));
+ }
+
+ for (Entry<Absolute, Set<DOMDataTreeIdentifier>> e : diff.entriesOnlyOnRight().entrySet()) {
+ added.addAll(Collections2.transform(e.getValue(), i -> DOMActionInstance.of(e.getKey(), i)));
+ }
+
+ for (Entry<Absolute, ValueDifference<Set<DOMDataTreeIdentifier>>> 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()) {
+ listener.onActionsChanged(removed, added);
+ }
+ }
+ }
+
+ @NonNullByDefault
+ private final class ActionServiceFacade implements DOMActionService, DOMActionAvailabilityExtension {
+ @Override
+ public List<Extension> supportedExtensions() {
+ return List.of(this);
+ }
+
+ @Override
+ public ListenableFuture<? extends DOMActionResult> invokeAction(final Absolute type,
+ final DOMDataTreeIdentifier path, final ContainerNode input) {
+ final YangInstanceIdentifier pathRoot = path.path();
+ 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));
+ }
+
+ @Override
+ public Registration registerAvailabilityListener(final AvailabilityListener listener) {
+ synchronized (DOMRpcRouter.this) {
+ final var ret = new ActionAvailReg(DOMRpcRouter.this, listener,
+ actionRoutingTable.getOperations(listener));
+ actionListeners = ImmutableList.<ActionAvailReg>builder()
+ .addAll(actionListeners)
+ .add(ret)
+ .build();
+
+ listenerNotifier.execute(ret::initialTable);
+ return ret;
+ }
+ }
+ }
+
+ @NonNullByDefault
+ private final class ActionProviderServiceFacade implements DOMActionProviderService {
+ @Override
+ public Registration registerActionImplementation(final DOMActionImplementation implementation,
+ final Set<DOMActionInstance> 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));