/*
- * Copyright (C) 2016 Roland Häder
+ * Copyright (C) 2016 - 2020 Free Software Foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
package org.mxchange.jjobs.beans.localization;
import java.text.MessageFormat;
+import java.text.NumberFormat;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
+import javax.enterprise.event.Event;
import javax.enterprise.event.Observes;
+import javax.enterprise.inject.Any;
import javax.faces.context.FacesContext;
+import javax.inject.Inject;
import javax.inject.Named;
-import org.mxchange.jjobs.beans.BaseJobsController;
-import org.mxchange.jusercore.events.login.ObservableUserLoggedInEvent;
-import org.mxchange.jusercore.events.logout.ObservableUserLogoutEvent;
+import org.mxchange.jcoreee.events.locale.LocaleChangeEvent;
+import org.mxchange.jcoreee.events.locale.ObservableLocaleChangeEvent;
+import org.mxchange.jjobs.beans.BaseJobsBean;
+import org.mxchange.juserlogincore.events.login.ObservableUserLoggedInEvent;
+import org.mxchange.juserlogincore.events.logout.ObservableUserLogoutEvent;
/**
- * A session bean for handling localization/internationalization changes. This
- * class is based on an example at [1] from mkyong.
+ * A session-scoped bean for handling localization/internationalization changes.
+ * This class is based on an example at [1] from mkyong.
* <p>
* 1: http://www.mkyong.com/jsf2/jsf-2-internationalization-example/
* <p>
*/
@Named ("localizationController")
@SessionScoped
-public class JobsLocalizationSessionBean extends BaseJobsController implements JobsLocalizationSessionController {
+public class JobsLocalizationSessionBean extends BaseJobsBean implements JobsLocalizationSessionController {
+
+ /**
+ * Number format
+ */
+ private static NumberFormat NUMBER_FORMAT;
/**
* Serial number
*/
- private static final long serialVersionUID = 1_867_671_657_629_601_528L;
+ private static final long serialVersionUID = 158_768_216_759_107L;
/**
* Current Locale
*/
private Locale locale;
- @Override
+ /**
+ * Event being fired when a locale has changed successfully
+ */
+ @Inject
+ @Any
+ private Event<ObservableLocaleChangeEvent> localeChangeEvent;
+
+ /**
+ * Locale code (example: de for Germany)
+ */
+ private String localeCode;
+
+ /**
+ * A map of all supported locales, using language code as key
+ */
+ private final Map<String, Locale> supportedLocales;
+
+ /**
+ * Default constructor
+ */
+ public JobsLocalizationSessionBean () {
+ // Call super constructor
+ super();
+
+ // Init locale list
+ this.supportedLocales = new LinkedHashMap<>(2);
+ }
+
+ /**
+ * Event observer for logged-in user
+ * <p>
+ * @param event Event instance
+ */
public void afterUserLoginEvent (@Observes final ObservableUserLoggedInEvent event) {
- // event should not be null
+ // Event and contained entity instance should not be null
if (null == event) {
// Throw NPE
throw new NullPointerException("event is null"); //NOI18N
// Is the locale set?
if (event.getLoggedInUser().getUserLocale() instanceof Locale) {
- // Set locale here
- this.setLocale(event.getLoggedInUser().getUserLocale());
+ // Get user local
+ final Locale userLocale = event.getLoggedInUser().getUserLocale();
+
+ // Change locale
+ this.changeLocale(userLocale, Boolean.TRUE);
}
}
- @Override
+ /**
+ * Event observer for logged-out user
+ * <p>
+ * @param event Event instance
+ */
public void afterUserLogoutEvent (@Observes final ObservableUserLogoutEvent event) {
- // event should not be null
+ // Event and contained entity instance should not be null
if (null == event) {
// Throw NPE
throw new NullPointerException("event is null"); //NOI18N
throw new IllegalArgumentException(MessageFormat.format("userId of user={0} is not valid: {1}", event.getLoggedOutUser(), event.getLoggedOutUser().getUserId())); //NOI18N
}
- // Trace message
- //* NOISY-DEBUG: */ System.out.println("LandingLocalizationSessionBean:afterUserLogin - EXIT!"); //NOI18N
+ // Clear this bean as well
+ this.clear();
}
- @Override
- public String getLanguage () {
- //* NOISY-DEBUG: */ System.out.println(MessageFormat.format("JobsLocalizationSessionBean::getLanguage(): locale.language={0} - EXIT!", this.getLocale().getLanguage())); //NOI18N
- return this.getLocale().getLanguage().toLowerCase();
- }
-
- @Override
- public void setLanguage (final String language) {
- // Log trace message
- //* NOISY-DEBUG: */ System.out.println(MessageFormat.format("JobsLocalizationSessionBean::setLanguage: language={0} - CALLED!", language)); //NOI18N
-
- // Is the language null?
- if (null == language) {
- // This may sometimes happen, so abort here
- return;
+ /**
+ * Changes locale in application
+ */
+ public void doChangeLocale () {
+ // Is locale code set?
+ if (this.getLocaleCode() == null) {
+ // Throw NPE
+ throw new NullPointerException("this.localeCode is null"); //NOI18N
+ } else if (this.getLocaleCode().isEmpty()) {
+ // Throw IAE
+ throw new IllegalArgumentException("this.localeCode is empty"); //NOI18N
}
- // Language splits
- String[] splits = language.split("_"); //NOI18N
- if (null == splits[1]) {
- splits[1] = ""; //NOI18N
+ // Default new locale is null, will be handled later
+ Locale newLocale = null;
+
+ // Iterate over whole map
+ for (final Map.Entry<String, Locale> entry : this.getSupportedLocales().entrySet()) {
+ final Locale foundLocale = entry.getValue();
+
+ // Does the language match?
+ if (Objects.equals(foundLocale.toString(), this.getLocaleCode())) {
+ // Is found, take it as request locale
+ newLocale = foundLocale;
+ break;
+ }
}
- // Get new locale with upper-case country code
- Locale loc = new Locale(splits[0], splits[1]);
+ // Clear locale code field
+ this.clear();
- // Log debug message
- //* NOISY-DEBUG: */ System.out.println(MessageFormat.format("JobsLocalizationSessionBean::setLanguage: loc={0}", loc)); //NOI18N
+ // Has a matching locale
+ if (null == newLocale) {
+ // Throw NPE
+ throw new NullPointerException("this.localeCode=" + this.getLocaleCode() + " cannot be found."); //NOI18N
+ }
+
+ // Then change it
+ this.changeLocale(newLocale, Boolean.TRUE);
- // Set it here and in the JSF context
- this.setLocale(loc);
- FacesContext.getCurrentInstance().getViewRoot().setLocale(loc);
+ // Change formatting
+ NUMBER_FORMAT = NumberFormat.getNumberInstance(newLocale);
+ }
- // Log trace message
- //* NOISY-DEBUG: */ System.out.println("JobsLocalizationSessionBean::setLanguage: EXIT!"); //NOI18N
+ @Override
+ public String formatCurrency (final Float amount) {
+ // Format amount
+ return NUMBER_FORMAT.format(amount);
}
@Override
public Locale getLocale () {
- //* NOISY-DEBUG: */ System.out.println(MessageFormat.format("JobsLocalizationSessionBean::getLocale(): locale={0} - EXIT!", this.locale)); //NOI18N
return this.locale;
}
- @Override
+ /**
+ * Setter for locale
+ * <p>
+ * @param locale Locale
+ */
public void setLocale (final Locale locale) {
- //* NOISY-DEBUG: */ System.out.println(MessageFormat.format("JobsLocalizationSessionBean::setLocale(): locale={0} - CALLED!", locale)); //NOI18N
this.locale = locale;
}
- @Override
- public Locale[] getSelectableLocalizations () {
- Locale[] locales = {
- Locale.GERMANY,
- Locale.US
- };
- return locales;
+ /**
+ * Getter for localeCode code
+ * <p>
+ * @return Language code
+ */
+ public String getLocaleCode () {
+ return this.localeCode;
+ }
+
+ /**
+ * Setter for localeCode code
+ * <p>
+ * @param localeCode Language code
+ */
+ public void setLocaleCode (final String localeCode) {
+ this.localeCode = localeCode;
+ }
+
+ /**
+ * Getter for selectable localizations
+ * <p>
+ * @return Selectable localizations
+ */
+ @SuppressWarnings ("ReturnOfCollectionOrArrayField")
+ public Map<String, Locale> getSupportedLocales () {
+ // Return full list
+ return this.supportedLocales;
}
/**
*/
@PostConstruct
public void init () {
- // Log trace message
- //* NOISY-DEBUG: */ System.out.println("JobsLocalizationSessionBean::init: CALLED!"); //NOI18N
+ // Get default locale
+ final Locale defaultLocale = FacesContext.getCurrentInstance().getApplication().getDefaultLocale();
+
+ // Add it to list
+ this.getSupportedLocales().put(defaultLocale.toString(), defaultLocale);
+
+ // Get iterator from faces context
+ final Iterator<Locale> iterator = FacesContext.getCurrentInstance().getApplication().getSupportedLocales();
+
+ // Add all locales
+ while (iterator.hasNext()) {
+ // Get next locale
+ Locale supportedLocale = iterator.next();
+
+ // Add it
+ this.getSupportedLocales().put(supportedLocale.toString(), supportedLocale);
+ }
- // Create locale instance from context
- Locale loc = FacesContext.getCurrentInstance().getExternalContext().getRequestLocale();
+ // Get locale instance from request (e.g. browser)
+ Locale requestLocale = FacesContext.getCurrentInstance().getExternalContext().getRequestLocale();
- // Log debug message
- //* NOISY-DEBUG: */ System.out.println(MessageFormat.format("JobsLocalizationSessionBean::init: loc={0}", loc)); //NOI18N
+ // Is no country code found?
+ if (requestLocale.getCountry().isEmpty()) {
+ // Then try to find one, get language from it
+ final String language = requestLocale.getLanguage();
+ Boolean found = Boolean.FALSE;
- // Set it here
- this.setLocale(loc);
+ // Iterate over whole map
+ for (final Map.Entry<String, Locale> entry : this.getSupportedLocales().entrySet()) {
+ final String languageCode = entry.getKey();
+ final Locale foundLocale = entry.getValue();
- // Log trace message
- //* NOISY-DEBUG: */ System.out.println("JobsLocalizationSessionBean::init: EXIT!"); //NOI18N
+ // Does the language match?
+ if (languageCode.startsWith(language)) {
+ // Is found, take it as request locale
+ requestLocale = foundLocale;
+ found = Boolean.TRUE;
+ break;
+ }
+ }
+
+ // Nothing found?
+ if (!found) {
+ // Then set default locale
+ requestLocale = defaultLocale;
+ }
+ }
+
+ // Change locale, may set same back in faces context, but triggers event
+ this.changeLocale(requestLocale, Boolean.FALSE);
+
+ // Initial formatting, may change when user chooses other locale
+ NUMBER_FORMAT = NumberFormat.getNumberInstance(this.locale);
+ }
+
+ /**
+ * Changes current locale in this controller and faces context to given.
+ * This method makes sure that locales with at least language and country
+ * information are being changed to.
+ * <p>
+ * @param locale New locale to set
+ * @param notifyBeans Whether to notify other beans
+ */
+ private void changeLocale (final Locale locale, final Boolean notifyBeans) {
+ // Is the locale language_country at least?
+ if (null == locale) {
+ // Throw NPE
+ throw new NullPointerException("locale is null"); //NOI18N
+ } else if (!locale.toString().contains("_")) { //NOI18N
+ // Throw IAE
+ throw new IllegalArgumentException(MessageFormat.format("locale={0} does not have country information set.", locale)); //NOI18N
+ }
+
+ // Set locale + code here
+ this.setLocale(locale);
+ this.setLocaleCode(locale.toString());
+
+ // Inform faces context
+ FacesContext.getCurrentInstance().getViewRoot().setLocale(locale);
+
+ // Notify other beans?
+ if (notifyBeans) {
+ // Fire event
+ this.localeChangeEvent.fire(new LocaleChangeEvent(locale));
+ }
+ }
+
+ /**
+ * Clears this bean
+ */
+ private void clear () {
+ // Clear all fields
+ this.setLocaleCode(null);
+ this.setLocale(null);
}
}