2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.sal.dom.broker;
10 import java.util.Collection;
11 import java.util.Collections;
13 import java.util.Map.Entry;
16 import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
17 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
18 import org.opendaylight.controller.sal.core.api.BrokerService;
19 import org.opendaylight.controller.sal.core.api.Consumer.ConsumerFunctionality;
20 import org.opendaylight.controller.sal.core.api.Provider.ProviderFunctionality;
21 import org.opendaylight.controller.sal.core.api.notify.NotificationListener;
22 import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
23 import org.opendaylight.controller.sal.core.api.notify.NotificationService;
24 import org.opendaylight.controller.sal.core.spi.BrokerModule;
25 import org.opendaylight.yangtools.concepts.Registration;
26 import org.opendaylight.yangtools.yang.common.QName;
27 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
31 import com.google.common.collect.HashMultimap;
32 import com.google.common.collect.ImmutableSet;
33 import com.google.common.collect.Multimap;
35 public class NotificationModule implements BrokerModule {
36 private static Logger log = LoggerFactory
37 .getLogger(NotificationModule.class);
39 private final Multimap<QName, NotificationListener> listeners = HashMultimap
42 private static final Set<Class<? extends BrokerService>> PROVIDED_SERVICE_TYPE = ImmutableSet
43 .<Class<? extends BrokerService>>of(NotificationService.class,
44 NotificationPublishService.class);
46 private static final Set<Class<? extends ConsumerFunctionality>> SUPPORTED_CONSUMER_FUNCTIONALITY = ImmutableSet
47 .of((Class<? extends ConsumerFunctionality>) NotificationListener.class,
48 NotificationListener.class); // Workaround: if we use the
49 // version of method with only
50 // one argument, the generics
51 // inference will not work
54 public Set<Class<? extends BrokerService>> getProvidedServices() {
55 return PROVIDED_SERVICE_TYPE;
59 public Set<Class<? extends ConsumerFunctionality>> getSupportedConsumerFunctionality() {
60 return SUPPORTED_CONSUMER_FUNCTIONALITY;
64 public <T extends BrokerService> T getServiceForSession(Class<T> service,
65 ConsumerSession session) {
66 if (NotificationPublishService.class.equals(service)
67 && session instanceof ProviderSession) {
68 @SuppressWarnings("unchecked")
69 T ret = (T) newNotificationPublishService(session);
71 } else if (NotificationService.class.equals(service)) {
73 @SuppressWarnings("unchecked")
74 T ret = (T) newNotificationConsumerService(session);
78 throw new IllegalArgumentException(
79 "The requested session-specific service is not provided by this module.");
82 private void sendNotification(CompositeNode notification) {
83 QName type = notification.getNodeType();
84 Collection<NotificationListener> toNotify = listeners.get(type);
85 log.trace("Publishing notification " + type);
87 if (toNotify == null) {
88 // No listeners were registered - returns.
92 for (NotificationListener listener : toNotify) {
94 // FIXME: ensure that notification is immutable
95 listener.onNotification(notification);
96 } catch (Exception e) {
97 log.error("Uncaught exception in NotificationListener", e);
103 private NotificationService newNotificationConsumerService(
104 ConsumerSession session) {
105 return new NotificationConsumerSessionImpl();
108 private NotificationPublishService newNotificationPublishService(
109 ConsumerSession session) {
110 return new NotificationProviderSessionImpl();
113 private class NotificationConsumerSessionImpl implements
114 NotificationService {
116 private final Multimap<QName, NotificationListener> consumerListeners = HashMultimap
118 private boolean closed = false;
122 public Registration<NotificationListener> addNotificationListener(QName notification,
123 NotificationListener listener) {
125 if (notification == null) {
126 throw new IllegalArgumentException(
127 "Notification type must not be null.");
129 if (listener == null) {
130 throw new IllegalArgumentException("Listener must not be null.");
133 consumerListeners.put(notification, listener);
134 listeners.put(notification, listener);
135 log.trace("Registered listener for notification: " + notification);
136 return null; // Return registration Object.
139 public void removeNotificationListener(QName notification,
140 NotificationListener listener) {
142 if (notification == null) {
143 throw new IllegalArgumentException(
144 "Notification type must not be null.");
146 if (listener == null) {
147 throw new IllegalArgumentException("Listener must not be null.");
149 consumerListeners.remove(notification, listener);
150 listeners.remove(notification, listener);
153 public void closeSession() {
155 Map<QName, Collection<NotificationListener>> toRemove = consumerListeners
157 for (Entry<QName, Collection<NotificationListener>> entry : toRemove
159 listeners.remove(entry.getKey(), entry.getValue());
163 protected void checkSessionState() {
165 throw new IllegalStateException("Session is closed");
169 private class NotificationProviderSessionImpl extends
170 NotificationConsumerSessionImpl implements
171 NotificationPublishService {
174 public void publish(CompositeNode notification) {
176 if (notification == null)
177 throw new IllegalArgumentException(
178 "Notification must not be null.");
179 NotificationModule.this.sendNotification(notification);
184 public Set<Class<? extends ProviderFunctionality>> getSupportedProviderFunctionality() {
185 return Collections.emptySet();