6181b0edc4c2af367407c3f6da04f6c0196931ee
[controller.git] / opendaylight / md-sal / sal-binding-broker / src / main / java / org / opendaylight / controller / md / sal / binding / compat / HeliumNotificationProviderServiceWithInterestListeners.java
1 /*
2  * Copyright (c) 2015 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.md.sal.binding.compat;
9
10 import com.google.common.collect.Sets;
11 import java.util.Collections;
12 import java.util.Iterator;
13 import java.util.Set;
14 import org.opendaylight.controller.md.sal.binding.impl.BindingDOMNotificationPublishServiceAdapter;
15 import org.opendaylight.controller.md.sal.binding.impl.BindingDOMNotificationServiceAdapter;
16 import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
17 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService;
18 import org.opendaylight.controller.md.sal.dom.spi.DOMNotificationSubscriptionListener;
19 import org.opendaylight.controller.md.sal.dom.spi.DOMNotificationSubscriptionListenerRegistry;
20 import org.opendaylight.controller.sal.binding.api.NotificationListener;
21 import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
22 import org.opendaylight.yangtools.concepts.ListenerRegistration;
23 import org.opendaylight.yangtools.util.ListenerRegistry;
24 import org.opendaylight.yangtools.yang.binding.Notification;
25 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
26 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 public class HeliumNotificationProviderServiceWithInterestListeners extends HeliumNotificationProviderServiceAdapter {
31
32     private static final Logger LOG = LoggerFactory.getLogger(
33             HeliumNotificationProviderServiceWithInterestListeners.class);
34
35     private final ListenerRegistry<NotificationInterestListener> interestListeners = ListenerRegistry.create();
36     private final ListenerRegistration<Listener> domListener;
37     private final DOMNotificationService domService;
38     private final BindingToNormalizedNodeCodec codec;
39
40     public HeliumNotificationProviderServiceWithInterestListeners(
41             final BindingDOMNotificationPublishServiceAdapter publishService,
42             final BindingDOMNotificationServiceAdapter listenService,
43             final DOMNotificationSubscriptionListenerRegistry registry) {
44         super(publishService, listenService);
45         this.codec = publishService.getCodecRegistry();
46         this.domListener = registry.registerSubscriptionListener(new Listener());
47         this.domService = listenService.getDomService();
48     }
49
50     @Override
51     public ListenerRegistration<NotificationInterestListener> registerInterestListener(
52             final NotificationInterestListener listener) {
53         notifyListener(listener, translate(domListener.getInstance().getAllObserved()));
54         return interestListeners.register(listener);
55     }
56
57     private Set<Class<? extends Notification>> translate(final Set<SchemaPath> added) {
58         return codec.getNotificationClasses(added);
59     }
60
61     @SuppressWarnings("checkstyle:IllegalCatch")
62     private void notifyAllListeners(final Set<SchemaPath> added) {
63         final Iterator<ListenerRegistration<NotificationInterestListener>> listeners = interestListeners.iterator();
64         if (listeners.hasNext()) {
65             final Set<Class<? extends Notification>> baEvent = translate(added);
66             while (listeners.hasNext()) {
67                 final NotificationInterestListener listenerRef = listeners.next().getInstance();
68                 try {
69                     notifyListener(listenerRef, baEvent);
70                 } catch (RuntimeException  e) {
71                     LOG.warn("Unhandled exception during invoking listener {}", e, listenerRef);
72                 }
73             }
74         }
75     }
76
77     @Override
78     public <T extends Notification> ListenerRegistration<NotificationListener<T>> registerNotificationListener(
79             final Class<T> type, final NotificationListener<T> listener) {
80
81         final FunctionalNotificationListenerAdapter<T> adapter =
82                 new FunctionalNotificationListenerAdapter<>(codec, type, listener);
83         final SchemaPath domType = SchemaPath.create(true, BindingReflections.findQName(type));
84         final ListenerRegistration<?> domReg = domService.registerNotificationListener(adapter, domType);
85         return new AbstractListenerRegistration<NotificationListener<T>>(listener) {
86             @Override
87             protected void removeRegistration() {
88                 domReg.close();
89             }
90         };
91     }
92
93     private void notifyListener(final NotificationInterestListener listener,
94             final Set<Class<? extends Notification>> baEvent) {
95         for (final Class<? extends Notification> event: baEvent) {
96             listener.onNotificationSubscribtion(event);
97         }
98     }
99
100     private final class Listener implements DOMNotificationSubscriptionListener {
101
102         private volatile Set<SchemaPath> allObserved = Collections.emptySet();
103
104         @Override
105         public void onSubscriptionChanged(final Set<SchemaPath> currentTypes) {
106             final Set<SchemaPath> added = Sets.difference(currentTypes, allObserved).immutableCopy();
107             notifyAllListeners(added);
108             allObserved = Sets.union(allObserved, added).immutableCopy();
109         }
110
111         Set<SchemaPath> getAllObserved() {
112             return allObserved;
113         }
114     }
115
116     @Override
117     public void close() throws Exception {
118         super.close();
119         domListener.close();
120     }
121 }