b0994719f023581df53f05ba52926fc796b7a67d
[packetcable.git] / packetcable-policy-server / src / main / java / org / opendaylight / controller / packetcable / provider / AbstractDataChangeListener.java
1 /*
2  * Copyright (c) 2015 CableLabs 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
9 package org.opendaylight.controller.packetcable.provider;
10
11 import static com.google.common.base.Preconditions.checkNotNull;
12 import static org.opendaylight.controller.packetcable.provider.DataChangeUtils.collectTypeFromMap;
13 import static org.opendaylight.controller.packetcable.provider.DataChangeUtils.collectTypeFromSet;
14 import static org.opendaylight.controller.packetcable.provider.DataChangeUtils.logChange;
15 import static org.opendaylight.controller.packetcable.provider.DataChangeUtils.relativeComplement;
16
17 import com.google.common.collect.Maps;
18 import java.util.Map;
19 import java.util.Set;
20 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
21 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
22 import org.opendaylight.yangtools.yang.binding.DataObject;
23 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 /**
28  * @author rvail
29  */
30 public abstract class AbstractDataChangeListener<T extends DataObject> implements DataChangeListener {
31
32     protected final Logger logger = LoggerFactory.getLogger(getClass());
33
34     private final Class<T> tClass;
35
36     public AbstractDataChangeListener(Class<T> tClass) {
37         this.tClass = checkNotNull(tClass);
38     }
39
40     @Override
41     public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> asyncDataChangeEvent) {
42         logger.debug("############{}.onDataChanged()", getClass().getSimpleName());
43         logChange(logger, asyncDataChangeEvent);
44
45         final Map<InstanceIdentifier<?>, DataObject> allCreatedData = asyncDataChangeEvent.getCreatedData();
46         final Map<InstanceIdentifier<?>, DataObject> allOriginalData = asyncDataChangeEvent.getOriginalData();
47         final Map<InstanceIdentifier<?>, DataObject> allUpdatedData = asyncDataChangeEvent.getUpdatedData();
48
49         // UpdatedData also contains all data that was created, remove it to get the set of only updated data
50         final Map<InstanceIdentifier<?>, DataObject> trueUpdatedData =
51                 relativeComplement(allCreatedData, allUpdatedData);
52         final Map<InstanceIdentifier<?>, DataObject> trueOriginalData =
53                 relativeComplement(allCreatedData, allOriginalData);
54
55         if (!allCreatedData.isEmpty()) {
56             final Map<InstanceIdentifier<T>, T> createdTs = collectTypeFromMap(tClass, allCreatedData);
57
58             if (createdTs.isEmpty()) {
59                 // this should not happen since this object only listens for changes in one tree
60                 logger.warn("Expected created {}(s) but none were found: {}", tClass.getSimpleName(), allCreatedData);
61             }
62             else {
63                 handleCreatedData(createdTs);
64             }
65         }
66
67         if (!trueUpdatedData.isEmpty()) {
68             final Map<InstanceIdentifier<T>, T> updatedTs = collectTypeFromMap(tClass, trueUpdatedData);
69             if (updatedTs.isEmpty()) {
70                 // this should not happen since this object should only listen for changes in its tree
71                 logger.warn("Expected updated {}(s) but none were found: {}", tClass.getSimpleName(), trueUpdatedData);
72             }
73             else {
74
75                 final Map<InstanceIdentifier<T>, T> originalTs = collectTypeFromMap(tClass, trueOriginalData);
76                 for (InstanceIdentifier<T> iid : updatedTs.keySet()) {
77                     if (!originalTs.containsKey(iid)) {
78                         logger.warn("No original data for updated object {}", iid);
79                     }
80                 }
81
82                 handleUpdatedData(updatedTs, originalTs);
83             }
84         }
85
86         final Set<InstanceIdentifier<?>> allRemovedPaths = asyncDataChangeEvent.getRemovedPaths();
87         if (!allRemovedPaths.isEmpty()) {
88             final Set<InstanceIdentifier<T>> removedTPaths = collectTypeFromSet(tClass, allRemovedPaths);
89             if (removedTPaths.isEmpty()) {
90                 // this should not happen since this object should only listen for changes in its tree
91                 logger.warn("Expected removed {} but none were found: {}", tClass.getSimpleName(), allRemovedPaths);
92             }
93
94             Map<InstanceIdentifier<T>, T> originalTData = Maps.newHashMapWithExpectedSize(removedTPaths.size());
95             for (InstanceIdentifier<T> iid : removedTPaths) {
96                 if (allOriginalData.containsKey(iid)) {
97
98                     originalTData.put(iid, (T) allOriginalData.get(iid));
99                 }
100             }
101
102             handleRemovedData(removedTPaths, originalTData);
103         }
104     }
105
106     protected abstract void handleCreatedData(final Map<InstanceIdentifier<T>, T> createdData);
107
108     protected abstract void handleUpdatedData(final Map<InstanceIdentifier<T>, T> updatedData,
109             final Map<InstanceIdentifier<T>, T> originalData);
110
111     protected abstract void handleRemovedData(final Set<InstanceIdentifier<T>> removedPaths,
112             final Map<InstanceIdentifier<T>, T> originalData);
113
114
115
116 }