ed31c25e4d04dfadbab28e6fedd7ef95a7140540
[netvirt.git] / elanmanager / impl / src / main / java / org / opendaylight / netvirt / elan / l2gw / ha / commands / MergeCommand.java
1 /*
2  * Copyright (c) 2016, 2017 Ericsson India Global Services Pvt Ltd. 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.netvirt.elan.l2gw.ha.commands;
9
10 import static org.opendaylight.mdsal.common.api.LogicalDatastoreType.OPERATIONAL;
11 import static org.opendaylight.netvirt.elan.l2gw.ha.HwvtepHAUtil.isEmptyList;
12
13 import java.io.Serializable;
14 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.Comparator;
17 import java.util.List;
18 import java.util.Objects;
19 import java.util.stream.Collectors;
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.opendaylight.mdsal.binding.api.ReadWriteTransaction;
23 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
24 import org.opendaylight.netvirt.elan.l2gw.ha.HwvtepHAUtil;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
26 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
27 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
28 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
29 import org.opendaylight.yangtools.concepts.Builder;
30 import org.opendaylight.yangtools.yang.binding.DataObject;
31 import org.opendaylight.yangtools.yang.binding.Identifier;
32 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36
37
38
39 public abstract class MergeCommand<T extends DataObject, Y extends Builder, Z extends DataObject>
40         extends BaseCommand<T> implements IMergeCommand<T, Y, Z> {
41
42     private static final Logger LOG = LoggerFactory.getLogger(MergeCommand.class);
43
44     public List<T> transformOpData(List<T> existingData, List<T> src, InstanceIdentifier<Node> nodePath) {
45         if (isEmptyList(src)) {
46             return new ArrayList<>();
47         }
48         List<T> added = diffOf(src, existingData);//do not add existing data again
49         return transform(nodePath, added);
50     }
51
52     public List<T> transformConfigData(List<T> updatedSrc, InstanceIdentifier<Node> nodePath) {
53         if (isEmptyList(updatedSrc)) {
54             return new ArrayList<>();//what difference returning null makes ?
55         }
56         return transform(nodePath, updatedSrc);
57     }
58
59     @NonNull
60     public List<T> diffByKey(List<T> updated, final List<T> original) {
61         if (updated == null) {
62             return new ArrayList<>();
63         }
64         if (original == null) {
65             return new ArrayList<>(updated);
66         }
67
68         List<T> result = new ArrayList<>();
69         for (T ele : updated) {
70             boolean present = false;
71             for (T orig : original) {
72                 if (Objects.equals(getKey(ele), getKey(orig))) {
73                     present = true;
74                     break;
75                 }
76             }
77             if (!present) {
78                 result.add(ele);
79             }
80         }
81         return result;
82     }
83
84     //TODO validate the perf of the following against direct setting of the data in dst node
85     public void transformUpdate(List<T> existing,
86                                 List<T> updated,
87                                 List<T> orig,
88                                 InstanceIdentifier<Node> nodePath,
89                                 LogicalDatastoreType datastoreType,
90                                 ReadWriteTransaction tx) {
91
92         if (updated == null) {
93             updated = new ArrayList<>();
94         }
95         if (orig == null) {
96             orig = new ArrayList<>();
97         }
98         List<T> added   = new ArrayList<>(updated);
99
100         added.removeAll(orig);
101         added = diffOf(added, existing);//do not add the existing data again
102         if (added.size() > 0) {
103             for (T addedItem : added) {
104                 InstanceIdentifier<T> transformedId = generateId(nodePath, addedItem);
105                 T transformedItem = transform(nodePath, addedItem);
106                 String nodeId = transformedId.firstKeyOf(Node.class).getNodeId().getValue();
107                 LOG.trace("adding {} {} {}", getDescription(), nodeId, getKey(transformedItem));
108                 tx.mergeParentStructurePut(datastoreType, transformedId, transformedItem);
109             }
110         }
111         List<T> removed = new ArrayList<>(orig);
112         removed = diffByKey(removed, updated);
113
114         List<T> removedTransformed  = new ArrayList<>();
115         for (T ele : removed) {
116             removedTransformed.add(transform(nodePath, ele));
117         }
118
119         List<T> skip = diffByKey(removedTransformed, existing);//skip the ones which are not present in cfg ds
120         removedTransformed = diffByKey(removedTransformed, skip);
121         if (removedTransformed.size() > 0) {
122             for (T removedItem : removedTransformed) {
123                 InstanceIdentifier<T> transformedId = generateId(nodePath, removedItem);
124                 String nodeId = transformedId.firstKeyOf(Node.class).getNodeId().getValue();
125                 LOG.trace("removing {} {} {}",getDescription(), nodeId, getKey(removedItem));
126                 tx.delete(datastoreType, transformedId);
127             }
128         }
129     }
130
131     public List<T> transform(InstanceIdentifier<Node> nodePath, List<T> list) {
132         if (list != null) {
133             return list.stream().map(t -> transform(nodePath, t)).collect(Collectors.toList());
134         }
135         return new ArrayList<>();
136     }
137
138     public abstract T transform(InstanceIdentifier<Node> nodePath, T objT);
139
140     List<T> getDataSafe(Z existingData) {
141         if (existingData == null) {
142             return Collections.EMPTY_LIST;
143         }
144         List<T> result = getData(existingData);
145         if (result == null) {
146             return Collections.EMPTY_LIST;
147         }
148         return result;
149     }
150
151     @Override
152     public void mergeOperationalData(Y dst,
153                                      Z existingData,
154                                      Z src,
155                                      InstanceIdentifier<Node> nodePath) {
156         List<T> origDstData = getDataSafe(existingData);
157         List<T> srcData = getDataSafe(src);
158         List<T> data = transformOpData(origDstData, srcData, nodePath);
159         setData(dst, data);
160         if (!isEmptyList(data)) {
161             String nodeId = nodePath.firstKeyOf(Node.class).getNodeId().getValue();
162             LOG.trace("merging op {} to {} size {}",getDescription(), nodeId, data.size());
163         }
164     }
165
166     @Override
167     public void mergeConfigData(Y dst,
168                                 Z src,
169                                 InstanceIdentifier<Node> nodePath) {
170         List<T> data        = getDataSafe(src);
171         List<T> transformed = transformConfigData(data, nodePath);
172         setData(dst, transformed);
173         if (!isEmptyList(data)) {
174             String nodeId = nodePath.firstKeyOf(Node.class).getNodeId().getValue();
175             LOG.trace("copying config {} to {} size {}",getDescription(), nodeId, data.size());
176         }
177     }
178
179     @Override
180     public void mergeOpUpdate(Z origDst,
181                               Z updatedSrc,
182                               Z origSrc,
183                               InstanceIdentifier<Node> nodePath,
184                               ReadWriteTransaction tx) {
185         List<T> updatedData     = getData(updatedSrc);
186         List<T> origData        = getData(origSrc);
187         List<T> existingData    = getData(origDst);
188         transformUpdate(existingData, updatedData, origData, nodePath, OPERATIONAL, tx);
189     }
190
191     boolean areSameSize(@Nullable List objA, @Nullable List objB) {
192         if (HwvtepHAUtil.isEmptyList(objA) && HwvtepHAUtil.isEmptyList(objB)) {
193             return true;
194         }
195         if (!HwvtepHAUtil.isEmptyList(objA) && !HwvtepHAUtil.isEmptyList(objB)) {
196             return objA.size() == objB.size();
197         }
198         return false;
199     }
200
201
202     static LocatorSetComparator locatorSetComparator = new LocatorSetComparator();
203
204     static class LocatorSetComparator implements Comparator<LocatorSet>, Serializable {
205         private static final long serialVersionUID = 1L;
206
207         @Override
208         public int compare(final LocatorSet updatedLocatorSet, final LocatorSet origLocatorSet) {
209             InstanceIdentifier<?> updatedLocatorRefIndentifier = updatedLocatorSet.getLocatorRef().getValue();
210             TpId updatedLocatorSetTpId = updatedLocatorRefIndentifier.firstKeyOf(TerminationPoint.class).getTpId();
211
212             InstanceIdentifier<?> origLocatorRefIndentifier = origLocatorSet.getLocatorRef().getValue();
213             TpId origLocatorSetTpId = origLocatorRefIndentifier.firstKeyOf(TerminationPoint.class).getTpId();
214
215             if (updatedLocatorSetTpId.equals(origLocatorSetTpId)) {
216                 return 0;
217             }
218             return 1;
219         }
220     }
221
222     @Nullable
223     public abstract List<T> getData(Z node);
224
225     public abstract void setData(Y builder, List<T> data);
226
227     public abstract InstanceIdentifier<T> generateId(InstanceIdentifier<Node> id, T node);
228
229     public abstract Identifier getKey(T data);
230
231     public abstract String getDescription();
232
233     public abstract T withoutUuid(T data);
234 }