From: Robert Varga Date: Wed, 17 Sep 2014 19:17:43 +0000 (+0200) Subject: BUG-2288: DOMNotification API X-Git-Tag: release/lithium~753^2 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=2585706cfb4d3fff8538535212032511388bee07 BUG-2288: DOMNotification API This API definition tries to fix the missing pieces in the CompositeNode-centered APIs, such as inability to drop a notification rather than waiting for resources needed to publish it to become available. Also adds missing documentation to the DOMService concept, which is used by the two services being defined. Change-Id: I93d22cf6121a7cf231b2da424e94d14b59fb883f Signed-off-by: Robert Varga --- 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); + } +}