BUG 2090 : Clustering : Bring akka-raft unit test coverage upto 80%
[controller.git] / opendaylight / md-sal / samples / l2switch / implementation / src / main / java / org / opendaylight / controller / sample / l2switch / md / topology / TopologyLinkDataChangeHandler.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.controller.sample.l2switch.md.topology;
9
10 import com.google.common.base.Preconditions;
11 import org.opendaylight.controller.sample.l2switch.md.util.InstanceIdentifierUtils;
12 import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
13 import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
14 import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
15 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
16 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
17 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
18 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
19 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
20 import org.opendaylight.yangtools.yang.binding.DataObject;
21 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24
25 import java.util.List;
26 import java.util.Map;
27 import java.util.concurrent.Executors;
28 import java.util.concurrent.ScheduledExecutorService;
29 import java.util.concurrent.TimeUnit;
30
31 /**
32  * Listens to data change events on topology links
33  * {@link org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link}
34  * and maintains a topology graph using provided NetworkGraphService
35  * {@link org.opendaylight.controller.sample.l2switch.md.topology.NetworkGraphService}.
36  * It refreshes the graph after a delay(default 10 sec) to accommodate burst of change events if they come in bulk.
37  * This is to avoid continuous refresh of graph on a series of change events in short time.
38  */
39 public class TopologyLinkDataChangeHandler implements DataChangeListener {
40   private static final Logger _logger = LoggerFactory.getLogger(TopologyLinkDataChangeHandler.class);
41   private static final String DEFAULT_TOPOLOGY_ID = "flow:1";
42
43   private boolean networkGraphRefreshScheduled = false;
44   private final ScheduledExecutorService networkGraphRefreshScheduler = Executors.newScheduledThreadPool(1);
45   private final long DEFAULT_GRAPH_REFRESH_DELAY = 10;
46   private final long graphRefreshDelayInSec;
47
48   private final NetworkGraphService networkGraphService;
49   private final DataBrokerService dataBrokerService;
50
51   /**
52    * Uses default delay to refresh topology graph if this constructor is used.
53    * @param dataBrokerService
54    * @param networkGraphService
55    */
56   public TopologyLinkDataChangeHandler(DataBrokerService dataBrokerService, NetworkGraphService networkGraphService) {
57     Preconditions.checkNotNull(dataBrokerService, "dataBrokerService should not be null.");
58     Preconditions.checkNotNull(networkGraphService, "networkGraphService should not be null.");
59     this.dataBrokerService = dataBrokerService;
60     this.networkGraphService = networkGraphService;
61     this.graphRefreshDelayInSec = DEFAULT_GRAPH_REFRESH_DELAY;
62   }
63
64   /**
65    *
66    * @param dataBrokerService
67    * @param networkGraphService
68    * @param graphRefreshDelayInSec
69    */
70   public TopologyLinkDataChangeHandler(DataBrokerService dataBrokerService, NetworkGraphService networkGraphService,
71                                        long graphRefreshDelayInSec) {
72     Preconditions.checkNotNull(dataBrokerService, "dataBrokerService should not be null.");
73     Preconditions.checkNotNull(networkGraphService, "networkGraphService should not be null.");
74     this.dataBrokerService = dataBrokerService;
75     this.networkGraphService = networkGraphService;
76     this.graphRefreshDelayInSec = graphRefreshDelayInSec;
77   }
78
79   /**
80    * Based on if links have been added or removed in topology data store, schedules a refresh of network graph.
81    * @param dataChangeEvent
82    */
83   @Override
84   public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> dataChangeEvent) {
85     if(dataChangeEvent == null) {
86       _logger.info("In onDataChanged: No Processing done as dataChangeEvent is null.");
87     }
88     Map<InstanceIdentifier<?>, DataObject> linkOriginalData = dataChangeEvent.getOriginalOperationalData();
89     Map<InstanceIdentifier<?>, DataObject> linkUpdatedData = dataChangeEvent.getUpdatedOperationalData();
90     // change this logic, once MD-SAL start populating DeletedOperationData Set
91     if(linkOriginalData != null && linkUpdatedData != null
92         && (linkOriginalData.size() != 0 || linkUpdatedData.size() != 0)
93         && !networkGraphRefreshScheduled) {
94       networkGraphRefreshScheduled = linkOriginalData.size() != linkUpdatedData.size();
95       if(networkGraphRefreshScheduled) {
96         networkGraphRefreshScheduler.schedule(new NetworkGraphRefresher(), graphRefreshDelayInSec, TimeUnit.SECONDS);
97       }
98     }
99
100   }
101
102   /**
103    * Registers as a data listener to receive changes done to
104    * {@link org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link}
105    * under {@link org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology}
106    * operation data root.
107    */
108
109   public void registerAsDataChangeListener() {
110     InstanceIdentifier<Link> linkInstance = InstanceIdentifier.builder(NetworkTopology.class)
111         .child(Topology.class, new TopologyKey(new TopologyId(DEFAULT_TOPOLOGY_ID))).child(Link.class).toInstance();
112     dataBrokerService.registerDataChangeListener(linkInstance, this);
113   }
114
115   /**
116    *
117    */
118   private class NetworkGraphRefresher implements Runnable {
119     /**
120      *
121      */
122     @Override
123     public void run() {
124       networkGraphRefreshScheduled = false;
125       //TODO: it should refer to changed links only from DataChangeEvent above.
126       List<Link> links = getLinksFromTopology(DEFAULT_TOPOLOGY_ID);
127       networkGraphService.clear();// can remove this once changed links are addressed
128       if(links != null && !links.isEmpty()) {
129         networkGraphService.addLinks(links);
130       }
131     }
132
133     /**
134      * @param topologyId
135      * @return
136      */
137     private List<Link> getLinksFromTopology(String topologyId) {
138       InstanceIdentifier<Topology> topologyInstanceIdentifier = InstanceIdentifierUtils.generateTopologyInstanceIdentifier(topologyId);
139       Topology topology = (Topology) dataBrokerService.readOperationalData(topologyInstanceIdentifier);
140       return topology.getLink();
141     }
142   }
143 }