90b12a93e6b6a3f1c85b3ca839fc45ec8dde737a
[transportpce.git] / renderer / src / main / java / org / opendaylight / transportpce / renderer / RendererNotificationsImpl.java
1 /*
2  * Copyright © 2017 AT&T 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.transportpce.renderer;
9
10 import com.google.common.base.Optional;
11 import com.google.common.base.Preconditions;
12 import com.google.common.cache.CacheBuilder;
13 import com.google.common.cache.CacheLoader;
14 import com.google.common.cache.LoadingCache;
15
16 import java.util.Collection;
17 import java.util.List;
18 import java.util.Set;
19 import java.util.concurrent.ExecutionException;
20 import java.util.concurrent.Future;
21 import java.util.stream.Collectors;
22
23 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
24 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
25 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType;
26 import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
27 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
28 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
29 import org.opendaylight.controller.md.sal.binding.api.MountPoint;
30 import org.opendaylight.controller.md.sal.binding.api.MountPointService;
31 import org.opendaylight.controller.md.sal.binding.api.NotificationService;
32 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
33 import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry;
34 import org.opendaylight.transportpce.renderer.listeners.AlarmNotificationListener;
35 import org.opendaylight.transportpce.renderer.listeners.DeOperationsListener;
36 import org.opendaylight.transportpce.renderer.listeners.DeviceListener;
37 import org.opendaylight.transportpce.renderer.listeners.LldpListener;
38 import org.opendaylight.transportpce.renderer.listeners.TcaListener;
39 import org.opendaylight.transportpce.renderer.mapping.PortMapping;
40 import org.opendaylight.yang.gen.v1.http.org.openroadm.alarm.rev161014.AlarmNotification;
41 import org.opendaylight.yang.gen.v1.http.org.openroadm.alarm.rev161014.OrgOpenroadmAlarmListener;
42 import org.opendaylight.yang.gen.v1.http.org.openroadm.de.operations.rev161014.OrgOpenroadmDeOperationsListener;
43 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev161014.OrgOpenroadmDeviceListener;
44 import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.OrgOpenroadmLldpListener;
45 import org.opendaylight.yang.gen.v1.http.org.openroadm.tca.rev161014.OrgOpenroadmTcaListener;
46 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.CreateSubscriptionInputBuilder;
47 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.NotificationsService;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.StreamNameType;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.network.topology.topology.topology.types.TopologyNetconf;
52 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
53 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
54 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
55 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
56 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
57 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
58 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
59 import org.opendaylight.yangtools.concepts.ListenerRegistration;
60 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
61 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
62 import org.opendaylight.yangtools.yang.common.RpcResult;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
65
66 public class RendererNotificationsImpl implements DataTreeChangeListener<Node> {
67
68     private final DataBroker dataBroker;
69     private final MountPointService mountService;
70     private static final Logger LOG = LoggerFactory.getLogger(RendererNotificationsImpl.class);
71     private ListenerRegistration<RendererNotificationsImpl> dataTreeChangeListenerRegistration;
72
73     private final Set<String> currentMountedDevice;
74     public static final InstanceIdentifier<Topology> NETCONF_TOPO_IID = InstanceIdentifier.create(NetworkTopology.class)
75         .child(Topology.class, new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName())));
76
77     LoadingCache<String, KeyedInstanceIdentifier<Node, NodeKey>> mountIds = CacheBuilder.newBuilder().maximumSize(20)
78         .build(new CacheLoader<String, KeyedInstanceIdentifier<Node, NodeKey>>() {
79             @Override
80             public KeyedInstanceIdentifier<Node, NodeKey> load(final String key) {
81                 return NETCONF_TOPO_IID.child(Node.class, new NodeKey(new NodeId(key)));
82             }
83         });
84
85     public RendererNotificationsImpl(final DataBroker dataBroker, final MountPointService mountService,
86         Set<String> currentMountedDevice) {
87         this.dataBroker = dataBroker;
88         this.mountService = mountService;
89         this.currentMountedDevice = currentMountedDevice;
90         if (mountService == null) {
91             LOG.error("Mount service is null");
92
93         }
94         if (dataBroker != null) {
95             this.dataTreeChangeListenerRegistration = dataBroker.registerDataTreeChangeListener(
96                 new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL, NETCONF_TOPO_IID.child(Node.class)), this);
97         }
98     }
99
100     private void registerNotificationListener(final NodeId nodeId) {
101         final Optional<MountPoint> mountPoint;
102         try {
103             // Get mount point for specified device
104             mountPoint = mountService.getMountPoint(mountIds.get(nodeId.getValue()));
105             if (!mountPoint.isPresent()) {
106                 LOG.error("Mount point for node {} doesn't exist", nodeId.getValue());
107             }
108         } catch (ExecutionException e) {
109             throw new IllegalArgumentException(e);
110         }
111
112         // Register notification service
113         final Optional<NotificationService> notificationService = mountPoint.get().getService(
114             NotificationService.class);
115         if (!notificationService.isPresent()) {
116             LOG.error("Failed to get RpcService for node {}", nodeId.getValue());
117         }
118
119         final OrgOpenroadmAlarmListener alarmListener;
120         alarmListener = new AlarmNotificationListener();
121         LOG.info("Registering notification listener on {} for node: {}", AlarmNotification.QNAME, nodeId);
122         // Register notification listener
123         final ListenerRegistration<OrgOpenroadmAlarmListener>
124             accessAlarmNotificationListenerRegistration =
125                 notificationService.get().registerNotificationListener(alarmListener);
126
127         final OrgOpenroadmDeOperationsListener deOperationsListener;
128         deOperationsListener = new DeOperationsListener();
129         LOG.info("Registering notification listener on OrgOpenroadmDeOperationsListener for node: {}", nodeId);
130         // Register notification listener
131         final ListenerRegistration<OrgOpenroadmDeOperationsListener>
132             accessDeOperationasNotificationListenerRegistration =
133                 notificationService.get().registerNotificationListener(deOperationsListener);
134
135         final OrgOpenroadmDeviceListener deviceListener;
136         deviceListener = new DeviceListener();
137         LOG.info("Registering notification listener on OrgOpenroadmDeviceListener for node: {}", nodeId);
138         // Register notification listener
139         final ListenerRegistration<OrgOpenroadmDeviceListener>
140             accessDeviceNotificationListenerRegistration = notificationService.get()
141                 .registerNotificationListener(deviceListener);
142
143         final OrgOpenroadmLldpListener lldpListener;
144         lldpListener = new LldpListener();
145         LOG.info("Registering notification listener on OrgOpenroadmLldpListener for node: {}", nodeId);
146         // Register notification listener
147         final ListenerRegistration<OrgOpenroadmLldpListener> accessLldpNotificationListenerRegistration =
148             notificationService.get().registerNotificationListener(lldpListener);
149
150         final OrgOpenroadmTcaListener tcaListener;
151         tcaListener = new TcaListener();
152         LOG.info("Registering notification listener on OrgOpenroadmTcaListener for node: {}", nodeId);
153         // Register notification listener
154         final ListenerRegistration<OrgOpenroadmTcaListener> accessTcaNotificationListenerRegistration =
155             notificationService.get().registerNotificationListener(tcaListener);
156
157         // Listening to NETCONF datastream
158         final String streamName = "NETCONF";
159         final Optional<RpcConsumerRegistry> service = mountPoint.get().getService(RpcConsumerRegistry.class);
160         if (!service.isPresent()) {
161             LOG.error("Failed to get RpcService for node {}", nodeId.getValue());
162         }
163         final NotificationsService rpcService = service.get().getRpcService(NotificationsService.class);
164         final CreateSubscriptionInputBuilder createSubscriptionInputBuilder = new CreateSubscriptionInputBuilder();
165         createSubscriptionInputBuilder.setStream(new StreamNameType(streamName));
166         LOG.info("Triggering notification stream {} for node {}", streamName, nodeId);
167         final Future<RpcResult<Void>> subscription = rpcService.createSubscription(createSubscriptionInputBuilder
168             .build());
169     }
170
171     public void close() {
172         LOG.info("RenderernotificationsImpl Closed");
173         // Clean up the Data Change Listener registration
174         if (dataTreeChangeListenerRegistration != null) {
175             dataTreeChangeListenerRegistration.close();
176         }
177     }
178
179     @Override
180     public void onDataTreeChanged(Collection<DataTreeModification<Node>> changes) {
181
182         for (DataTreeModification<Node> change : changes) {
183
184             DataObjectModification<Node> rootNode = change.getRootNode();
185             String nodeId = rootNode.getDataAfter().getKey().getNodeId().getValue();
186             NetconfNode nnode = Preconditions.checkNotNull(rootNode.getDataAfter().getAugmentation(NetconfNode.class),
187                 "Node not connected via Netconf protocol");
188             if (nnode != null) {
189
190                 if (rootNode.getModificationType() == ModificationType.WRITE) {
191                     LOG.info("Node added " + nodeId);
192
193                 } else if (rootNode.getModificationType() == ModificationType.SUBTREE_MODIFIED) {
194
195                     LOG.info("Node modified " + nodeId);
196                     ConnectionStatus csts = nnode.getConnectionStatus();
197
198                     switch (csts) {
199                         case Connected: {
200                             LOG.info("NETCONF Node: {} is fully connected", nodeId);
201                             List<String> capabilities = nnode.getAvailableCapabilities().getAvailableCapability()
202                                 .stream().map(cp -> cp.getCapability()).collect(Collectors.toList());
203                             LOG.info("Capabilities: {}", capabilities);
204                             /*
205                              * TODO: check for required
206                              * capabilities to listen for notifications
207                              * registerNotificationListener(rootNode.
208                              * getDataAfter(). getNodeId());
209                              */
210                             currentMountedDevice.add(nodeId);
211                             new PortMapping(dataBroker, mountService, nodeId).createMappingData();
212                             break;
213                         }
214                         case Connecting: {
215                             LOG.info("NETCONF Node: {} was disconnected", nodeId);
216                             break;
217                         }
218                         case UnableToConnect: {
219                             LOG.info("NETCONF Node: {} connection failed", nodeId);
220                             break;
221                         }
222                         default:
223                             LOG.warn("Unexpected connection status " + csts.getName());
224                     }
225                 } else if (rootNode.getModificationType() ==  ModificationType.DELETE) {
226                     LOG.info("Node removed " + nodeId);
227                     currentMountedDevice.remove(nodeId);
228                 }
229             }
230         }
231     }
232 }