[CORD-2903] Improve SR/Multicast APIs

Change-Id: Id44af87569e0a83129c96504b21c69e1d455f785
(cherry picked from commit a2858a34a26e02e9d2dd66dc562d0f6fb2c4bdd1)
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/McastTreeListCommand.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/McastTreeListCommand.java
index d1de73c..a1ee1f2 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/McastTreeListCommand.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/McastTreeListCommand.java
@@ -16,7 +16,10 @@
 
 package org.onosproject.segmentrouting.cli;
 
-import com.google.common.collect.ArrayListMultimap;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Multimap;
 import org.apache.karaf.shell.commands.Command;
 import org.apache.karaf.shell.commands.Option;
@@ -24,21 +27,13 @@
 import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.mcast.cli.McastGroupCompleter;
 import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
 import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.mcast.McastRole;
-import org.onosproject.segmentrouting.storekey.McastStoreKey;
 
-import java.util.Collection;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
 
 import static com.google.common.base.Strings.isNullOrEmpty;
-import static org.onosproject.segmentrouting.mcast.McastRole.EGRESS;
-import static org.onosproject.segmentrouting.mcast.McastRole.INGRESS;
-import static org.onosproject.segmentrouting.mcast.McastRole.TRANSIT;
 
 /**
  * Command to show the list of mcast trees.
@@ -51,9 +46,9 @@
     McastGroupCompleter completer;
 
     // Format for group line
-    private static final String G_FORMAT_MAPPING = "group=%s, ingress=%s, transit=%s, egress=%s";
+    private static final String G_FORMAT_MAPPING = "group=%s";
     // Format for sink line
-    private static final String S_FORMAT_MAPPING = "\tsink=%s\tpath=%s";
+    private static final String S_FORMAT_MAPPING = "  sink=%s\tpath=%s";
 
     @Option(name = "-gAddr", aliases = "--groupAddress",
             description = "IP Address of the multicast group",
@@ -61,53 +56,76 @@
             required = false, multiValued = false)
     String gAddr = null;
 
+    @Option(name = "-src", aliases = "--connectPoint",
+            description = "Source port of:XXXXXXXXXX/XX",
+            valueToShowInHelp = "of:0000000000000001/1",
+            required = false, multiValued = false)
+    String source = null;
+
     @Override
     protected void execute() {
-        // Verify mcast group
-        IpAddress mcastGroup = null;
-        if (!isNullOrEmpty(gAddr)) {
-            mcastGroup = IpAddress.valueOf(gAddr);
-
-        }
-        // Get SR service
+        // Get SR service and the handled mcast groups
         SegmentRoutingService srService = get(SegmentRoutingService.class);
-        // Get the mapping
-        Map<McastStoreKey, McastRole> keyToRole = srService.getMcastRoles(mcastGroup);
-        // Reduce to the set of mcast groups
-        Set<IpAddress> mcastGroups = keyToRole.keySet().stream()
-                .map(McastStoreKey::mcastIp)
-                .collect(Collectors.toSet());
-        // Print the trees for each group
+        Set<IpAddress> mcastGroups = ImmutableSet.copyOf(srService.getMcastLeaders(null)
+                                                                         .keySet());
+
+        if (!isNullOrEmpty(gAddr)) {
+            mcastGroups = mcastGroups.stream()
+                    .filter(mcastIp -> mcastIp.equals(IpAddress.valueOf(gAddr)))
+                    .collect(Collectors.toSet());
+        }
+
+        ObjectMapper mapper = new ObjectMapper();
+        ObjectNode root = mapper.createObjectNode();
+
+        // Print the trees for each group or build json objects
         mcastGroups.forEach(group -> {
-            // Create a new map for the group
-            Multimap<McastRole, DeviceId> roleDeviceIdMap = ArrayListMultimap.create();
-            keyToRole.entrySet()
-                    .stream()
-                    // Filter only the elements related to this group
-                    .filter(entry -> entry.getKey().mcastIp().equals(group))
-                    // For each create a new entry in the group related map
-                    .forEach(entry -> roleDeviceIdMap.put(entry.getValue(), entry.getKey().deviceId()));
-            // Print the map
-            printMcastRole(group,
-                           roleDeviceIdMap.get(INGRESS),
-                           roleDeviceIdMap.get(TRANSIT),
-                           roleDeviceIdMap.get(EGRESS)
-            );
-            // Get sinks paths
-            Map<ConnectPoint, List<ConnectPoint>> mcastPaths = srService.getMcastPaths(group);
-            // Print the paths
-            mcastPaths.forEach(this::printMcastSink);
+            // We want to use source cp only for a specific group
+            ConnectPoint sourcecp = null;
+            if (!isNullOrEmpty(source) &&
+                    !isNullOrEmpty(gAddr)) {
+                sourcecp = ConnectPoint.deviceConnectPoint(source);
+            }
+            Multimap<ConnectPoint, List<ConnectPoint>> mcastTree = srService.getMcastTrees(group,
+                                                                                           sourcecp);
+            // Build a json object for each group
+            if (outputJson()) {
+                root.putPOJO(group.toString(), json(mcastTree));
+            } else {
+                // Banner and then the trees
+                printMcastGroup(group);
+                mcastTree.forEach(this::printMcastSink);
+            }
         });
+
+        // Print the json object at the end
+        if (outputJson()) {
+            print("%s", root);
+        }
+
     }
 
-    private void printMcastRole(IpAddress mcastGroup,
-                                Collection<DeviceId> ingress,
-                                Collection<DeviceId> transit,
-                                Collection<DeviceId> egress) {
-        print(G_FORMAT_MAPPING, mcastGroup, ingress, transit, egress);
+    private void printMcastGroup(IpAddress mcastGroup) {
+        print(G_FORMAT_MAPPING, mcastGroup);
     }
 
     private void printMcastSink(ConnectPoint sink, List<ConnectPoint> path) {
         print(S_FORMAT_MAPPING, sink, path);
     }
-}
+
+    private ObjectNode json(Multimap<ConnectPoint, List<ConnectPoint>> mcastTree) {
+        ObjectMapper mapper = new ObjectMapper();
+        ObjectNode jsonSinks = mapper.createObjectNode();
+        mcastTree.asMap().forEach((sink, paths) -> {
+            ArrayNode jsonPaths = mapper.createArrayNode();
+            paths.forEach(path -> {
+                ArrayNode jsonPath = mapper.createArrayNode();
+                path.forEach(connectPoint -> jsonPath.add(connectPoint.toString()));
+                jsonPaths.addPOJO(jsonPath);
+            });
+            jsonSinks.putPOJO(sink.toString(), jsonPaths);
+        });
+        return jsonSinks;
+    }
+
+}
\ No newline at end of file