+ LOG.info("DOM RPC/Action router stopped");
+ }
+
+ @VisibleForTesting
+ synchronized List<?> listeners() {
+ return listeners;
+ }
+
+ @VisibleForTesting
+ synchronized List<?> actionListeners() {
+ return actionListeners;
+ }
+
+ @VisibleForTesting
+ DOMRpcRoutingTable routingTable() {
+ return routingTable;
+ }
+
+ private static final class RpcAvailReg extends AbstractRegistration {
+ private final DOMRpcAvailabilityListener listener;
+
+ private Map<QName, Set<YangInstanceIdentifier>> prevRpcs;
+ private DOMRpcRouter router;
+
+ RpcAvailReg(final DOMRpcRouter router, final DOMRpcAvailabilityListener listener,
+ final Map<QName, Set<YangInstanceIdentifier>> rpcs) {
+ this.listener = requireNonNull(listener);
+ this.router = requireNonNull(router);
+ prevRpcs = requireNonNull(rpcs);
+ }
+
+ @Override
+ protected void removeRegistration() {
+ router.removeListener(this);
+ router = null;
+ }
+
+ void initialTable() {
+ 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)));
+ }
+ if (!added.isEmpty()) {
+ listener.onRpcAvailable(added);
+ }
+ }
+
+ void addRpc(final DOMRpcRoutingTable newTable, final DOMRpcImplementation impl) {
+ if (!listener.acceptsImplementation(impl)) {
+ return;
+ }
+
+ final Map<QName, Set<YangInstanceIdentifier>> rpcs = verifyNotNull(newTable.getOperations(listener));
+ final MapDifference<QName, Set<YangInstanceIdentifier>> diff = Maps.difference(prevRpcs, rpcs);
+
+ 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)));
+ }
+ for (Entry<QName, ValueDifference<Set<YangInstanceIdentifier>>> e : diff.entriesDiffering().entrySet()) {
+ for (YangInstanceIdentifier i : Sets.difference(e.getValue().rightValue(), e.getValue().leftValue())) {
+ added.add(DOMRpcIdentifier.create(e.getKey(), i));
+ }
+ }
+
+ prevRpcs = rpcs;
+ if (!added.isEmpty()) {
+ listener.onRpcAvailable(added);
+ }
+ }
+
+ void removeRpc(final DOMRpcRoutingTable newTable, final DOMRpcImplementation impl) {
+ if (!listener.acceptsImplementation(impl)) {
+ return;
+ }
+
+ final Map<QName, Set<YangInstanceIdentifier>> rpcs = verifyNotNull(newTable.getOperations(listener));
+ final MapDifference<QName, Set<YangInstanceIdentifier>> diff = Maps.difference(prevRpcs, rpcs);
+
+ 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)));
+ }
+ for (Entry<QName, ValueDifference<Set<YangInstanceIdentifier>>> e : diff.entriesDiffering().entrySet()) {
+ for (YangInstanceIdentifier i : Sets.difference(e.getValue().leftValue(), e.getValue().rightValue())) {
+ removed.add(DOMRpcIdentifier.create(e.getKey(), i));
+ }
+ }
+
+ prevRpcs = rpcs;
+ if (!removed.isEmpty()) {
+ 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);
+ }
+ }