From: Tony Tkacik Date: Thu, 18 Dec 2014 14:13:12 +0000 (+0000) Subject: Merge "BUG-2288: DOMNotification API" X-Git-Tag: release/lithium~753 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=159881b2b1c44301f740a6d20199df58eea04851;hp=3591817114661bb7971d6d355186ff1b39636fcd Merge "BUG-2288: DOMNotification API" --- diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotification.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotification.java new file mode 100644 index 0000000000..d99001ea5c --- /dev/null +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotification.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.dom.api; + +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; + +/** + * A single YANG notification. + */ +public interface DOMNotification { + /** + * Return the type of this notification. + * + * @return Notification type. + */ + @Nonnull SchemaPath getType(); + + /** + * Return the body of this notification. + * + * @return Notification body. + */ + @Nonnull ContainerNode getBody(); +} diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotificationListener.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotificationListener.java new file mode 100644 index 0000000000..7085588e87 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotificationListener.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.dom.api; + +import java.util.EventListener; +import javax.annotation.Nonnull; + +/** + * Interface implemented by listeners interested in {@link DOMNotification}s. + */ +public interface DOMNotificationListener extends EventListener { + /** + * Invoked whenever a {@link DOMNotification} matching the subscription + * criteria is received. + * + * @param notification Received notification + */ + void onNotification(@Nonnull DOMNotification notification); +} diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotificationListenerRegistration.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotificationListenerRegistration.java new file mode 100644 index 0000000000..4dccad2e42 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotificationListenerRegistration.java @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.dom.api; + +import org.opendaylight.yangtools.concepts.ListenerRegistration; + +/** + * A registration of a {@link DOMNotificationListener}. Invoking {@link #close()} will prevent further + * delivery of events to the listener. + */ +public interface DOMNotificationListenerRegistration extends ListenerRegistration { + +} diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotificationPublishService.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotificationPublishService.java new file mode 100644 index 0000000000..8a845e8729 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotificationPublishService.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.dom.api; + +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import java.util.concurrent.TimeUnit; +import javax.annotation.Nonnegative; +import javax.annotation.Nonnull; + +/** + * A {@link DOMService} which allows its user to send {@link DOMNotification}s. It + * provides two styles of initiating the notification delivery, similar to + * {@link java.util.concurrent.BlockingQueue}: + * - a put-style method which waits until the implementation can accept the notification + * for delivery, and + * - an offer-style method, which attempts to enqueue the notification, but allows + * the caller to specify that it should never wait, or put an upper bound on how + * long it is going to wait. + */ +public interface DOMNotificationPublishService extends DOMService { + /** + * Well-known value indicating that the implementation is currently not + * able to accept a notification. + */ + ListenableFuture REJECTED = Futures.immediateFailedFuture(new Throwable("Unacceptable blocking conditions encountered")); + + /** + * Publish a notification. The result of this method is a {@link ListenableFuture} + * which will complete once the notification has been delivered to all immediate + * registrants. The type of the object resulting from the future is not defined + * and implementations may use it to convey additional information related to the + * publishing process. + * + * Abstract subclasses can refine the return type as returning a promise of a + * more specific type, e.g.: + * + * public interface DeliveryStatus { int getListenerCount(); } + * ListenableFuture putNotification(DOMNotification notification); + * + * Once the Future succeeds, the resulting object can be queried for traits using + * instanceof, e.g: + * + * // Can block when (for example) the implemention's ThreadPool queue is full + * Object o = service.putNotification(notif).get(); + * if (o instanceof DeliveryStatus) { + * DeliveryStatus ds = (DeliveryStatus)o; + * LOG.debug("Notification was received by {} listeners", ds.getListenerCount();); + * } + * } + * + * In case an implementation is running out of resources, it can block the calling + * thread until enough resources become available to accept the notification for + * processing, or it is interrupted. + * + * Caution: completion here means that the implementation has completed processing + * of the notification. This does not mean that all existing registrants + * have seen the notification. Most importantly, the delivery process at + * other cluster nodes may have not begun yet. + * + * @param notification Notification to be published. + * @return A listenable future which will report completion when the service + * has finished propagating the notification to its immediate registrants. + * @throws InterruptedException if interrupted while waiting + * @throws NullPointerException if notification is null. + */ + @Nonnull ListenableFuture putNotification(@Nonnull DOMNotification notification) throws InterruptedException; + + /** + * Attempt to publish a notification. The result of this method is a {@link ListenableFuture} + * which will complete once the notification has been delivered to all immediate + * registrants. The type of the object resulting from the future is not defined + * and implementations may use it to convey additional information related to the + * publishing process. Unlike {@link #putNotification(DOMNotification)}, this method + * is guaranteed not to block if the underlying implementation encounters contention. + * + * @param notification Notification to be published. + * @return A listenable future which will report completion when the service + * has finished propagating the notification to its immediate registrants, + * or {@value #REJECTED} if resource constraints prevent + * the implementation from accepting the notification for delivery. + * @throws NullPointerException if notification is null. + */ + @Nonnull ListenableFuture offerNotification(@Nonnull DOMNotification notification); + + /** + * Attempt to publish a notification. The result of this method is a {@link ListenableFuture} + * which will complete once the notification has been delivered to all immediate + * registrants. The type of the object resulting from the future is not defined + * and implementations may use it to convey additional information related to the + * publishing process. Unlike {@link #putNotification(DOMNotification)}, this method + * is guaranteed to block more than the specified timeout. + * + * @param notification Notification to be published. + * @param timeout how long to wait before giving up, in units of unit + * @param unit a TimeUnit determining how to interpret the timeout parameter + * @return A listenable future which will report completion when the service + * has finished propagating the notification to its immediate registrants, + * or {@value #REJECTED} if resource constraints prevent + * the implementation from accepting the notification for delivery. + * @throws InterruptedException if interrupted while waiting + * @throws NullPointerException if notification or unit is null. + * @throws IllegalArgumentException if timeout is negative. + */ + @Nonnull ListenableFuture offerNotification(@Nonnull DOMNotification notification, + @Nonnegative long timeout, @Nonnull TimeUnit unit) throws InterruptedException; +} diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotificationService.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotificationService.java new file mode 100644 index 0000000000..6bce9c447a --- /dev/null +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotificationService.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.dom.api; + +import java.util.Collection; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; + +/** + * A {@link DOMService} which allows its users to subscribe to receive + * {@link DOMNotification}s. + */ +public interface DOMNotificationService { + /** + * Register a {@link DOMNotificationListener} to receive a set of notifications. As with + * other ListenerRegistration-based interfaces, registering an instance multiple times + * results in notifications being delivered for each registration. + * + * @param listener Notification instance to register + * @param types Notification types which should be delivered to the listener. Duplicate + * entries are processed only once, null entries are ignored. + * @return Registration handle. Invoking {@link DOMNotificationListenerRegistration#close()} + * will stop the delivery of notifications to the listener + * @throws IllegalArgumentException if types is empty or contains an invalid element, such as + * null or a SchemaPath which does not represent a valid {@link DOMNotification} type. + * @throws NullPointerException if either of the arguments is null + */ + DOMNotificationListenerRegistration registerNotificationListener(@Nonnull DOMNotificationListener listener, @Nonnull Collection types); + + /** + * Register a {@link DOMNotificationListener} to receive a set of notifications. As with + * other ListenerRegistration-based interfaces, registering an instance multiple times + * results in notifications being delivered for each registration. + * + * @param listener Notification instance to register + * @param types Notification types which should be delivered to the listener. Duplicate + * entries are processed only once, null entries are ignored. + * @return Registration handle. Invoking {@link DOMNotificationListenerRegistration#close()} + * will stop the delivery of notifications to the listener + * @throws IllegalArgumentException if types is empty or contains an invalid element, such as + * null or a SchemaPath which does not represent a valid {@link DOMNotification} type. + * @throws NullPointerException if listener is null + */ + // FIXME: Java 8: provide a default implementation of this method. + DOMNotificationListenerRegistration registerNotificationListener(@Nonnull DOMNotificationListener listener, SchemaPath... types); +} diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMService.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMService.java index 357cb8bfe6..dc18394ffd 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMService.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMService.java @@ -5,9 +5,12 @@ * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html. */ - package org.opendaylight.controller.md.sal.dom.api; +/** + * Marker interface for services which can be obtained from a {@link DOMMountPoint} + * instance. No further semantics are implied. + */ public interface DOMService { } diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/AbstractDOMNotificationListenerRegistration.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/AbstractDOMNotificationListenerRegistration.java new file mode 100644 index 0000000000..2934b0da35 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/AbstractDOMNotificationListenerRegistration.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.dom.spi; + +import javax.annotation.Nonnull; +import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListener; +import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListenerRegistration; +import org.opendaylight.yangtools.concepts.AbstractListenerRegistration; + +/** + * Utility base class for {@link DOMNotificationListenerRegistration} + * implementations. + */ +public abstract class AbstractDOMNotificationListenerRegistration extends AbstractListenerRegistration implements DOMNotificationListenerRegistration { + /** + * Default constructor. Subclasses need to invoke it from their + * constructor(s). + * + * @param listener {@link DOMNotificationListener} instance which is + * being held by this registration. May not be null. + */ + protected AbstractDOMNotificationListenerRegistration(final @Nonnull DOMNotificationListener listener) { + super(listener); + } +} diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/ForwardingDOMNotificationPublishService.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/ForwardingDOMNotificationPublishService.java new file mode 100644 index 0000000000..6bc11079e2 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/ForwardingDOMNotificationPublishService.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.dom.spi; + +import com.google.common.collect.ForwardingObject; +import com.google.common.util.concurrent.ListenableFuture; +import java.util.concurrent.TimeUnit; +import org.opendaylight.controller.md.sal.dom.api.DOMNotification; +import org.opendaylight.controller.md.sal.dom.api.DOMNotificationPublishService; + +/** + * Utility implementations of {@link DOMNotificationPublishService} which forwards + * all requests to a delegate instance. + */ +public abstract class ForwardingDOMNotificationPublishService extends ForwardingObject implements DOMNotificationPublishService { + @Override + protected abstract DOMNotificationPublishService delegate(); + + @Override + public ListenableFuture putNotification(final DOMNotification notification) throws InterruptedException { + return delegate().putNotification(notification); + } + + @Override + public ListenableFuture offerNotification(final DOMNotification notification) { + return delegate().offerNotification(notification); + } + + @Override + public ListenableFuture offerNotification(final DOMNotification notification, final long timeout, + final TimeUnit unit) throws InterruptedException { + return delegate().offerNotification(notification, timeout, unit); + } +} diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/ForwardingDOMNotificationService.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/ForwardingDOMNotificationService.java new file mode 100644 index 0000000000..5199a3893b --- /dev/null +++ b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/ForwardingDOMNotificationService.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.dom.spi; + +import com.google.common.collect.ForwardingObject; +import java.util.Collection; +import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListener; +import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListenerRegistration; +import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; + +/** + * Utility implementation of a {@link DOMNotificationService} which forwards all requests + * to a delegate instance. + */ +public abstract class ForwardingDOMNotificationService extends ForwardingObject implements DOMNotificationService { + @Override + protected abstract DOMNotificationService delegate(); + + @Override + public DOMNotificationListenerRegistration registerNotificationListener(final DOMNotificationListener listener, + final Collection types) { + return delegate().registerNotificationListener(listener, types); + } + + @Override + public DOMNotificationListenerRegistration registerNotificationListener(final DOMNotificationListener listener, + final SchemaPath... types) { + return delegate().registerNotificationListener(listener, types); + } +}