Bulk merge of l2gw changes
[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.netvirt.elan.l2gw.ha.HwvtepHAUtil.isEmptyList;
11
12 import java.io.Serializable;
13 import java.lang.reflect.ParameterizedType;
14 import java.lang.reflect.Type;
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.Comparator;
18 import java.util.List;
19 import java.util.Objects;
20 import java.util.Optional;
21 import java.util.stream.Collectors;
22 import org.eclipse.jdt.annotation.NonNull;
23 import org.eclipse.jdt.annotation.Nullable;
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.global.attributes.RemoteUcastMacs;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
27 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
28 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
29 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
30 import org.opendaylight.yangtools.concepts.Builder;
31 import org.opendaylight.yangtools.yang.binding.DataObject;
32 import org.opendaylight.yangtools.yang.binding.Identifiable;
33 import org.opendaylight.yangtools.yang.binding.Identifier;
34 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38
39
40
41 public abstract class MergeCommand<T extends DataObject, Y extends Builder, Z extends DataObject>
42         extends BaseCommand<T> implements IMergeCommand<T, Y, Z> {
43
44     private static final Logger LOG = LoggerFactory.getLogger(MergeCommand.class);
45
46     Class<? extends Identifiable> classType = getType();
47
48     public List<T> transformOpData(List<T> existingData, List<T> src, InstanceIdentifier<Node> nodePath) {
49         List<T> added = diffOf(src, existingData);//do not add existing data again
50         return transform(nodePath, added);
51     }
52
53     public List<T> transformConfigData(List<T> updatedSrc, InstanceIdentifier<Node> nodePath) {
54         return transform(nodePath, updatedSrc);
55     }
56
57     @NonNull
58     public List<T> diffByKey(List<T> updated, final List<T> original) {
59         if (updated == null) {
60             return new ArrayList<>();
61         }
62         if (original == null) {
63             return new ArrayList<>(updated);
64         }
65
66         List<T> result = new ArrayList<>();
67         for (T ele : updated) {
68             boolean present = false;
69             for (T orig : original) {
70                 if (Objects.equals(getKey(ele), getKey(orig))) {
71                     present = true;
72                     break;
73                 }
74             }
75             if (!present) {
76                 result.add(ele);
77             }
78         }
79         return result;
80     }
81
82     Class<? extends Identifiable> getType() {
83         Type type = getClass().getGenericSuperclass();
84         return (Class<? extends Identifiable>)((ParameterizedType) type).getActualTypeArguments()[0];
85
86     }
87
88     <T extends DataObject> boolean isDataUpdated(Optional<T> existingDataOptional, T newData) {
89         return !existingDataOptional.isPresent() || !Objects.equals(existingDataOptional.get(), newData);
90     }
91
92     public List<T> transform(InstanceIdentifier<Node> nodePath, List<T> list) {
93         if (list != null) {
94             return list.stream().map(t -> transform(nodePath, t)).collect(Collectors.toList());
95         }
96         return new ArrayList<>();
97     }
98
99     public abstract T transform(InstanceIdentifier<Node> nodePath, T objT);
100
101     List<T> getDataSafe(Z existingData) {
102         if (existingData == null) {
103             return Collections.EMPTY_LIST;
104         }
105         List<T> result = getData(existingData);
106         if (result == null) {
107             return Collections.EMPTY_LIST;
108         }
109         return result;
110     }
111
112     @Override
113     public void mergeOperationalData(Y dst,
114                                      Z existingData,
115                                      Z src,
116                                      InstanceIdentifier<Node> nodePath) {
117         List<T> origDstData = getDataSafe(existingData);
118         List<T> srcData = getDataSafe(src);
119         List<T> data = transformOpData(origDstData, srcData, nodePath);
120         if (classType == RemoteUcastMacs.class) {
121             return;
122         }
123         setData(dst, data);
124         if (!isEmptyList(data)) {
125             String nodeId = nodePath.firstKeyOf(Node.class).getNodeId().getValue();
126             LOG.trace("merging op {} to {} size {}",getDescription(), nodeId, data.size());
127         }
128     }
129
130     @Override
131     public void mergeConfigData(Y dst,
132                                 Z src,
133                                 InstanceIdentifier<Node> nodePath) {
134         List<T> data        = getDataSafe(src);
135         List<T> transformed = transformConfigData(data, nodePath);
136         setData(dst, transformed);
137         if (!isEmptyList(data)) {
138             String nodeId = nodePath.firstKeyOf(Node.class).getNodeId().getValue();
139             LOG.trace("copying config {} to {} size {}",getDescription(), nodeId, data.size());
140         }
141     }
142
143     boolean areSameSize(@Nullable List objA,@Nullable List objB) {
144         if (HwvtepHAUtil.isEmptyList(objA) && HwvtepHAUtil.isEmptyList(objB)) {
145             return true;
146         }
147         if (!HwvtepHAUtil.isEmptyList(objA) && !HwvtepHAUtil.isEmptyList(objB)) {
148             return objA.size() == objB.size();
149         }
150         return false;
151     }
152
153
154     static LocatorSetComparator locatorSetComparator = new LocatorSetComparator();
155
156     static class LocatorSetComparator implements Comparator<LocatorSet>, Serializable {
157         private static final long serialVersionUID = 1L;
158
159         @Override
160         public int compare(final LocatorSet updatedLocatorSet, final LocatorSet origLocatorSet) {
161             InstanceIdentifier<?> updatedLocatorRefIndentifier = updatedLocatorSet.getLocatorRef().getValue();
162             TpId updatedLocatorSetTpId = updatedLocatorRefIndentifier.firstKeyOf(TerminationPoint.class).getTpId();
163
164             InstanceIdentifier<?> origLocatorRefIndentifier = origLocatorSet.getLocatorRef().getValue();
165             TpId origLocatorSetTpId = origLocatorRefIndentifier.firstKeyOf(TerminationPoint.class).getTpId();
166
167             if (updatedLocatorSetTpId.equals(origLocatorSetTpId)) {
168                 return 0;
169             }
170             return 1;
171         }
172     }
173
174     @Nullable
175     public abstract List<T> getData(Z node);
176
177     public abstract void setData(Y builder, List<T> data);
178
179     public abstract InstanceIdentifier<T> generateId(InstanceIdentifier<Node> id, T node);
180
181     public abstract Identifier getKey(T data);
182
183     public abstract String getDescription();
184
185     public abstract T withoutUuid(T data);
186 }