Added ability to configure or programmatically inject default maximum number of paths when computing topology using default methods.

Change-Id: Ic0c17f2e40c7334b325c0dd799f781ec65c889d6
diff --git a/core/api/src/main/java/org/onosproject/net/topology/PathAdminService.java b/core/api/src/main/java/org/onosproject/net/topology/PathAdminService.java
index fb67c91..959b5ef 100644
--- a/core/api/src/main/java/org/onosproject/net/topology/PathAdminService.java
+++ b/core/api/src/main/java/org/onosproject/net/topology/PathAdminService.java
@@ -41,4 +41,13 @@
      */
     void setDefaultGraphPathSearch(GraphPathSearch<TopologyVertex, TopologyEdge> graphPathSearch);
 
+    /**
+     * Sets the default maximum path count to be used when computing paths. If
+     * -1 is specified, the builtin default <code>ALL_PATHS</code>, signifying
+     * that all available paths should be returned is used.
+     *
+     * @param maxPaths new default max path count
+     */
+    default void setDefaultMaxPaths(int maxPaths) {};
+
 }
diff --git a/core/common/src/main/java/org/onosproject/common/DefaultTopology.java b/core/common/src/main/java/org/onosproject/common/DefaultTopology.java
index ecbb573..feccf56 100644
--- a/core/common/src/main/java/org/onosproject/common/DefaultTopology.java
+++ b/core/common/src/main/java/org/onosproject/common/DefaultTopology.java
@@ -94,6 +94,7 @@
             new LazyKShortestPathsSearch<>();
 
 
+    private static int defaultMaxPaths = ALL_PATHS;
     private static LinkWeigher defaultLinkWeigher = null;
     private static GraphPathSearch<TopologyVertex, TopologyEdge> defaultGraphPathSearch = null;
 
@@ -112,6 +113,18 @@
     private final Supplier<ClusterIndexes> clusterIndexes;
 
     /**
+     * Sets the default maximum path count to be used when computing paths. If
+     * -1 is specified, the builtin default <code>ALL_PATHS</code>, signifying
+     * that all available paths should be returned is used.
+     *
+     * @param maxPaths new default max path count
+     */
+    public static synchronized void setDefaultMaxPaths(int maxPaths) {
+        log.info("Setting new default maximum paths count to {}", maxPaths);
+        defaultMaxPaths = maxPaths;
+    }
+
+    /**
      * Sets the default link-weight to be used when computing paths. If null is
      * specified, the builtin default link-weight measuring hop-counts will be
      * used.
@@ -152,7 +165,7 @@
 
         // Build the graph
         this.graph = new DefaultTopologyGraph(description.vertexes(),
-                description.edges());
+                                              description.edges());
 
         this.clusterResults = Suppliers.memoize(this::searchForClusters);
         this.clusters = Suppliers.memoize(this::buildTopologyClusters);
@@ -304,7 +317,7 @@
         // Find the cluster to which the device belongs.
         TopologyCluster cluster = clustersByDevice().get(connectPoint.deviceId());
         checkArgument(cluster != null,
-                "No cluster found for device %s", connectPoint.deviceId());
+                      "No cluster found for device %s", connectPoint.deviceId());
 
         // If the broadcast set is null or empty, or if the point explicitly
         // belongs to it, return true.
@@ -341,7 +354,7 @@
      * @return set of shortest paths
      */
     public Set<Path> getPaths(DeviceId src, DeviceId dst) {
-        return getPaths(src, dst, linkWeight(), ALL_PATHS);
+        return getPaths(src, dst, linkWeight(), defaultMaxPaths);
     }
 
     /**
@@ -354,7 +367,7 @@
      * @return set of shortest paths
      */
     public Set<Path> getPaths(DeviceId src, DeviceId dst, LinkWeigher weigher) {
-        return getPaths(src, dst, weigher, ALL_PATHS);
+        return getPaths(src, dst, weigher, defaultMaxPaths);
     }
 
     /**
@@ -368,9 +381,9 @@
      * which paths will be returned depends on the currently specified
      * {@code GraphPathSearch}. See {@link #setDefaultGraphPathSearch}.
      *
-     * @param src    source device
-     * @param dst    destination device
-     * @param weigher link weight function
+     * @param src      source device
+     * @param dst      destination device
+     * @param weigher  link weight function
      * @param maxPaths maximum number of paths
      * @return set of shortest paths
      */
@@ -397,8 +410,8 @@
      * Computes on-demand the k-shortest paths between source and
      * destination devices.
      *
-     * @param src    source device
-     * @param dst    destination device
+     * @param src      source device
+     * @param dst      destination device
      * @param maxPaths maximum number of paths (k)
      * @return set of k-shortest paths
      */
@@ -411,13 +424,13 @@
     /**
      * Computes on-demand the k-shortest paths between source and
      * destination devices.
-     *
+     * <p>
      * The first {@code maxPaths} paths will be returned
      * in ascending order according to the provided {@code weigher}
      *
-     * @param src    source device
-     * @param dst    destination device
-     * @param weigher link weight function
+     * @param src      source device
+     * @param dst      destination device
+     * @param weigher  link weight function
      * @param maxPaths maximum number of paths (k)
      * @return set of k-shortest paths
      */
@@ -434,17 +447,16 @@
 
         return KSHORTEST.search(graph, srcV, dstV, weigher, maxPaths)
                 .paths().stream()
-                    .map(this::networkPath)
-                    .collect(ImmutableSet.toImmutableSet());
+                .map(this::networkPath)
+                .collect(ImmutableSet.toImmutableSet());
     }
 
     /**
      * Lazily computes on-demand the k-shortest paths between source and
      * destination devices.
      *
-     *
-     * @param src    source device
-     * @param dst    destination device
+     * @param src source device
+     * @param dst destination device
      * @return stream of k-shortest paths
      */
     public Stream<Path> getKShortestPaths(DeviceId src, DeviceId dst) {
@@ -455,9 +467,8 @@
      * Lazily computes on-demand the k-shortest paths between source and
      * destination devices.
      *
-     *
-     * @param src    source device
-     * @param dst    destination device
+     * @param src     source device
+     * @param dst     destination device
      * @param weigher link weight function
      * @return stream of k-shortest paths
      */
@@ -472,7 +483,7 @@
         }
 
         return LAZY_KSHORTEST.lazyPathSearch(graph, srcV, dstV, weigher)
-                    .map(this::networkPath);
+                .map(this::networkPath);
     }
 
     /**
@@ -507,7 +518,7 @@
         }
 
         GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
-                SUURBALLE.search(graph, srcV, dstV, weigher, ALL_PATHS);
+                SUURBALLE.search(graph, srcV, dstV, weigher, defaultMaxPaths);
         ImmutableSet.Builder<DisjointPath> builder = ImmutableSet.builder();
         for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
             DisjointPath disjointPath =
@@ -544,7 +555,7 @@
         SrlgGraphSearch<TopologyVertex, TopologyEdge> srlg =
                 new SrlgGraphSearch<>(riskProfile);
         GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
-                srlg.search(graph, srcV, dstV, weigher, ALL_PATHS);
+                srlg.search(graph, srcV, dstV, weigher, defaultMaxPaths);
         ImmutableSet.Builder<DisjointPath> builder = ImmutableSet.builder();
         for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
             DisjointPath disjointPath =
@@ -619,12 +630,12 @@
         if (!path.hasBackup()) {
             // There was no secondary path available.
             return new DefaultDisjointPath(CORE_PROVIDER_ID,
-                    (DefaultPath) networkPath(path.primary()),
-                    null);
+                                           (DefaultPath) networkPath(path.primary()),
+                                           null);
         }
         return new DefaultDisjointPath(CORE_PROVIDER_ID,
-                (DefaultPath) networkPath(path.primary()),
-                (DefaultPath) networkPath(path.secondary()));
+                                       (DefaultPath) networkPath(path.primary()),
+                                       (DefaultPath) networkPath(path.secondary()));
     }
 
     // Searches for SCC clusters in the network topology graph using Tarjan
@@ -651,9 +662,9 @@
 
             ClusterId cid = ClusterId.clusterId(i);
             DefaultTopologyCluster cluster = new DefaultTopologyCluster(cid,
-                    vertexSet.size(),
-                    edgeSet.size(),
-                    findRoot(vertexSet));
+                                                                        vertexSet.size(),
+                                                                        edgeSet.size(),
+                                                                        findRoot(vertexSet));
             clusterBuilder.put(cid, cluster);
         }
         return clusterBuilder.build();
@@ -756,8 +767,8 @@
 
         // Finalize all indexes.
         return new ClusterIndexes(clusterBuilder.build(),
-                devicesBuilder.build(),
-                linksBuilder.build());
+                                  devicesBuilder.build(),
+                                  linksBuilder.build());
     }
 
     private GraphPathSearch<TopologyVertex, TopologyEdge> graphPathSearch() {
diff --git a/core/store/dist/src/main/java/org/onosproject/store/OsgiPropertyConstants.java b/core/store/dist/src/main/java/org/onosproject/store/OsgiPropertyConstants.java
index 9266bf6..a26061d 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/OsgiPropertyConstants.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/OsgiPropertyConstants.java
@@ -64,4 +64,7 @@
 
     public static final String LINK_WEIGHT_FUNCTION = "linkWeightFunction";
     public static final String LINK_WEIGHT_FUNCTION_DEFAULT = "hopCount";
+
+    public static final String MAX_PATHS = "maxPaths";
+    public static final int MAX_PATHS_DEFAULT = -1;
 }
diff --git a/core/store/dist/src/main/java/org/onosproject/store/topology/impl/DistributedTopologyStore.java b/core/store/dist/src/main/java/org/onosproject/store/topology/impl/DistributedTopologyStore.java
index 0ea6845..3e10016 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/topology/impl/DistributedTopologyStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/topology/impl/DistributedTopologyStore.java
@@ -69,11 +69,11 @@
 import java.util.stream.Stream;
 
 import static com.google.common.base.Preconditions.checkArgument;
+import static org.onlab.graph.GraphPathSearch.ALL_PATHS;
 import static org.onlab.util.Tools.get;
 import static org.onlab.util.Tools.isNullOrEmpty;
 import static org.onosproject.net.topology.TopologyEvent.Type.TOPOLOGY_CHANGED;
-import static org.onosproject.store.OsgiPropertyConstants.LINK_WEIGHT_FUNCTION;
-import static org.onosproject.store.OsgiPropertyConstants.LINK_WEIGHT_FUNCTION_DEFAULT;
+import static org.onosproject.store.OsgiPropertyConstants.*;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
@@ -89,7 +89,8 @@
                 TopologyStore.class, PathAdminService.class
         },
         property = {
-                LINK_WEIGHT_FUNCTION + "=" + LINK_WEIGHT_FUNCTION_DEFAULT
+                LINK_WEIGHT_FUNCTION + "=" + LINK_WEIGHT_FUNCTION_DEFAULT,
+                MAX_PATHS + "=" + MAX_PATHS_DEFAULT,
         }
 )
 public class DistributedTopologyStore
@@ -128,6 +129,9 @@
     /** Default link-weight function: hopCount, linkMetric, geoDistance. */
     private String linkWeightFunction = LINK_WEIGHT_FUNCTION_DEFAULT;
 
+    /** Default max-paths count. */
+    private int maxPaths = ALL_PATHS;
+
     // Cluster root to broadcast points bindings to allow convergence to
     // a shared broadcast tree; node that is the master of the cluster root
     // is the primary.
@@ -174,6 +178,15 @@
                             new GeoDistanceLinkWeight(deviceService) : null;
             setDefaultLinkWeigher(weight);
         }
+
+        String newMaxPaths = get(properties, MAX_PATHS);
+        if (newMaxPaths != null) {
+            try {
+                setDefaultMaxPaths(Integer.parseInt(newMaxPaths));
+            } catch (NumberFormatException e) {
+                log.warn("maxPaths must be a number; not {}", newMaxPaths);
+            }
+        }
         log.info(FORMAT, linkWeightFunction);
     }
 
@@ -338,6 +351,11 @@
     }
 
     @Override
+    public void setDefaultMaxPaths(int maxPaths) {
+        this.maxPaths = maxPaths;
+        DefaultTopology.setDefaultMaxPaths(maxPaths);
+    }
+    @Override
     public void setDefaultLinkWeigher(LinkWeigher linkWeigher) {
         DefaultTopology.setDefaultLinkWeigher(linkWeigher);
     }