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;
12 import java.util.HashSet;
14 import java.util.Map.Entry;
17 import org.opendaylight.controller.sal.core.api.BrokerService;
18 import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
19 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
20 import org.opendaylight.controller.sal.core.api.Consumer.ConsumerFunctionality;
21 import org.opendaylight.controller.sal.core.api.Provider.ProviderFunctionality;
22 import org.opendaylight.controller.sal.core.api.notify.NotificationListener;
23 import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
24 import org.opendaylight.controller.sal.core.api.notify.NotificationService;
25 import org.opendaylight.controller.sal.core.spi.BrokerModule;
26 import org.opendaylight.yangtools.concepts.Registration;
27 import org.opendaylight.yangtools.yang.common.QName;
28 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
32 import com.google.common.collect.HashMultimap;
33 import com.google.common.collect.ImmutableSet;
34 import com.google.common.collect.Multimap;
36 public class NotificationModule implements BrokerModule {
37 private static Logger log = LoggerFactory
38 .getLogger(NotificationModule.class);
40 private Multimap<QName, NotificationListener> listeners = HashMultimap
43 private static final Set<Class<? extends BrokerService>> PROVIDED_SERVICE_TYPE = ImmutableSet
44 .<Class<? extends BrokerService>>of(NotificationService.class,
45 NotificationPublishService.class);
47 private static final Set<Class<? extends ConsumerFunctionality>> SUPPORTED_CONSUMER_FUNCTIONALITY = ImmutableSet
48 .of((Class<? extends ConsumerFunctionality>) NotificationListener.class,
49 NotificationListener.class); // Workaround: if we use the
50 // version of method with only
51 // one argument, the generics
52 // inference will not work
55 public Set<Class<? extends BrokerService>> getProvidedServices() {
56 return PROVIDED_SERVICE_TYPE;
60 public Set<Class<? extends ConsumerFunctionality>> getSupportedConsumerFunctionality() {
61 return SUPPORTED_CONSUMER_FUNCTIONALITY;
65 public <T extends BrokerService> T getServiceForSession(Class<T> service,
66 ConsumerSession session) {
67 if (NotificationPublishService.class.equals(service)
68 && session instanceof ProviderSession) {
69 @SuppressWarnings("unchecked")
70 T ret = (T) newNotificationPublishService(session);
72 } else if (NotificationService.class.equals(service)) {
74 @SuppressWarnings("unchecked")
75 T ret = (T) newNotificationConsumerService(session);
79 throw new IllegalArgumentException(
80 "The requested session-specific service is not provided by this module.");
83 private void sendNotification(CompositeNode notification) {
84 QName type = notification.getNodeType();
85 Collection<NotificationListener> toNotify = listeners.get(type);
86 log.info("Publishing notification " + type);
88 if (toNotify == null) {
89 // No listeners were registered - returns.
93 for (NotificationListener listener : toNotify) {
95 // FIXME: ensure that notification is immutable
96 listener.onNotification(notification);
97 } catch (Exception e) {
98 log.error("Uncaught exception in NotificationListener", e);
104 private NotificationService newNotificationConsumerService(
105 ConsumerSession session) {
106 return new NotificationConsumerSessionImpl();
109 private NotificationPublishService newNotificationPublishService(
110 ConsumerSession session) {
111 return new NotificationProviderSessionImpl();
114 private class NotificationConsumerSessionImpl implements
115 NotificationService {
117 private Multimap<QName, NotificationListener> consumerListeners = HashMultimap
119 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.info("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 sendNotification(CompositeNode notification) {
176 if (notification == null)
177 throw new IllegalArgumentException(
178 "Notification must not be null.");
179 NotificationModule.this.sendNotification(notification);
183 public void publish(CompositeNode notification) {
184 sendNotification(notification);
189 public Set<Class<? extends ProviderFunctionality>> getSupportedProviderFunctionality() {
190 return Collections.emptySet();