2 * Copyright © 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.netvirt.elan.l2gw.listeners;
10 import java.util.Collection;
11 import java.util.HashMap;
13 import java.util.concurrent.ConcurrentHashMap;
14 import javax.annotation.PreDestroy;
15 import org.eclipse.jdt.annotation.Nullable;
16 import org.opendaylight.genius.datastoreutils.TaskRetryLooper;
17 import org.opendaylight.mdsal.binding.api.DataBroker;
18 import org.opendaylight.mdsal.binding.api.DataObjectModification;
19 import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
20 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
21 import org.opendaylight.mdsal.binding.api.DataTreeModification;
22 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
23 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
24 import org.opendaylight.yangtools.concepts.ListenerRegistration;
25 import org.opendaylight.yangtools.yang.binding.DataObject;
26 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
31 * ChildListener class listens to provided P node and its child node C.
32 * It can act on some special condition based on the parameter set.
33 * When the children are updated and same update is processed by parent listener , it
34 * takes a toll on the performance , specially in cases where child updates are too often .
35 * In case there are any Sub-Tree modification , it can be handled and not handled based on the parameters.
36 * @param <P> - Parent DataObject
37 * @param <C> - Child DataObject (Subtree)
38 * @param <G> - Group type (Mostly key of Subtree DataObject)
40 public abstract class ChildListener<P extends DataObject, C extends DataObject, G>
41 implements DataTreeChangeListener<P>, AutoCloseable {
43 private static final Logger LOG = LoggerFactory.getLogger(ChildListener.class);
44 private static final long STARTUP_LOOP_TICK = 500;
45 private static final int STARTUP_LOOP_MAX_RETRIES = 8;
47 protected final DataBroker dataBroker;
48 private ListenerRegistration<?> registration;
49 private final boolean processParentDeletes;
51 public ChildListener(DataBroker dataBroker, boolean processParentDeletes) {
52 this.dataBroker = dataBroker;
53 this.processParentDeletes = processParentDeletes;
56 public void init() throws Exception {
57 //registration = registerListener(LogicalDatastoreType.OPERATIONAL, getParentWildCardPath());
60 protected ListenerRegistration<?> registerListener(final LogicalDatastoreType dsType,
61 final InstanceIdentifier wildCard) throws Exception {
62 if (registration != null) {
63 LOG.error("LocalUcast listener already registered");
66 DataTreeIdentifier<P> treeId = DataTreeIdentifier.create(dsType, wildCard);
67 TaskRetryLooper looper = new TaskRetryLooper(STARTUP_LOOP_TICK, STARTUP_LOOP_MAX_RETRIES);
68 registration = looper.loopUntilNoException(() -> dataBroker.registerDataTreeChangeListener(treeId, this));
73 * Upon parent added will be called.
74 * @param parent - Added parent node
76 protected abstract void onParentAdded(DataTreeModification<P> parent);
79 * Upon parent delete will be called.
80 * @param parent - Deleted parent
82 protected abstract void onParentRemoved(InstanceIdentifier<P> parent);
85 * Based on the return type of this function , processing on the dataTreeChanges takes place.
86 * @param parent - Parent node which is add/update/delete
87 * @return boolean value .
89 protected abstract boolean proceed(InstanceIdentifier<P> parent);
92 * Group of data for bulk child update cases.
93 * @param child - Subtree Node data
94 * @return - Group value
96 protected abstract G getGroup(C child);
99 * Process the added/updated/Deleted subtree data.
100 * @param updatedMacsGrouped - Updated Subtree Data
101 * @param deletedMacsGrouped - Deleted Subtree Data
103 protected abstract void onUpdate(
104 Map<G, Map<InstanceIdentifier, C>> updatedMacsGrouped,
105 Map<G, Map<InstanceIdentifier, C>> deletedMacsGrouped);
108 * Returns the all subtree data modified.
109 * @param parentIid - Parent Node iid
110 * @param mod - Modified Data
111 * @return subtree modified data map with IID
113 protected abstract Map<InstanceIdentifier<C>, DataObjectModification<C>> getChildMod(
114 InstanceIdentifier<P> parentIid,
115 DataObjectModification<P> mod);
117 protected abstract InstanceIdentifier<Node> getParentWildCardPath();
121 public void close() {
122 if (registration != null) {
123 registration.close();
129 public void onDataTreeChanged(final Collection<DataTreeModification<P>> changes) {
130 Map<G, Map<InstanceIdentifier, C>> updatedData = new HashMap<>();
131 Map<G, Map<InstanceIdentifier, C>> deletedData = new HashMap<>();
132 extractUpdatedAndDeletedMacs(changes, updatedData, deletedData);
133 onUpdate(updatedData, deletedData);
137 * Taked the data changes and process them based on Add/Delete/Update or Subtree Modification.
138 * @param changes - Data tree changes
139 * @param updatedMacsGrouped - Updated Subtree Data
140 * @param deletedMacsGrouped - Deleted Subtree Data
142 void extractUpdatedAndDeletedMacs(Collection<DataTreeModification<P>> changes,
143 Map<G, Map<InstanceIdentifier, C>> updatedMacsGrouped,
144 Map<G, Map<InstanceIdentifier, C>> deletedMacsGrouped) {
146 .filter(change -> proceed(change.getRootPath().getRootIdentifier()))
147 .forEach((change) -> {
148 InstanceIdentifier<P> iid = change.getRootPath().getRootIdentifier();
149 DataObjectModification<P> modification = change.getRootNode();
150 switch (getModificationType(modification)) {
152 if (modification.getDataBefore() == null) {
153 onParentAdded(change);
155 extractDataChanged(iid, modification, updatedMacsGrouped, deletedMacsGrouped);
157 case SUBTREE_MODIFIED:
158 extractDataChanged(iid, modification, updatedMacsGrouped, deletedMacsGrouped);
161 if (processParentDeletes) {
162 extractDataChanged(iid, modification, updatedMacsGrouped, deletedMacsGrouped);
164 onParentRemoved(iid);
165 //Do not process the disconnected nodes
174 * Only when Subtree modification happen this is called .
175 * @param key - IID of child data
176 * @param parentModification - Modified data
177 * @param updatedMacsGrouped - Subtree updated data
178 * @param deletedMacsGrouped - Subtree deleted datas
180 private void extractDataChanged(final InstanceIdentifier<P> key,
181 final DataObjectModification<P> parentModification,
182 final Map<G, Map<InstanceIdentifier, C>> updatedMacsGrouped,
183 final Map<G, Map<InstanceIdentifier, C>> deletedMacsGrouped) {
185 Map<InstanceIdentifier<C>, DataObjectModification<C>> children = getChildMod(key, parentModification);
186 for (Map.Entry<InstanceIdentifier<C>, DataObjectModification<C>> entry : children.entrySet()) {
187 DataObjectModification<C> childMod = entry.getValue();
188 InstanceIdentifier<C> childIid = entry.getKey();
189 DataObjectModification.ModificationType modificationType = getModificationType(childMod);
191 C dataBefore = childMod.getDataBefore();
192 C dataAfter = childMod.getDataAfter();
193 switch (modificationType) {
195 case SUBTREE_MODIFIED:
196 group = getGroup(dataAfter);
197 updatedMacsGrouped.computeIfAbsent(group, (grp) -> new ConcurrentHashMap<>());
198 updatedMacsGrouped.get(group).put(childIid, dataAfter);
201 group = getGroup(dataBefore);
202 deletedMacsGrouped.computeIfAbsent(group, (grp) -> new ConcurrentHashMap<>());
203 deletedMacsGrouped.get(group).put(childIid, dataBefore);
211 protected DataObjectModification.@Nullable ModificationType getModificationType(
212 final DataObjectModification<? extends DataObject> mod) {
214 return mod.getModificationType();
215 } catch (IllegalStateException e) {
216 //LOG.warn("Failed to get the modification type for mod {}", mod);