package org.opendaylight.ovsdb.hwvtepsouthbound.transact;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
import com.google.common.collect.Lists;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepDeviceInfo;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundUtil;
import org.opendaylight.ovsdb.lib.notation.UUID;
import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
import org.opendaylight.yangtools.yang.binding.Identifiable;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-public abstract class AbstractTransactCommand<T extends Identifiable> implements TransactCommand<T> {
+public abstract class AbstractTransactCommand<T extends Identifiable, Aug extends Augmentation<Node>> implements TransactCommand<T> {
private HwvtepOperationalState operationalState;
private Collection<DataTreeModification<Node>> changes;
return changes;
}
- void updateCurrentTxDeleteData(InstanceIdentifier key, T data) {
- Class<? extends Identifiable> cls = data.getClass();
+ void updateCurrentTxDeleteData(Class<? extends Identifiable> cls, InstanceIdentifier key, T data) {
operationalState.updateCurrentTxDeleteData(cls, key);
operationalState.getDeviceInfo().clearConfigData(cls, key);
}
//we can skip the config termination point dependency as we can create them in device as part of this tx
confingDependencies.remove(TerminationPoint.class);
+ Type type = getClass().getGenericSuperclass();
+ Type classType = ((ParameterizedType)type).getActualTypeArguments()[0];
+
//If this key itself is in transit wait for the response of this key itself
- if (deviceInfo.isKeyInTransit(data.getClass(), key)) {
- inTransitDependencies.put(data.getClass(), Lists.newArrayList(key));
+ if (deviceInfo.isKeyInTransit((Class<? extends Identifiable>) classType, key)) {
+ inTransitDependencies.put((Class<? extends Identifiable>) classType, Lists.newArrayList(key));
}
- if (confingDependencies.isEmpty() && inTransitDependencies.isEmpty()) {
+ if (HwvtepSouthboundUtil.isEmptyMap(confingDependencies) && HwvtepSouthboundUtil.isEmptyMap(inTransitDependencies)) {
doDeviceTransaction(transaction, nodeIid, data, key, extraData);
//TODO put proper uuid
- updateCurrentTxData(data.getClass(), key, new UUID("uuid"), data);
+ updateCurrentTxData((Class<? extends Identifiable>) classType, key, new UUID("uuid"), data);
}
- if (!confingDependencies.isEmpty()) {
+ if (!HwvtepSouthboundUtil.isEmptyMap(confingDependencies)) {
DependentJob<T> configWaitingJob = new DependentJob.ConfigWaitingJob(
key, data, confingDependencies) {
};
deviceInfo.addJobToQueue(configWaitingJob);
}
- if (inTransitDependencies.size() > 0) {
+ if (!HwvtepSouthboundUtil.isEmptyMap(inTransitDependencies)) {
DependentJob<T> opWaitingJob = new DependentJob.OpWaitingJob(
key, data, inTransitDependencies) {
InstanceIdentifier key, Object... extraData) {
//tobe removed as part of refactoring patch
}
+
+ protected Aug getAugmentation(Node node) {
+ if (node == null) {
+ return null;
+ }
+ ParameterizedType parameterizedType = (ParameterizedType) getClass().getGenericSuperclass();
+ Class<? extends Augmentation<Node>> augType = (Class<? extends Augmentation<Node>>) parameterizedType.getActualTypeArguments()[1];
+ Augmentation<Node> augmentation = node.getAugmentation(augType);
+ return (Aug)augmentation;
+ }
+
+ protected List<T> getData(Aug augmentation) {
+ return Collections.EMPTY_LIST;
+ }
+
+ protected List<T> getData(Node node) {
+ Aug augmentation = getAugmentation(node);
+ if (augmentation != null) {
+ List<T> data = getData(augmentation);
+ if (data != null) {
+ return Lists.newArrayList(data);
+ }
+ }
+ return Collections.EMPTY_LIST;
+ }
+
+ protected Map<InstanceIdentifier<Node>, List<T>> extractRemoved(
+ Collection<DataTreeModification<Node>> changes, Class<T> class1) {
+ Map<InstanceIdentifier<Node>, List<T>> result
+ = new HashMap<InstanceIdentifier<Node>, List<T>>();
+ List<T> removed = Collections.EMPTY_LIST;
+ if (changes != null && !changes.isEmpty()) {
+ for (DataTreeModification<Node> change : changes) {
+ final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
+ removed = getRemoved(change);
+ removed.addAll(getCascadeDeleteData(change));
+ result.put(key, removed);
+ }
+ }
+ return result;
+ }
+
+ protected Map<InstanceIdentifier<Node>, List<T>> extractUpdated(
+ Collection<DataTreeModification<Node>> changes, Class<T> class1) {
+ Map<InstanceIdentifier<Node>, List<T>> result
+ = new HashMap<InstanceIdentifier<Node>, List<T>>();
+ if (changes != null && !changes.isEmpty()) {
+ for (DataTreeModification<Node> change : changes) {
+ InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
+ result.put(key, getUpdated(change));
+ }
+ }
+ return result;
+ }
+
+ List<T> getCascadeDeleteData(DataTreeModification<Node> change) {
+ if (!cascadeDelete()) {
+ return Collections.EMPTY_LIST;
+ }
+ DataObjectModification<Node> mod = change.getRootNode();
+ Node updatedNode = TransactUtils.getUpdated(mod);
+ List<T> updatedData = getData(updatedNode);
+ Set<InstanceIdentifier> deleted = getOperationalState().getDeletedKeysInCurrentTx(LogicalSwitches.class);
+ UnMetDependencyGetter dependencyGetter = getDependencyGetter();
+ if (!HwvtepSouthboundUtil.isEmpty(deleted) && !HwvtepSouthboundUtil.isEmpty(updatedData) && dependencyGetter != null) {
+ List<T> removed = new ArrayList<T>();
+ for (T ele : updatedData) {
+ if (deleted.containsAll(dependencyGetter.getLogicalSwitchDependencies(ele))) {
+ removed.add(ele);
+ }
+ }
+ return removed;
+ }
+ return Collections.EMPTY_LIST;
+ }
+
+ List<T> getRemoved(DataTreeModification<Node> change) {
+ DataObjectModification<Node> mod = change.getRootNode();
+
+ Node removed = TransactUtils.getRemoved(mod);
+ Node updated = TransactUtils.getUpdated(mod);
+ Node before = mod.getDataBefore();
+ return diffOf(removed, before, updated, true);
+ }
+
+ List<T> getUpdated(DataTreeModification<Node> change) {
+ DataObjectModification<Node> mod = change.getRootNode();
+ Node created = TransactUtils.getCreated(mod);
+ Node updated = TransactUtils.getUpdated(mod);
+ Node before = mod.getDataBefore();
+ return diffOf(created, updated, before, false);
+ }
+
+ List<T> diffOf(Node include, Node a, Node b, boolean compareKeyOnly) {
+ List<T> data1 = getData(include);
+ List<T> data2 = diffOf(a, b, compareKeyOnly);
+ if (HwvtepSouthboundUtil.isEmpty(data1) && HwvtepSouthboundUtil.isEmpty(data2)) {
+ return Collections.EMPTY_LIST;
+ }
+ List<T> result = Lists.newArrayList(data1);
+ result.addAll(data2);
+ return result;
+ }
+
+ List<T> diffOf(Node a, Node b, boolean compareKeyOnly) {
+ List<T> result = new ArrayList<T>();
+
+ List<T> list1 = getData(a);
+ List<T> list2 = getData(b);
+
+ if (HwvtepSouthboundUtil.isEmpty(list1)) {
+ return Collections.EMPTY_LIST;
+ }
+ if (HwvtepSouthboundUtil.isEmpty(list2)) {
+ return HwvtepSouthboundUtil.isEmpty(list1) ? Collections.EMPTY_LIST : list1;
+ }
+
+ Iterator<T> it1 = list1.iterator();
+
+ while(it1.hasNext()) {
+ T ele = it1.next();
+ Iterator<T> it2 = list2.iterator();
+ boolean found = false;
+ while (it2.hasNext()) {
+ T other = it2.next();
+ found = compareKeyOnly ? Objects.equals(ele.getKey(), other.getKey()) : areEqual(ele, other);
+ if ( found ) {
+ it2.remove();
+ break;
+ }
+ }
+ if (!found) {
+ result.add(ele);
+ }
+ }
+ return result;
+ }
+
+ protected boolean areEqual(T a , T b) {
+ return a.getKey().equals(b.getKey());
+ }
+
+ protected UnMetDependencyGetter getDependencyGetter() {
+ return null;
+ }
+
+ /**
+ * Tells if this object needs to be deleted if its dependent object gets deleted
+ * Ex : LocalUcastMac and LocalMacstMac
+ * @return true if this object needs to be deleted if its dependent object gets deleted
+ */
+ protected boolean cascadeDelete() {
+ return false;
+ }
}