[ONOS-6528] Avoid VPLS race condition problem

Change-Id: I2d1ce9a20e76eabf9489e3361dbf95e518294b6d
diff --git a/apps/vpls/src/main/java/org/onosproject/vpls/VplsManager.java b/apps/vpls/src/main/java/org/onosproject/vpls/VplsManager.java
index 58ea4a2..6be3a23 100644
--- a/apps/vpls/src/main/java/org/onosproject/vpls/VplsManager.java
+++ b/apps/vpls/src/main/java/org/onosproject/vpls/VplsManager.java
@@ -103,7 +103,8 @@
     @Override
     public VplsData removeVpls(VplsData vplsData) {
         requireNonNull(vplsData);
-        vplsData.state(VplsData.VplsState.REMOVING);
+        VplsData newData = VplsData.of(vplsData);
+        newData.state(VplsData.VplsState.REMOVING);
         vplsStore.removeVpls(vplsData);
         return vplsData;
     }
@@ -112,28 +113,31 @@
     public void addInterfaces(VplsData vplsData, Collection<Interface> interfaces) {
         requireNonNull(vplsData);
         requireNonNull(interfaces);
-        vplsData.addInterfaces(interfaces);
-        updateVplsStatus(vplsData, VplsData.VplsState.UPDATING);
+        VplsData newData = VplsData.of(vplsData);
+        newData.addInterfaces(interfaces);
+        updateVplsStatus(newData, VplsData.VplsState.UPDATING);
     }
 
     @Override
     public void addInterface(VplsData vplsData, Interface iface) {
         requireNonNull(vplsData);
         requireNonNull(iface);
-        vplsData.addInterface(iface);
-        updateVplsStatus(vplsData, VplsData.VplsState.UPDATING);
+        VplsData newData = VplsData.of(vplsData);
+        newData.addInterface(iface);
+        updateVplsStatus(newData, VplsData.VplsState.UPDATING);
     }
 
     @Override
     public void setEncapsulationType(VplsData vplsData, EncapsulationType encapsulationType) {
         requireNonNull(vplsData);
         requireNonNull(encapsulationType);
-        if (vplsData.encapsulationType().equals(encapsulationType)) {
+        VplsData newData = VplsData.of(vplsData);
+        if (newData.encapsulationType().equals(encapsulationType)) {
             // Encap type not changed.
             return;
         }
-        vplsData.encapsulationType(encapsulationType);
-        updateVplsStatus(vplsData, VplsData.VplsState.UPDATING);
+        newData.encapsulationType(encapsulationType);
+        updateVplsStatus(newData, VplsData.VplsState.UPDATING);
     }
 
     @Override
@@ -146,8 +150,9 @@
     public Collection<Interface> removeInterfaces(VplsData vplsData, Collection<Interface> interfaces) {
         requireNonNull(vplsData);
         requireNonNull(interfaces);
-        vplsData.removeInterfaces(interfaces);
-        updateVplsStatus(vplsData, VplsData.VplsState.UPDATING);
+        VplsData newData = VplsData.of(vplsData);
+        newData.removeInterfaces(interfaces);
+        updateVplsStatus(newData, VplsData.VplsState.UPDATING);
         return interfaces;
     }
 
@@ -155,8 +160,9 @@
     public Interface removeInterface(VplsData vplsData, Interface iface) {
         requireNonNull(vplsData);
         requireNonNull(iface);
-        vplsData.removeInterface(iface);
-        updateVplsStatus(vplsData, VplsData.VplsState.UPDATING);
+        VplsData newData = VplsData.of(vplsData);
+        newData.removeInterface(iface);
+        updateVplsStatus(newData, VplsData.VplsState.UPDATING);
         return iface;
     }
 
diff --git a/apps/vpls/src/main/java/org/onosproject/vpls/cli/VplsCommand.java b/apps/vpls/src/main/java/org/onosproject/vpls/cli/VplsCommand.java
index 4718453..334ef94 100644
--- a/apps/vpls/src/main/java/org/onosproject/vpls/cli/VplsCommand.java
+++ b/apps/vpls/src/main/java/org/onosproject/vpls/cli/VplsCommand.java
@@ -15,6 +15,7 @@
  */
 package org.onosproject.vpls.cli;
 
+import com.google.common.collect.ImmutableSet;
 import org.apache.karaf.shell.commands.Argument;
 import org.apache.karaf.shell.commands.Command;
 import org.onosproject.cli.AbstractShellCommand;
@@ -23,6 +24,7 @@
 import org.onosproject.net.EncapsulationType;
 import org.onosproject.vpls.api.VplsData;
 import org.onosproject.vpls.api.Vpls;
+import org.onosproject.vpls.api.VplsData.VplsState;
 
 import java.util.Collection;
 import java.util.Collections;
@@ -31,6 +33,7 @@
 import java.util.stream.Collectors;
 
 import static com.google.common.base.Strings.isNullOrEmpty;
+import static org.onosproject.vpls.api.VplsData.VplsState.*;
 
 
 /**
@@ -39,6 +42,8 @@
 @Command(scope = "onos", name = "vpls",
         description = "Manages the VPLS application")
 public class VplsCommand extends AbstractShellCommand {
+    private static final Set<VplsState> CHANGING_STATE =
+            ImmutableSet.of(ADDING, REMOVING, UPDATING);
 
     // Color codes and style
     private static final String BOLD = "\u001B[1m";
@@ -180,6 +185,11 @@
             print(VPLS_NOT_FOUND, vplsName);
             return;
         }
+        if (CHANGING_STATE.contains(vplsData.state())) {
+            // when a VPLS is updating, we shouldn't try modify it.
+            print("VPLS %s still updating, please wait it finished", vplsData.name());
+            return;
+        }
         if (iface == null) {
             print(IFACE_NOT_FOUND, ifaceName);
             return;
@@ -225,6 +235,11 @@
             print(VPLS_NOT_FOUND, vplsName);
             return;
         }
+        if (CHANGING_STATE.contains(vplsData.state())) {
+            // when a VPLS is updating, we shouldn't try modify it.
+            print("VPLS %s still updating, please wait it finished", vplsData.name());
+            return;
+        }
         vpls.removeVpls(vplsData);
     }
 
@@ -263,6 +278,11 @@
             print(VPLS_NOT_FOUND, vplsName);
             return;
         }
+        if (CHANGING_STATE.contains(vplsData.state())) {
+            // when a VPLS is updating, we shouldn't try modify it.
+            print("VPLS %s still updating, please wait it finished", vplsData.name());
+            return;
+        }
         if (iface == null) {
             print(IFACE_NOT_FOUND, ifaceName);
             return;
diff --git a/apps/vpls/src/main/java/org/onosproject/vpls/store/DistributedVplsStore.java b/apps/vpls/src/main/java/org/onosproject/vpls/store/DistributedVplsStore.java
index 6b50508..e2c4956 100644
--- a/apps/vpls/src/main/java/org/onosproject/vpls/store/DistributedVplsStore.java
+++ b/apps/vpls/src/main/java/org/onosproject/vpls/store/DistributedVplsStore.java
@@ -217,6 +217,10 @@
                     }
                     break;
                 case REMOVE:
+                    if (vplsData == null) {
+                        vplsData = VplsData.of(event.key());
+                    }
+                    vplsData.state(VplsData.VplsState.REMOVING);
                     VplsStoreEvent vplsStoreEvent =
                             new VplsStoreEvent(VplsStoreEvent.Type.REMOVE, vplsData);
                     notifyDelegate(vplsStoreEvent);
diff --git a/apps/vpls/src/test/java/org/onosproject/vpls/VplsTest.java b/apps/vpls/src/test/java/org/onosproject/vpls/VplsTest.java
index a99e07f..dae4086 100644
--- a/apps/vpls/src/test/java/org/onosproject/vpls/VplsTest.java
+++ b/apps/vpls/src/test/java/org/onosproject/vpls/VplsTest.java
@@ -471,6 +471,7 @@
         @Override
         public VplsData createVpls(String vplsName, EncapsulationType encapsulationType) {
             VplsData vplsData = VplsData.of(vplsName, encapsulationType);
+            vplsData.state(VplsData.VplsState.ADDED);
             testData.put(vplsName, vplsData);
             return vplsData;
         }