Bug 6324 - Notifications stream output is not same as restconf data
[netconf.git] / restconf / sal-rest-connector / src / main / java / org / opendaylight / netconf / sal / streams / listeners / Notificator.java
1 /*
2  * Copyright (c) 2014 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.netconf.sal.streams.listeners;
9
10 import java.util.ArrayList;
11 import java.util.List;
12 import java.util.Map;
13 import java.util.Set;
14 import java.util.concurrent.ConcurrentHashMap;
15 import java.util.concurrent.locks.Lock;
16 import java.util.concurrent.locks.ReentrantLock;
17 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
18 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
19 import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory;
21
22 /**
23  * {@link Notificator} is responsible to create, remove and find
24  * {@link ListenerAdapter} listener.
25  */
26 public class Notificator {
27
28     private static Map<String, ListenerAdapter> listenersByStreamName = new ConcurrentHashMap<>();
29     private static Map<String, List<NotificationListenerAdapter>> notificationListenersByStreamName = new ConcurrentHashMap<>();
30
31     private static final Logger LOG = LoggerFactory.getLogger(Notificator.class);
32     private static final Lock lock = new ReentrantLock();
33
34     private Notificator() {
35     }
36
37     /**
38      * Returns list of all stream names
39      */
40     public static Set<String> getStreamNames() {
41         return listenersByStreamName.keySet();
42     }
43
44     /**
45      * Gets {@link ListenerAdapter} specified by stream name.
46      *
47      * @param streamName
48      *            The name of the stream.
49      * @return {@link ListenerAdapter} specified by stream name.
50      */
51     public static ListenerAdapter getListenerFor(final String streamName) {
52         return listenersByStreamName.get(streamName);
53     }
54
55     /**
56      * Checks if the listener specified by {@link YangInstanceIdentifier} path exist.
57      *
58      * @param streamName
59      * @return True if the listener exist, false otherwise.
60      */
61     public static boolean existListenerFor(final String streamName) {
62         return listenersByStreamName.containsKey(streamName);
63     }
64
65     /**
66      * Creates new {@link ListenerAdapter} listener from {@link YangInstanceIdentifier} path and stream name.
67      *
68      * @param path
69      *            Path to data in data repository.
70      * @param streamName
71      *            The name of the stream.
72      * @return New {@link ListenerAdapter} listener from {@link YangInstanceIdentifier} path and stream name.
73      */
74     public static ListenerAdapter createListener(final YangInstanceIdentifier path, final String streamName) {
75         final ListenerAdapter listener = new ListenerAdapter(path, streamName);
76         try {
77             lock.lock();
78             listenersByStreamName.put(streamName, listener);
79         } finally {
80             lock.unlock();
81         }
82         return listener;
83     }
84
85     /**
86      * Looks for listener determined by {@link YangInstanceIdentifier} path and removes it.
87      * Creates String representation of stream name from URI. Removes slash from URI in start and end position.
88      *
89      * @param uri
90      *            URI for creation stream name.
91      * @return String representation of stream name.
92      */
93     public static String createStreamNameFromUri(final String uri) {
94         if (uri == null) {
95             return null;
96         }
97         String result = uri;
98         if (result.startsWith("/")) {
99             result = result.substring(1);
100         }
101         if (result.endsWith("/")) {
102             result = result.substring(0, result.length()-1);
103         }
104         return result;
105     }
106
107     /**
108      * Removes all listeners.
109      */
110     public static void removeAllListeners() {
111         for (final ListenerAdapter listener : listenersByStreamName.values()) {
112             try {
113                 listener.close();
114             } catch (final Exception e) {
115                 LOG.error("Failed to close listener", e);
116             }
117         }
118         try {
119             lock.lock();
120             listenersByStreamName = new ConcurrentHashMap<>();
121         } finally {
122             lock.unlock();
123         }
124     }
125
126     /**
127      * Checks if listener has at least one subscriber. In case it doesn't have any, delete listener.
128      *
129      * @param listener
130      *            ListenerAdapter
131      */
132     public static void removeListenerIfNoSubscriberExists(final ListenerAdapter listener) {
133         if (!listener.hasSubscribers()) {
134             deleteListener(listener);
135         }
136     }
137
138     /**
139      * Delete {@link ListenerAdapter} listener specified in parameter.
140      *
141      * @param listener
142      *            ListenerAdapter
143      */
144     private static void deleteListener(final ListenerAdapter listener) {
145         if (listener != null) {
146             try {
147                 listener.close();
148             } catch (final Exception e) {
149                 LOG.error("Failed to close listener", e);
150             }
151             try {
152                 lock.lock();
153                 listenersByStreamName.remove(listener.getStreamName());
154             } finally {
155                 lock.unlock();
156             }
157         }
158     }
159
160     /**
161      * Check if the listener specified by qnames of request exist.
162      *
163      * @param streamName
164      *            - name of stream
165      * @return True if the listener exist, false otherwise.
166      */
167     public static boolean existNotificationListenerFor(final String streamName) {
168         return notificationListenersByStreamName.containsKey(streamName);
169     }
170
171     public static List<NotificationListenerAdapter> createNotificationListener(final List<SchemaPath> paths,
172             final String streamName, final String outputType) {
173         final List<NotificationListenerAdapter> listListeners = new ArrayList<>();
174         for (final SchemaPath path : paths) {
175             final NotificationListenerAdapter listener = new NotificationListenerAdapter(path, streamName, outputType);
176             listListeners.add(listener);
177         }
178         try {
179             lock.lock();
180             notificationListenersByStreamName.put(streamName, listListeners);
181         } finally {
182             lock.unlock();
183         }
184         return listListeners;
185     }
186
187     public static void removeNotificationListenerIfNoSubscriberExists(final NotificationListenerAdapter listener) {
188         if (!listener.hasSubscribers()) {
189             deleteNotificationListener(listener);
190         }
191     }
192
193     private static void deleteNotificationListener(final NotificationListenerAdapter listener) {
194         if (listener != null) {
195             try {
196                 listener.close();
197             } catch (final Exception e) {
198                 LOG.error("Failed to close listener", e);
199             }
200             try {
201                 lock.lock();
202                 notificationListenersByStreamName.remove(listener.getStreamName());
203             } finally {
204                 lock.unlock();
205             }
206         }
207     }
208
209     public static List<NotificationListenerAdapter> getNotificationListenerFor(final String streamName) {
210         return notificationListenersByStreamName.get(streamName);
211     }
212 }