Fix warnings reported in toaster
[controller.git] / opendaylight / md-sal / sal-dom-broker / src / main / java / org / opendaylight / controller / sal / dom / broker / NotificationModule.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.sal.dom.broker;
9
10 import java.util.Collection;
11 import java.util.Collections;
12 import java.util.HashSet;
13 import java.util.Map;
14 import java.util.Map.Entry;
15 import java.util.Set;
16
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;
31
32 import com.google.common.collect.HashMultimap;
33 import com.google.common.collect.ImmutableSet;
34 import com.google.common.collect.Multimap;
35
36 public class NotificationModule implements BrokerModule {
37     private static Logger log = LoggerFactory
38             .getLogger(NotificationModule.class);
39
40     private Multimap<QName, NotificationListener> listeners = HashMultimap
41             .create();
42
43     private static final Set<Class<? extends BrokerService>> PROVIDED_SERVICE_TYPE = ImmutableSet
44             .<Class<? extends BrokerService>>of(NotificationService.class,
45                     NotificationPublishService.class);
46
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
53
54     @Override
55     public Set<Class<? extends BrokerService>> getProvidedServices() {
56         return PROVIDED_SERVICE_TYPE;
57     }
58
59     @Override
60     public Set<Class<? extends ConsumerFunctionality>> getSupportedConsumerFunctionality() {
61         return SUPPORTED_CONSUMER_FUNCTIONALITY;
62     }
63
64     @Override
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);
71             return ret;
72         } else if (NotificationService.class.equals(service)) {
73
74             @SuppressWarnings("unchecked")
75             T ret = (T) newNotificationConsumerService(session);
76             return ret;
77         }
78
79         throw new IllegalArgumentException(
80                 "The requested session-specific service is not provided by this module.");
81     }
82
83     private void sendNotification(CompositeNode notification) {
84         QName type = notification.getNodeType();
85         Collection<NotificationListener> toNotify = listeners.get(type);
86         log.trace("Publishing notification " + type);
87
88         if (toNotify == null) {
89             // No listeners were registered - returns.
90             return;
91         }
92
93         for (NotificationListener listener : toNotify) {
94             try {
95                 // FIXME: ensure that notification is immutable
96                 listener.onNotification(notification);
97             } catch (Exception e) {
98                 log.error("Uncaught exception in NotificationListener", e);
99             }
100         }
101
102     }
103
104     private NotificationService newNotificationConsumerService(
105             ConsumerSession session) {
106         return new NotificationConsumerSessionImpl();
107     }
108
109     private NotificationPublishService newNotificationPublishService(
110             ConsumerSession session) {
111         return new NotificationProviderSessionImpl();
112     }
113
114     private class NotificationConsumerSessionImpl implements
115             NotificationService {
116
117         private Multimap<QName, NotificationListener> consumerListeners = HashMultimap
118                 .create();
119         private boolean closed = false;
120
121
122         public Registration<NotificationListener> addNotificationListener(QName notification,
123                 NotificationListener listener) {
124             checkSessionState();
125             if (notification == null) {
126                 throw new IllegalArgumentException(
127                         "Notification type must not be null.");
128             }
129             if (listener == null) {
130                 throw new IllegalArgumentException("Listener must not be null.");
131             }
132
133             consumerListeners.put(notification, listener);
134             listeners.put(notification, listener);
135             log.trace("Registered listener for notification: " + notification);
136             return null; // Return registration Object.
137         }
138
139         public void removeNotificationListener(QName notification,
140                 NotificationListener listener) {
141             checkSessionState();
142             if (notification == null) {
143                 throw new IllegalArgumentException(
144                         "Notification type must not be null.");
145             }
146             if (listener == null) {
147                 throw new IllegalArgumentException("Listener must not be null.");
148             }
149             consumerListeners.remove(notification, listener);
150             listeners.remove(notification, listener);
151         }
152
153         public void closeSession() {
154             closed = true;
155             Map<QName, Collection<NotificationListener>> toRemove = consumerListeners
156                     .asMap();
157             for (Entry<QName, Collection<NotificationListener>> entry : toRemove
158                     .entrySet()) {
159                 listeners.remove(entry.getKey(), entry.getValue());
160             }
161         }
162
163         protected void checkSessionState() {
164             if (closed)
165                 throw new IllegalStateException("Session is closed");
166         }
167     }
168
169     private class NotificationProviderSessionImpl extends
170             NotificationConsumerSessionImpl implements
171             NotificationPublishService {
172
173         @Override
174         public void sendNotification(CompositeNode notification) {
175             checkSessionState();
176             if (notification == null)
177                 throw new IllegalArgumentException(
178                         "Notification must not be null.");
179             NotificationModule.this.sendNotification(notification);
180         }
181
182         @Override
183         public void publish(CompositeNode notification) {
184             sendNotification(notification);
185         }
186     }
187
188     @Override
189     public Set<Class<? extends ProviderFunctionality>> getSupportedProviderFunctionality() {
190         return Collections.emptySet();
191     }
192 }