[VOL-3016] OLTPipeline removes empty next group if the last group  was removed because of empty buckets

Change-Id: Ife4973a1bdd4137fd43fa4d2a49b94a5f3280aeb
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/OltPipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/OltPipeline.java
index 841e444..2ef01d2 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/OltPipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/OltPipeline.java
@@ -301,28 +301,34 @@
         if (nextObjective.type() != NextObjective.Type.BROADCAST) {
             log.error("OLT only supports broadcast groups.");
             fail(nextObjective, ObjectiveError.BADPARAMS);
+            return;
         }
 
-        if (nextObjective.next().size() != 1) {
+        if (nextObjective.next().size() != 1 && !nextObjective.op().equals(Objective.Operation.REMOVE)) {
             log.error("OLT only supports singleton broadcast groups.");
             fail(nextObjective, ObjectiveError.BADPARAMS);
+            return;
         }
 
-        TrafficTreatment treatment = nextObjective.next().stream().findFirst().get();
+        Optional<TrafficTreatment> treatmentOpt = nextObjective.next().stream().findFirst();
+        if (treatmentOpt.isEmpty() && !nextObjective.op().equals(Objective.Operation.REMOVE)) {
+            log.error("Next objective {} does not have a treatment", nextObjective);
+            fail(nextObjective, ObjectiveError.BADPARAMS);
+            return;
+        }
 
-
-        GroupBucket bucket = DefaultGroupBucket.createAllGroupBucket(treatment);
         GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id()));
 
-
         pendingGroups.put(key, nextObjective);
-
+        log.trace("NextObjective Operation {}", nextObjective.op());
         switch (nextObjective.op()) {
             case ADD:
                 GroupDescription groupDesc =
                         new DefaultGroupDescription(deviceId,
                                                     GroupDescription.Type.ALL,
-                                                    new GroupBuckets(Collections.singletonList(bucket)),
+                                                    new GroupBuckets(
+                                                            Collections.singletonList(
+                                                                buildBucket(treatmentOpt.get()))),
                                                     key,
                                                     null,
                                                     nextObjective.appId());
@@ -333,12 +339,16 @@
                 break;
             case ADD_TO_EXISTING:
                 groupService.addBucketsToGroup(deviceId, key,
-                                               new GroupBuckets(Collections.singletonList(bucket)),
+                                               new GroupBuckets(
+                                                       Collections.singletonList(
+                                                               buildBucket(treatmentOpt.get()))),
                                                key, nextObjective.appId());
                 break;
             case REMOVE_FROM_EXISTING:
                 groupService.removeBucketsFromGroup(deviceId, key,
-                                                    new GroupBuckets(Collections.singletonList(bucket)),
+                                                    new GroupBuckets(
+                                                            Collections.singletonList(
+                                                                buildBucket(treatmentOpt.get()))),
                                                     key, nextObjective.appId());
                 break;
             default:
@@ -348,6 +358,10 @@
 
     }
 
+    private GroupBucket buildBucket(TrafficTreatment treatment) {
+        return DefaultGroupBucket.createAllGroupBucket(treatment);
+    }
+
     private void processMulticastRule(ForwardingObjective fwd) {
         if (fwd.nextId() == null) {
             log.error("Multicast objective does not have a next id");
@@ -1015,16 +1029,23 @@
     private class InnerGroupListener implements GroupListener {
         @Override
         public void event(GroupEvent event) {
+            GroupKey key = event.subject().appCookie();
+            NextObjective obj = pendingGroups.getIfPresent(key);
+            if (obj == null) {
+                log.debug("No pending group for {}, moving on", key);
+                return;
+            }
+            log.trace("Event {} for group {}, handling pending" +
+                              "NextGroup {}", event.type(), key, obj.id());
             if (event.type() == GroupEvent.Type.GROUP_ADDED ||
                     event.type() == GroupEvent.Type.GROUP_UPDATED) {
-                GroupKey key = event.subject().appCookie();
-
-                NextObjective obj = pendingGroups.getIfPresent(key);
-                if (obj != null) {
                     flowObjectiveStore.putNextGroup(obj.id(), new OLTPipelineGroup(key));
                     pass(obj);
                     pendingGroups.invalidate(key);
-                }
+            } else if (event.type() == GroupEvent.Type.GROUP_REMOVED) {
+                    flowObjectiveStore.removeNextGroup(obj.id());
+                    pass(obj);
+                    pendingGroups.invalidate(key);
             }
         }
     }