Fix Mcast store and Mcast CLI

Change-Id: I8f2bfe37738d7a7ee19ebcd79e13baa4abb01a76
diff --git a/apps/mcast/api/pom.xml b/apps/mcast/api/pom.xml
index a43d269..2f4fff3 100644
--- a/apps/mcast/api/pom.xml
+++ b/apps/mcast/api/pom.xml
@@ -39,10 +39,6 @@
             <version>${project.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.compendium</artifactId>
-        </dependency>
-        <dependency>
             <groupId>org.onosproject</groupId>
             <artifactId>onlab-osgi</artifactId>
             <classifier>tests</classifier>
diff --git a/apps/mcast/cli/pom.xml b/apps/mcast/cli/pom.xml
index cb45a37..7947624 100644
--- a/apps/mcast/cli/pom.xml
+++ b/apps/mcast/cli/pom.xml
@@ -32,10 +32,6 @@
     <dependencies>
         <dependency>
             <groupId>org.onosproject</groupId>
-            <artifactId>onlab-osgi</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.onosproject</groupId>
             <artifactId>onos-apps-mcast-api</artifactId>
             <version>${project.version}</version>
         </dependency>
diff --git a/apps/mcast/cli/src/main/java/org/onosproject/mcast/cli/McastGroupCompleter.java b/apps/mcast/cli/src/main/java/org/onosproject/mcast/cli/McastGroupCompleter.java
new file mode 100644
index 0000000..9c4bddd
--- /dev/null
+++ b/apps/mcast/cli/src/main/java/org/onosproject/mcast/cli/McastGroupCompleter.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.mcast.cli;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.util.Tools;
+import org.onosproject.cli.AbstractChoicesCompleter;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.mcast.api.McastRoute;
+import org.onosproject.mcast.api.MulticastRouteService;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Mcast group Completer.
+ */
+public class McastGroupCompleter extends AbstractChoicesCompleter {
+
+    @Override
+    protected List<String> choices() {
+        MulticastRouteService service = AbstractShellCommand.get(MulticastRouteService.class);
+
+        return Tools.stream(service.getRoutes())
+                .map(McastRoute::group)
+                .map(IpAddress::toString)
+                .collect(Collectors.toList());
+    }
+
+}
diff --git a/apps/mcast/cli/src/main/java/org/onosproject/mcast/cli/McastHostDeleteCommand.java b/apps/mcast/cli/src/main/java/org/onosproject/mcast/cli/McastHostDeleteCommand.java
index 88250bb..121a6c0 100644
--- a/apps/mcast/cli/src/main/java/org/onosproject/mcast/cli/McastHostDeleteCommand.java
+++ b/apps/mcast/cli/src/main/java/org/onosproject/mcast/cli/McastHostDeleteCommand.java
@@ -58,29 +58,42 @@
     @Override
     protected void execute() {
         MulticastRouteService mcastRouteManager = get(MulticastRouteService.class);
-
+        // Clear all routes
         if ("*".equals(sAddr) && "*".equals(gAddr)) {
-            // Clear all routes
             mcastRouteManager.getRoutes().forEach(mcastRouteManager::remove);
             return;
         }
-        if (host != null && host.isEmpty()) {
-            print("Please provide a non-empty host Id");
+        // Removing/updating a specific entry
+        IpAddress sAddrIp = null;
+        //If the source Ip is * we want ASM so we leave it as null and the route will have it as an optional.empty()
+        if (!sAddr.equals("*")) {
+            sAddrIp = IpAddress.valueOf(sAddr);
+        }
+        McastRoute mRoute = new McastRoute(sAddrIp, IpAddress.valueOf(gAddr),
+                                           McastRoute.Type.STATIC);
+        // If the user provides only sAddr and gAddr, we have to remove the route
+        if (host == null || host.isEmpty()) {
+            mcastRouteManager.remove(mRoute);
+            printMcastRoute(D_FORMAT_MAPPING, mRoute);
             return;
         }
-        print("%s", host);
+        // Otherwise we need to remove a specific sink
         HostId hostId = HostId.hostId(host);
-        McastRoute mRoute = new McastRoute(IpAddress.valueOf(sAddr),
-                IpAddress.valueOf(gAddr), McastRoute.Type.STATIC);
         if (!mcastRouteManager.getRoutes().contains(mRoute)) {
             print("Route is not present, store it first");
-            print(U_FORMAT_MAPPING, mRoute.type(), mRoute.group(), mRoute.source());
             return;
         }
+        // Otherwise remove the entire host id
         if (host != null) {
             mcastRouteManager.removeSink(mRoute, hostId);
         }
-        print(U_FORMAT_MAPPING, mRoute.type(), mRoute.group(), mRoute.source());
-        print("%s", mcastRouteManager.routeData(mRoute));
+        // We have done
+        printMcastRoute(U_FORMAT_MAPPING, mRoute);
+    }
+
+    private void printMcastRoute(String format, McastRoute mcastRoute) {
+        // If the source is present let's use it, otherwise we need to print *
+        print(format, mcastRoute.type(), mcastRoute.group(),
+              mcastRoute.source().isPresent() ? mcastRoute.source().get() : "*");
     }
 }
diff --git a/apps/mcast/cli/src/main/java/org/onosproject/mcast/cli/McastHostJoinCommand.java b/apps/mcast/cli/src/main/java/org/onosproject/mcast/cli/McastHostJoinCommand.java
index 1391822..629cb2a 100644
--- a/apps/mcast/cli/src/main/java/org/onosproject/mcast/cli/McastHostJoinCommand.java
+++ b/apps/mcast/cli/src/main/java/org/onosproject/mcast/cli/McastHostJoinCommand.java
@@ -20,7 +20,6 @@
 import org.onlab.packet.IpAddress;
 import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.mcast.api.McastRoute;
-import org.onosproject.mcast.api.McastRouteData;
 import org.onosproject.mcast.api.MulticastRouteService;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.HostId;
@@ -76,14 +75,12 @@
         }
 
         McastRoute mRoute = new McastRoute(sAddrIp, IpAddress.valueOf(gAddr), McastRoute.Type.STATIC);
-        log.info("Route {}", mRoute);
         mcastRouteManager.add(mRoute);
 
         if (sources != null) {
             Set<ConnectPoint> sourcesSet = Arrays.stream(sources)
                     .map(ConnectPoint::deviceConnectPoint)
                     .collect(Collectors.toSet());
-            log.info("{}", sourcesSet);
             mcastRouteManager.addSources(mRoute, sourcesSet);
         }
 
@@ -94,14 +91,12 @@
             }
         }
         printMcastRoute(mRoute);
-        printMcastRouteData(mcastRouteManager.routeData(mRoute));
     }
 
     private void printMcastRoute(McastRoute mcastRoute) {
-        print(FORMAT_MAPPING, mcastRoute.type(), mcastRoute.group(), mcastRoute.source());
+        // If the source is present let's use it, otherwise we need to print *
+        print(FORMAT_MAPPING, mcastRoute.type(), mcastRoute.group(),
+              mcastRoute.source().isPresent() ? mcastRoute.source().get() : "*");
     }
 
-    private void printMcastRouteData(McastRouteData mcastRouteData) {
-        print("%s", mcastRouteData);
-    }
 }
diff --git a/apps/mcast/cli/src/main/java/org/onosproject/mcast/cli/McastShowHostCommand.java b/apps/mcast/cli/src/main/java/org/onosproject/mcast/cli/McastShowHostCommand.java
index 562afad..24ee11b 100644
--- a/apps/mcast/cli/src/main/java/org/onosproject/mcast/cli/McastShowHostCommand.java
+++ b/apps/mcast/cli/src/main/java/org/onosproject/mcast/cli/McastShowHostCommand.java
@@ -15,15 +15,17 @@
  */
 package org.onosproject.mcast.cli;
 
-import org.apache.karaf.shell.commands.Argument;
 import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Option;
 import org.onlab.packet.IpAddress;
 import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.mcast.api.McastRoute;
 import org.onosproject.mcast.api.MulticastRouteService;
 import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.HostId;
 
 import java.util.Comparator;
+import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -36,11 +38,13 @@
 public class McastShowHostCommand extends AbstractShellCommand {
 
     // Format for group line
-    private static final String FORMAT_MAPPING = "origin=%s, group=%s, source=%s, sinks=%s";
+    private static final String FORMAT_MAPPING = "origin=%s, group=%s, source IP=%s, sources=%s, sinks=%s";
 
-    @Argument(index = 0, name = "mcastIp", description = "mcast Ip",
+    @Option(name = "-gAddr", aliases = "--groupAddress",
+            description = "IP Address of the multicast group",
+            valueToShowInHelp = "224.0.0.0",
             required = false, multiValued = false)
-    String mcastIp;
+    String gAddr = null;
 
     @Override
     protected void execute() {
@@ -49,19 +53,15 @@
         // Get the routes
         Set<McastRoute> routes = mcastService.getRoutes();
         // Verify mcast group
-        if (!isNullOrEmpty(mcastIp)) {
+        if (!isNullOrEmpty(gAddr)) {
             // Let's find the group
-            IpAddress mcastGroup = IpAddress.valueOf(mcastIp);
+            IpAddress mcastGroup = IpAddress.valueOf(gAddr);
             McastRoute mcastRoute = routes.stream()
                     .filter(route -> route.group().equals(mcastGroup))
                     .findAny().orElse(null);
             // If it exists
             if (mcastRoute != null) {
-                // Get the sinks and print info
-                Set<ConnectPoint> sinks = mcastService.sinks(mcastRoute);
-                Set<ConnectPoint> sources = mcastService.sources(mcastRoute);
-                print(FORMAT_MAPPING, mcastRoute.type(), mcastRoute.group(),
-                        sources, sinks);
+                printRoute(mcastService, mcastRoute);
             }
             return;
         }
@@ -73,11 +73,7 @@
         ipv4Routes.stream()
                 .sorted(Comparator.comparing(McastRoute::group))
                 .forEach(route -> {
-                    // Get sinks
-                    Set<ConnectPoint> sinks = mcastService.sinks(route);
-                    Set<ConnectPoint> sources = mcastService.sources(route);
-                    print(FORMAT_MAPPING, route.type(), route.group(),
-                            sources, sinks);
+                    printRoute(mcastService, route);
                 });
         // Filter ipv6
         Set<McastRoute> ipv6Routes = routes.stream()
@@ -87,12 +83,19 @@
         ipv6Routes.stream()
                 .sorted(Comparator.comparing(McastRoute::group))
                 .forEach(route -> {
-                    // Get sinks
-                    Set<ConnectPoint> sinks = mcastService.sinks(route);
-                    Set<ConnectPoint> sources = mcastService.sources(route);
-                    print(FORMAT_MAPPING, route.type(), route.group(),
-                            sources, sinks);
+                    printRoute(mcastService, route);
                 });
     }
 
+    private void printRoute(MulticastRouteService mcastService, McastRoute route) {
+        Map<HostId, Set<ConnectPoint>> sinks = mcastService.routeData(route).sinks();
+        Set<ConnectPoint> sources = mcastService.sources(route);
+        String srcIp = "*";
+        if (route.source().isPresent()) {
+            srcIp = route.source().get().toString();
+        }
+
+        print(FORMAT_MAPPING, route.type(), route.group(), srcIp, sources, sinks);
+    }
+
 }
diff --git a/apps/mcast/cli/src/main/java/org/onosproject/mcast/cli/McastSourceDeleteCommand.java b/apps/mcast/cli/src/main/java/org/onosproject/mcast/cli/McastSourceDeleteCommand.java
index d85e155..0a6080c 100644
--- a/apps/mcast/cli/src/main/java/org/onosproject/mcast/cli/McastSourceDeleteCommand.java
+++ b/apps/mcast/cli/src/main/java/org/onosproject/mcast/cli/McastSourceDeleteCommand.java
@@ -64,31 +64,40 @@
     @Override
     protected void execute() {
         MulticastRouteService mcastRouteManager = get(MulticastRouteService.class);
-
+        // Clear all routes
         if ("*".equals(sAddr) && "*".equals(gAddr)) {
-            // Clear all routes
             mcastRouteManager.getRoutes().forEach(mcastRouteManager::remove);
             return;
         }
-
-        McastRoute mRoute = new McastRoute(IpAddress.valueOf(sAddr),
-                IpAddress.valueOf(gAddr), McastRoute.Type.STATIC);
-        if (!mcastRouteManager.getRoutes().contains(mRoute)) {
-            print("Route is not present, store it first");
-            print("origin=%s, group=%s, source=%s", mRoute.type(), mRoute.group(), mRoute.source());
-            return;
+        // Removing/updating a specific entry
+        IpAddress sAddrIp = null;
+        // If the source Ip is * we want ASM so we leave it as null and the route will have it as an optional.empty()
+        if (!sAddr.equals("*")) {
+            sAddrIp = IpAddress.valueOf(sAddr);
         }
+        McastRoute mRoute = new McastRoute(sAddrIp, IpAddress.valueOf(gAddr),
+                                           McastRoute.Type.STATIC);
+        // No specific connect points, we have to remove everything
         if (sourceList == null) {
             mcastRouteManager.remove(mRoute);
-            print(D_FORMAT_MAPPING, mRoute.type(), mRoute.group(), mRoute.source());
+            printMcastRoute(D_FORMAT_MAPPING, mRoute);
             return;
         }
-
+        // Otherwise we need to remove specific connect points
+        if (!mcastRouteManager.getRoutes().contains(mRoute)) {
+            print("Route is not present, store it first");
+            return;
+        }
         Set<ConnectPoint> sourcesSet = Arrays.stream(sourceList)
                 .map(ConnectPoint::deviceConnectPoint)
                 .collect(Collectors.toSet());
         mcastRouteManager.removeSources(mRoute, sourcesSet);
-        print(U_FORMAT_MAPPING, mRoute.type(), mRoute.group(), mRoute.source());
-        print("%s", mcastRouteManager.routeData(mRoute));
+        printMcastRoute(U_FORMAT_MAPPING, mRoute);
+    }
+
+    private void printMcastRoute(String format, McastRoute mcastRoute) {
+        // If the source is present let's use it, otherwise we need to print *
+        print(format, mcastRoute.type(), mcastRoute.group(),
+              mcastRoute.source().isPresent() ? mcastRoute.source().get() : "*");
     }
 }
diff --git a/apps/mcast/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/apps/mcast/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index 7ab4273..0c3cc10 100644
--- a/apps/mcast/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/apps/mcast/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -20,30 +20,38 @@
         <command>
             <action class="org.onosproject.mcast.cli.McastHostJoinCommand"/>
             <optional-completers>
-                <entry key="-srcs" value-ref="deviceIdCompleter"/>
+                <entry key="-gAddr" value-ref="mcastGroupCompleter"/>
+                <entry key="-srcs" value-ref="connectpointCompleter"/>
                 <entry key="-sinks" value-ref="hostIdCompleter"/>
             </optional-completers>
         </command>
         <command>
             <action class="org.onosproject.mcast.cli.McastShowHostCommand"/>
+            <optional-completers>
+                <entry key="-gAddr" value-ref="mcastGroupCompleter"/>
+            </optional-completers>
         </command>
         <command>
             <action class="org.onosproject.mcast.cli.McastHostDeleteCommand"/>
             <optional-completers>
-                <entry key="-cps" value-ref="deviceIdCompleter"/>
+                <entry key="-gAddr" value-ref="mcastGroupCompleter"/>
+                <entry key="-cps" value-ref="connectpointCompleter"/>
                 <entry key="-h" value-ref="hostIdCompleter"/>
             </optional-completers>
         </command>
         <command>
             <action class="org.onosproject.mcast.cli.McastSourceDeleteCommand"/>
             <optional-completers>
-                <entry key="-src" value-ref="deviceIdCompleter"/>
+                <entry key="-gAddr" value-ref="mcastGroupCompleter"/>
+                <entry key="-src" value-ref="connectpointCompleter"/>
             </optional-completers>
         </command>
 
     </command-bundle>
 
     <bean id="hostIdCompleter" class="org.onosproject.cli.net.HostIdCompleter"/>
-    <bean id="deviceIdCompleter" class="org.onosproject.cli.net.DeviceIdCompleter"/>
+    <bean id="connectpointCompleter" class="org.onosproject.cli.net.ConnectPointCompleter"/>
+    <bean id="mcastGroupCompleter" class="org.onosproject.mcast.cli.McastGroupCompleter"/>
+
 
 </blueprint>
diff --git a/apps/mcast/impl/pom.xml b/apps/mcast/impl/pom.xml
index fb4109b..fb53b7b 100644
--- a/apps/mcast/impl/pom.xml
+++ b/apps/mcast/impl/pom.xml
@@ -39,10 +39,6 @@
             <version>${project.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.compendium</artifactId>
-        </dependency>
-        <dependency>
             <groupId>org.onosproject</groupId>
             <artifactId>onos-apps-mcast-api</artifactId>
             <version>${project.version}</version>
diff --git a/apps/mcast/impl/src/main/java/org/onosproject/mcast/impl/DistributedMcastRoutesStore.java b/apps/mcast/impl/src/main/java/org/onosproject/mcast/impl/DistributedMcastRoutesStore.java
index 8c90a1d..84e2131 100644
--- a/apps/mcast/impl/src/main/java/org/onosproject/mcast/impl/DistributedMcastRoutesStore.java
+++ b/apps/mcast/impl/src/main/java/org/onosproject/mcast/impl/DistributedMcastRoutesStore.java
@@ -103,7 +103,7 @@
 
     @Override
     public void storeRoute(McastRoute route) {
-        mcastRoutes.put(route, McastRouteData.empty());
+        mcastRoutes.putIfAbsent(route, McastRouteData.empty());
     }
 
     @Override
@@ -123,7 +123,8 @@
     public void removeSources(McastRoute route) {
         mcastRoutes.compute(route, (k, v) -> {
             v.removeSources();
-            return v;
+            // Since we have cleared the sources, we should remove the route
+            return null;
         });
     }
 
@@ -131,9 +132,9 @@
     public void removeSources(McastRoute route, Set<ConnectPoint> sources) {
         mcastRoutes.compute(route, (k, v) -> {
             v.removeSources(sources);
-            return v;
+            // Since there are no sources, we should remove the route
+            return v.sources().isEmpty() ? null : v;
         });
-
     }
 
     @Override
@@ -256,7 +257,6 @@
                                 mcastRouteUpdate(route, oldData.sources(), oldData.sinks()),
                                 mcastRouteUpdate(route, newData.sources(), newData.sinks())));
                     } else if (newData.allSinks().size() < oldData.allSinks().size()) {
-                        log.info("Removed");
                         notifyDelegate(new McastEvent(McastEvent.Type.SINKS_REMOVED,
                                 mcastRouteUpdate(route, oldData.sources(), oldData.sinks()),
                                 mcastRouteUpdate(route, newData.sources(), newData.sinks())));
diff --git a/apps/mcast/pom.xml b/apps/mcast/pom.xml
index 4989e0d..578abc5 100644
--- a/apps/mcast/pom.xml
+++ b/apps/mcast/pom.xml
@@ -37,21 +37,5 @@
         <module>api</module>
         <module>app</module>
     </modules>
-    <dependencies>
-        <dependency>
-            <groupId>org.onosproject</groupId>
-            <artifactId>onlab-junit</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>com.google.guava</groupId>
-            <artifactId>guava-testlib</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.easymock</groupId>
-            <artifactId>easymock</artifactId>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
+
 </project>