dd64e7707325527e6d4f8b1e0e99dc993a8f0c7f
[controller.git] / opendaylight / md-sal / messagebus-impl / src / main / java / org / opendaylight / controller / messagebus / eventsources / netconf / NetconfEventSourceManager.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
9 package org.opendaylight.controller.messagebus.eventsources.netconf;
10
11
12 import java.util.HashMap;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.concurrent.ConcurrentHashMap;
16
17 import org.opendaylight.controller.config.yang.messagebus.app.impl.NamespaceToStream;
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
20 import org.opendaylight.controller.md.sal.binding.api.MountPointService;
21 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
22 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
23 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
24 import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
25 import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
26 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationPublishService;
27 import org.opendaylight.controller.messagebus.spi.EventSourceRegistration;
28 import org.opendaylight.controller.messagebus.spi.EventSourceRegistry;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeFields.ConnectionStatus;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.network.topology.topology.topology.types.TopologyNetconf;
32 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
33 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
34 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
35 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
36 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
37 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
38 import org.opendaylight.yangtools.concepts.ListenerRegistration;
39 import org.opendaylight.yangtools.yang.binding.DataObject;
40 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
41 import org.opendaylight.yangtools.yang.common.QName;
42 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46 import com.google.common.base.Optional;
47 import com.google.common.base.Preconditions;
48
49 public final class NetconfEventSourceManager implements DataChangeListener, AutoCloseable {
50
51     private static final Logger LOG = LoggerFactory.getLogger(NetconfEventSourceManager.class);
52     private static final TopologyKey NETCONF_TOPOLOGY_KEY = new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName()));
53     private static final InstanceIdentifier<Node> NETCONF_DEVICE_PATH = InstanceIdentifier.create(NetworkTopology.class)
54                 .child(Topology.class, NETCONF_TOPOLOGY_KEY)
55                 .child(Node.class);
56
57     private static final YangInstanceIdentifier NETCONF_DEVICE_DOM_PATH = YangInstanceIdentifier.builder()
58             .node(NetworkTopology.QNAME)
59             .node(Topology.QNAME)
60             .nodeWithKey(Topology.QNAME, QName.create(Topology.QNAME, "topology-id"),TopologyNetconf.QNAME.getLocalName())
61             .node(Node.QNAME)
62             .build();
63     private static final QName NODE_ID_QNAME = QName.create(Node.QNAME,"node-id");
64
65     private final Map<String, String> streamMap;
66     private final ConcurrentHashMap<InstanceIdentifier<?>, EventSourceRegistration<NetconfEventSource>> eventSourceRegistration = new ConcurrentHashMap<>();
67     private final DOMNotificationPublishService publishService;
68     private final DOMMountPointService domMounts;
69     private final MountPointService bindingMounts;
70     private ListenerRegistration<DataChangeListener> listenerRegistration;
71     private final EventSourceRegistry eventSourceRegistry;
72
73     public static NetconfEventSourceManager create(final DataBroker dataBroker,
74             final DOMNotificationPublishService domPublish,
75             final DOMMountPointService domMount,
76             final MountPointService bindingMount,
77             final EventSourceRegistry eventSourceRegistry,
78             final List<NamespaceToStream> namespaceMapping){
79
80         final NetconfEventSourceManager eventSourceManager =
81                 new NetconfEventSourceManager(domPublish, domMount, bindingMount, eventSourceRegistry, namespaceMapping);
82
83         eventSourceManager.initialize(dataBroker);
84
85         return eventSourceManager;
86
87     }
88
89     private NetconfEventSourceManager(final DOMNotificationPublishService domPublish,
90                               final DOMMountPointService domMount,
91                               final MountPointService bindingMount,
92                               final EventSourceRegistry eventSourceRegistry,
93                               final List<NamespaceToStream> namespaceMapping) {
94
95         Preconditions.checkNotNull(domPublish);
96         Preconditions.checkNotNull(domMount);
97         Preconditions.checkNotNull(bindingMount);
98         Preconditions.checkNotNull(eventSourceRegistry);
99         Preconditions.checkNotNull(namespaceMapping);
100         this.streamMap = namespaceToStreamMapping(namespaceMapping);
101         this.domMounts = domMount;
102         this.bindingMounts = bindingMount;
103         this.publishService = domPublish;
104         this.eventSourceRegistry = eventSourceRegistry;
105     }
106
107     private void initialize(final DataBroker dataBroker){
108         Preconditions.checkNotNull(dataBroker);
109         listenerRegistration = dataBroker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, NETCONF_DEVICE_PATH, this, DataChangeScope.SUBTREE);
110         LOG.info("NetconfEventSourceManager initialized.");
111     }
112
113     private Map<String,String> namespaceToStreamMapping(final List<NamespaceToStream> namespaceMapping) {
114         final Map<String, String> streamMap = new HashMap<>(namespaceMapping.size());
115
116         for (final NamespaceToStream nToS  : namespaceMapping) {
117             streamMap.put(nToS.getUrnPrefix(), nToS.getStreamName());
118         }
119
120         return streamMap;
121     }
122
123     @Override
124     public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> event) {
125
126         LOG.debug("[DataChangeEvent<InstanceIdentifier<?>, DataObject>: {}]", event);
127         for (final Map.Entry<InstanceIdentifier<?>, DataObject> changeEntry : event.getCreatedData().entrySet()) {
128             if (changeEntry.getValue() instanceof Node) {
129                 nodeUpdated(changeEntry.getKey(),(Node) changeEntry.getValue());
130             }
131         }
132
133         for (final Map.Entry<InstanceIdentifier<?>, DataObject> changeEntry : event.getUpdatedData().entrySet()) {
134             if (changeEntry.getValue() instanceof Node) {
135                 nodeUpdated(changeEntry.getKey(),(Node) changeEntry.getValue());
136             }
137         }
138
139     }
140
141     private void nodeUpdated(final InstanceIdentifier<?> key, final Node node) {
142
143         // we listen on node tree, therefore we should rather throw IllegalStateException when node is null
144         if ( node == null ) {
145             throw new IllegalStateException("Node is null");
146         }
147         if ( isNetconfNode(node) == false ) {
148             LOG.debug("OnDataChanged Event. Not a Netconf node.");
149             return;
150         }
151         if ( isEventSource(node) == false ) {
152             LOG.debug("OnDataChanged Event. Node an EventSource node.");
153             return;
154         }
155         if(node.getAugmentation(NetconfNode.class).getConnectionStatus() != ConnectionStatus.Connected ) {
156             return;
157         }
158
159         if(!eventSourceRegistration.containsKey(key)) {
160             createEventSource(key,node);
161         }
162     }
163
164     private void createEventSource(final InstanceIdentifier<?> key, final Node node) {
165         final Optional<DOMMountPoint> netconfMount = domMounts.getMountPoint(domMountPath(node.getNodeId()));
166
167         if(netconfMount.isPresent()) {
168             final NetconfEventSource netconfEventSource =
169                     new NetconfEventSource(node, streamMap, netconfMount.get(), publishService);
170             final EventSourceRegistration<NetconfEventSource> registration = eventSourceRegistry.registerEventSource(netconfEventSource);
171             LOG.info("Event source {} has been registered",node.getNodeId().getValue());
172             eventSourceRegistration.putIfAbsent(key, registration);
173
174         }
175     }
176
177     private YangInstanceIdentifier domMountPath(final NodeId nodeId) {
178         return YangInstanceIdentifier.builder(NETCONF_DEVICE_DOM_PATH).nodeWithKey(Node.QNAME, NODE_ID_QNAME, nodeId.getValue()).build();
179     }
180
181     private boolean isNetconfNode(final Node node)  {
182         return node.getAugmentation(NetconfNode.class) != null ;
183     }
184
185     private boolean isEventSource(final Node node) {
186
187         final NetconfNode netconfNode = node.getAugmentation(NetconfNode.class);
188         return isEventSource(netconfNode);
189
190     }
191
192     private boolean isEventSource(final NetconfNode node) {
193         if (node.getAvailableCapabilities() == null) {
194             return false;
195         }
196         final List<String> capabilities = node.getAvailableCapabilities().getAvailableCapability();
197         if(capabilities == null) {
198              return false;
199         }
200         for (final String capability : node.getAvailableCapabilities().getAvailableCapability()) {
201             if(capability.startsWith("(urn:ietf:params:xml:ns:netconf:notification")) {
202                 return true;
203             }
204         }
205
206         return false;
207     }
208
209     @Override
210     public void close() {
211         for(final EventSourceRegistration<NetconfEventSource> reg : eventSourceRegistration.values()){
212             reg.close();
213         }
214         listenerRegistration.close();
215     }
216
217 }