189c58555fbb562337335bac30a77c469b0b2461
[controller.git] / opendaylight / sal / yang-prototype / sal / sal-binding-broker-impl / src / main / java / org / opendaylight / controller / sal / binding / impl / NotificationModule.java
1 package org.opendaylight.controller.sal.binding.impl;
2
3 import java.util.Collection;
4 import java.util.Collections;
5 import java.util.HashMap;
6 import java.util.HashSet;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.Set;
10
11 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
12 import org.opendaylight.controller.sal.binding.api.BindingAwareService;
13 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
14 import org.opendaylight.controller.sal.binding.api.NotificationService;
15 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerSession;
16 import org.opendaylight.controller.sal.binding.spi.SALBindingModule;
17 import org.opendaylight.controller.sal.binding.spi.Mapper;
18 import org.opendaylight.controller.sal.binding.spi.MappingProvider;
19 import org.opendaylight.controller.sal.binding.spi.MappingProvider.MappingExtensionFactory;
20 import org.opendaylight.controller.sal.core.api.Provider;
21 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
22 import org.opendaylight.controller.yang.binding.DataObject;
23 import org.opendaylight.controller.yang.binding.Notification;
24 import org.opendaylight.controller.yang.binding.NotificationListener;
25 import org.opendaylight.controller.yang.common.QName;
26 import org.opendaylight.controller.yang.data.api.CompositeNode;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 public class NotificationModule implements SALBindingModule {
31
32     private ProviderSession biSession;
33     private org.opendaylight.controller.sal.core.api.notify.NotificationProviderService biNotifyService;
34     private BindingAwareBroker broker;
35     private MappingProvider mappingProvider;
36
37     private Map<Class<? extends Notification>, List<NotificationListener>> listeners = new HashMap<Class<? extends Notification>, List<NotificationListener>>();
38     private static Logger log = LoggerFactory.getLogger(NotificationModule.class);
39
40     @Override
41     public Set<Class<? extends BindingAwareService>> getProvidedServices() {
42
43         Set<Class<? extends BindingAwareService>> ret = new HashSet<Class<? extends BindingAwareService>>();
44         ret.add(NotificationService.class);
45         ret.add(NotificationProviderService.class);
46         return ret;
47     }
48
49     @Override
50     public <T extends BindingAwareService> T getServiceForSession(
51             Class<T> service, ConsumerSession session) {
52         if (service == null)
53             throw new IllegalArgumentException("Service should not be null");
54         if (session == null)
55             throw new IllegalArgumentException("Session should not be null");
56
57         if (NotificationProviderSession.class.equals(service)) {
58             if (session instanceof org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderSession) {
59                 @SuppressWarnings("unchecked")
60                 T ret = (T) new NotificationProviderSession(session);
61                 return ret;
62             } else {
63                 throw new IllegalArgumentException(
64                         "NotificationProviderService is available only to ProviderSession");
65             }
66         }
67
68         if (NotificationService.class.equals(service)) {
69             @SuppressWarnings("unchecked")
70             T ret = (T) new NotificationSession(session);
71             return ret;
72         }
73         return null;
74     }
75
76     @Override
77     public Set<Class<? extends org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality>> getSupportedProviderFunctionality() {
78         return Collections.emptySet();
79     }
80
81     @Override
82     public void setBroker(BindingAwareBroker broker) {
83         this.broker = broker;
84     }
85
86     @Override
87     public void setMappingProvider(MappingProvider provider) {
88         this.mappingProvider = provider;
89     }
90
91     @Override
92     public void onBISessionAvailable(ProviderSession session) {
93         biSession = session;
94         if (biSession != null) {
95             biNotifyService = session
96                     .getService(org.opendaylight.controller.sal.core.api.notify.NotificationProviderService.class);
97         }
98     }
99
100     private void notify(Notification notification) {
101         notifyBindingIndependent(notification);
102         notifyBindingAware(notification);
103     }
104
105     private void notifyBindingAware(Notification notification) {
106         Class<? extends Notification> type = notification.getClass();
107         List<NotificationListener> toNotify = listeners.get(type);
108
109         // Invocation of notification on registered listeners
110         if (toNotify != null) {
111
112             // We get factory for Notification Invoker
113             MappingExtensionFactory<NotificationInvoker> invokerFactory = mappingProvider
114                     .getExtensionFactory(NotificationInvoker.class);
115
116             // We get generated invoker for NoficiationListener interface
117             // associated to Notification Type
118             NotificationInvoker invoker = invokerFactory.forClass(type);
119             for (NotificationListener listener : toNotify) {
120                 try {
121                     // Invoker invokes the right method on subtype of
122                     // NotificationListener
123                     // associated to the type of notification
124                     invoker.notify(notification, listener);
125                 } catch (Exception e) {
126
127                 }
128             }
129         }
130     }
131
132     private void notifyBindingIndependent(Notification notification) {
133         Class<? extends Notification> type = notification.getClass();
134
135         if (biSession == null) {
136             return;
137         }
138         if (biSession.isClosed()) {
139             return;
140         }
141         if (biNotifyService == null) {
142             return;
143         }
144
145         // FIXME: Somehow we need to resolve this for class hierarchy.
146         // probably use type.getInterfaces()
147         Mapper<? extends Notification> mapper = mappingProvider.getMapper(type);
148         CompositeNode domNotification = mapper.domFromObject(notification);
149
150         biNotifyService.sendNotification(domNotification);
151     }
152
153     private class NotificationSession implements NotificationService {
154         private final ConsumerSession session;
155
156         public NotificationSession(ConsumerSession session) {
157             this.session = session;
158         }
159
160         private Map<Class<? extends Notification>, List<NotificationListener>> sessionListeners = new HashMap<Class<? extends Notification>, List<NotificationListener>>();
161
162         @Override
163         public void addNotificationListener(
164                 Class<? extends Notification> notificationType,
165                 NotificationListener listener) {
166             // TODO Implement this method
167             throw new UnsupportedOperationException("Not implemented");
168         }
169
170         @Override
171         public void removeNotificationListener(
172                 Class<? extends Notification> notificationType,
173                 NotificationListener listener) {
174             // TODO Implement this method
175             throw new UnsupportedOperationException("Not implemented");
176         }
177
178     }
179
180     private class NotificationProviderSession extends NotificationSession
181             implements NotificationProviderService {
182
183         public NotificationProviderSession(ConsumerSession session) {
184             super(session);
185         }
186
187         @Override
188         public void notify(Notification notification) {
189             NotificationModule.this.notify(notification);
190         }
191
192     }
193     
194     private class BindingIndependentListener implements org.opendaylight.controller.sal.core.api.notify.NotificationListener {
195
196         @Override
197         public Set<QName> getSupportedNotifications() {
198             return Collections.emptySet();
199         }
200
201         @Override
202         public void onNotification(CompositeNode notification) {
203             NotificationModule.this.onBindingIndependentNotification(notification);
204         }
205         
206     }
207
208     private void onBindingIndependentNotification(CompositeNode biNotification) {
209         QName biType = biNotification.getNodeType();
210         
211         Mapper<DataObject> mapper = mappingProvider.getMapper(biType);
212         if(mapper == null) {
213             log.info("Received notification does not have a binding defined.");
214             return;
215         }
216         Class<DataObject> type = mapper.getDataObjectClass();
217         
218         // We check if the received QName / type is really Notification
219         if(Notification.class.isAssignableFrom(type)) {
220             Notification notification = (Notification) mapper.objectFromDom(biNotification);
221             notifyBindingAware(notification);
222         } else {
223             // The generated type for this QName does not inherits from notification
224             // something went wrong - generated APIs and/or provider sending notification
225             // which was incorectly described in the YANG schema.
226             log.error("Received notification "+  biType +" is not binded as notification");
227         }
228         
229     }
230 }