/* * Copyright © 2017 Ericsson India Global Services Pvt Ltd. 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.netvirt.elan.l2gw.listeners; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import javax.annotation.PreDestroy; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.DataObjectModification; import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener; import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier; import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.genius.datastoreutils.TaskRetryLooper; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * ChildListener class listens to provided P node and its child node C. * It can act on some special condition based on the parameter set. * When the children are updated and same update is processed by parent listener , it * takes a toll on the performance , specially in cases where child updates are too often . * In case there are any Sub-Tree modification , it can be handled and not handled based on the parameters. * @param
- Parent DataObject
* @param
implements DataTreeChangeListener , AutoCloseable {
public static final Logger LOG = LoggerFactory.getLogger(ChildListener.class);
private static final long STARTUP_LOOP_TICK = 500;
private static final int STARTUP_LOOP_MAX_RETRIES = 8;
protected final DataBroker dataBroker;
private ListenerRegistration> registration;
private final boolean processParentDeletes;
public ChildListener(DataBroker dataBroker, boolean processParentDeletes) {
this.dataBroker = dataBroker;
this.processParentDeletes = processParentDeletes;
}
public void init() throws Exception {
registration = registerListener(LogicalDatastoreType.OPERATIONAL, getParentWildCardPath());
}
private ListenerRegistration> registerListener(final LogicalDatastoreType dsType,
final InstanceIdentifier wildCard) throws Exception {
DataTreeIdentifier treeId = new DataTreeIdentifier<>(dsType, wildCard);
TaskRetryLooper looper = new TaskRetryLooper(STARTUP_LOOP_TICK, STARTUP_LOOP_MAX_RETRIES);
return looper.loopUntilNoException(() -> dataBroker.registerDataTreeChangeListener(treeId, this));
}
/**
* Upon parent added will be called.
* @param parent - Added parent node
*/
protected abstract void onParentAdded(DataTreeModification parent);
/**
* Upon parent delete will be called.
* @param parent - Deleted parent
*/
protected abstract void onParentRemoved(InstanceIdentifier parent);
/**
* Based on the return type of this function , processing on the dataTreeChanges takes place.
* @param parent - Parent node which is add/update/delete
* @return boolean value .
*/
protected abstract boolean proceed(InstanceIdentifier parent);
/**
* Group of data for bulk child update cases.
* @param childIid - Subtree Node iid
* @param child - Subtree Node data
* @return - Group value
*/
protected abstract G getGroup(InstanceIdentifier parentIid,
DataObjectModification mod);
protected abstract InstanceIdentifier iid = change.getRootPath().getRootIdentifier();
DataObjectModification modification = change.getRootNode();
switch (getModificationType(modification)) {
case WRITE:
if (modification.getDataBefore() == null) {
onParentAdded(change);
} else {
LOG.info("Unexpected write to parent before {}", modification.getDataBefore());
LOG.info("Unexpected write to parent after {}", modification.getDataAfter());
}
extractDataChanged(iid, modification, updatedMacsGrouped, deletedMacsGrouped);
break;
case SUBTREE_MODIFIED:
extractDataChanged(iid, modification, updatedMacsGrouped, deletedMacsGrouped);
break;
case DELETE:
if (processParentDeletes) {
extractDataChanged(iid, modification, updatedMacsGrouped, deletedMacsGrouped);
}
onParentRemoved(iid);
//Do not process the disconnected nodes
break;
default:
break;
}
});
}
/**
* Only when Subtree modification happen this is called .
* @param key - IID of child data
* @param parentModification - Modified data
* @param updatedMacsGrouped - Subtree updated data
* @param deletedMacsGrouped - Subtree deleted datas
*/
private void extractDataChanged(final InstanceIdentifier key,
final DataObjectModification parentModification,
final Map