2 * Copyright (c) 2015 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.HashSet;
18 import java.util.Iterator;
19 import java.util.List;
21 import java.util.Objects;
24 import com.google.common.collect.Lists;
25 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
26 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
27 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepDeviceInfo;
28 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundUtil;
29 import org.opendaylight.ovsdb.lib.notation.UUID;
30 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
31 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
32 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
33 import org.opendaylight.yangtools.yang.binding.Identifiable;
34 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
36 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
37 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
38 import org.opendaylight.yangtools.yang.binding.Augmentation;
39 import org.opendaylight.yangtools.yang.binding.Identifiable;
40 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
42 public abstract class AbstractTransactCommand<T extends Identifiable, Aug extends Augmentation<Node>> implements TransactCommand<T> {
44 private HwvtepOperationalState operationalState;
45 private Collection<DataTreeModification<Node>> changes;
47 protected AbstractTransactCommand() {
51 public AbstractTransactCommand(HwvtepOperationalState state, Collection<DataTreeModification<Node>> changes) {
52 this.operationalState = state;
53 this.changes = changes;
56 public HwvtepOperationalState getOperationalState() {
57 return operationalState;
60 public Collection<DataTreeModification<Node>> getChanges() {
64 void updateCurrentTxDeleteData(Class<? extends Identifiable> cls, InstanceIdentifier key, T data) {
65 operationalState.updateCurrentTxDeleteData(cls, key);
66 operationalState.getDeviceInfo().clearConfigData(cls, key);
69 void updateCurrentTxData(Class<? extends Identifiable> cls, InstanceIdentifier key, UUID uuid, Object data) {
70 operationalState.updateCurrentTxData(cls, key, uuid);
71 operationalState.getDeviceInfo().markKeyAsInTransit(cls, key);
72 operationalState.getDeviceInfo().updateConfigData(cls, key, data);
75 void processDependencies(UnMetDependencyGetter<T> unMetDependencyGetter,
76 TransactionBuilder transaction,
77 final InstanceIdentifier<Node> nodeIid,
78 final InstanceIdentifier key,
79 final T data, final Object... extraData) {
81 HwvtepDeviceInfo deviceInfo = operationalState.getDeviceInfo();
82 Map inTransitDependencies = unMetDependencyGetter.getInTransitDependencies(operationalState, data);
83 Map confingDependencies = unMetDependencyGetter.getUnMetConfigDependencies(operationalState, data);
84 //we can skip the config termination point dependency as we can create them in device as part of this tx
85 confingDependencies.remove(TerminationPoint.class);
87 Type type = getClass().getGenericSuperclass();
88 Type classType = ((ParameterizedType)type).getActualTypeArguments()[0];
90 //If this key itself is in transit wait for the response of this key itself
91 if (deviceInfo.isKeyInTransit((Class<? extends Identifiable>) classType, key)) {
92 inTransitDependencies.put((Class<? extends Identifiable>) classType, Lists.newArrayList(key));
95 if (HwvtepSouthboundUtil.isEmptyMap(confingDependencies) && HwvtepSouthboundUtil.isEmptyMap(inTransitDependencies)) {
96 doDeviceTransaction(transaction, nodeIid, data, key, extraData);
97 //TODO put proper uuid
98 updateCurrentTxData((Class<? extends Identifiable>) classType, key, new UUID("uuid"), data);
100 if (!HwvtepSouthboundUtil.isEmptyMap(confingDependencies)) {
101 DependentJob<T> configWaitingJob = new DependentJob.ConfigWaitingJob(
102 key, data, confingDependencies) {
105 public void onDependencyResolved(HwvtepOperationalState operationalState,
106 TransactionBuilder transactionBuilder) {
107 AbstractTransactCommand.this.operationalState = operationalState;
108 onConfigUpdate(transactionBuilder, nodeIid, data, key, extraData);
111 deviceInfo.addJobToQueue(configWaitingJob);
113 if (!HwvtepSouthboundUtil.isEmptyMap(inTransitDependencies)) {
115 DependentJob<T> opWaitingJob = new DependentJob.OpWaitingJob(
116 key, data, inTransitDependencies) {
119 public void onDependencyResolved(HwvtepOperationalState operationalState,
120 TransactionBuilder transactionBuilder) {
121 AbstractTransactCommand.this.operationalState = operationalState;
122 onConfigUpdate(transactionBuilder, nodeIid, data, key, extraData);
125 deviceInfo.addJobToQueue(opWaitingJob);
129 public void doDeviceTransaction(TransactionBuilder transaction, InstanceIdentifier<Node> nodeIid, T data,
130 InstanceIdentifier key, Object... extraData) {
131 //tobe removed as part of refactoring patch
134 public void onConfigUpdate(TransactionBuilder transaction, InstanceIdentifier<Node> nodeIid, T data,
135 InstanceIdentifier key, Object... extraData) {
136 //tobe removed as part of refactoring patch
139 protected Aug getAugmentation(Node node) {
143 ParameterizedType parameterizedType = (ParameterizedType) getClass().getGenericSuperclass();
144 Class<? extends Augmentation<Node>> augType = (Class<? extends Augmentation<Node>>) parameterizedType.getActualTypeArguments()[1];
145 Augmentation<Node> augmentation = node.getAugmentation(augType);
146 return (Aug)augmentation;
149 protected List<T> getData(Aug augmentation) {
150 return Collections.EMPTY_LIST;
153 protected List<T> getData(Node node) {
154 Aug augmentation = getAugmentation(node);
155 if (augmentation != null) {
156 List<T> data = getData(augmentation);
158 return Lists.newArrayList(data);
161 return Collections.EMPTY_LIST;
164 protected Map<InstanceIdentifier<Node>, List<T>> extractRemoved(
165 Collection<DataTreeModification<Node>> changes, Class<T> class1) {
166 Map<InstanceIdentifier<Node>, List<T>> result
167 = new HashMap<InstanceIdentifier<Node>, List<T>>();
168 List<T> removed = Collections.EMPTY_LIST;
169 if (changes != null && !changes.isEmpty()) {
170 for (DataTreeModification<Node> change : changes) {
171 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
172 Class<? extends Identifiable> classType = (Class<? extends Identifiable>) getClassType();
173 if (operationalState.isInReconciliation()) {
174 removed = getRemoved(change);
176 removed = (List<T>) operationalState.getDeletedData(key, classType);
178 removed.addAll(getCascadeDeleteData(change));
179 result.put(key, removed);
185 protected Map<InstanceIdentifier<Node>, List<T>> extractUpdated(
186 Collection<DataTreeModification<Node>> changes, Class<T> class1) {
187 Map<InstanceIdentifier<Node>, List<T>> result
188 = new HashMap<InstanceIdentifier<Node>, List<T>>();
189 if (changes != null && !changes.isEmpty()) {
190 for (DataTreeModification<Node> change : changes) {
191 InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
192 Class<? extends Identifiable> classType = (Class<? extends Identifiable>) getClassType();
193 List<T> updated = null;
194 if (operationalState.isInReconciliation()) {
195 updated = getUpdated(change);
197 updated = (List<T>) operationalState.getUpdatedData(key, classType);
199 result.put(key, updated);
205 List<T> getCascadeDeleteData(DataTreeModification<Node> change) {
206 if (!cascadeDelete()) {
207 return Collections.EMPTY_LIST;
209 DataObjectModification<Node> mod = change.getRootNode();
210 Node updatedNode = TransactUtils.getUpdated(mod);
211 List<T> updatedData = getData(updatedNode);
212 Set<InstanceIdentifier> deleted = getOperationalState().getDeletedKeysInCurrentTx(LogicalSwitches.class);
213 UnMetDependencyGetter dependencyGetter = getDependencyGetter();
214 if (!HwvtepSouthboundUtil.isEmpty(deleted) && !HwvtepSouthboundUtil.isEmpty(updatedData) && dependencyGetter != null) {
215 List<T> removed = new ArrayList<T>();
216 for (T ele : updatedData) {
217 if (deleted.containsAll(dependencyGetter.getLogicalSwitchDependencies(ele))) {
223 return Collections.EMPTY_LIST;
226 List<T> getRemoved(DataTreeModification<Node> change) {
227 DataObjectModification<Node> mod = change.getRootNode();
229 Node removed = TransactUtils.getRemoved(mod);
230 Node updated = TransactUtils.getUpdated(mod);
231 Node before = mod.getDataBefore();
232 return diffOf(removed, before, updated, true);
235 List<T> getUpdated(DataTreeModification<Node> change) {
236 DataObjectModification<Node> mod = change.getRootNode();
237 Node updated = TransactUtils.getUpdated(mod);
238 Node before = mod.getDataBefore();
239 return diffOf(updated, before, false);
242 List<T> diffOf(Node include, Node a, Node b, boolean compareKeyOnly) {
243 List<T> data1 = getData(include);
244 List<T> data2 = diffOf(a, b, compareKeyOnly);
245 if (HwvtepSouthboundUtil.isEmpty(data1) && HwvtepSouthboundUtil.isEmpty(data2)) {
246 return Collections.EMPTY_LIST;
248 List<T> result = Lists.newArrayList(data1);
249 result.addAll(data2);
253 List<T> diffOf(Node a, Node b, boolean compareKeyOnly) {
254 List<T> result = new ArrayList<T>();
256 List<T> list1 = getData(a);
257 List<T> list2 = getData(b);
259 if (HwvtepSouthboundUtil.isEmpty(list1)) {
260 return Collections.EMPTY_LIST;
262 if (HwvtepSouthboundUtil.isEmpty(list2)) {
263 return HwvtepSouthboundUtil.isEmpty(list1) ? Collections.EMPTY_LIST : list1;
266 Iterator<T> it1 = list1.iterator();
268 while(it1.hasNext()) {
270 Iterator<T> it2 = list2.iterator();
271 boolean found = false;
272 while (it2.hasNext()) {
273 T other = it2.next();
274 found = compareKeyOnly ? Objects.equals(ele.getKey(), other.getKey()) : areEqual(ele, other);
288 protected Type getClassType() {
289 Type type = getClass().getGenericSuperclass();
290 Type classType = ((ParameterizedType)type).getActualTypeArguments()[0];
294 protected boolean areEqual(T a , T b) {
295 return a.getKey().equals(b.getKey());
298 protected UnMetDependencyGetter getDependencyGetter() {
303 * Tells if this object needs to be deleted if its dependent object gets deleted
304 * Ex : LocalUcastMac and LocalMacstMac
305 * @return true if this object needs to be deleted if its dependent object gets deleted
307 protected boolean cascadeDelete() {