+ private static final class ActionRegistration<T extends AvailabilityListener>
+ extends AbstractListenerRegistration<T> {
+
+ private Map<Absolute, Set<DOMDataTreeIdentifier>> prevActions;
+ private DOMRpcRouter router;
+
+ ActionRegistration(final DOMRpcRouter router, final T listener,
+ final Map<Absolute, Set<DOMDataTreeIdentifier>> actions) {
+ super(listener);
+ this.router = requireNonNull(router);
+ this.prevActions = requireNonNull(actions);
+ }
+
+ @Override
+ protected void removeRegistration() {
+ router.removeActionListener(this);
+ router = null;
+ }
+
+ void initialTable() {
+ 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)));
+ }
+ 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<Absolute, Set<DOMDataTreeIdentifier>> actions = verifyNotNull(newTable.getOperations(l));
+ 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()) {
+ l.onActionsChanged(removed, added);
+ }
+ }
+ }
+
+ @NonNullByDefault
+ private final class ActionAvailabilityFacade implements DOMActionAvailabilityExtension {
+ @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));
+ actionListeners = ImmutableList.<ActionRegistration<?>>builder()
+ .addAll(actionListeners)
+ .add(ret)
+ .build();
+
+ listenerNotifier.execute(ret::initialTable);
+ return ret;
+ }
+ }
+ }
+
+ @NonNullByDefault
+ private final class ActionServiceFacade implements DOMActionService {
+ private final ClassToInstanceMap<DOMActionServiceExtension> extensions = ImmutableClassToInstanceMap.of(
+ DOMActionAvailabilityExtension.class, new ActionAvailabilityFacade());
+
+ @Override
+ public ClassToInstanceMap<DOMActionServiceExtension> getExtensions() {
+ return extensions;
+ }
+
+ @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);
+ 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 <T extends DOMActionImplementation> ObjectRegistration<T> registerActionImplementation(
+ final T implementation, final Set<DOMActionInstance> instances) {
+
+ 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);
+ }
+ };
+ }
+ }
+