*/
package org.opendaylight.mdsal.binding.api;
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
import com.google.common.util.concurrent.MoreExecutors;
import java.util.EventListener;
+import java.util.Set;
import java.util.concurrent.Executor;
import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
return registerListener(type, listener, MoreExecutors.directExecutor());
}
+ /**
+ * Registers a {@link Listener} to receive callbacks for {@link Notification}s of a particular type.
+ *
+ * @param listener Composite listener containing listener implementations that will receive notifications
+ * @param executor Executor to use for invoking the listener's methods
+ * @return a {@link Registration} instance that should be used to unregister the listener by invoking the
+ * {@link Registration#close()} method when no longer needed
+ */
+ @Beta
+ @NonNull Registration registerCompositeListener(CompositeListener listener, Executor executor);
+
+ /**
+ * Registers a {@link Listener} to receive callbacks for {@link Notification}s of a particular type.
+ *
+ * @implSpec
+ * This method is equivalent to {@code registerCompositeListener(listener, MoreExecutors.directExecutor())},
+ * i.e. listeners will be invoked on some implementation-specific thread.
+ *
+ * @param listener Composite listener containing listener implementations that will receive notifications
+ * @return a {@link Registration} instance that should be used to unregister the listener by invoking the
+ * {@link Registration#close()} method when no longer needed
+ */
+ @Beta
+ default @NonNull Registration registerCompositeListener(final CompositeListener listener) {
+ return registerCompositeListener(listener, MoreExecutors.directExecutor());
+ }
+
/**
* Interface for listeners on global (YANG 1.0) notifications. Such notifications are identified by their generated
* interface which extends {@link Notification}. Each listener instance can listen to only a single notification
*/
void onNotification(@NonNull N notification);
}
+
+ /**
+ * A composite listener. This class allows registering multiple {@link Listener}s in a single operation. Constituent
+ * listeners are available through {@link #constituents()}.
+ */
+ @Beta
+ record CompositeListener(@NonNull Set<CompositeListener.Component<?>> constituents) {
+ @Beta
+ public record Component<T extends Notification<T> & DataObject>(@NonNull Class<T> type, Listener<T> listener) {
+ public Component {
+ requireNonNull(type);
+ requireNonNull(listener);
+ checkArgument(DataObject.class.isAssignableFrom(type), "%s is not a DataObject", type);
+ checkArgument(Notification.class.isAssignableFrom(type), "%s is not a Notification", type);
+ }
+ }
+
+ public CompositeListener {
+ requireNonNull(constituents);
+ checkArgument(!constituents.isEmpty(), "Composite listener requires at least one constituent listener");
+ }
+ }
}
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ClassToInstanceMap;
import com.google.common.collect.ImmutableSet;
+import java.util.HashMap;
import java.util.Set;
import java.util.concurrent.Executor;
import org.opendaylight.mdsal.binding.api.NotificationService;
import org.opendaylight.mdsal.binding.dom.adapter.BindingDOMAdapterBuilder.Factory;
+import org.opendaylight.mdsal.dom.api.DOMNotificationListener;
import org.opendaylight.mdsal.dom.api.DOMNotificationService;
import org.opendaylight.mdsal.dom.api.DOMService;
import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.Notification;
import org.opendaylight.yangtools.yang.binding.NotificationListener;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
@VisibleForTesting
// FIXME: 10.0.0: make this class final
return domNotifService.registerNotificationListener(domListener, domListener.getSupportedNotifications());
}
+ @Override
+ public Registration registerCompositeListener(final CompositeListener listener, final Executor executor) {
+ final var exec = requireNonNull(executor);
+ final var listeners = new HashMap<Absolute, DOMNotificationListener>();
+ for (var constituent : listener.constituents()) {
+ final var domListener = new SingleBindingDOMNotificationAdapter<>(adapterContext, constituent, exec);
+ listeners.put(domListener.getSupportedNotifications().iterator().next(), domListener);
+ }
+
+ return domNotifService.registerNotificationListeners(listeners);
+ }
+
@Deprecated(since = "10.0.0", forRemoval = true)
private static final class ListenerRegistrationImpl<T extends NotificationListener>
extends AbstractListenerRegistration<T> {
import java.util.Set;
import java.util.concurrent.Executor;
+import org.opendaylight.mdsal.binding.api.NotificationService.CompositeListener.Component;
import org.opendaylight.mdsal.binding.api.NotificationService.Listener;
import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
import org.opendaylight.yangtools.yang.binding.DataObject;
this.executor = requireNonNull(executor);
}
+ SingleBindingDOMNotificationAdapter(final AdapterContext adapterContext, final Component<N> component,
+ final Executor executor) {
+ this(adapterContext, component.type(), component.listener(), executor);
+ }
+
@Override
void onNotification(final Absolute domType, final Notification<?> notification) {
executor.execute(() -> delegate.onNotification(type.cast(notification)));
import java.util.Map;
import java.util.concurrent.Executor;
import org.opendaylight.mdsal.binding.api.NotificationService;
+import org.opendaylight.mdsal.binding.api.NotificationService.CompositeListener;
import org.opendaylight.mdsal.binding.api.NotificationService.Listener;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.concepts.Registration;
return delegate().registerListener(type, listener, executor);
}
+ @Override
+ public Registration registerCompositeListener(final CompositeListener listener, final Executor executor) {
+ return delegate().registerCompositeListener(listener, executor);
+ }
+
@Activate
void activate(final Map<String, ?> properties) {
start(properties);