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.binding.impl;
10 import java.util.Collections;
11 import java.util.HashMap;
12 import java.util.HashSet;
13 import java.util.List;
17 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
18 import org.opendaylight.controller.sal.binding.api.BindingAwareService;
19 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
20 import org.opendaylight.controller.sal.binding.api.NotificationService;
21 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerSession;
22 import org.opendaylight.controller.sal.binding.spi.SALBindingModule;
23 import org.opendaylight.controller.sal.binding.spi.Mapper;
24 import org.opendaylight.controller.sal.binding.spi.MappingProvider;
25 import org.opendaylight.controller.sal.binding.spi.MappingProvider.MappingExtensionFactory;
27 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
28 import org.opendaylight.controller.yang.binding.DataObject;
29 import org.opendaylight.controller.yang.binding.Notification;
30 import org.opendaylight.controller.yang.binding.NotificationListener;
31 import org.opendaylight.controller.yang.common.QName;
32 import org.opendaylight.controller.yang.data.api.CompositeNode;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
36 public class NotificationModule implements SALBindingModule {
38 private ProviderSession biSession;
39 private org.opendaylight.controller.sal.core.api.notify.NotificationProviderService biNotifyService;
40 private BindingAwareBroker broker;
41 private MappingProvider mappingProvider;
43 private Map<Class<? extends Notification>, List<NotificationListener>> listeners = new HashMap<Class<? extends Notification>, List<NotificationListener>>();
44 private Set<QName> biNotifications = new HashSet<QName>();
45 private static final Logger log = LoggerFactory
46 .getLogger(NotificationModule.class);
47 private final BindingIndependentListener biListener = new BindingIndependentListener();
50 public Set<Class<? extends BindingAwareService>> getProvidedServices() {
52 Set<Class<? extends BindingAwareService>> ret = new HashSet<Class<? extends BindingAwareService>>();
53 ret.add(NotificationService.class);
54 ret.add(NotificationProviderService.class);
59 public <T extends BindingAwareService> T getServiceForSession(
60 Class<T> service, ConsumerSession session) {
62 throw new IllegalArgumentException("Service should not be null");
64 throw new IllegalArgumentException("Session should not be null");
66 if (NotificationProviderSession.class.equals(service)) {
67 if (session instanceof org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderSession) {
68 @SuppressWarnings("unchecked")
69 T ret = (T) new NotificationProviderSession(session);
72 throw new IllegalArgumentException(
73 "NotificationProviderService is available only to ProviderSession");
77 if (NotificationService.class.equals(service)) {
78 @SuppressWarnings("unchecked")
79 T ret = (T) new NotificationSession(session);
86 public Set<Class<? extends org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality>> getSupportedProviderFunctionality() {
87 return Collections.emptySet();
91 public void setBroker(BindingAwareBroker broker) {
96 public void setMappingProvider(MappingProvider provider) {
97 this.mappingProvider = provider;
101 public void onBISessionAvailable(ProviderSession session) {
103 if (biSession != null) {
104 biNotifyService = session
105 .getService(org.opendaylight.controller.sal.core.api.notify.NotificationProviderService.class);
109 private void notify(Notification notification) {
110 notifyBindingIndependent(notification);
111 notifyBindingAware(notification);
114 private void notifyBindingAware(Notification notification) {
115 Class<? extends Notification> type = notification.getClass();
116 List<NotificationListener> toNotify = listeners.get(type);
118 // Invocation of notification on registered listeners
119 if (toNotify != null) {
121 // We get factory for Notification Invoker
122 MappingExtensionFactory<NotificationInvoker> invokerFactory = mappingProvider
123 .getExtensionFactory(NotificationInvoker.class);
125 // We get generated invoker for NoficiationListener interface
126 // associated to Notification Type
127 NotificationInvoker invoker = invokerFactory.forClass(type);
128 for (NotificationListener listener : toNotify) {
130 // Invoker invokes the right method on subtype of
131 // NotificationListener
132 // associated to the type of notification
133 invoker.notify(notification, listener);
134 } catch (Exception e) {
141 private void notifyBindingIndependent(Notification notification) {
142 Class<? extends Notification> type = notification.getClass();
144 if (biSession == null) {
147 if (biSession.isClosed()) {
150 if (biNotifyService == null) {
154 // FIXME: Somehow we need to resolve this for class hierarchy.
155 // probably use type.getInterfaces()
156 Mapper<? extends Notification> mapper = mappingProvider.getMapper(type);
157 CompositeNode domNotification = mapper.domFromObject(notification);
159 biNotifyService.sendNotification(domNotification);
162 private void addBAListener(Class<? extends Notification> notificationType,
163 NotificationListener listener) {
165 BrokerUtils.addToMap(listeners, notificationType, listener);
166 Mapper<? extends Notification> mapper = mappingProvider
167 .getMapper(notificationType);
168 QName biType = mapper.getQName();
169 if (false == biNotifications.contains(biType)) {
170 // The listener is not registered for binding independent
172 biNotifications.add(biType);
174 if (biNotifyService != null) {
175 biNotifyService.addNotificationListener(biType, biListener);
181 private void removeBAListener(
182 Class<? extends Notification> notificationType,
183 NotificationListener listener) {
184 BrokerUtils.removeFromMap(listeners, notificationType, listener);
187 private class NotificationSession implements NotificationService {
188 private final ConsumerSession session;
190 public NotificationSession(ConsumerSession session) {
191 this.session = session;
194 private Map<Class<? extends Notification>, List<NotificationListener>> sessionListeners = new HashMap<Class<? extends Notification>, List<NotificationListener>>();
197 public void addNotificationListener(
198 Class<? extends Notification> notificationType,
199 NotificationListener listener) {
201 NotificationModule.this.addBAListener(notificationType, listener);
202 BrokerUtils.addToMap(sessionListeners, notificationType, listener);
207 public void removeNotificationListener(
208 Class<? extends Notification> notificationType,
209 NotificationListener listener) {
210 BrokerUtils.removeFromMap(sessionListeners, notificationType,
212 NotificationModule.this
213 .removeBAListener(notificationType, listener);
218 private class NotificationProviderSession extends NotificationSession
219 implements NotificationProviderService {
221 public NotificationProviderSession(ConsumerSession session) {
226 public void notify(Notification notification) {
227 NotificationModule.this.notify(notification);
232 private class BindingIndependentListener
234 org.opendaylight.controller.sal.core.api.notify.NotificationListener {
237 public Set<QName> getSupportedNotifications() {
238 return biNotifications;
242 public void onNotification(CompositeNode notification) {
243 NotificationModule.this
244 .onBindingIndependentNotification(notification);
249 private void onBindingIndependentNotification(CompositeNode biNotification) {
250 QName biType = biNotification.getNodeType();
252 Mapper<DataObject> mapper = mappingProvider.getMapper(biType);
253 if (mapper == null) {
254 log.info("Received notification does not have a binding defined.");
257 Class<DataObject> type = mapper.getDataObjectClass();
259 // We check if the received QName / type is really Notification
260 if (Notification.class.isAssignableFrom(type)) {
261 Notification notification = (Notification) mapper
262 .objectFromDom(biNotification);
263 notifyBindingAware(notification);
265 // The generated type for this QName does not inherits from
266 // notification something went wrong - generated APIs and/or
267 // provider sending notification
268 // which was incorectly described in the YANG schema.
269 log.error("Received notification " + biType
270 + " is not binded as notification");