Enhance the RouteEvent to notify listeners of alternative viable routes.

Traditionally the route event only notified listeners of the best selected
route for a given prefix, but some listeners are interested in all resolved
routes for the prefix.

CORD-905

Change-Id: Ia3e1e3a8e3e825ba894e6835e0860c3ed698d29b
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/routing/impl/RouteManager.java b/incubator/net/src/main/java/org/onosproject/incubator/net/routing/impl/RouteManager.java
index 5b637b8..539b2cb 100644
--- a/incubator/net/src/main/java/org/onosproject/incubator/net/routing/impl/RouteManager.java
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/routing/impl/RouteManager.java
@@ -23,7 +23,7 @@
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
 import org.onlab.packet.IpAddress;
-import org.onosproject.event.ListenerService;
+import org.onlab.packet.IpPrefix;
 import org.onosproject.incubator.net.routing.InternalRouteEvent;
 import org.onosproject.incubator.net.routing.NextHop;
 import org.onosproject.incubator.net.routing.ResolvedRoute;
@@ -68,8 +68,7 @@
  */
 @Service
 @Component
-public class RouteManager implements ListenerService<RouteEvent, RouteListener>,
-        RouteService, RouteAdminService {
+public class RouteManager implements RouteService, RouteAdminService {
 
     private final Logger log = LoggerFactory.getLogger(getClass());
 
@@ -129,7 +128,8 @@
             resolvedRouteStore.getRouteTables().stream()
                     .map(resolvedRouteStore::getRoutes)
                     .flatMap(Collection::stream)
-                    .map(route -> new RouteEvent(RouteEvent.Type.ROUTE_ADDED, route))
+                    .map(route -> new RouteEvent(RouteEvent.Type.ROUTE_ADDED, route,
+                            resolvedRouteStore.getAllRoutes(route.prefix())))
                     .forEach(l::post);
 
             listeners.put(listener, l);
@@ -259,25 +259,31 @@
     }
 
     private ResolvedRoute decide(ResolvedRoute route1, ResolvedRoute route2) {
-        return Comparator.<ResolvedRoute, IpAddress>comparing(route -> route.nextHop())
+        return Comparator.comparing(ResolvedRoute::nextHop)
                        .compare(route1, route2) <= 0 ? route1 : route2;
     }
 
-    private void store(ResolvedRoute route) {
-        post(resolvedRouteStore.updateRoute(route));
+    private void store(ResolvedRoute route, Set<ResolvedRoute> alternatives) {
+        post(resolvedRouteStore.updateRoute(route, alternatives));
+    }
+
+    private void remove(IpPrefix prefix) {
+        post(resolvedRouteStore.removeRoute(prefix));
     }
 
     private void resolve(RouteSet routes) {
-        Optional<ResolvedRoute> resolvedRoute =
-        routes.routes().stream()
-                    .map(this::resolve)
-                    .filter(Objects::nonNull)
+        Set<ResolvedRoute> resolvedRoutes = routes.routes().stream()
+                .map(this::resolve)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toSet());
+
+        Optional<ResolvedRoute> bestRoute = resolvedRoutes.stream()
                     .reduce(this::decide);
 
-        if (resolvedRoute.isPresent()) {
-            this.store(resolvedRoute.get());
+        if (bestRoute.isPresent()) {
+            store(bestRoute.get(), resolvedRoutes);
         } else {
-            post(resolvedRouteStore.removeRoute(routes.prefix()));
+            remove(routes.prefix());
         }
     }