/* * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.controller.sample.l2switch.md.topology; import com.google.common.base.Preconditions; import org.opendaylight.controller.sample.l2switch.md.util.InstanceIdentifierUtils; import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; import java.util.Map; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; /** * Listens to data change events on topology links * {@link org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link} * and maintains a topology graph using provided NetworkGraphService * {@link org.opendaylight.controller.sample.l2switch.md.topology.NetworkGraphService}. * It refreshes the graph after a delay(default 10 sec) to accommodate burst of change events if they come in bulk. * This is to avoid continuous refresh of graph on a series of change events in short time. */ public class TopologyLinkDataChangeHandler implements DataChangeListener { private static final Logger _logger = LoggerFactory.getLogger(TopologyLinkDataChangeHandler.class); private static final String DEFAULT_TOPOLOGY_ID = "flow:1"; private boolean networkGraphRefreshScheduled = false; private final ScheduledExecutorService networkGraphRefreshScheduler = Executors.newScheduledThreadPool(1); private final long DEFAULT_GRAPH_REFRESH_DELAY = 10; private final long graphRefreshDelayInSec; private final NetworkGraphService networkGraphService; private final DataBrokerService dataBrokerService; /** * Uses default delay to refresh topology graph if this constructor is used. * @param dataBrokerService * @param networkGraphService */ public TopologyLinkDataChangeHandler(DataBrokerService dataBrokerService, NetworkGraphService networkGraphService) { Preconditions.checkNotNull(dataBrokerService, "dataBrokerService should not be null."); Preconditions.checkNotNull(networkGraphService, "networkGraphService should not be null."); this.dataBrokerService = dataBrokerService; this.networkGraphService = networkGraphService; this.graphRefreshDelayInSec = DEFAULT_GRAPH_REFRESH_DELAY; } /** * * @param dataBrokerService * @param networkGraphService * @param graphRefreshDelayInSec */ public TopologyLinkDataChangeHandler(DataBrokerService dataBrokerService, NetworkGraphService networkGraphService, long graphRefreshDelayInSec) { Preconditions.checkNotNull(dataBrokerService, "dataBrokerService should not be null."); Preconditions.checkNotNull(networkGraphService, "networkGraphService should not be null."); this.dataBrokerService = dataBrokerService; this.networkGraphService = networkGraphService; this.graphRefreshDelayInSec = graphRefreshDelayInSec; } /** * Based on if links have been added or removed in topology data store, schedules a refresh of network graph. * @param dataChangeEvent */ @Override public void onDataChanged(DataChangeEvent, DataObject> dataChangeEvent) { if(dataChangeEvent == null) { _logger.info("In onDataChanged: No Processing done as dataChangeEvent is null."); } Map, DataObject> linkOriginalData = dataChangeEvent.getOriginalOperationalData(); Map, DataObject> linkUpdatedData = dataChangeEvent.getUpdatedOperationalData(); // change this logic, once MD-SAL start populating DeletedOperationData Set if(linkOriginalData != null && linkUpdatedData != null && (linkOriginalData.size() != 0 || linkUpdatedData.size() != 0) && !networkGraphRefreshScheduled) { networkGraphRefreshScheduled = linkOriginalData.size() != linkUpdatedData.size(); if(networkGraphRefreshScheduled) { networkGraphRefreshScheduler.schedule(new NetworkGraphRefresher(), graphRefreshDelayInSec, TimeUnit.SECONDS); } } } /** * Registers as a data listener to receive changes done to * {@link org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link} * under {@link org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology} * operation data root. */ public void registerAsDataChangeListener() { InstanceIdentifier linkInstance = InstanceIdentifier.builder(NetworkTopology.class) .child(Topology.class, new TopologyKey(new TopologyId(DEFAULT_TOPOLOGY_ID))).child(Link.class).toInstance(); dataBrokerService.registerDataChangeListener(linkInstance, this); } /** * */ private class NetworkGraphRefresher implements Runnable { /** * */ @Override public void run() { networkGraphRefreshScheduled = false; //TODO: it should refer to changed links only from DataChangeEvent above. List links = getLinksFromTopology(DEFAULT_TOPOLOGY_ID); networkGraphService.clear();// can remove this once changed links are addressed if(links != null && !links.isEmpty()) { networkGraphService.addLinks(links); } } /** * @param topologyId * @return */ private List getLinksFromTopology(String topologyId) { InstanceIdentifier topologyInstanceIdentifier = InstanceIdentifierUtils.generateTopologyInstanceIdentifier(topologyId); Topology topology = (Topology) dataBrokerService.readOperationalData(topologyInstanceIdentifier); return topology.getLink(); } } }