bug 6579 removed boilerplate code
[ovsdb.git] / hwvtepsouthbound / hwvtepsouthbound-impl / src / main / java / org / opendaylight / ovsdb / hwvtepsouthbound / transact / AbstractTransactCommand.java
index c62dc862ff7fc5ff79a1036d676a06d4a7c2ca37..349cf3db26cfa17732783a6f1e7ce8e62532dbfd 100644 (file)
@@ -8,20 +8,38 @@
 
 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;
@@ -43,8 +61,7 @@ public abstract class AbstractTransactCommand<T extends Identifiable> implements
         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);
     }
@@ -67,17 +84,20 @@ public abstract class AbstractTransactCommand<T extends Identifiable> implements
         //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) {
 
@@ -90,7 +110,7 @@ public abstract class AbstractTransactCommand<T extends Identifiable> implements
             };
             deviceInfo.addJobToQueue(configWaitingJob);
         }
-        if (inTransitDependencies.size() > 0) {
+        if (!HwvtepSouthboundUtil.isEmptyMap(inTransitDependencies)) {
 
             DependentJob<T> opWaitingJob = new DependentJob.OpWaitingJob(
                     key, data, inTransitDependencies) {
@@ -115,4 +135,158 @@ public abstract class AbstractTransactCommand<T extends Identifiable> implements
                                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;
+    }
 }