/* * Copyright 2008-2014 the original author or authors * * Licensed 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 * * 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.kaleidofoundry.core.i18n; import static org.kaleidofoundry.core.env.model.EnvironmentConstants.I18N_JPA_ACTIVATION_PROPERTY; import static org.kaleidofoundry.core.env.model.EnvironmentConstants.STATIC_ENV_PARAMETERS; import static org.kaleidofoundry.core.i18n.I18nContextBuilder.BaseName; import static org.kaleidofoundry.core.i18n.I18nContextBuilder.ClassLoaderClass; import static org.kaleidofoundry.core.i18n.I18nContextBuilder.LocaleCountry; import static org.kaleidofoundry.core.i18n.I18nContextBuilder.LocaleLanguage; import java.util.Locale; import java.util.ResourceBundle; import org.kaleidofoundry.core.context.AbstractProviderService; import org.kaleidofoundry.core.context.EmptyContextParameterException; import org.kaleidofoundry.core.context.IllegalContextParameterException; import org.kaleidofoundry.core.context.RuntimeContext; import org.kaleidofoundry.core.lang.annotation.NotNull; import org.kaleidofoundry.core.util.Registry; import org.kaleidofoundry.core.util.StringHelper; import org.kaleidofoundry.core.util.locale.LocaleFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author jraduget */ public class I18nMessagesProvider extends AbstractProviderService<I18nMessages> { private static final Logger LOGGER = LoggerFactory.getLogger(I18nMessagesProvider.class); /** * @param genericClassInterface */ public I18nMessagesProvider(final Class<I18nMessages> genericClassInterface) { super(genericClassInterface); } /* * (non-Javadoc) * @see org.kaleidofoundry.core.context.AbstractProviderService#getRegistry() */ @Override protected Registry<String, I18nMessages> getRegistry() { throw new IllegalStateException("I18nMessages registry is managed by java ResourceBundle api"); } /* * (non-Javadoc) * @see org.kaleidofoundry.core.context.ProviderService#_provides(org.kaleidofoundry.core.context.RuntimeContext) */ @Override public I18nMessages _provides(@NotNull final RuntimeContext<I18nMessages> context) { String baseName = context.getString(BaseName); final String localeLanguageCode = context.getString(LocaleLanguage); final String countryLanguageCode = context.getString(LocaleCountry); final String classLoaderClass = context.getString(ClassLoaderClass); ClassLoader classLoader = null; Locale locale = null; // default baseName is not defined if (StringHelper.isEmpty(baseName)) { if (StringHelper.isEmpty(context.getName())) { throw new EmptyContextParameterException(BaseName, context); } baseName = "i18n/" + context.getName(); } // managed classloader context try { classLoader = StringHelper.isEmpty(classLoaderClass) ? null : Class.forName(classLoaderClass).getClassLoader(); } catch (final ClassNotFoundException cnfe) { throw new IllegalContextParameterException(ClassLoaderClass, classLoaderClass, context, cnfe); } // managed locale language & country context if (!StringHelper.isEmpty(localeLanguageCode) && !StringHelper.isEmpty(countryLanguageCode)) { locale = new Locale(localeLanguageCode, countryLanguageCode); } else if (!StringHelper.isEmpty(localeLanguageCode) && StringHelper.isEmpty(countryLanguageCode)) { locale = new Locale(localeLanguageCode, defaultLocale().getCountry()); } else if (StringHelper.isEmpty(localeLanguageCode) && !StringHelper.isEmpty(countryLanguageCode)) { locale = new Locale(defaultLocale().getLanguage(), countryLanguageCode); } return getBundle(baseName, locale, classLoader, null, context); } /** * @param baseName name of the resource * @return ResourceBundle with server default locale, and with properties loaded from the same classLoader than ResourceBundle class */ public I18nMessages provides(@NotNull final String baseName) { return getBundle(baseName, null, null, null, new RuntimeContext<I18nMessages>(I18nMessages.class)); } /** * @param baseName name of the resource * @param context runtime context * @return ResourceBundle with server default locale, and with properties loaded from the same classLoader than ResourceBundle class */ public I18nMessages provides(@NotNull final String baseName, final RuntimeContext<I18nMessages> context) { return getBundle(baseName, null, null, null, context); } /** * @param baseName name of the resource * @param locale specified locale * @return ResourceBundle with specified locale, and with properties loaded from the same classLoader than ResourceBundle class */ public I18nMessages provides(@NotNull final String baseName, @NotNull final Locale locale) { return getBundle(baseName, locale, null, null, new RuntimeContext<I18nMessages>(I18nMessages.class)); } /** * @param baseName name of the resource * @param parent parent ResourceBundle * @return ResourceBundle with server default locale having a parent resource bundle */ public I18nMessages provides(@NotNull final String baseName, final I18nMessages parent) { return getBundle(baseName, null, null, (ResourceBundle) parent, new RuntimeContext<I18nMessages>(I18nMessages.class)); } /** * @param baseName name of the resource * @param parent parent ResourceBundle * @return ResourceBundle build with given locale, and having a parent resource bundle */ public I18nMessages provides(@NotNull final String baseName, final ResourceBundle parent) { return getBundle(baseName, null, null, parent, new RuntimeContext<I18nMessages>(I18nMessages.class)); } /** * @param baseName * @param locale * @param parent parent ResourceBundle * @return ResourceBundle with server default locale having a parent resource bundle */ public I18nMessages provides(@NotNull final String baseName, @NotNull final Locale locale, final ResourceBundle parent) { return getBundle(baseName, locale, null, parent, new RuntimeContext<I18nMessages>(I18nMessages.class)); } /** * @param baseName * @param locale * @param parent parent ResourceBundle * @return ResourceBundle build with given locale, and having a parent resource bundle */ public I18nMessages provides(@NotNull final String baseName, @NotNull final Locale locale, final I18nMessages parent) { return getBundle(baseName, locale, null, (ResourceBundle) parent, new RuntimeContext<I18nMessages>(I18nMessages.class)); } /** * @param baseName name of the resource * @param locale specified locale * @param loader target class loader * @param parent resourceBundle parent * @return ResourceBundle build with given locale, and having a parent resource bundle */ public I18nMessages provides(@NotNull final String baseName, @NotNull final Locale locale, final ClassLoader loader, final I18nMessages parent) { return getBundle(baseName, locale, loader, (ResourceBundle) parent, new RuntimeContext<I18nMessages>(I18nMessages.class)); } /** * @param baseName name of the resource * @param locale specified locale * @param loader target class loader * @return ResourceBundle with specified locale, and with properties loaded from specified classLoader */ public I18nMessages provides(@NotNull final String baseName, @NotNull final Locale locale, final ClassLoader loader) { return getBundle(baseName, locale, loader, null, new RuntimeContext<I18nMessages>(I18nMessages.class)); } /** * it clear internal java resource bundle cache<br/> * <br/> * when you call multiple times {@link #provides(String)}, jdk use an internal cache to get the current bundle * once you call {@link #clearCache()}, then next call to {@link #provides(String)} will instantiate / load ... a new * {@link DefaultMessageBundle} * * @see ResourceBundle#clearCache() */ public static void clearCache() { LOGGER.info("Clear all resources bundles caches"); ResourceBundle.clearCache(); ResourceBundle.clearCache(I18nMessagesFactory.class.getClassLoader()); } /* * Build full base name of a class, using its package name and class name */ static String buildBaseName(final Class<?> baseClass) { final StringBuilder str = new StringBuilder(); if (baseClass.getClass().getPackage() != null) { str.append(baseClass.getClass().getPackage().getName()).append("."); } str.append(baseClass.getCanonicalName()); return str.toString(); } /** * @param baseName name of the resource * @param locale specified locale * @param loader target class loader * @param parent resourceBundle parent * @param context runtime context * @return ResourceBundle build with given locale, and having a parent resource bundle */ static I18nMessages getBundle(@NotNull final String baseName, final Locale locale, final ClassLoader loader, final ResourceBundle parent, @NotNull final RuntimeContext<I18nMessages> context) { final DefaultMessageBundle bundle = (DefaultMessageBundle) ResourceBundle.getBundle(baseName, locale != null ? locale : defaultLocale(), loader != null ? loader : DefaultMessageBundle.class.getClassLoader(), new MessageBundleControl(context)); bundle.setParent(parent); return bundle; } /** * enable the jpa resource bundle control resolver */ public static void enableJpaControl() { STATIC_ENV_PARAMETERS.put(I18N_JPA_ACTIVATION_PROPERTY, Boolean.TRUE.toString()); } /** * disable the jpa resource bundle control resolver */ public static void disableJpaControl() { STATIC_ENV_PARAMETERS.put(I18N_JPA_ACTIVATION_PROPERTY, Boolean.FALSE.toString()); } /** * @return do JPA is enable to get and persist i18n messages bundle */ public static boolean isJpaEnabledForI18n() { String result = STATIC_ENV_PARAMETERS.get(I18N_JPA_ACTIVATION_PROPERTY); if (result == null) { return false; } else { return Boolean.valueOf(result); } } /** * @return Default user or server local */ @NotNull static Locale defaultLocale() { return LocaleFactory.getDefaultFactory().getCurrentLocale(); } }