2 * Copyright (c) 2016, 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.ha.commands;
10 import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION;
11 import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.OPERATIONAL;
12 import static org.opendaylight.netvirt.elan.l2gw.ha.HwvtepHAUtil.isEmptyList;
14 import java.io.Serializable;
15 import java.util.ArrayList;
16 import java.util.Comparator;
17 import java.util.List;
18 import java.util.Objects;
19 import java.util.stream.Collectors;
20 import javax.annotation.Nonnull;
21 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
22 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
23 import org.opendaylight.controller.md.sal.common.api.data.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;
39 public abstract class MergeCommand<T extends DataObject, Y extends Builder, Z extends DataObject>
40 extends BaseCommand<T> implements IMergeCommand<T, Y, Z> {
42 private static final Logger LOG = LoggerFactory.getLogger(MergeCommand.class);
44 public List<T> transformOpData(List<T> existingData, List<T> src, InstanceIdentifier<Node> nodePath) {
45 if (isEmptyList(src)) {
46 return new ArrayList<>();
48 List<T> added = diffOf(src, existingData);//do not add existing data again
49 return transform(nodePath, added);
52 public List<T> transformConfigData(List<T> updatedSrc, InstanceIdentifier<Node> nodePath) {
53 if (isEmptyList(updatedSrc)) {
54 return new ArrayList<>();//what difference returning null makes ?
56 return transform(nodePath, updatedSrc);
60 public List<T> diffByKey(List<T> updated, final List<T> original) {
61 if (updated == null) {
62 return new ArrayList<>();
64 if (original == null) {
65 return new ArrayList<>(updated);
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))) {
84 //TODO validate the perf of the following against direct setting of the data in dst node
85 public void transformUpdate(List<T> existing,
88 InstanceIdentifier<Node> nodePath,
89 LogicalDatastoreType datastoreType,
90 ReadWriteTransaction tx) {
92 if (updated == null) {
93 updated = new ArrayList<>();
96 orig = new ArrayList<>();
98 List<T> added = new ArrayList<>(updated);
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.put(datastoreType, transformedId, transformedItem, WriteTransaction.CREATE_MISSING_PARENTS);
111 List<T> removed = new ArrayList<>(orig);
112 removed = diffByKey(removed, updated);
114 List<T> removedTransformed = new ArrayList<>();
115 for (T ele : removed) {
116 removedTransformed.add(transform(nodePath, ele));
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);
131 public List<T> transform(InstanceIdentifier<Node> nodePath, List<T> list) {
132 return list.stream().map(t -> transform(nodePath, t)).collect(Collectors.toList());
135 public abstract T transform(InstanceIdentifier<Node> nodePath, T objT);
138 public void mergeOperationalData(Y dst,
141 InstanceIdentifier<Node> nodePath) {
142 List<T> origDstData = getData(existingData);
143 List<T> srcData = getData(src);
144 List<T> data = transformOpData(origDstData, srcData, nodePath);
146 if (!isEmptyList(data)) {
147 String nodeId = nodePath.firstKeyOf(Node.class).getNodeId().getValue();
148 LOG.trace("merging op {} to {} size {}",getDescription(), nodeId, data.size());
153 public void mergeConfigData(Y dst,
155 InstanceIdentifier<Node> nodePath) {
156 List<T> data = getData(src);
157 List<T> transformed = transformConfigData(data, nodePath);
158 setData(dst, transformed);
159 if (!isEmptyList(data)) {
160 String nodeId = nodePath.firstKeyOf(Node.class).getNodeId().getValue();
161 LOG.trace("copying config {} to {} size {}",getDescription(), nodeId, data.size());
166 public void mergeConfigUpdate(Z existing,
169 InstanceIdentifier<Node> nodePath,
170 ReadWriteTransaction tx) {
171 List<T> updatedData = getData(updated);
172 List<T> origData = getData(orig);
173 List<T> existingData = getData(existing);
174 transformUpdate(existingData, updatedData, origData, nodePath, CONFIGURATION, tx);
178 public void mergeOpUpdate(Z origDst,
181 InstanceIdentifier<Node> nodePath,
182 ReadWriteTransaction tx) {
183 List<T> updatedData = getData(updatedSrc);
184 List<T> origData = getData(origSrc);
185 List<T> existingData = getData(origDst);
186 transformUpdate(existingData, updatedData, origData, nodePath, OPERATIONAL, tx);
189 boolean areSameSize(List objA, List objB) {
190 if (HwvtepHAUtil.isEmptyList(objA) && HwvtepHAUtil.isEmptyList(objB)) {
193 if (!HwvtepHAUtil.isEmptyList(objA) && !HwvtepHAUtil.isEmptyList(objB)) {
194 return objA.size() == objB.size();
200 static LocatorSetComparator locatorSetComparator = new LocatorSetComparator();
202 static class LocatorSetComparator implements Comparator<LocatorSet>, Serializable {
203 private static final long serialVersionUID = 1L;
206 public int compare(final LocatorSet updatedLocatorSet, final LocatorSet origLocatorSet) {
207 InstanceIdentifier<?> updatedLocatorRefIndentifier = updatedLocatorSet.getLocatorRef().getValue();
208 TpId updatedLocatorSetTpId = updatedLocatorRefIndentifier.firstKeyOf(TerminationPoint.class).getTpId();
210 InstanceIdentifier<?> origLocatorRefIndentifier = origLocatorSet.getLocatorRef().getValue();
211 TpId origLocatorSetTpId = origLocatorRefIndentifier.firstKeyOf(TerminationPoint.class).getTpId();
213 if (updatedLocatorSetTpId.equals(origLocatorSetTpId)) {
220 public abstract List<T> getData(Z node);
222 public abstract void setData(Y builder, List<T> data);
224 public abstract InstanceIdentifier<T> generateId(InstanceIdentifier<Node> id, T node);
226 public abstract Identifier getKey(T data);
228 public abstract String getDescription();
230 public abstract T withoutUuid(T data);