diff --git a/build.gradle b/build.gradle index 8ea3b30d5f8..ac6aa86b493 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,6 @@ plugins { id 'build-announcements' id 'com.github.kt3k.coveralls' version '2.8.2' id 'com.moowork.node' version '1.2.0' - id 'me.champeau.buildscan-recipes' version '0.2.0' id 'net.researchgate.release' version '2.6.0' // Records all tasks in task graph, generates `build/reports/visteg.dot` // dot file can be converted to an image using graphviz. `dot -Tsvg -O -v visteg.dot` @@ -12,7 +11,7 @@ plugins { // Sub project plugins id 'com.github.sherter.google-java-format' version '0.6' apply false - id 'nebula.lint' version '8.3.1' apply false + id 'nebula.lint' version '8.3.2' apply false //id 'net.ltgt.errorprone' version '0.0.13' apply false } @@ -35,9 +34,6 @@ buildScan { licenseAgreementUrl = 'https://gradle.com/terms-of-service' licenseAgree = 'yes' } -buildScanRecipes { - recipes 'travis-ci', 'git-commit' -} allprojects { apply plugin: 'java' @@ -60,11 +56,11 @@ allprojects { } dependencies { - //errorprone 'com.google.errorprone:error_prone_core:2.1.2' + //errorprone 'com.google.errorprone:error_prone_core:2.2.0' } codenarc { - toolVersion = '1.0' + toolVersion = '1.1' reportFormat = 'console' } @@ -108,8 +104,6 @@ subprojects { apply plugin: 'maven-publish' apply plugin: 'maven' apply plugin: 'signing' - apply plugin: 'maven-publish' - /*======== Dependency Management ========**/ repositories { diff --git a/docs/implement/README.md b/docs/implement/README.md index cb4845f5bb7..ca652281ec6 100644 --- a/docs/implement/README.md +++ b/docs/implement/README.md @@ -11,3 +11,4 @@ users, groups, layouts, *etc.* 5. Content (TBD) 2. [Frontend](frontend/README.md) 3. [Security](security.md) +4. [Internationalization](i18n.md) diff --git a/docs/implement/i18n.md b/docs/implement/i18n.md new file mode 100644 index 00000000000..c1fe1d936fb --- /dev/null +++ b/docs/implement/i18n.md @@ -0,0 +1,31 @@ +# Internationalization + +uPortal provides internationalization features. There are three aspects to implementing support for +another language in the portal: the uPortal (Spring) _MessageSource_, _uPortal Data_, and _Content +Modules_. + +## uPortal MessageSource + +uPortal provides support for internationalizing UI strings through a Spring `MessageSource`. +uPortal comes with several languages available, but you can add your own (or update an existing +one) by adding a `Messages_{code}.properties` file in the classpath at `/properties/i18n/` where +{code} is the two-character country code (e.g. 'fr' for French and 'de' for German). + +Use the `org.apereo.portal.i18n.LocaleManager.portal_locales` property to define the languages +available in the portal. Add this property to either `uPortal.properties` or `global.properties`. + +### Portal Locales Example + +```properties +org.apereo.portal.i18n.LocaleManager.portal_locales=fr_FR +``` + +This value will limit the portal to _French_. + +## uPortal Data + +_TBD._ + +## Content Modules + +_TBD._ diff --git a/gradle.properties b/gradle.properties index 79af101e24e..85430824166 100644 --- a/gradle.properties +++ b/gradle.properties @@ -39,8 +39,8 @@ portletApiDependency=org.apache.portals:portlet-api_2.1.0_spec:1.0 # Dependency Versions activationVersion=1.0.2 -antVersion=1.10.1 -awsVersion=1.11.255 +antVersion=1.10.2 +awsVersion=1.11.285 apereoPortletUtilsVersion=1.1.2 aspectjVersion=1.8.13 casClientVersion=3.4.1 @@ -72,7 +72,7 @@ hibernateJpamodelgenVersion=1.2.0.Final hsqldbVersion=2.4.0 httpclientVersion=4.5.4 httpcomponentsVersion=4.4.4 -jacksonVersion=2.9.3 +jacksonVersion=2.9.4 jansiVersion=1.11 javaxMailVersion=1.4.7 javaxmlVersion=1.3.1 @@ -89,10 +89,10 @@ jspApiVersion=2.2 junitVersion=4.12 lesscssVersion=1.7.0.1.1 logbackVersion=1.2.3 -mockitoVersion=2.13.0 +mockitoVersion=2.15.0 nodejsVersion=8.9.4 oauthVersion=20100527 -orgJsonVersion=20090211 +orgJsonVersion=20171018 personDirectoryVersion=1.8.5 plutoVersion=2.1.0-M3 resourceServerVersion=1.0.46 diff --git a/uPortal-api/uPortal-api-internal/src/main/java/org/apereo/portal/portlets/account/UserAccountHelper.java b/uPortal-api/uPortal-api-internal/src/main/java/org/apereo/portal/portlets/account/UserAccountHelper.java index 2308d769d13..4f5be55c4ff 100644 --- a/uPortal-api/uPortal-api-internal/src/main/java/org/apereo/portal/portlets/account/UserAccountHelper.java +++ b/uPortal-api/uPortal-api-internal/src/main/java/org/apereo/portal/portlets/account/UserAccountHelper.java @@ -17,6 +17,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.List; @@ -36,6 +37,7 @@ import org.apereo.portal.groups.IGroupMember; import org.apereo.portal.i18n.ILocaleStore; import org.apereo.portal.i18n.LocaleManager; +import org.apereo.portal.i18n.LocaleManagerFactory; import org.apereo.portal.layout.dlm.remoting.IGroupListHelper; import org.apereo.portal.layout.dlm.remoting.JsonEntityBean; import org.apereo.portal.persondir.ILocalAccountDao; @@ -65,6 +67,7 @@ public class UserAccountHelper { private static final String PORTLET_FNAME_LOGIN = "login"; private ILocaleStore localeStore; + private LocaleManagerFactory localeManagerFactory; private ILocalAccountDao accountDao; private IPortalPasswordService passwordService; private List accountEditAttributes; @@ -80,6 +83,11 @@ public void setLocaleStore(ILocaleStore localeStore) { this.localeStore = localeStore; } + @Autowired + public void setLocaleManagerFactory(LocaleManagerFactory localeManagerFactory) { + this.localeManagerFactory = localeManagerFactory; + } + @Autowired public void setLocalAccountDao(ILocalAccountDao accountDao) { this.accountDao = accountDao; @@ -487,8 +495,9 @@ public void createPassword(PersonForm form, String token) { protected Locale getCurrentUserLocale(final HttpServletRequest request) { final IPerson person = personManager.getPerson(request); final Locale[] userLocales = localeStore.getUserLocales(person); - final LocaleManager localeManager = new LocaleManager(person, userLocales); - final Locale locale = localeManager.getLocales()[0]; + final LocaleManager localeManager = + localeManagerFactory.createLocaleManager(person, Arrays.asList(userLocales)); + final Locale locale = localeManager.getLocales().get(0); return locale; } diff --git a/uPortal-api/uPortal-api-internal/src/main/java/org/apereo/portal/portlets/localization/UserLocaleHelper.java b/uPortal-api/uPortal-api-internal/src/main/java/org/apereo/portal/portlets/localization/UserLocaleHelper.java index ddfa60f2a0d..c0dcecb3486 100644 --- a/uPortal-api/uPortal-api-internal/src/main/java/org/apereo/portal/portlets/localization/UserLocaleHelper.java +++ b/uPortal-api/uPortal-api-internal/src/main/java/org/apereo/portal/portlets/localization/UserLocaleHelper.java @@ -15,6 +15,7 @@ package org.apereo.portal.portlets.localization; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Locale; import javax.portlet.PortletRequest; @@ -24,6 +25,7 @@ import org.apereo.portal.PortalException; import org.apereo.portal.i18n.ILocaleStore; import org.apereo.portal.i18n.LocaleManager; +import org.apereo.portal.i18n.LocaleManagerFactory; import org.apereo.portal.layout.dlm.Constants; import org.apereo.portal.security.IPerson; import org.apereo.portal.url.IPortalRequestUtils; @@ -39,6 +41,7 @@ public class UserLocaleHelper { private IUserInstanceManager userInstanceManager; private IPortalRequestUtils portalRequestUtils; private ILocaleStore localeStore; + private LocaleManagerFactory localeManagerFactory; @Autowired public void setLocaleStore(ILocaleStore localeStore) { @@ -48,7 +51,7 @@ public void setLocaleStore(ILocaleStore localeStore) { /** * Set the UserInstanceManager * - * @param userInstanceManager + * @param userInstanceManager The {@link IUserInstanceManager} */ @Autowired public void setUserInstanceManager(IUserInstanceManager userInstanceManager) { @@ -60,6 +63,11 @@ public void setPortalRequestUtils(IPortalRequestUtils portalRequestUtils) { this.portalRequestUtils = portalRequestUtils; } + @Autowired + public void setLocaleManagerFactory(LocaleManagerFactory localeManagerFactory) { + this.localeManagerFactory = localeManagerFactory; + } + /** * Return a list of LocaleBeans matching the currently available locales for the portal. * @@ -67,10 +75,10 @@ public void setPortalRequestUtils(IPortalRequestUtils portalRequestUtils) { * @return */ public List getLocales(Locale currentLocale) { - List locales = new ArrayList(); + List locales = new ArrayList<>(); // get the array of locales available from the portal - Locale[] portalLocales = getPortalLocales(); + List portalLocales = localeManagerFactory.getPortalLocales(); for (Locale locale : portalLocales) { if (currentLocale != null) { // if a current locale is available, display language names @@ -86,7 +94,7 @@ public List getLocales(Locale currentLocale) { /** * Return the current user's locale. * - * @param request + * @param request The current {@link PortletRequest} * @return */ public Locale getCurrentUserLocale(PortletRequest request) { @@ -98,15 +106,15 @@ public Locale getCurrentUserLocale(PortletRequest request) { LocaleManager localeManager = userProfile.getLocaleManager(); // first check the session locales - Locale[] sessionLocales = localeManager.getSessionLocales(); - if (sessionLocales != null && sessionLocales.length > 0) { - return sessionLocales[0]; + List sessionLocales = localeManager.getSessionLocales(); + if (sessionLocales != null && sessionLocales.size() > 0) { + return sessionLocales.get(0); } // if no session locales were found, check the user locales - Locale[] userLocales = localeManager.getUserLocales(); - if (userLocales != null && userLocales.length > 0) { - return userLocales[0]; + List userLocales = localeManager.getUserLocales(); + if (userLocales != null && userLocales.size() > 0) { + return userLocales.get(0); } // if no selected locale was found either in the session or user layout, @@ -131,9 +139,9 @@ public void updateUserLocale(HttpServletRequest request, String localeString) { if (localeString != null) { - // build a new Locale[] array from the specified locale - Locale userLocale = parseLocale(localeString); - Locale[] locales = new Locale[] {userLocale}; + // build a new List from the specified locale + Locale userLocale = localeManagerFactory.parseLocale(localeString); + List locales = Collections.singletonList(userLocale); // set this locale in the session localeManager.setSessionLocales(locales); @@ -143,7 +151,7 @@ public void updateUserLocale(HttpServletRequest request, String localeString) { final IPerson person = ui.getPerson(); if (!person.isGuest()) { try { - localeManager.persistUserLocales(new Locale[] {userLocale}); + localeManager.setUserLocales(Collections.singletonList(userLocale)); localeStore.updateUserLocales(person, new Locale[] {userLocale}); // remove person layout framgent from session since it contains some of the data @@ -158,27 +166,4 @@ public void updateUserLocale(HttpServletRequest request, String localeString) { } } } - - /* - * Convenience methods to enhance testability by wrapping static methods - */ - - /** - * Get the available portal locales. - * - * @return - */ - protected Locale[] getPortalLocales() { - return LocaleManager.getPortalLocales(); - } - - /** - * Parse a string representation of a locale and return the matching Locale. - * - * @param localeString - * @return - */ - protected Locale parseLocale(String localeString) { - return LocaleManager.parseLocale(localeString); - } } diff --git a/uPortal-api/uPortal-api-rest/src/main/java/org/apereo/portal/layout/dlm/remoting/ChannelListController.java b/uPortal-api/uPortal-api-rest/src/main/java/org/apereo/portal/layout/dlm/remoting/ChannelListController.java index 2d71ddad0aa..16f28214d2f 100644 --- a/uPortal-api/uPortal-api-rest/src/main/java/org/apereo/portal/layout/dlm/remoting/ChannelListController.java +++ b/uPortal-api/uPortal-api-rest/src/main/java/org/apereo/portal/layout/dlm/remoting/ChannelListController.java @@ -14,6 +14,7 @@ */ package org.apereo.portal.layout.dlm.remoting; +import java.util.Arrays; import java.util.HashSet; import java.util.Locale; import java.util.Map; @@ -25,6 +26,7 @@ import org.apereo.portal.EntityIdentifier; import org.apereo.portal.i18n.ILocaleStore; import org.apereo.portal.i18n.LocaleManager; +import org.apereo.portal.i18n.LocaleManagerFactory; import org.apereo.portal.layout.dlm.remoting.registry.ChannelBean; import org.apereo.portal.layout.dlm.remoting.registry.ChannelCategoryBean; import org.apereo.portal.layout.dlm.remoting.registry.v43.PortletCategoryBean; @@ -76,6 +78,7 @@ public class ChannelListController { private IPersonManager personManager; private IPortalSpELService spELService; private ILocaleStore localeStore; + private LocaleManagerFactory localeManagerFactory; private MessageSource messageSource; private IAuthorizationService authorizationService; @@ -112,6 +115,11 @@ public void setLocaleStore(ILocaleStore localeStore) { this.localeStore = localeStore; } + @Autowired + public void setLocaleManagerFactory(LocaleManagerFactory localeManagerFactory) { + this.localeManagerFactory = localeManagerFactory; + } + @Autowired public void setMessageSource(MessageSource messageSource) { this.messageSource = messageSource; @@ -465,9 +473,9 @@ private PortletDefinitionBean preparePortletDefinitionBean( private Locale getUserLocale(IPerson user) { // get user locale Locale[] locales = localeStore.getUserLocales(user); - LocaleManager localeManager = new LocaleManager(user, locales); - Locale rslt = localeManager.getLocales()[0]; - return rslt; + LocaleManager localeManager = + localeManagerFactory.createLocaleManager(user, Arrays.asList(locales)); + return localeManager.getLocales().get(0); } /** diff --git a/uPortal-core/src/main/java/org/apereo/portal/i18n/ILocaleManager.java b/uPortal-core/src/main/java/org/apereo/portal/i18n/ILocaleManager.java new file mode 100644 index 00000000000..0bea98c1e32 --- /dev/null +++ b/uPortal-core/src/main/java/org/apereo/portal/i18n/ILocaleManager.java @@ -0,0 +1,49 @@ +/** + * Licensed to Apereo under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright ownership. Apereo + * licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of the License at the + * following location: + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apereo.portal.i18n; + +import java.util.List; +import java.util.Locale; + +/** + * An instance of this interface manages locales on behalf of a user. Locale managers currently keep + * track of locales at the following levels:
+ * + *

    + *
  1. User's locale preferences (associated with a user ID) + *
  2. Browser's locale preferences (from the Accept-Language request header) + *
  3. Session's locale preferences (set via the portal request parameter uP_locales) + *
  4. Portal's locale preferences (set in portal.properties) + *
+ * + * Eventually, they will also keep track of locale preferences at the following levels:
+ * + *
    + *
  1. Layout node's locale preferences + *
  2. User profile's locale preferences + *
+ * + * @since 5.0 + */ +public interface ILocaleManager { + + List getUserLocales(); + + void setUserLocales(List userLocales); + + List getSessionLocales(); + + void setSessionLocales(List sessionLocales); +} diff --git a/uPortal-core/src/main/java/org/apereo/portal/i18n/LocaleManager.java b/uPortal-core/src/main/java/org/apereo/portal/i18n/LocaleManager.java index 8dcac3614cb..1d6e0f037e0 100644 --- a/uPortal-core/src/main/java/org/apereo/portal/i18n/LocaleManager.java +++ b/uPortal-core/src/main/java/org/apereo/portal/i18n/LocaleManager.java @@ -18,14 +18,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; -import java.util.StringTokenizer; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apereo.portal.properties.PropertiesManager; import org.apereo.portal.security.IPerson; -import org.apereo.portal.utils.DocumentFactory; -import org.w3c.dom.Document; -import org.w3c.dom.Element; /** * Manages locales on behalf of a user. This class currently keeps track of locales at the following @@ -45,113 +38,44 @@ *
  • User profile's locale preferences * */ -public class LocaleManager implements Serializable { - - private static final Log log = LogFactory.getLog(LocaleManager.class); - - /** - * Default value for localeAware. This value will be used when the corresponding property cannot - * be loaded. - */ - public static final boolean DEFAULT_LOCALE_AWARE = false; - - private static boolean localeAware = - PropertiesManager.getPropertyAsBoolean( - "org.apereo.portal.i18n.LocaleManager.locale_aware", DEFAULT_LOCALE_AWARE); - private static Locale jvmLocale; - private static Locale[] portalLocales; +public class LocaleManager implements ILocaleManager, Serializable { private final IPerson person; - private Locale[] sessionLocales; - private Locale[] browserLocales; - private Locale[] userLocales; + private List sessionLocales; + private List userLocales; + private List portalLocales; /** * Constructor that associates a locale manager with a user. * * @param person the user */ - public LocaleManager(IPerson person, Locale[] userLocales) { + /* package-private */ LocaleManager( + IPerson person, List userLocales, List portalLocales) { this.person = person; - jvmLocale = Locale.getDefault(); - if (localeAware) { - portalLocales = loadPortalLocales(); - try { - this.userLocales = userLocales; - } catch (Exception e) { - log.error("Error populating userLocals", e); - } - } - } - - /** - * Constructor that sets up locales according to the Accept-Language request header - * from a user's browser. - * - * @param person the user - * @param acceptLanguage the Accept-Language request header from a user's browser - */ - public LocaleManager(IPerson person, Locale[] userLocales, String acceptLanguage) { - this(person, userLocales); - this.browserLocales = parseLocales(acceptLanguage); - } - - // Getters - public static boolean isLocaleAware() { - return localeAware; - } - - public static Locale getJvmLocale() { - return jvmLocale; - } - - public static Locale[] getPortalLocales() { - return portalLocales; - } - - public Locale[] getBrowserLocales() { - return browserLocales; + this.userLocales = userLocales; + this.portalLocales = portalLocales; } - public Locale[] getUserLocales() { + @Override + public List getUserLocales() { return userLocales; } - public Locale[] getSessionLocales() { - return sessionLocales; - } - - // Setters - public static void setJvmLocale(Locale jvmLocale) { - LocaleManager.jvmLocale = jvmLocale; - } - - public static void setPortalLocales(Locale[] portalLocales) { - LocaleManager.portalLocales = portalLocales; - } - - public void setBrowserLocales(Locale[] browserLocales) { - this.browserLocales = browserLocales; - } - - public void setUserLocales(Locale[] userLocales) { + @Override + public void setUserLocales(List userLocales) { this.userLocales = userLocales; this.sessionLocales = userLocales; } - public void setSessionLocales(Locale[] sessionLocales) { - this.sessionLocales = sessionLocales; + @Override + public List getSessionLocales() { + return sessionLocales; } - /** - * Read and parse portal_locales from portal.properties. portal_locales will be in the form of a - * comma-separated list, e.g. en_US,ja_JP,sv_SE - */ - private Locale[] loadPortalLocales() { - String portalLocalesString = - PropertiesManager.getProperty( - "org.apereo.portal.i18n.LocaleManager.portal_locales"); - return parseLocales(portalLocalesString); + @Override + public void setSessionLocales(List sessionLocales) { + this.sessionLocales = sessionLocales; } /** @@ -160,192 +84,28 @@ private Locale[] loadPortalLocales() { * * @return the sorted list of locales */ - public Locale[] getLocales() { + public List getLocales() { // Need logic to construct ordered locale list. // Consider creating a separate ILocaleResolver // interface to do this work. - List locales = new ArrayList(); + final List rslt = new ArrayList(); // Add highest priority locales first - addToLocaleList(locales, sessionLocales); - addToLocaleList(locales, userLocales); + addToLocaleList(rslt, sessionLocales); + addToLocaleList(rslt, userLocales); // We will ignore browser locales until we know how to // translate them into proper java.util.Locales // addToLocaleList(locales, browserLocales); - addToLocaleList(locales, portalLocales); - addToLocaleList(locales, new Locale[] {jvmLocale}); - return (Locale[]) locales.toArray(new Locale[0]); + addToLocaleList(rslt, portalLocales); + return rslt; } /** Add locales to the locale list if they aren't in there already */ - private void addToLocaleList(List localeList, Locale[] locales) { + private void addToLocaleList(List localeList, List locales) { if (locales != null) { - for (int i = 0; i < locales.length; i++) { - if (locales[i] != null && !localeList.contains(locales[i])) - localeList.add(locales[i]); - } - } - } - - /** - * Helper method to produce a java.util.Locale array from a comma-delimited locale - * string list, e.g. "en_US,ja_JP" - * - * @param localeStringList the locales to parse - * @return an array of locales representing the locale string list - */ - public static Locale[] parseLocales(String localeStringList) { - Locale[] locales = null; - if (localeStringList != null) { - StringTokenizer st = new StringTokenizer(localeStringList, ","); - locales = new Locale[st.countTokens()]; - for (int i = 0; st.hasMoreTokens(); i++) { - String localeString = st.nextToken().trim(); - locales[i] = parseLocale(localeString); + for (Locale locale : locales) { + if (locale != null && !localeList.contains(locale)) localeList.add(locale); } } - return locales; - } - - /** - * Helper method to produce a java.util.Locale object from a locale string such as - * en_US or ja_JP. - * - * @param localeString a locale string such as en_US - * @return a java.util.Locale object representing the locale string - */ - public static Locale parseLocale(String localeString) { - String language = null; - String country = null; - String variant = null; - - // Sometimes people specify "en-US" instead of "en_US", so - // we'll try to clean that up. - localeString = localeString.replaceAll("-", "_"); - - StringTokenizer st = new StringTokenizer(localeString, "_"); - - if (st.hasMoreTokens()) { - language = st.nextToken(); - } - if (st.hasMoreTokens()) { - country = st.nextToken(); - } - if (st.hasMoreTokens()) { - variant = st.nextToken(); - } - - Locale locale = null; - - if (variant != null) { - locale = new Locale(language, country, variant); - } else if (country != null) { - locale = new Locale(language, country); - } else if (language != null) { - // Uncomment the following line - // when we can count on JDK 1.4! - // locale = new Locale(language); - locale = new Locale(language, ""); - } - - return locale; - } - - /** - * Constructs a comma-delimited list of locales that could be parsed back into a Locale array - * with parseLocales(String localeStringList). - * - * @param locales the list of locales - * @return a string representing the list of locales - */ - public static String stringValueOf(Locale[] locales) { - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < locales.length; i++) { - Locale locale = locales[i]; - sb.append(locale.toString()); - if (i < locales.length - 1) { - sb.append(","); - } - } - return sb.toString(); - } - - /** - * Stores the user locales persistantly. - * - * @param userLocales the user locales preference - * @throws Exception - */ - public void persistUserLocales(Locale[] userLocales) throws Exception { - setUserLocales(userLocales); - } - - /** - * Creates an XML representation of a list of locales. - * - * @param locales the locale list - * @return the locale list as XML - */ - public static Document xmlValueOf(Locale[] locales) { - return xmlValueOf(locales, null); - } - - /** - * Creates an XML representation of a list of locales. If a selected locale is supplied, the XML - * element representing the selected locale will have an attribute of selected with value of - * true. This is helpful when constructing user interfaces that indicate which locale is - * selected. - * - * @param locales the locale list - * @param selectedLocale a locale that should be selected if it is in the list - * @return the locale list as XML - */ - public static Document xmlValueOf(Locale[] locales, Locale selectedLocale) { - Document doc = DocumentFactory.getThreadDocument(); - - // - Element localesE = doc.createElement("locales"); - for (int i = 0; i < locales.length; i++) { - Element locE = doc.createElement("locale"); - locE.setAttribute("displayName", locales[i].getDisplayName(locales[0])); - locE.setAttribute("code", locales[i].toString()); - - // Mark which locale is the user's preference - if (selectedLocale != null && selectedLocale.equals(locales[i])) { - locE.setAttribute("selected", "true"); - } - - // - Element languageE = doc.createElement("language"); - languageE.setAttribute("iso2", locales[i].getLanguage()); - try { - languageE.setAttribute("iso3", locales[i].getISO3Language()); - } catch (Exception e) { - // Do nothing - } - languageE.setAttribute("displayName", locales[i].getDisplayLanguage(locales[0])); - locE.appendChild(languageE); - - // - Element countryE = doc.createElement("country"); - countryE.setAttribute("iso2", locales[i].getCountry()); - try { - countryE.setAttribute("iso3", locales[i].getISO3Country()); - } catch (Exception e) { - // Do nothing - } - countryE.setAttribute("displayName", locales[i].getDisplayCountry(locales[0])); - locE.appendChild(countryE); - - // - Element variantE = doc.createElement("variant"); - variantE.setAttribute("code", locales[i].getVariant()); - variantE.setAttribute("displayName", locales[i].getDisplayVariant(locales[0])); - locE.appendChild(variantE); - - localesE.appendChild(locE); - } - doc.appendChild(localesE); - return doc; } @Override @@ -363,27 +123,35 @@ public String toString() { sb.append(stringValueOf(userLocales)); } sb.append("\n"); - sb.append("Browser locales: "); - if (browserLocales != null) { - sb.append(stringValueOf(browserLocales)); - } - sb.append("\n"); sb.append("Portal locales: "); if (portalLocales != null) { sb.append(stringValueOf(portalLocales)); } sb.append("\n"); - sb.append("JVM locale: "); - if (jvmLocale != null) { - sb.append(jvmLocale.toString()); - } - sb.append("\n"); sb.append("Sorted locales: "); - Locale[] sortedLocales = getLocales(); + List sortedLocales = getLocales(); if (sortedLocales != null) { sb.append(stringValueOf(sortedLocales)); } sb.append("\n"); return sb.toString(); } + + /** + * Constructs a comma-delimited list of locales that could be parsed back into a Locale array + * with parseLocales(String localeStringList). + * + * @param locales the list of locales + * @return a string representing the list of locales + */ + private String stringValueOf(List locales) { + StringBuffer sb = new StringBuffer(); + for (Locale locale : locales) { + if (sb.length() > 0) { + sb.append(","); + } + sb.append(locale.toString()); + } + return sb.toString(); + } } diff --git a/uPortal-core/src/main/java/org/apereo/portal/i18n/LocaleManagerFactory.java b/uPortal-core/src/main/java/org/apereo/portal/i18n/LocaleManagerFactory.java new file mode 100644 index 00000000000..4b9fea0ea5b --- /dev/null +++ b/uPortal-core/src/main/java/org/apereo/portal/i18n/LocaleManagerFactory.java @@ -0,0 +1,120 @@ +/** + * Licensed to Apereo under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright ownership. Apereo + * licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of the License at the + * following location: + * + *

    http://www.apache.org/licenses/LICENSE-2.0 + * + *

    Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apereo.portal.i18n; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.StringTokenizer; +import javax.annotation.PostConstruct; +import org.apache.commons.lang3.StringUtils; +import org.apereo.portal.security.IPerson; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * Spring-managed bean that produces {@link ILocaleManager} instances when needed. + * + * @since 5.0 + */ +@Component +public class LocaleManagerFactory { + + @Value("${org.apereo.portal.i18n.LocaleManager.locale_aware:true}") + private boolean localeAware; + + @Value( + "${org.apereo.portal.i18n.LocaleManager.portal_locales:en_US,fr_FR,es_ES,ja_JP,sv_SE,de_DE,mk_MK,lv_LV}") + private String portalLocalesProperty; + + private List portalLocales; + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + /** + * Populate portalLocales from a comma-delimited locale string list, e.g. + * "en_US,ja_JP" + */ + @PostConstruct + public void init() { + logger.info("Using localeAware={}", localeAware); + logger.info("Using portalLocalesProperty='{}'", portalLocalesProperty); + if (StringUtils.isNotBlank(portalLocalesProperty)) { + final List list = new ArrayList<>(); + for (String token : portalLocalesProperty.split(",")) { + list.add(parseLocale(token.trim())); + } + portalLocales = Collections.unmodifiableList(list); + logger.info("Loaded the following portalLocales: {}", portalLocales); + } + } + + public boolean isLocaleAware() { + return localeAware; + } + + public List getPortalLocales() { + return portalLocales; + } + + public LocaleManager createLocaleManager(IPerson person, List userLocales) { + logger.debug("Creating LocalManager for user '{}'", person.getUserName()); + return new LocaleManager(person, userLocales, portalLocales); + } + + /** + * Helper method to produce a java.util.Locale object from a locale string such as + * en_US or ja_JP. + * + * @param localeString a locale string such as en_US + * @return a java.util.Locale object representing the locale string + */ + public Locale parseLocale(String localeString) { + String language = null; + String country = null; + String variant = null; + + // Sometimes people specify "en-US" instead of "en_US", so + // we'll try to clean that up. + localeString = localeString.replaceAll("-", "_"); + + StringTokenizer st = new StringTokenizer(localeString, "_"); + + if (st.hasMoreTokens()) { + language = st.nextToken(); + } + if (st.hasMoreTokens()) { + country = st.nextToken(); + } + if (st.hasMoreTokens()) { + variant = st.nextToken(); + } + + Locale locale = null; + + if (variant != null) { + locale = new Locale(language, country, variant); + } else if (country != null) { + locale = new Locale(language, country); + } else if (language != null) { + locale = new Locale(language); + } + + return locale; + } +} diff --git a/uPortal-i18n/src/main/java/org/apereo/portal/i18n/LocaleManagerLocaleResolver.java b/uPortal-i18n/src/main/java/org/apereo/portal/i18n/LocaleManagerLocaleResolver.java index 54b69fb0897..23576388252 100644 --- a/uPortal-i18n/src/main/java/org/apereo/portal/i18n/LocaleManagerLocaleResolver.java +++ b/uPortal-i18n/src/main/java/org/apereo/portal/i18n/LocaleManagerLocaleResolver.java @@ -14,6 +14,8 @@ */ package org.apereo.portal.i18n; +import java.util.Collections; +import java.util.List; import java.util.Locale; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -53,9 +55,9 @@ public Locale resolveLocale(HttpServletRequest request) { final IUserInstance userInstance = this.userInstanceManager.getUserInstance(request); final LocaleManager localeManager = userInstance.getLocaleManager(); - Locale[] locales = localeManager.getLocales(); - if (locales != null && locales.length > 0) { - return locales[0]; + List locales = localeManager.getLocales(); + if (locales != null && locales.size() > 0) { + return locales.get(0); } // if there was no LocaleManager was not able to determine the locale, return the locale @@ -67,14 +69,14 @@ public Locale resolveLocale(HttpServletRequest request) { public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) { final IUserInstance userInstance = this.userInstanceManager.getUserInstance(request); final LocaleManager localeManager = userInstance.getLocaleManager(); - localeManager.setSessionLocales(new Locale[] {locale}); + localeManager.setSessionLocales(Collections.singletonList(locale)); // if the current user is logged in, also update the persisted user locale final IUserInstance ui = userInstanceManager.getUserInstance(request); final IPerson person = ui.getPerson(); if (!person.isGuest()) { try { - localeManager.persistUserLocales(new Locale[] {locale}); + localeManager.setUserLocales(Collections.singletonList(locale)); localeStore.updateUserLocales(person, new Locale[] {locale}); final IUserPreferencesManager upm = ui.getPreferencesManager(); upm.getUserLayoutManager().loadUserLayout(); diff --git a/uPortal-i18n/src/main/java/org/apereo/portal/i18n/RDBMLocaleStore.java b/uPortal-i18n/src/main/java/org/apereo/portal/i18n/RDBMLocaleStore.java index 2363f753727..d1fc91e96e0 100644 --- a/uPortal-i18n/src/main/java/org/apereo/portal/i18n/RDBMLocaleStore.java +++ b/uPortal-i18n/src/main/java/org/apereo/portal/i18n/RDBMLocaleStore.java @@ -48,6 +48,7 @@ public class RDBMLocaleStore implements ILocaleStore { protected TransactionOperations transactionOperations; protected JdbcOperations jdbcOperations; + private LocaleManagerFactory localeManagerFactory; @Autowired public void setPlatformTransactionManager( @@ -61,6 +62,11 @@ public void setDataSource(DataSource dataSource) { this.jdbcOperations = new JdbcTemplate(dataSource); } + @Autowired + public void setLocaleManagerFactory(LocaleManagerFactory localeManagerFactory) { + this.localeManagerFactory = localeManagerFactory; + } + @Override public Locale[] getUserLocales(final IPerson person) { return jdbcOperations.execute( @@ -81,7 +87,8 @@ public Locale[] doInConnection(Connection con) try { while (rs.next()) { final String localeString = rs.getString("LOCALE"); - final Locale locale = LocaleManager.parseLocale(localeString); + final Locale locale = + localeManagerFactory.parseLocale(localeString); localeList.add(locale); } } finally { diff --git a/uPortal-layout/uPortal-layout-impl/src/main/java/org/apereo/portal/layout/dlm/FragmentActivator.java b/uPortal-layout/uPortal-layout-impl/src/main/java/org/apereo/portal/layout/dlm/FragmentActivator.java index d0d2097e276..b1456b60d5c 100644 --- a/uPortal-layout/uPortal-layout-impl/src/main/java/org/apereo/portal/layout/dlm/FragmentActivator.java +++ b/uPortal-layout/uPortal-layout-impl/src/main/java/org/apereo/portal/layout/dlm/FragmentActivator.java @@ -18,6 +18,7 @@ import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import java.io.Serializable; +import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.concurrent.CopyOnWriteArrayList; @@ -32,6 +33,7 @@ import org.apereo.portal.IUserProfile; import org.apereo.portal.UserProfile; import org.apereo.portal.i18n.LocaleManager; +import org.apereo.portal.i18n.LocaleManagerFactory; import org.apereo.portal.layout.IUserLayoutStore; import org.apereo.portal.properties.PropertiesManager; import org.apereo.portal.security.IPerson; @@ -65,6 +67,7 @@ public List load(String key) throws Exception { private IUserIdentityStore identityStore; private IUserLayoutStore userLayoutStore; private ConfigurationLoader configurationLoader; + private LocaleManagerFactory localeManagerFactory; private static final String PROPERTY_ALLOW_EXPANDED_CONTENT = "org.apereo.portal.layout.dlm.allowExpandedContent"; @@ -124,6 +127,11 @@ public void setUserLayoutStore(IUserLayoutStore userLayoutStore) { this.userLayoutStore = userLayoutStore; } + @Autowired + public void setLocaleManagerFactory(LocaleManagerFactory localeManagerFactory) { + this.localeManagerFactory = localeManagerFactory; + } + private static class UserViewKey implements Serializable { private static final long serialVersionUID = 1L; private final String ownerId; @@ -356,7 +364,10 @@ private void loadLayout( try { // fix hard coded 1 later for multiple profiles IUserProfile profile = userLayoutStore.getUserProfileByFname(owner, "default"); - profile.setLocaleManager(new LocaleManager(owner, new Locale[] {locale})); + final LocaleManager localeManager = + localeManagerFactory.createLocaleManager( + owner, Collections.singletonList(locale)); + profile.setLocaleManager(localeManager); // see if we have structure & theme stylesheets for this user yet. // If not then fall back on system's selected stylesheets. diff --git a/uPortal-layout/uPortal-layout-impl/src/main/java/org/apereo/portal/layout/dlm/RDBMDistributedLayoutStore.java b/uPortal-layout/uPortal-layout-impl/src/main/java/org/apereo/portal/layout/dlm/RDBMDistributedLayoutStore.java index 49297c12ed2..9d53298a597 100644 --- a/uPortal-layout/uPortal-layout-impl/src/main/java/org/apereo/portal/layout/dlm/RDBMDistributedLayoutStore.java +++ b/uPortal-layout/uPortal-layout-impl/src/main/java/org/apereo/portal/layout/dlm/RDBMDistributedLayoutStore.java @@ -37,7 +37,6 @@ import org.apereo.portal.IUserIdentityStore; import org.apereo.portal.IUserProfile; import org.apereo.portal.PortalException; -import org.apereo.portal.i18n.LocaleManager; import org.apereo.portal.io.xml.IPortalDataHandlerService; import org.apereo.portal.jdbc.RDBMServices; import org.apereo.portal.layout.LayoutStructure; @@ -196,9 +195,9 @@ public void setErrorOnMissingUser(boolean errorOnMissingUser) { public Map getFragmentLayoutCopies() { // since this is only visible in fragment list in administrative portlet, use default portal // locale - final Locale defaultLocale = LocaleManager.getPortalLocales()[0]; + final Locale defaultLocale = localeManagerFactory.getPortalLocales().get(0); - final Map layouts = new HashMap(); + final Map layouts = new HashMap<>(); final List definitions = this.fragmentUtils.getFragmentDefinitions(); for (final FragmentDefinition fragmentDefinition : definitions) { @@ -230,7 +229,7 @@ private IStylesheetUserPreferences loadDistributedStylesheetUserPreferences( Set fragmentNames) { final boolean isFragmentOwner = this.isFragmentOwner(person); - final Locale locale = profile.getLocaleManager().getLocales()[0]; + final Locale locale = profile.getLocaleManager().getLocales().get(0); final IStylesheetDescriptor stylesheetDescriptor = this.stylesheetDescriptorDao.getStylesheetDescriptor(stylesheetDescriptorId); final IStylesheetUserPreferences stylesheetUserPreferences = @@ -278,8 +277,7 @@ private IStylesheetUserPreferences loadDistributedStylesheetUserPreferences( ? fragmentNodeId : labelBase + fragmentNodeId; - final MapPopulator layoutAttributesPopulator = - new MapPopulator(); + final MapPopulator layoutAttributesPopulator = new MapPopulator<>(); fragmentStylesheetUserPreferences.populateLayoutAttributes( fragmentNodeId, layoutAttributesPopulator); final Map layoutAttributes = layoutAttributesPopulator.getMap(); @@ -690,8 +688,7 @@ private void addStylesheetUserPreferencesAttributes( ssup.getAllLayoutAttributeNodeIds(); for (final String nodeId : allLayoutAttributeNodeIds) { - final MapPopulator layoutAttributesPopulator = - new MapPopulator(); + final MapPopulator layoutAttributesPopulator = new MapPopulator<>(); ssup.populateLayoutAttributes(nodeId, layoutAttributesPopulator); final Map layoutAttributes = layoutAttributesPopulator.getMap(); @@ -959,7 +956,7 @@ public void importLayout(org.dom4j.Element layout) { // track which entities from the user's pre-existing set are touched (all non-touched // entities will be removed) final Set oldPortletEntities = - new LinkedHashSet( + new LinkedHashSet<>( this.portletEntityDao.getPortletEntitiesForUser(ownerUserId)); final List entries = preferencesElement.selectNodes("entry"); @@ -981,7 +978,7 @@ public void importLayout(org.dom4j.Element layout) { portletEntity.getPortletPreferences(); final List valueElements = entry.selectNodes("value"); - final List values = new ArrayList(valueElements.size()); + final List values = new ArrayList<>(valueElements.size()); for (final org.dom4j.Element valueElement : valueElements) { values.add(valueElement.getText()); } @@ -1061,11 +1058,9 @@ private void loadStylesheetUserPreferencesAttributes( stylesheetDescriptor, person, profile); } - final Map> oldLayoutAttributes = - new HashMap>(); + final Map> oldLayoutAttributes = new HashMap<>(); for (final String nodeId : ssup.getAllLayoutAttributeNodeIds()) { - final MapPopulator nodeAttributes = - new MapPopulator(); + final MapPopulator nodeAttributes = new MapPopulator<>(); ssup.populateLayoutAttributes(nodeId, nodeAttributes); oldLayoutAttributes.put(nodeId, nodeAttributes.getMap()); } @@ -1185,7 +1180,7 @@ private final int addIdAttributesIfNecessary(org.dom4j.Element e, int nextId) { } private final ThreadLocal, Document>> layoutCacheHolder = - new ThreadLocal, Document>>(); + new ThreadLocal<>(); public void setLayoutImportExportCache(Cache, Document> layoutCache) { if (layoutCache == null) { @@ -1214,7 +1209,7 @@ private Document _safeGetUserLayout(IPerson person, IUserProfile profile) { final Cache, Document> layoutCache = getLayoutImportExportCache(); if (layoutCache != null) { - key = new Tuple(person.getUserName(), profile.getProfileFname()); + key = new Tuple<>(person.getUserName(), profile.getProfileFname()); layoutDoc = layoutCache.getIfPresent(key); if (layoutDoc != null) { return (Document) layoutDoc.cloneNode(true); @@ -1246,7 +1241,7 @@ private DistributedUserLayout _getUserLayout(IPerson person, IUserProfile profil final FragmentDefinition ownedFragment = this.fragmentUtils.getFragmentDefinitionByOwner(person); final boolean isLayoutOwnerDefault = this.isLayoutOwnerDefault(person); - final Set fragmentNames = new LinkedHashSet(); + final Set fragmentNames = new LinkedHashSet<>(); final Document ILF; final Document PLF = this.getPLF(person, profile); @@ -1285,7 +1280,7 @@ private DistributedUserLayout _getUserLayout(IPerson person, IUserProfile profil (String) person.getAttribute("username")); } } else { - final Locale locale = profile.getLocaleManager().getLocales()[0]; + final Locale locale = profile.getLocaleManager().getLocales().get(0); final List applicableFragmentDefinitions = this.fragmentUtils.getFragmentDefinitionsApplicableToPerson(person); final List applicableLayouts = @@ -1393,7 +1388,7 @@ public String getNextStructDirectiveId(IPerson person) { */ private void updateCachedLayout( Document layout, IUserProfile profile, FragmentDefinition fragment) { - final Locale locale = profile.getLocaleManager().getLocales()[0]; + final Locale locale = profile.getLocaleManager().getLocales().get(0); // need to make a copy that we can fragmentize layout = (Document) layout.cloneNode(true); @@ -1536,7 +1531,7 @@ public FragmentChannelInfo getFragmentChannelInfo(String sId) { public FragmentNodeInfo getFragmentNodeInfo(String sId) { // grab local pointers to variables subject to change at any time final List fragments = this.fragmentUtils.getFragmentDefinitions(); - final Locale defaultLocale = LocaleManager.getPortalLocales()[0]; + final Locale defaultLocale = localeManagerFactory.getPortalLocales().get(0); final net.sf.ehcache.Element element = this.fragmentNodeInfoCache.get(sId); FragmentNodeInfo info = @@ -1608,7 +1603,7 @@ protected Element getStructure(Document doc, LayoutStructure ls) { structure.setAttribute("hidden", (ls.isHidden() ? "true" : "false")); structure.setAttribute("immutable", (ls.isImmutable() ? "true" : "false")); structure.setAttribute("unremovable", (ls.isUnremovable() ? "true" : "false")); - if (localeAware) { + if (localeManagerFactory.isLocaleAware()) { structure.setAttribute("locale", ls.getLocale()); // for i18n by Shoji } diff --git a/uPortal-layout/uPortal-layout-impl/src/main/java/org/apereo/portal/layout/simple/RDBMUserLayoutStore.java b/uPortal-layout/uPortal-layout-impl/src/main/java/org/apereo/portal/layout/simple/RDBMUserLayoutStore.java index 36a22c8412d..ddf4755cc35 100644 --- a/uPortal-layout/uPortal-layout-impl/src/main/java/org/apereo/portal/layout/simple/RDBMUserLayoutStore.java +++ b/uPortal-layout/uPortal-layout-impl/src/main/java/org/apereo/portal/layout/simple/RDBMUserLayoutStore.java @@ -20,6 +20,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import java.util.Arrays; import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; @@ -36,6 +37,7 @@ import org.apereo.portal.UserProfile; import org.apereo.portal.i18n.ILocaleStore; import org.apereo.portal.i18n.LocaleManager; +import org.apereo.portal.i18n.LocaleManagerFactory; import org.apereo.portal.jdbc.DatabaseMetaDataImpl; import org.apereo.portal.jdbc.IDatabaseMetadata; import org.apereo.portal.jdbc.IJoinQueryString; @@ -93,18 +95,21 @@ public abstract class RDBMUserLayoutStore implements IUserLayoutStore, Initializ protected JdbcOperations jdbcOperations; private ILocaleStore localeStore; + protected LocaleManagerFactory localeManagerFactory; protected IDatabaseMetadata databaseMetadata; protected IPortletDefinitionRegistry portletDefinitionRegistry; protected IStylesheetDescriptorDao stylesheetDescriptorDao; - // I18n property - protected static final boolean localeAware = LocaleManager.isLocaleAware(); - @Autowired public void setLocaleStore(ILocaleStore localeStore) { this.localeStore = localeStore; } + @Autowired + public void setLocaleManagerFactory(LocaleManagerFactory localeManagerFactory) { + this.localeManagerFactory = localeManagerFactory; + } + @Autowired public void setStylesheetDescriptorDao(IStylesheetDescriptorDao stylesheetDescriptorDao) { this.stylesheetDescriptorDao = stylesheetDescriptorDao; @@ -640,7 +645,7 @@ public Tuple doInTransaction( } String sql; - if (localeAware) { + if (localeManagerFactory.isLocaleAware()) { // This needs to be changed to get the localized strings sql = "SELECT ULS.STRUCT_ID,ULS.NEXT_STRUCT_ID,ULS.CHLD_STRUCT_ID,ULS.CHAN_ID,ULS.NAME,ULS.TYPE,ULS.HIDDEN," @@ -736,9 +741,9 @@ public Tuple doInTransaction( // uPortal i18n int name_index, value_index; - if (localeAware) { - Locale[] locales = localeManager.getLocales(); - String locale = locales[0].toString(); + if (localeManagerFactory.isLocaleAware()) { + List locales = localeManager.getLocales(); + String locale = locales.get(0).toString(); ls = new LayoutStructure( structId, @@ -993,8 +998,10 @@ public UserProfile doInConnection(Connection con) themeSsId); final Locale[] userLocales = localeStore.getUserLocales(person); - userProfile.setLocaleManager( - new LocaleManager(person, userLocales)); + final LocaleManager localeManager = + localeManagerFactory.createLocaleManager( + person, Arrays.asList(userLocales)); + userProfile.setLocaleManager(localeManager); return userProfile; } @@ -1036,8 +1043,13 @@ public UserProfile doInConnection(Connection con) newUserProfile = addUserProfile(person, newUserProfile); - newUserProfile.setLocaleManager( - new LocaleManager(person, userLocales)); + final LocaleManager localeManager = + localeManagerFactory + .createLocaleManager( + person, + Arrays.asList( + userLocales)); + newUserProfile.setLocaleManager(localeManager); return newUserProfile; } } diff --git a/uPortal-layout/uPortal-layout-impl/src/main/java/org/apereo/portal/user/UserInstanceManagerImpl.java b/uPortal-layout/uPortal-layout-impl/src/main/java/org/apereo/portal/user/UserInstanceManagerImpl.java index 73f7050ffd9..f004774f38f 100644 --- a/uPortal-layout/uPortal-layout-impl/src/main/java/org/apereo/portal/user/UserInstanceManagerImpl.java +++ b/uPortal-layout/uPortal-layout-impl/src/main/java/org/apereo/portal/user/UserInstanceManagerImpl.java @@ -15,6 +15,7 @@ package org.apereo.portal.user; import java.io.Serializable; +import java.util.Arrays; import java.util.Locale; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; @@ -27,6 +28,7 @@ import org.apereo.portal.UserPreferencesManager; import org.apereo.portal.i18n.ILocaleStore; import org.apereo.portal.i18n.LocaleManager; +import org.apereo.portal.i18n.LocaleManagerFactory; import org.apereo.portal.layout.IUserLayoutManager; import org.apereo.portal.layout.IUserLayoutStore; import org.apereo.portal.layout.UserLayoutManagerFactory; @@ -51,6 +53,7 @@ public class UserInstanceManagerImpl implements IUserInstanceManager { private IPortalRequestUtils portalRequestUtils; private IProfileMapper profileMapper; private UserLayoutManagerFactory userLayoutManagerFactory; + private LocaleManagerFactory localeManagerFactory; @Autowired public void setUserLayoutManagerFactory(UserLayoutManagerFactory userLayoutManagerFactory) { @@ -82,6 +85,11 @@ public void setProfileMapper(IProfileMapper profileMapper) { this.profileMapper = profileMapper; } + @Autowired + public void setLocaleManagerFactory(LocaleManagerFactory localeManagerFactory) { + this.localeManagerFactory = localeManagerFactory; + } + /** * Returns the UserInstance object that is associated with the given request. * @@ -171,7 +179,7 @@ protected IUserProfile getUserProfile( userProfile = userLayoutStore.getSystemProfileByFname(profileFname); } - if (localeManager != null && LocaleManager.isLocaleAware()) { + if (localeManager != null && localeManagerFactory.isLocaleAware()) { userProfile.setLocaleManager(localeManager); } @@ -181,7 +189,7 @@ protected IUserProfile getUserProfile( protected LocaleManager getLocaleManager(HttpServletRequest request, IPerson person) { final String acceptLanguage = request.getHeader("Accept-Language"); final Locale[] userLocales = localeStore.getUserLocales(person); - return new LocaleManager(person, userLocales, acceptLanguage); + return localeManagerFactory.createLocaleManager(person, Arrays.asList(userLocales)); } protected String getUserAgent(HttpServletRequest request) { diff --git a/uPortal-portlets/src/main/java/org/apereo/portal/portlets/translator/MessageEntityTranslationController.java b/uPortal-portlets/src/main/java/org/apereo/portal/portlets/translator/MessageEntityTranslationController.java index 7ff62f0c1a0..c822ad3b31f 100644 --- a/uPortal-portlets/src/main/java/org/apereo/portal/portlets/translator/MessageEntityTranslationController.java +++ b/uPortal-portlets/src/main/java/org/apereo/portal/portlets/translator/MessageEntityTranslationController.java @@ -18,7 +18,7 @@ import java.util.List; import java.util.Locale; import java.util.Set; -import org.apereo.portal.i18n.LocaleManager; +import org.apereo.portal.i18n.LocaleManagerFactory; import org.apereo.portal.i18n.Message; import org.apereo.portal.i18n.dao.IMessageDao; import org.springframework.beans.factory.annotation.Autowired; @@ -42,12 +42,18 @@ public class MessageEntityTranslationController { private IMessageDao messageDao; + private LocaleManagerFactory localeManagerFactory; @Autowired public void setMessageDao(IMessageDao messageDao) { this.messageDao = messageDao; } + @Autowired + public void setLocaleManagerFactory(LocaleManagerFactory localeManagerFactory) { + this.localeManagerFactory = localeManagerFactory; + } + @ResourceMapping @RequestMapping(params = "action=getEntityList") public ModelAndView getEntityList() throws Exception { @@ -67,7 +73,7 @@ public ModelAndView getEntityList() throws Exception { @RequestMapping(params = "action=getEntity") public ModelAndView getEntity( @RequestParam("id") String code, @RequestParam("locale") String localeStr) { - final Locale locale = LocaleManager.parseLocale(localeStr); + final Locale locale = localeManagerFactory.parseLocale(localeStr); final Message message = messageDao.getMessage(code, locale); return new ModelAndView("json", "message", message); } @@ -78,7 +84,7 @@ public ModelAndView postTranslation( @RequestParam("id") String code, @RequestParam("locale") String localeStr, @RequestParam("value") String value) { - final Locale locale = LocaleManager.parseLocale(localeStr); + final Locale locale = localeManagerFactory.parseLocale(localeStr); if (locale != null && StringUtils.hasText(code) && StringUtils.hasText(value)) { final Message message = messageDao.getMessage(code, locale); if (message != null) { diff --git a/uPortal-rendering/src/main/java/org/apereo/portal/rendering/xslt/LocaleTransformerConfigurationSource.java b/uPortal-rendering/src/main/java/org/apereo/portal/rendering/xslt/LocaleTransformerConfigurationSource.java index d9cbd3d831e..b5390e70978 100644 --- a/uPortal-rendering/src/main/java/org/apereo/portal/rendering/xslt/LocaleTransformerConfigurationSource.java +++ b/uPortal-rendering/src/main/java/org/apereo/portal/rendering/xslt/LocaleTransformerConfigurationSource.java @@ -15,6 +15,7 @@ package org.apereo.portal.rendering.xslt; import java.util.Collections; +import java.util.List; import java.util.Locale; import java.util.Map; import javax.servlet.http.HttpServletRequest; @@ -51,9 +52,9 @@ public Map getParameters( HttpServletRequest request, HttpServletResponse response) { final LocaleManager localeManager = this.getLocaleManager(request); - final Locale[] locales = localeManager.getLocales(); - if (locales != null && locales.length > 0 && locales[0] != null) { - final String locale = locales[0].toString(); + final List locales = localeManager.getLocales(); + if (locales != null && locales.size() > 0 && locales.get(0) != null) { + final String locale = locales.get(0).toString(); final String xslLocale = locale.replace('_', '-'); this.logger.debug("Setting USER_LANG to {}", xslLocale); return Collections.singletonMap("USER_LANG", (Object) xslLocale); @@ -69,9 +70,9 @@ public Map getParameters( public CacheKey getCacheKey(HttpServletRequest request, HttpServletResponse response) { final LocaleManager localeManager = this.getLocaleManager(request); - final Locale[] locales = localeManager.getLocales(); - if (locales != null && locales.length > 0 && locales[0] != null) { - final String locale = locales[0].toString(); + final List locales = localeManager.getLocales(); + if (locales != null && locales.size() > 0 && locales.get(0) != null) { + final String locale = locales.get(0).toString(); final String xslLocale = locale.replace('_', '-'); return CacheKey.build(this.getClass().getName(), xslLocale); } diff --git a/uPortal-security/uPortal-security-xslt/src/main/java/org/apereo/portal/security/xslt/XalanLayoutElementTitleHelper.java b/uPortal-security/uPortal-security-xslt/src/main/java/org/apereo/portal/security/xslt/XalanLayoutElementTitleHelper.java index 1d948cf024a..c01f4eb7799 100644 --- a/uPortal-security/uPortal-security-xslt/src/main/java/org/apereo/portal/security/xslt/XalanLayoutElementTitleHelper.java +++ b/uPortal-security/uPortal-security-xslt/src/main/java/org/apereo/portal/security/xslt/XalanLayoutElementTitleHelper.java @@ -15,7 +15,7 @@ package org.apereo.portal.security.xslt; import java.util.Locale; -import org.apereo.portal.i18n.LocaleManager; +import org.apereo.portal.i18n.LocaleManagerFactory; import org.apereo.portal.layout.dlm.Constants; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; @@ -29,11 +29,18 @@ public class XalanLayoutElementTitleHelper { private static MessageSource messageSource; + private static LocaleManagerFactory localeManagerFactory; + @Autowired public void setMessageSource(MessageSource messageSource) { XalanLayoutElementTitleHelper.messageSource = messageSource; } + @Autowired + public void setLocaleManagerFactory(LocaleManagerFactory localeManagerFactory) { + XalanLayoutElementTitleHelper.localeManagerFactory = localeManagerFactory; + } + /** * This method checks whether id indicates that it is a layout owner's structure element (or at * least derived from it). If it is the case, then it asks {@link MessageSource} to resolve the @@ -49,7 +56,7 @@ public void setMessageSource(MessageSource messageSource) { */ public static String getTitle(String id, String language, String name) { if (id != null && id.startsWith(Constants.FRAGMENT_ID_USER_PREFIX)) { - final Locale locale = LocaleManager.parseLocale(language); + final Locale locale = localeManagerFactory.parseLocale(language); return messageSource.getMessage(name, new Object[] {}, name, locale); } return name; diff --git a/uPortal-security/uPortal-security-xslt/src/main/java/org/apereo/portal/security/xslt/XalanMessageHelperBean.java b/uPortal-security/uPortal-security-xslt/src/main/java/org/apereo/portal/security/xslt/XalanMessageHelperBean.java index 5c678eff9bd..5315ceae9d9 100644 --- a/uPortal-security/uPortal-security-xslt/src/main/java/org/apereo/portal/security/xslt/XalanMessageHelperBean.java +++ b/uPortal-security/uPortal-security-xslt/src/main/java/org/apereo/portal/security/xslt/XalanMessageHelperBean.java @@ -16,7 +16,8 @@ import java.util.Locale; import org.apache.commons.lang3.StringEscapeUtils; -import org.apereo.portal.i18n.LocaleManager; +import org.apereo.portal.i18n.LocaleManagerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; import org.springframework.context.MessageSourceAware; import org.springframework.stereotype.Service; @@ -25,33 +26,40 @@ public class XalanMessageHelperBean implements IXalanMessageHelper, MessageSourceAware { private MessageSource messageSource; + private LocaleManagerFactory localeManagerFactory; + @Override public void setMessageSource(MessageSource messageSource) { this.messageSource = messageSource; } + @Autowired + public void setLocaleManagerFactory(LocaleManagerFactory localeManagerFactory) { + this.localeManagerFactory = localeManagerFactory; + } + @Override public String getMessage(String code, String language) { - final Locale locale = LocaleManager.parseLocale(language); + final Locale locale = localeManagerFactory.parseLocale(language); final String message = messageSource.getMessage(code, null, locale); return message; } @Override public String getMessage(String code, String language, String arg1) { - final Locale locale = LocaleManager.parseLocale(language); + final Locale locale = localeManagerFactory.parseLocale(language); return messageSource.getMessage(code, new Object[] {arg1}, locale); } @Override public String getMessage(String code, String language, String arg1, String arg2) { - final Locale locale = LocaleManager.parseLocale(language); + final Locale locale = localeManagerFactory.parseLocale(language); return messageSource.getMessage(code, new Object[] {arg1, arg2}, locale); } @Override public String getMessage(String code, String language, String arg1, String arg2, String arg3) { - final Locale locale = LocaleManager.parseLocale(language); + final Locale locale = localeManagerFactory.parseLocale(language); return messageSource.getMessage(code, new Object[] {arg1, arg2, arg3}, locale); } diff --git a/uPortal-soffit/uPortal-soffit-connector/src/main/java/org/apereo/portal/soffit/DefinitionHeaderProvider.java b/uPortal-soffit/uPortal-soffit-connector/src/main/java/org/apereo/portal/soffit/DefinitionHeaderProvider.java index cb286c4bf86..38137b3ae76 100644 --- a/uPortal-soffit/uPortal-soffit-connector/src/main/java/org/apereo/portal/soffit/DefinitionHeaderProvider.java +++ b/uPortal-soffit/uPortal-soffit-connector/src/main/java/org/apereo/portal/soffit/DefinitionHeaderProvider.java @@ -15,6 +15,7 @@ package org.apereo.portal.soffit; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -27,6 +28,7 @@ import org.apache.http.message.BasicHeader; import org.apereo.portal.i18n.ILocaleStore; import org.apereo.portal.i18n.LocaleManager; +import org.apereo.portal.i18n.LocaleManagerFactory; import org.apereo.portal.portlet.marketplace.IMarketplaceService; import org.apereo.portal.portlet.marketplace.MarketplacePortletDefinition; import org.apereo.portal.portlet.om.IPortletDefinition; @@ -63,6 +65,8 @@ public class DefinitionHeaderProvider extends AbstractHeaderProvider { @Autowired private DefinitionService definitionService; + @Autowired private LocaleManagerFactory localeManagerFactory; + @Override public Header createHeader(RenderRequest renderRequest, RenderResponse renderResponse) { @@ -130,8 +134,8 @@ public Header createHeader(RenderRequest renderRequest, RenderResponse renderRes private Locale getUserLocale(IPerson user) { // get user locale Locale[] locales = localeStore.getUserLocales(user); - LocaleManager localeManager = new LocaleManager(user, locales); - Locale rslt = localeManager.getLocales()[0]; - return rslt; + LocaleManager localeManager = + localeManagerFactory.createLocaleManager(user, Arrays.asList(locales)); + return localeManager.getLocales().get(0); } } diff --git a/uPortal-tenants/src/main/java/org/apereo/portal/tenants/AbstractTenantOperationsListener.java b/uPortal-tenants/src/main/java/org/apereo/portal/tenants/AbstractTenantOperationsListener.java index 5b7f106a519..2b3bc53d17a 100644 --- a/uPortal-tenants/src/main/java/org/apereo/portal/tenants/AbstractTenantOperationsListener.java +++ b/uPortal-tenants/src/main/java/org/apereo/portal/tenants/AbstractTenantOperationsListener.java @@ -14,12 +14,14 @@ */ package org.apereo.portal.tenants; +import java.util.Arrays; import java.util.Collections; import java.util.Locale; import java.util.Set; import javax.servlet.http.HttpServletRequest; import org.apereo.portal.i18n.ILocaleStore; import org.apereo.portal.i18n.LocaleManager; +import org.apereo.portal.i18n.LocaleManagerFactory; import org.apereo.portal.security.IPerson; import org.apereo.portal.security.IPersonManager; import org.apereo.portal.url.IPortalRequestUtils; @@ -44,6 +46,8 @@ public abstract class AbstractTenantOperationsListener implements ITenantOperati @Autowired private ILocaleStore localeStore; + @Autowired private LocaleManagerFactory localeManagerFactory; + @Autowired private MessageSource messageSource; protected AbstractTenantOperationsListener(final String fname) { @@ -107,8 +111,9 @@ private Locale getCurrentUserLocale() { final HttpServletRequest req = this.portalRequestUtils.getCurrentPortalRequest(); final IPerson person = personManager.getPerson(req); final Locale[] userLocales = localeStore.getUserLocales(person); - final LocaleManager localeManager = new LocaleManager(person, userLocales); - final Locale locale = localeManager.getLocales()[0]; + final LocaleManager localeManager = + localeManagerFactory.createLocaleManager(person, Arrays.asList(userLocales)); + final Locale locale = localeManager.getLocales().get(0); return locale; } diff --git a/uPortal-url/src/main/java/org/apereo/portal/url/PortalHttpServletRequestWrapper.java b/uPortal-url/src/main/java/org/apereo/portal/url/PortalHttpServletRequestWrapper.java index cd8b89fd1c6..d779f720788 100644 --- a/uPortal-url/src/main/java/org/apereo/portal/url/PortalHttpServletRequestWrapper.java +++ b/uPortal-url/src/main/java/org/apereo/portal/url/PortalHttpServletRequestWrapper.java @@ -19,6 +19,7 @@ import java.util.Enumeration; import java.util.LinkedHashMap; import java.util.LinkedHashSet; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; @@ -35,7 +36,6 @@ import org.apereo.portal.services.GroupService; import org.apereo.portal.user.IUserInstance; import org.apereo.portal.user.IUserInstanceManager; -import org.apereo.portal.utils.ArrayEnumerator; import org.apereo.portal.utils.web.AbstractHttpServletRequestWrapper; /** @@ -58,7 +58,7 @@ public class PortalHttpServletRequestWrapper extends AbstractHttpServletRequestW protected final Log logger = LogFactory.getLog(this.getClass()); - private final Map additionalHeaders = new LinkedHashMap(); + private final Map additionalHeaders = new LinkedHashMap<>(); private final HttpServletResponse httpServletResponse; private final IUserInstanceManager userInstanceManager; @@ -128,7 +128,7 @@ public Enumeration getHeaders(String name) { @Override public Enumeration getHeaderNames() { - final Set headerNames = new LinkedHashSet(); + final Set headerNames = new LinkedHashSet<>(); for (final Enumeration headerNamesEnum = super.getHeaderNames(); headerNamesEnum.hasMoreElements(); ) { @@ -263,8 +263,8 @@ public Locale getLocale() { final IUserInstance userInstance = this.userInstanceManager.getUserInstance(this.getWrappedRequest()); final LocaleManager localeManager = userInstance.getLocaleManager(); - final Locale[] locales = localeManager.getLocales(); - return locales[0]; + final List locales = localeManager.getLocales(); + return locales.get(0); } /* (non-Javadoc) @@ -279,7 +279,7 @@ public Enumeration getLocales() { final IUserInstance userInstance = this.userInstanceManager.getUserInstance(this.getWrappedRequest()); final LocaleManager localeManager = userInstance.getLocaleManager(); - final Locale[] locales = localeManager.getLocales(); - return new ArrayEnumerator(locales); + final List locales = localeManager.getLocales(); + return Collections.enumeration(locales); } } diff --git a/uPortal-webapp/src/test/resources/org/apereo/portal/rendering/renderingPipelineTestContext.xml b/uPortal-webapp/src/test/resources/org/apereo/portal/rendering/renderingPipelineTestContext.xml index 04eaef8dcee..8067ed7313a 100644 --- a/uPortal-webapp/src/test/resources/org/apereo/portal/rendering/renderingPipelineTestContext.xml +++ b/uPortal-webapp/src/test/resources/org/apereo/portal/rendering/renderingPipelineTestContext.xml @@ -19,19 +19,19 @@ under the License. --> - - + - + - + @@ -52,12 +52,12 @@ - + - + @@ -96,7 +96,7 @@ - + @@ -125,7 +125,7 @@ - + @@ -143,7 +143,7 @@ - + @@ -157,9 +157,9 @@ - + - - + - + - + - + - + - - + + - + - + - + - + - + - + - + - - + @@ -232,8 +231,9 @@ classpath:/properties/i18n/Messages - + - - + + +