Make methods static
[ovsdb.git] / southbound / southbound-impl / src / main / java / org / opendaylight / ovsdb / southbound / OvsdbOperGlobalListener.java
1 /*
2  * Copyright (c) 2019 Ericsson India Global Services Pvt Ltd. 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.ovsdb.southbound;
9
10 import java.util.Collection;
11 import java.util.Map;
12 import java.util.concurrent.ConcurrentHashMap;
13 import java.util.concurrent.ConcurrentMap;
14 import java.util.concurrent.ScheduledFuture;
15 import java.util.concurrent.TimeUnit;
16 import org.opendaylight.mdsal.binding.api.ClusteredDataTreeChangeListener;
17 import org.opendaylight.mdsal.binding.api.DataBroker;
18 import org.opendaylight.mdsal.binding.api.DataObjectModification;
19 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
20 import org.opendaylight.mdsal.binding.api.DataTreeModification;
21 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
22 import org.opendaylight.ovsdb.southbound.transactions.md.TransactionInvoker;
23 import org.opendaylight.ovsdb.utils.mdsal.utils.Scheduler;
24 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
25 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
26 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
27 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
28 import org.opendaylight.yangtools.concepts.ListenerRegistration;
29 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 public class OvsdbOperGlobalListener implements ClusteredDataTreeChangeListener<Node>, AutoCloseable {
34     public static final ConcurrentMap<InstanceIdentifier<Node>, Node> OPER_NODE_CACHE = new ConcurrentHashMap<>();
35
36     private static final Logger LOG = LoggerFactory.getLogger(OvsdbOperGlobalListener.class);
37
38     private ListenerRegistration<OvsdbOperGlobalListener> registration;
39     private final DataBroker db;
40     private final OvsdbConnectionManager ovsdbConnectionManager;
41     private final TransactionInvoker txInvoker;
42
43     OvsdbOperGlobalListener(DataBroker db, OvsdbConnectionManager ovsdbConnectionManager,
44                             TransactionInvoker txInvoker) {
45         LOG.info("Registering OvsdbOperGlobalListener");
46         this.db = db;
47         this.ovsdbConnectionManager = ovsdbConnectionManager;
48         this.txInvoker = txInvoker;
49         registerListener();
50     }
51
52     public void registerListener() {
53         DataTreeIdentifier<Node> treeId =
54             DataTreeIdentifier.create(LogicalDatastoreType.OPERATIONAL, getWildcardPath());
55         registration = db.registerDataTreeChangeListener(treeId, this);
56     }
57
58     @Override
59     public void close() {
60         if (registration != null) {
61             registration.close();
62             LOG.info("OVSDB Oper Node listener has been closed.");
63         }
64     }
65
66     @Override
67     @SuppressWarnings("checkstyle:IllegalCatch")
68     public void onDataTreeChanged(Collection<DataTreeModification<Node>> changes) {
69         changes.forEach((change) -> {
70             try {
71                 InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
72                 DataObjectModification<Node> mod = change.getRootNode();
73                 Node addNode = getCreated(mod);
74                 if (addNode != null) {
75                     OPER_NODE_CACHE.put(key, addNode);
76                     LOG.info("Node added to oper {}", SouthboundUtil.getOvsdbNodeId(key));
77                 }
78                 Node removedNode = getRemoved(mod);
79                 if (removedNode != null) {
80                     OPER_NODE_CACHE.remove(key);
81                     LOG.info("Node deleted from oper {}", SouthboundUtil.getOvsdbNodeId(key));
82
83                     OvsdbConnectionInstance connectionInstance = ovsdbConnectionManager.getConnectionInstance(key);
84                     if (connectionInstance != null && connectionInstance.isActive()
85                             && connectionInstance.getHasDeviceOwnership() != null
86                             && connectionInstance.getHasDeviceOwnership()) {
87                         //Oops some one deleted the node held by me This should never happen.
88                         //put the node back in oper
89                         txInvoker.invoke(transaction -> {
90                             transaction.put(LogicalDatastoreType.OPERATIONAL, key, removedNode);
91                         });
92
93                     }
94                 }
95
96                 Node modifiedNode = getUpdated(mod);
97                 if (modifiedNode != null) {
98                     OPER_NODE_CACHE.put(key, modifiedNode);
99                 }
100             } catch (Exception e) {
101                 LOG.error("Failed to handle oper node ", e);
102             }
103         });
104     }
105
106     private static final Map<InstanceIdentifier<Node>, ScheduledFuture> TIMEOUT_FTS = new ConcurrentHashMap<>();
107
108     public static void runAfterTimeoutIfNodeNotCreated(InstanceIdentifier<Node> iid, Runnable job) {
109         ScheduledFuture<?> ft = TIMEOUT_FTS.get(iid);
110         if (ft != null) {
111             ft.cancel(false);
112         }
113         ft = Scheduler.getScheduledExecutorService().schedule(() -> {
114             TIMEOUT_FTS.remove(iid);
115             if (!OPER_NODE_CACHE.containsKey(iid)) {
116                 job.run();
117             }
118         }, SouthboundConstants.EOS_TIMEOUT, TimeUnit.SECONDS);
119         TIMEOUT_FTS.put(iid, ft);
120     }
121
122     private static Node getCreated(DataObjectModification<Node> mod) {
123         if (mod.getModificationType() == DataObjectModification.ModificationType.WRITE
124                 && mod.getDataBefore() == null) {
125             return mod.getDataAfter();
126         }
127         return null;
128     }
129
130     private static Node getRemoved(DataObjectModification<Node> mod) {
131         if (mod.getModificationType() == DataObjectModification.ModificationType.DELETE) {
132             return mod.getDataBefore();
133         }
134         return null;
135     }
136
137     private static Node getUpdated(DataObjectModification<Node> mod) {
138         Node node = null;
139         switch (mod.getModificationType()) {
140             case SUBTREE_MODIFIED:
141                 node = mod.getDataAfter();
142                 break;
143             case WRITE:
144                 if (mod.getDataBefore() !=  null) {
145                     node = mod.getDataAfter();
146                 }
147                 break;
148             default:
149                 break;
150         }
151         return node;
152     }
153
154     private static InstanceIdentifier<Node> getWildcardPath() {
155         return InstanceIdentifier.create(NetworkTopology.class)
156                 .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID))
157                 .child(Node.class);
158     }
159 }