2 * Copyright © 2015, 2017 China Telecom Beijing Research Institute 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
9 package org.opendaylight.ovsdb.hwvtepsouthbound.transact;
11 import java.lang.reflect.ParameterizedType;
12 import java.lang.reflect.Type;
13 import java.util.ArrayList;
14 import java.util.Collection;
15 import java.util.Collections;
16 import java.util.HashMap;
17 import java.util.Iterator;
18 import java.util.List;
20 import java.util.Objects;
23 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
24 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
25 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepDeviceInfo;
26 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundUtil;
27 import org.opendaylight.ovsdb.lib.notation.UUID;
28 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
30 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
31 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
32 import org.opendaylight.yangtools.yang.binding.Augmentation;
33 import org.opendaylight.yangtools.yang.binding.Identifiable;
34 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
36 public abstract class AbstractTransactCommand<T extends Identifiable, Aug extends Augmentation<Node>> implements TransactCommand<T> {
38 private HwvtepOperationalState operationalState;
39 private Collection<DataTreeModification<Node>> changes;
41 protected AbstractTransactCommand() {
45 public AbstractTransactCommand(HwvtepOperationalState state, Collection<DataTreeModification<Node>> changes) {
46 this.operationalState = state;
47 this.changes = changes;
50 public HwvtepOperationalState getOperationalState() {
51 return operationalState;
54 public Collection<DataTreeModification<Node>> getChanges() {
58 void updateCurrentTxDeleteData(Class<? extends Identifiable> cls, InstanceIdentifier key, T data) {
59 operationalState.updateCurrentTxDeleteData(cls, key);
60 operationalState.getDeviceInfo().clearConfigData(cls, key);
63 void updateCurrentTxData(Class<? extends Identifiable> cls, InstanceIdentifier key, UUID uuid, Object data) {
64 operationalState.updateCurrentTxData(cls, key, uuid);
65 operationalState.getDeviceInfo().updateConfigData(cls, key, data);
68 void processDependencies(final UnMetDependencyGetter<T> unMetDependencyGetter,
69 final TransactionBuilder transaction,
70 final InstanceIdentifier<Node> nodeIid,
71 final InstanceIdentifier key,
72 final T data, final Object... extraData) {
74 HwvtepDeviceInfo deviceInfo = operationalState.getDeviceInfo();
75 Map inTransitDependencies = Collections.EMPTY_MAP;
76 Map confingDependencies = Collections.EMPTY_MAP;
78 if (!isRemoveCommand() && unMetDependencyGetter != null) {
79 inTransitDependencies = unMetDependencyGetter.getInTransitDependencies(operationalState, data);
80 confingDependencies = unMetDependencyGetter.getUnMetConfigDependencies(operationalState, data);
81 //we can skip the config termination point dependency as we can create them in device as part of this tx
82 confingDependencies.remove(TerminationPoint.class);
85 Type type = getClass().getGenericSuperclass();
86 Type classType = ((ParameterizedType)type).getActualTypeArguments()[0];
88 //If this key itself is in transit wait for the response of this key itself
89 if (deviceInfo.isKeyInTransit((Class<? extends Identifiable>) classType, key)) {
90 inTransitDependencies.put(classType, Collections.singletonList(key));
93 if (HwvtepSouthboundUtil.isEmptyMap(confingDependencies) && HwvtepSouthboundUtil.isEmptyMap(inTransitDependencies)) {
94 doDeviceTransaction(transaction, nodeIid, data, key, extraData);
95 updateCurrentTxData((Class<? extends Identifiable>) classType, key, new UUID("uuid"), data);
97 if (!HwvtepSouthboundUtil.isEmptyMap(confingDependencies)) {
98 DependentJob<T> configWaitingJob = new DependentJob.ConfigWaitingJob(
99 key, data, confingDependencies) {
102 public void onDependencyResolved(HwvtepOperationalState operationalState,
103 TransactionBuilder transactionBuilder) {
104 AbstractTransactCommand.this.operationalState = operationalState;
105 onConfigUpdate(transactionBuilder, nodeIid, data, key, extraData);
108 deviceInfo.addJobToQueue(configWaitingJob);
110 if (!HwvtepSouthboundUtil.isEmptyMap(inTransitDependencies)) {
112 DependentJob<T> opWaitingJob = new DependentJob.OpWaitingJob(
113 key, data, inTransitDependencies) {
116 public void onDependencyResolved(HwvtepOperationalState operationalState,
117 TransactionBuilder transactionBuilder) {
118 AbstractTransactCommand.this.operationalState = operationalState;
119 onConfigUpdate(transactionBuilder, nodeIid, data, key, extraData);
122 deviceInfo.addJobToQueue(opWaitingJob);
126 public void doDeviceTransaction(TransactionBuilder transaction, InstanceIdentifier<Node> nodeIid, T data,
127 InstanceIdentifier key, Object... extraData) {
128 //tobe removed as part of refactoring patch
131 public void onConfigUpdate(TransactionBuilder transaction, InstanceIdentifier<Node> nodeIid, T data,
132 InstanceIdentifier key, Object... extraData) {
133 //tobe removed as part of refactoring patch
136 protected Aug getAugmentation(Node node) {
140 ParameterizedType parameterizedType = (ParameterizedType) getClass().getGenericSuperclass();
141 Class<? extends Augmentation<Node>> augType = (Class<? extends Augmentation<Node>>) parameterizedType.getActualTypeArguments()[1];
142 Augmentation<Node> augmentation = node.getAugmentation(augType);
143 return (Aug)augmentation;
146 protected List<T> getData(Aug augmentation) {
147 return Collections.EMPTY_LIST;
150 protected List<T> getData(Node node) {
151 Aug augmentation = getAugmentation(node);
152 if (augmentation != null) {
153 List<T> data = getData(augmentation);
155 return new ArrayList<>(data);
158 return Collections.emptyList();
161 protected Map<InstanceIdentifier<Node>, List<T>> extractRemoved(
162 Collection<DataTreeModification<Node>> changes, Class<T> class1) {
163 Map<InstanceIdentifier<Node>, List<T>> result = new HashMap<>();
164 if (changes != null && !changes.isEmpty()) {
165 for (DataTreeModification<Node> change : changes) {
166 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
167 Class<? extends Identifiable> classType = (Class<? extends Identifiable>) getClassType();
169 if (operationalState.isInReconciliation()) {
170 removed = getRemoved(change);
172 removed = (List<T>) operationalState.getDeletedData(key, classType);
174 removed.addAll(getCascadeDeleteData(change));
175 result.put(key, removed);
181 protected Map<InstanceIdentifier<Node>, List<T>> extractUpdated(
182 Collection<DataTreeModification<Node>> changes, Class<T> class1) {
183 Map<InstanceIdentifier<Node>, List<T>> result = new HashMap<>();
184 if (changes != null && !changes.isEmpty()) {
185 for (DataTreeModification<Node> change : changes) {
186 InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
187 Class<? extends Identifiable> classType = (Class<? extends Identifiable>) getClassType();
188 List<T> updated = null;
189 if (operationalState.isInReconciliation()) {
190 updated = getUpdated(change);
192 updated = (List<T>) operationalState.getUpdatedData(key, classType);
194 result.put(key, updated);
200 List<T> getCascadeDeleteData(DataTreeModification<Node> change) {
201 if (!cascadeDelete()) {
202 return Collections.EMPTY_LIST;
204 DataObjectModification<Node> mod = change.getRootNode();
205 Node updatedNode = TransactUtils.getUpdated(mod);
206 List<T> updatedData = getData(updatedNode);
207 Set<InstanceIdentifier> deleted = getOperationalState().getDeletedKeysInCurrentTx(LogicalSwitches.class);
208 UnMetDependencyGetter dependencyGetter = getDependencyGetter();
209 if (!HwvtepSouthboundUtil.isEmpty(deleted) && !HwvtepSouthboundUtil.isEmpty(updatedData) && dependencyGetter != null) {
210 List<T> removed = new ArrayList<>();
211 for (T ele : updatedData) {
212 if (deleted.containsAll(dependencyGetter.getLogicalSwitchDependencies(ele))) {
218 return Collections.EMPTY_LIST;
221 List<T> getRemoved(DataTreeModification<Node> change) {
222 DataObjectModification<Node> mod = change.getRootNode();
224 Node removed = TransactUtils.getRemoved(mod);
225 Node updated = TransactUtils.getUpdated(mod);
226 Node before = mod.getDataBefore();
227 return diffOf(removed, before, updated, true);
230 List<T> getUpdated(DataTreeModification<Node> change) {
231 DataObjectModification<Node> mod = change.getRootNode();
232 Node updated = TransactUtils.getUpdated(mod);
233 Node before = mod.getDataBefore();
234 return diffOf(updated, before, false);
237 List<T> diffOf(Node include, Node a, Node b, boolean compareKeyOnly) {
238 List<T> data1 = getData(include);
239 List<T> data2 = diffOf(a, b, compareKeyOnly);
240 if (HwvtepSouthboundUtil.isEmpty(data1) && HwvtepSouthboundUtil.isEmpty(data2)) {
241 return Collections.emptyList();
243 List<T> result = new ArrayList<>(data1);
244 result.addAll(data2);
248 List<T> diffOf(Node a, Node b, boolean compareKeyOnly) {
249 List<T> result = new ArrayList<>();
251 List<T> list1 = getData(a);
252 List<T> list2 = getData(b);
254 if (HwvtepSouthboundUtil.isEmpty(list1)) {
255 return Collections.emptyList();
257 if (HwvtepSouthboundUtil.isEmpty(list2)) {
258 return HwvtepSouthboundUtil.isEmpty(list1) ? Collections.emptyList() : list1;
261 Iterator<T> it1 = list1.iterator();
263 while(it1.hasNext()) {
265 Iterator<T> it2 = list2.iterator();
266 boolean found = false;
267 while (it2.hasNext()) {
268 T other = it2.next();
269 found = compareKeyOnly ? Objects.equals(ele.getKey(), other.getKey()) : areEqual(ele, other);
283 protected Type getClassType() {
284 Type type = getClass().getGenericSuperclass();
285 Type classType = ((ParameterizedType)type).getActualTypeArguments()[0];
289 protected boolean areEqual(T a , T b) {
290 return a.getKey().equals(b.getKey());
293 protected UnMetDependencyGetter getDependencyGetter() {
298 * Tells if this object needs to be deleted if its dependent object gets deleted
299 * Ex : LocalUcastMac and LocalMacstMac
300 * @return true if this object needs to be deleted if its dependent object gets deleted
302 protected boolean cascadeDelete() {
306 protected boolean isRemoveCommand() {