2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
\r
4 * This program and the accompanying materials are made available under the
\r
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
\r
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
\r
8 package org.opendaylight.controller.sal.binding.impl;
\r
10 import java.util.Collection;
\r
11 import java.util.Collections;
\r
12 import java.util.HashSet;
\r
13 import java.util.Set;
\r
15 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
\r
16 import org.opendaylight.controller.sal.binding.api.BindingAwareService;
\r
17 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
\r
18 import org.opendaylight.controller.sal.binding.api.NotificationService;
\r
19 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerSession;
\r
20 import org.opendaylight.controller.sal.binding.spi.SALBindingModule;
\r
21 import org.opendaylight.controller.sal.binding.spi.Mapper;
\r
22 import org.opendaylight.controller.sal.binding.spi.MappingProvider;
\r
23 import org.opendaylight.controller.sal.binding.spi.MappingProvider.MappingExtensionFactory;
\r
25 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
\r
26 import org.opendaylight.controller.yang.binding.DataObject;
\r
27 import org.opendaylight.controller.yang.binding.Notification;
\r
28 import org.opendaylight.controller.yang.binding.NotificationListener;
\r
29 import org.opendaylight.controller.yang.common.QName;
\r
30 import org.opendaylight.controller.yang.data.api.CompositeNode;
\r
31 import org.slf4j.Logger;
\r
32 import org.slf4j.LoggerFactory;
\r
34 import com.google.common.collect.HashMultimap;
\r
35 import com.google.common.collect.Multimap;
\r
37 public class NotificationModule implements SALBindingModule {
\r
39 private ProviderSession biSession;
\r
40 private org.opendaylight.controller.sal.core.api.notify.NotificationProviderService biNotifyService;
\r
41 private MappingProvider mappingProvider;
\r
43 private Multimap<Class<? extends Notification>, NotificationListener> listeners = HashMultimap
\r
45 private Set<QName> biNotifications = new HashSet<QName>();
\r
46 private static final Logger log = LoggerFactory
\r
47 .getLogger(NotificationModule.class);
\r
48 private final BindingIndependentListener biListener = new BindingIndependentListener();
\r
49 private BindingAwareBroker broker;
\r
52 public Set<Class<? extends BindingAwareService>> getProvidedServices() {
\r
54 Set<Class<? extends BindingAwareService>> ret = new HashSet<Class<? extends BindingAwareService>>();
\r
55 ret.add(NotificationService.class);
\r
56 ret.add(NotificationProviderService.class);
\r
61 public <T extends BindingAwareService> T getServiceForSession(
\r
62 Class<T> service, ConsumerSession session) {
\r
63 if (service == null)
\r
64 throw new IllegalArgumentException("Service should not be null");
\r
65 if (session == null)
\r
66 throw new IllegalArgumentException("Session should not be null");
\r
68 if (NotificationProviderSession.class.equals(service)) {
\r
69 if (session instanceof org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderSession) {
\r
70 @SuppressWarnings("unchecked")
\r
71 T ret = (T) new NotificationProviderSession(session);
\r
74 throw new IllegalArgumentException(
\r
75 "NotificationProviderService is available only to ProviderSession");
\r
79 if (NotificationService.class.equals(service)) {
\r
80 @SuppressWarnings("unchecked")
\r
81 T ret = (T) new NotificationSession(session);
\r
88 public Set<Class<? extends org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality>> getSupportedProviderFunctionality() {
\r
89 return Collections.emptySet();
\r
93 public void setBroker(BindingAwareBroker broker) {
\r
94 this.broker = broker;
\r
98 public void setMappingProvider(MappingProvider provider) {
\r
99 this.mappingProvider = provider;
\r
103 public void onBISessionAvailable(ProviderSession session) {
\r
104 biSession = session;
\r
105 if (biSession != null) {
\r
106 biNotifyService = session
\r
107 .getService(org.opendaylight.controller.sal.core.api.notify.NotificationProviderService.class);
\r
111 private void notify(Notification notification) {
\r
112 notifyBindingIndependent(notification);
\r
113 notifyBindingAware(notification);
\r
116 private void notifyBindingAware(Notification notification) {
\r
117 Class<? extends Notification> type = notification.getClass();
\r
118 Collection<NotificationListener> toNotify = listeners.get(type);
\r
120 // Invocation of notification on registered listeners
\r
121 if (toNotify != null) {
\r
123 // We get factory for Notification Invoker
\r
124 MappingExtensionFactory<NotificationInvoker> invokerFactory = mappingProvider
\r
125 .getExtensionFactory(NotificationInvoker.class);
\r
127 // We get generated invoker for NoficiationListener interface
\r
128 // associated to Notification Type
\r
129 NotificationInvoker invoker = invokerFactory.forClass(type);
\r
130 for (NotificationListener listener : toNotify) {
\r
132 // Invoker invokes the right method on subtype of
\r
133 // NotificationListener
\r
134 // associated to the type of notification
\r
135 invoker.notify(notification, listener);
\r
136 } catch (Exception e) {
\r
143 private void notifyBindingIndependent(Notification notification) {
\r
144 Class<? extends Notification> type = notification.getClass();
\r
146 if (biSession == null) {
\r
149 if (biSession.isClosed()) {
\r
152 if (biNotifyService == null) {
\r
156 // FIXME: Somehow we need to resolve this for class hierarchy.
\r
157 // probably use type.getInterfaces()
\r
158 Mapper<? extends Notification> mapper = mappingProvider
\r
159 .mapperForClass(type);
\r
160 CompositeNode domNotification = mapper.domFromObject(notification);
\r
162 biNotifyService.sendNotification(domNotification);
\r
165 private void addBAListener(Class<? extends Notification> notificationType,
\r
166 NotificationListener listener) {
\r
168 listeners.put(notificationType, listener);
\r
169 Mapper<? extends Notification> mapper = mappingProvider
\r
170 .mapperForClass(notificationType);
\r
171 QName biType = mapper.getQName();
\r
172 if (false == biNotifications.contains(biType)) {
\r
173 // The listener is not registered for binding independent
\r
175 biNotifications.add(biType);
\r
177 if (biNotifyService != null) {
\r
178 biNotifyService.addNotificationListener(biType, biListener);
\r
184 private void removeBAListener(
\r
185 Class<? extends Notification> notificationType,
\r
186 NotificationListener listener) {
\r
187 listeners.remove(notificationType, listener);
\r
190 private class NotificationSession implements NotificationService {
\r
191 private final ConsumerSession session;
\r
192 private Multimap<Class<? extends Notification>, NotificationListener> sessionListeners = HashMultimap
\r
195 public NotificationSession(ConsumerSession session) {
\r
196 this.session = session;
\r
200 public void addNotificationListener(
\r
201 Class<? extends Notification> notificationType,
\r
202 NotificationListener listener) {
\r
204 NotificationModule.this.addBAListener(notificationType, listener);
\r
205 sessionListeners.put(notificationType, listener);
\r
210 public void removeNotificationListener(
\r
211 Class<? extends Notification> notificationType,
\r
212 NotificationListener listener) {
\r
213 sessionListeners.remove(notificationType, listener);
\r
214 NotificationModule.this
\r
215 .removeBAListener(notificationType, listener);
\r
220 private class NotificationProviderSession extends NotificationSession
\r
221 implements NotificationProviderService {
\r
223 public NotificationProviderSession(ConsumerSession session) {
\r
228 public void notify(Notification notification) {
\r
229 NotificationModule.this.notify(notification);
\r
234 private class BindingIndependentListener
\r
236 org.opendaylight.controller.sal.core.api.notify.NotificationListener {
\r
239 public Set<QName> getSupportedNotifications() {
\r
240 return biNotifications;
\r
244 public void onNotification(CompositeNode notification) {
\r
245 NotificationModule.this
\r
246 .onBindingIndependentNotification(notification);
\r
251 private void onBindingIndependentNotification(CompositeNode biNotification) {
\r
252 QName biType = biNotification.getNodeType();
\r
254 Mapper<DataObject> mapper = mappingProvider.mapperForQName(biType);
\r
255 if (mapper == null) {
\r
256 log.info("Received notification does not have a binding defined.");
\r
259 Class<DataObject> type = mapper.getDataObjectClass();
\r
261 // We check if the received QName / type is really Notification
\r
262 if (Notification.class.isAssignableFrom(type)) {
\r
263 Notification notification = (Notification) mapper
\r
264 .objectFromDom(biNotification);
\r
265 notifyBindingAware(notification);
\r
267 // The generated type for this QName does not inherits from
\r
268 // notification something went wrong - generated APIs and/or
\r
269 // provider sending notification
\r
270 // which was incorectly described in the YANG schema.
\r
271 log.error("Received notification " + biType
\r
272 + " is not binded as notification");
\r