ONOS-6730: Topo View i18n:
- augmented UiMessageHandler base class to allow injection of
  localization bundles, so that the handler can look up localized
  text when composing data to ship to the client.
- i18n'd the Summary Panel in Topo view.

Change-Id: I15010d1e2fcce72e3133a9ce40e51510c8f5146f
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java b/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java
index 0d7ff82..3cbce06 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java
@@ -82,7 +82,9 @@
 import static org.onosproject.cluster.ClusterEvent.Type.INSTANCE_ADDED;
 import static org.onosproject.net.DeviceId.deviceId;
 import static org.onosproject.net.HostId.hostId;
-import static org.onosproject.net.device.DeviceEvent.Type.*;
+import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
+import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_UPDATED;
+import static org.onosproject.net.device.DeviceEvent.Type.PORT_STATS_UPDATED;
 import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED;
 import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED;
 import static org.onosproject.ui.JsonUtils.envelope;
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java b/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java
index 2437132..c2e290d 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java
@@ -18,6 +18,7 @@
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.ImmutableSet;
 import org.onlab.osgi.ServiceDirectory;
 import org.onlab.packet.IpAddress;
 import org.onlab.util.DefaultHashMap;
@@ -50,6 +51,7 @@
 import org.onosproject.ui.UiConnection;
 import org.onosproject.ui.UiMessageHandler;
 import org.onosproject.ui.impl.topo.util.ServicesBundle;
+import org.onosproject.ui.lion.LionBundle;
 import org.onosproject.ui.topo.PropertyPanel;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -66,6 +68,14 @@
 import static org.onosproject.net.PortNumber.portNumber;
 import static org.onosproject.ui.topo.TopoConstants.CoreButtons;
 import static org.onosproject.ui.topo.TopoConstants.Properties;
+import static org.onosproject.ui.topo.TopoConstants.Properties.DEVICES;
+import static org.onosproject.ui.topo.TopoConstants.Properties.FLOWS;
+import static org.onosproject.ui.topo.TopoConstants.Properties.HOSTS;
+import static org.onosproject.ui.topo.TopoConstants.Properties.INTENTS;
+import static org.onosproject.ui.topo.TopoConstants.Properties.LINKS;
+import static org.onosproject.ui.topo.TopoConstants.Properties.TOPOLOGY_SSCS;
+import static org.onosproject.ui.topo.TopoConstants.Properties.TUNNELS;
+import static org.onosproject.ui.topo.TopoConstants.Properties.VERSION;
 import static org.onosproject.ui.topo.TopoUtils.compactLinkString;
 
 /**
@@ -125,6 +135,11 @@
         return Collections.unmodifiableMap(metaUi);
     }
 
+    private static final String LION_TOPO = "core.view.Topo";
+
+    private static final Set<String> REQ_LION_BUNDLES = ImmutableSet.of(
+            LION_TOPO
+    );
 
     protected ServicesBundle services;
 
@@ -144,6 +159,11 @@
         version = ver.replace(".SNAPSHOT", "*").replaceFirst("~.*$", "");
     }
 
+    @Override
+    public Set<String> requiredLionBundles() {
+        return REQ_LION_BUNDLES;
+    }
+
     // Returns the first of the given set of IP addresses as a string.
     private String ip(Set<IpAddress> ipAddresses) {
         Iterator<IpAddress> it = ipAddresses.iterator();
@@ -351,18 +371,20 @@
     // Returns property panel model for summary response.
     protected PropertyPanel summmaryMessage() {
         Topology topology = services.topology().currentTopology();
+        LionBundle lion = getLionBundle(LION_TOPO);
+        String panelTitle = lion.getSafe("title_panel_summary");
 
-        return new PropertyPanel("ONOS Summary", "node")
-                .addProp(Properties.VERSION, version)
+        return new PropertyPanel(panelTitle, "node")
+                .addProp(VERSION, lion.getSafe(VERSION), version)
                 .addSeparator()
-                .addProp(Properties.DEVICES, services.device().getDeviceCount())
-                .addProp(Properties.LINKS, topology.linkCount())
-                .addProp(Properties.HOSTS, services.host().getHostCount())
-                .addProp(Properties.TOPOLOGY_SSCS, topology.clusterCount())
+                .addProp(DEVICES, lion.getSafe(DEVICES), services.device().getDeviceCount())
+                .addProp(LINKS, lion.getSafe(LINKS), topology.linkCount())
+                .addProp(HOSTS, lion.getSafe(HOSTS), services.host().getHostCount())
+                .addProp(TOPOLOGY_SSCS, lion.getSafe(TOPOLOGY_SSCS), topology.clusterCount())
                 .addSeparator()
-                .addProp(Properties.INTENTS, services.intent().getIntentCount())
-                .addProp(Properties.TUNNELS, services.tunnel().tunnelCount())
-                .addProp(Properties.FLOWS, services.flow().getFlowRuleCount());
+                .addProp(INTENTS, lion.getSafe(INTENTS), services.intent().getIntentCount())
+                .addProp(TUNNELS, lion.getSafe(TUNNELS), services.tunnel().tunnelCount())
+                .addProp(FLOWS, lion.getSafe(FLOWS), services.flow().getFlowRuleCount());
     }
 
     // Returns property panel model for device details response.
@@ -394,8 +416,8 @@
                 .addSeparator()
 
                 .addProp(Properties.PORTS, portCount)
-                .addProp(Properties.FLOWS, flowCount)
-                .addProp(Properties.TUNNELS, tunnelCount)
+                .addProp(FLOWS, flowCount)
+                .addProp(TUNNELS, tunnelCount)
 
                 .addButton(CoreButtons.SHOW_DEVICE_VIEW)
                 .addButton(CoreButtons.SHOW_FLOW_VIEW)
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java b/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java
index 55f3183..07a0b0d 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java
@@ -40,6 +40,7 @@
 import org.onosproject.ui.impl.topo.Topo2ViewMessageHandler;
 import org.onosproject.ui.impl.topo.UiTopoSession;
 import org.onosproject.ui.impl.topo.model.UiSharedTopologyModel;
+import org.onosproject.ui.lion.LionBundle;
 import org.onosproject.ui.model.topo.UiTopoLayout;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -97,6 +98,8 @@
     private TopoOverlayCache overlayCache;
     private Topo2OverlayCache overlay2Cache;
 
+    private Map<String, LionBundle> lionBundleMap;
+
     private UiSessionToken sessionToken;
 
 
@@ -289,14 +292,16 @@
         overlay2Cache = new Topo2OverlayCache();
 
         Map<Class<?>, UiMessageHandler> handlerInstances = new HashMap<>();
-
         UiExtensionService service = directory.get(UiExtensionService.class);
+        lionBundleMap = generateLionMap(service);
+
         service.getExtensions().forEach(ext -> {
             UiMessageHandlerFactory factory = ext.messageHandlerFactory();
             if (factory != null) {
                 factory.newHandlers().forEach(handler -> {
                     try {
                         handler.init(this, directory);
+                        injectLionBundles(handler, lionBundleMap);
                         handler.messageTypes().forEach(type -> handlers.put(type, handler));
                         handlerInstances.put(handler.getClass(), handler);
 
@@ -305,13 +310,34 @@
                     }
                 });
             }
-
             registerOverlays(ext);
         });
 
         handlerCrossConnects(handlerInstances);
 
-        log.debug("#handlers = {}, #overlays = {}", handlers.size(), overlayCache.size());
+        log.debug("#handlers = {}, #overlays = {}",
+                  handlers.size(), overlayCache.size());
+    }
+
+    private Map<String, LionBundle> generateLionMap(UiExtensionService service) {
+        Map<String, LionBundle> bundles = new HashMap<>();
+        service.getExtensions().forEach(ext -> {
+            ext.lionBundles().forEach(lb -> bundles.put(lb.id(), lb));
+        });
+        return bundles;
+    }
+
+    private void injectLionBundles(UiMessageHandler handler,
+                                   Map<String, LionBundle> lionBundleMap) {
+        handler.requiredLionBundles().forEach(lbid -> {
+            LionBundle lb = lionBundleMap.get(lbid);
+            if (lb != null) {
+                handler.cacheLionBundle(lb);
+            } else {
+                log.warn("handler {}: Lion bundle {} non existent!",
+                         handler.getClass().getName(), lbid);
+            }
+        });
     }
 
     private void authenticate(String type, ObjectNode message) {
@@ -424,9 +450,7 @@
         service.getExtensions().forEach(ext -> {
             ext.lionBundles().forEach(lb -> {
                 ObjectNode lionMap = objectNode();
-                lb.getItems().forEach(item -> {
-                    lionMap.put(item.key(), item.value());
-                });
+                lb.getItems().forEach(item -> lionMap.put(item.key(), item.value()));
                 lion.set(lb.id(), lionMap);
             });
         });