Lion Utilities:
- set local from user.* properties
- but allow override with ONOS_LOCALE env var

Change-Id: I5e455f3dc00abb0f4229e9afc50871f543ffaad4
diff --git a/core/api/src/main/java/org/onosproject/ui/lion/LionUtils.java b/core/api/src/main/java/org/onosproject/ui/lion/LionUtils.java
index d720888..6d9b24a 100644
--- a/core/api/src/main/java/org/onosproject/ui/lion/LionUtils.java
+++ b/core/api/src/main/java/org/onosproject/ui/lion/LionUtils.java
@@ -17,20 +17,105 @@
 
 package org.onosproject.ui.lion;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Locale;
 import java.util.ResourceBundle;
+import java.util.Set;
 
 /**
  * Utility methods for dealing with Localization Bundles etc.
  */
 public final class LionUtils {
 
+    private static final Logger log = LoggerFactory.getLogger(LionUtils.class);
+
+    private static final String USER_LANGUAGE = "user.language";
+    private static final String USER_COUNTRY = "user.country";
+    private static final String ONOS_LOCALE = "ONOS_LOCALE";
+    private static final String EMPTY = "";
     private static final String DOT = ".";
+    private static final String LOBAR = "_";
 
     // no instantiation
     private LionUtils() {
     }
 
     /**
+     * Parses the given string into language and country codes, and returns
+     * a {@link Locale} instance initialized with those parameters.
+     * For example:
+     * <pre>
+     *     Locale locale = LionUtils.localeFromString("en_GB");
+     *     locale.getLanguage();   // "en"
+     *     locale.getCountry();    // "GB"
+     *
+     *     locale = LionUtils.localeFromString("ru");
+     *     locale.getLanguage();   // "ru"
+     *     locale.getCountry();    // ""
+     * </pre>
+     *
+     * @param s the locale string
+     * @return a locale instance
+     */
+    public static Locale localeFromString(String s) {
+
+        if (!s.contains(LOBAR)) {
+            return new Locale(s);
+        }
+        String[] items = s.split(LOBAR);
+        return new Locale(items[0], items[1]);
+    }
+
+    /**
+     * Sets the default locale, based on the Java properties shown below.
+     * <pre>
+     *   user.language
+     *   user.country
+     * </pre>
+     * It is expected that the host system will have set these properties
+     * appropriately. Note, however, that the default values can be
+     * overridden by use of the environment variable {@code ONOS_LOCALE}.
+     * <p>
+     * For example, to set the Locale to French-Canadian one can invoke
+     * (from the shell)...
+     * <pre>
+     * $ ONOS_LOCALE=fr_CA {command-to-invoke-onos} ...
+     * </pre>
+     *
+     * @return the runtime locale
+     */
+    public static Locale setupRuntimeLocale() {
+        Locale systemDefault = Locale.getDefault();
+        log.info("System Default Locale: [{}]", systemDefault);
+        // TODO: Review- do we need to store the system default anywhere?
+
+        // Useful to log the "user.*" properties for debugging...
+        Set<String> pn = System.getProperties().stringPropertyNames();
+        pn.removeIf(f -> !(f.startsWith("user.")));
+        for (String ukey : pn) {
+            log.debug("  {}: {}", ukey, System.getProperty(ukey));
+        }
+
+        String language = System.getProperty(USER_LANGUAGE);
+        String country = System.getProperty(USER_COUNTRY);
+        log.info("Language: [{}], Country: [{}]", language, country);
+        Locale runtime = new Locale(language != null ? language : EMPTY,
+                                    country != null ? country : EMPTY);
+
+        String override = System.getenv(ONOS_LOCALE);
+        if (override != null) {
+            log.warn("Override with ONOS_LOCALE: [{}]", override);
+            runtime = localeFromString(override);
+        }
+
+        log.info("Setting runtime locale to: [{}]", runtime);
+        Locale.setDefault(runtime);
+        return runtime;
+    }
+
+    /**
      * This method takes a fully qualified name and returns a
      * {@link ResourceBundle} which is loaded from a properties file with
      * that base name.
diff --git a/core/api/src/test/java/org/onosproject/ui/lion/LionUtilsTest.java b/core/api/src/test/java/org/onosproject/ui/lion/LionUtilsTest.java
index 8469f24..ad693cd 100644
--- a/core/api/src/test/java/org/onosproject/ui/lion/LionUtilsTest.java
+++ b/core/api/src/test/java/org/onosproject/ui/lion/LionUtilsTest.java
@@ -38,6 +38,7 @@
     private static Locale systemLocale;
 
     private ResourceBundle res;
+    private Locale locale;
 
     @BeforeClass
     public static void classSetup() {
@@ -134,6 +135,68 @@
     }
 
     @Test
+    public void runtimeLocale() {
+        title("runtimeLocale");
+        Locale runtime = LionUtils.setupRuntimeLocale();
+        print("locale is [%s]", runtime);
+
+        // NOTE:
+        //   Yeah, I know, "a unit test without asserts is not a unit test".
+        //
+        //   But it would NOT be a good idea to assert the locale results in
+        //   this method, because that is dependent on environment variables.
+        //
+        //   This method is here to allow manual verification of the Locale
+        //   e.g. when running tests from IntelliJ, and setting the
+        //   env-vars via the "Edit Configurations..." dialog.
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void localeFromStringNull() {
+        LionUtils.localeFromString(null);
+    }
+
+    private void checkLanguageCountry(Locale locale, String expL, String expC) {
+        assertEquals("Wrong language: " + expL, expL, locale.getLanguage());
+        assertEquals("Wrong country: " + expC, expC, locale.getCountry());
+    }
+
+    @Test
+    public void localeFromStringEmpty() {
+        title("localeFromStringEmpty");
+        locale = LionUtils.localeFromString("");
+        checkLanguageCountry(locale, "", "");
+    }
+
+    @Test
+    public void localeFromStringRu() {
+        title("localeFromStringRu");
+        locale = LionUtils.localeFromString("ru");
+        checkLanguageCountry(locale, "ru", "");
+    }
+
+    @Test
+    public void localeFromStringEnGB() {
+        title("localeFromStringEnGB");
+        locale = LionUtils.localeFromString("en_GB");
+        checkLanguageCountry(locale, "en", "GB");
+    }
+
+    @Test
+    public void localeFromStringItIT() {
+        title("localeFromStringItIT");
+        locale = LionUtils.localeFromString("it_IT");
+        checkLanguageCountry(locale, "it", "IT");
+    }
+
+    @Test
+    public void localeFromStringFrCA() {
+        title("localeFromStringFrCA");
+        locale = LionUtils.localeFromString("fr_CA");
+        checkLanguageCountry(locale, "fr", "CA");
+    }
+
+    @Test
     @Ignore("Jenkins not chinese friendly, yet...")
     public void messagesInZhTw() {
         title("messagesInZhTW");
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java b/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java
index 9a016cf..32d1427 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java
@@ -61,6 +61,7 @@
 import org.onosproject.ui.impl.topo.Topo2TrafficMessageHandler;
 import org.onosproject.ui.impl.topo.Topo2ViewMessageHandler;
 import org.onosproject.ui.impl.topo.Traffic2Overlay;
+import org.onosproject.ui.lion.LionUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -246,6 +247,8 @@
         tokens = tokensConsistentMap.asJavaMap();
 
         register(core);
+        LionUtils.setupRuntimeLocale();
+
         log.info("Started");
     }