Network topology and inventory init
[transportpce.git] / inventory / src / main / java / org / opendaylight / transportpce / inventory / listener / DeviceListener.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
9 package org.opendaylight.transportpce.inventory.listener;
10
11 import java.util.Collection;
12 import java.util.List;
13 import java.util.concurrent.ExecutionException;
14 import java.util.stream.Collectors;
15 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType;
16 import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
17 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
18 import org.opendaylight.transportpce.common.StringConstants;
19 import org.opendaylight.transportpce.inventory.DeviceInventory;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus;
23 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 /**
28  * This class implements the {@link DataTreeChangeListener} on a {@link Node}. This listener should
29  * be registered on a netconf topology node.
30  *
31  */
32 public class DeviceListener implements DataTreeChangeListener<Node> {
33
34     private static final Logger LOG = LoggerFactory.getLogger(DeviceListener.class);
35     private final DeviceInventory deviceInventory;
36
37     /**
38      * Default constructor invoked by blueprint injects {@link DeviceInventory} as a persistence layer.
39      *
40      * @param deviceInventory reference to the {@link DeviceInventory}
41      */
42     public DeviceListener(DeviceInventory deviceInventory) {
43         this.deviceInventory = deviceInventory;
44     }
45
46     @Override
47     public void onDataTreeChanged(Collection<DataTreeModification<Node>> changes) {
48         List<DataTreeModification<Node>> changesWithoutDefaultNetconfNode = getRealDevicesOnly(changes);
49         for (DataTreeModification<Node> device : changesWithoutDefaultNetconfNode) {
50             String nodeId = device.getRootNode().getDataAfter().getKey().getNodeId().getValue();
51             NetconfNode netconfNode = device.getRootNode().getDataAfter().getAugmentation(NetconfNode.class);
52             if (isCreate(device) || isUpdate(device)) {
53                 LOG.info("Node {} was modified", nodeId);
54                 try {
55                     processModifiedSubtree(nodeId, netconfNode);
56                 } catch (InterruptedException | ExecutionException e) {
57                     LOG.error(e.getMessage(), e);
58                 }
59             } else if (isDelete(device)) {
60                 LOG.info("Node {} was deleted", nodeId);
61             }
62         }
63     }
64
65     /**
66      * Handles the {@link ModificationType#SUBTREE_MODIFIED} case. If the changed node has
67      * {@link StringConstants.OPENROADM_DEVICE_MODEL_NAME} capabilities it may be persisted.
68      *
69      * @param nodeId device id
70      * @param netconfNode netconf node
71      * @throws InterruptedException may be thrown if there is a problem getting the device from
72      *         datastore
73      * @throws ExecutionException may be thrown if there is a problem getting the device from datastore
74      */
75     private void processModifiedSubtree(String nodeId, NetconfNode netconfNode)
76             throws InterruptedException, ExecutionException {
77         NetconfNodeConnectionStatus.ConnectionStatus connectionStatus = netconfNode.getConnectionStatus();
78         long count = netconfNode.getAvailableCapabilities().getAvailableCapability().stream()
79                 .filter(cp -> cp.getCapability().contains(StringConstants.OPENROADM_DEVICE_MODEL_NAME)).count();
80         if (count < 1) {
81             LOG.info("No {} capable device was found", StringConstants.OPENROADM_DEVICE_MODEL_NAME);
82             return;
83         }
84         if (ConnectionStatus.Connected.equals(connectionStatus)) {
85             deviceInventory.initializeDevice(nodeId);
86         } else if (ConnectionStatus.Connecting.equals(connectionStatus)
87                 || ConnectionStatus.UnableToConnect.equals(connectionStatus)) {
88             LOG.info("The device is in {} state", connectionStatus);
89         } else {
90             LOG.warn("Invalid connection status {}", connectionStatus);
91         }
92     }
93
94     /**
95      * Filters the {@link StringConstants#DEFAULT_NETCONF_NODEID} nodes from the provided
96      * {@link Collection}.
97      *
98      * @param changes a change
99      * @return {@code List<DataTreeModification<Node>>} a list of modifcations
100      */
101     private static List<DataTreeModification<Node>> getRealDevicesOnly(Collection<DataTreeModification<Node>> changes) {
102         return changes.stream()
103                 .filter(change -> (change.getRootNode().getDataAfter() != null
104                         && !StringConstants.DEFAULT_NETCONF_NODEID
105                                 .equalsIgnoreCase(change.getRootNode().getDataAfter().getKey().getNodeId().getValue())
106                         && change.getRootNode().getDataAfter().getAugmentation(NetconfNode.class) != null)
107                         || (change.getRootNode().getDataBefore() != null
108                                 && !StringConstants.DEFAULT_NETCONF_NODEID.equalsIgnoreCase(
109                                         change.getRootNode().getDataBefore().getKey().getNodeId().getValue())
110                                 && change.getRootNode().getDataBefore().getAugmentation(NetconfNode.class) != null
111
112                         )).collect(Collectors.toList());
113     }
114
115     /**
116      * In the filtered collection checks if the change is a new write.
117      *
118      * @param change the change
119      * @return boolean true if the change is a new write
120      */
121     private static boolean isCreate(DataTreeModification<Node> change) {
122         return change.getRootNode().getDataBefore() == null && change.getRootNode().getDataAfter() != null
123                 && ModificationType.WRITE.equals(change.getRootNode().getModificationType());
124     }
125
126     /**
127      * In the filtered collection checks if the modification is update.
128      *
129      * @param change the change
130      * @return boolean true if the modification is update
131      */
132     private static boolean isUpdate(DataTreeModification<Node> change) {
133         return ModificationType.SUBTREE_MODIFIED.equals(change.getRootNode().getModificationType());
134     }
135
136     /**
137      * In the filtered collection checks if the node was deleted.
138      *
139      * @param change the change
140      * @return boolean true if the node was deleted
141      */
142     private static boolean isDelete(DataTreeModification<Node> change) {
143         return change.getRootNode().getDataBefore() != null && change.getRootNode().getDataAfter() == null
144                 && ModificationType.DELETE.equals(change.getRootNode().getModificationType());
145     }
146 }