Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* #%L
* Wisdom-Framework
* %%
* Copyright (C) 2013 - 2014 Wisdom Framework
* %%
* 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.
* #L%
*/
package org.wisdom.i18n;
import org.apache.felix.ipojo.annotations.*;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.util.tracker.BundleTracker;
import org.osgi.util.tracker.BundleTrackerCustomizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wisdom.api.configuration.ApplicationConfiguration;
import org.wisdom.api.i18n.InternationalizationService;
import java.util.*;
/**
* The default implementation of the internationalization service. It analyses bundles,
* and loads resource bundles from files contained in the 'i18n' folder of the bundle. The locale is extracted from
* the file name as follows: name_locale.properties. For example, app.properties is using the default locale,
* while app_fr is using the French locale. Resource bundles are loaded in UTF-8.
*/
@Component
@Provides(specifications = InternationalizationService.class)
@Instantiate
public class InternationalizationServiceSingleton implements InternationalizationService,
BundleTrackerCustomizer> {
private static final Logger LOGGER = LoggerFactory.getLogger(InternationalizationService.class);
private final BundleContext context;
private final Locale defaultLocale;
@Requires
ApplicationConfiguration configuration;
/**
* The managed extensions.
*/
private List extensions = new ArrayList<>();
private BundleTracker> tracker;
public InternationalizationServiceSingleton(BundleContext context) {
this.context = context;
// configuration is null in unit tests (on purpose).
if (configuration != null) {
this.defaultLocale = Locale.forLanguageTag(getDefaultLocale());
} else {
this.defaultLocale = null;
}
}
protected String getDefaultLocale() {
return configuration.getWithDefault(APPLICATION_DEFAULT_LOCALE,
configuration.getWithDefault(APPLICATION_DEFAULT_LOCALE_OLD, Locale.ENGLISH.toLanguageTag()));
}
@Validate
public void start() {
tracker = new BundleTracker<>(context, Bundle.ACTIVE, this);
tracker.open();
}
@Invalidate
public void stop() {
if (tracker != null) {
tracker.close();
}
extensions.clear();
}
/**
* Retrieves the default locale as configured by the application.
*
* @return the default locale
*/
@Override
public Locale defaultLocale() {
if (defaultLocale == null) {
return InternationalizationService.DEFAULT_LOCALE;
}
return defaultLocale;
}
/**
* Retrieves the set of resource bundles handled by the system.
*
* @return the set of resource bundle, empty if none.
*/
@Override
public Collection bundles() {
Set bundles = new LinkedHashSet<>();
for (I18nExtension extension : extensions) {
bundles.add(extension.bundle());
}
return bundles;
}
/**
* Retrieves the set of resource bundles handled by the system providing messages for the given locale.
*
* @param locale the locale
* @return the set of resource bundle, empty if none.
*/
@Override
public Collection bundles(Locale locale) {
Set bundles = new LinkedHashSet<>();
for (I18nExtension extension : extensions) {
if (extension.locale().equals(locale)) {
bundles.add(extension.bundle());
}
}
return bundles;
}
/**
* Gets the message identified by `key` for the first locale from the given set of locale that provide a value.
* The message can be parameterized using `args`, applied to the message using {@link java.text.MessageFormat}.
* If the message is not provided for the given locales, the default locale is tried. If the message is still not
* provided, {@literal null} is returned.
*
* @param locales the ordered set of locales
* @param key the key
* @param args the arguments (optional)
* @return the formatted internationalized message
*/
public String get(Locale[] locales, String key, Object... args) {
for (Locale locale : locales) {
I18nExtension extension = getExtension(locale, key);
if (extension != null) {
return extension.get(key, args);
}
}
// Use default.
I18nExtension extension = getExtension(InternationalizationService.DEFAULT_LOCALE, key);
if (extension != null) {
return extension.get(key, args);
}
return null;
}
/**
* Gets the message identified by `key` for the given locale. The message can be parameterized using `args`,
* applied to the message using {@link java.text.MessageFormat}. If the message is not provided for the given
* locale, the default locale is tried. If the message is still not provided, {@literal null} is returned.
*
* @param locale the locale
* @param key the key
* @param args the arguments (optional)
* @return the formatted internationalized message
*/
@Override
public String get(Locale locale, String key, Object... args) {
I18nExtension extension = getExtension(locale, key);
if (extension != null) {
return extension.get(key, args);
}
extension = getExtension(InternationalizationService.DEFAULT_LOCALE, key);
if (extension != null) {
return extension.get(key, args);
}
return null;
}
/**
* Gets all the messages defined in the given locale AND default locale (for messages not defined in the given
* locale). The returned map is composed pair of key:message.
*
* @param locale the locale
* @return the set of defined messages.
*/
public Map getAllMessages(Locale locale) {
return getAllMessages(new Locale[]{locale});
}
/**
* Gets all the messages defined in the given locales AND default locale (for messages not defined in the given
* any locale). The message are added to the map only if they are not provided in the previous locale,
* meaning that the order is important. The returned map is composed pair of key:message.
*
* @param locales the ordered set of locales
* @return the set of defined messages.
*/
@Override
public Map getAllMessages(Locale... locales) {
Map messages = new HashMap<>();
List extensionForLocale;
for (Locale locale : locales) {
extensionForLocale = getExtension(locale);
for (I18nExtension extension : extensionForLocale) {
merge(messages, extension.map());
}
}
// Now add the messages for the default locale
extensionForLocale = getExtension(DEFAULT_LOCALE);
for (I18nExtension extension : extensionForLocale) {
merge(messages, extension.map());
}
return messages;
}
private void merge(Map map1, Map map2) {
for (Map.Entry entry : map2.entrySet()) {
if (!map1.containsKey(entry.getKey())) {
map1.put(entry.getKey(), entry.getValue());
}
}
}
private List getExtension(Locale locale) {
if (locale.equals(defaultLocale)) {
locale = InternationalizationService.DEFAULT_LOCALE;
}
List list = new ArrayList<>();
for (I18nExtension extension : extensions) {
if (extension.locale().equals(locale)) {
list.add(extension);
} else if (locale.equals(defaultLocale) && extension.locale().equals(DEFAULT_LOCALE)) {
list.add(extension);
}
}
return list;
}
private I18nExtension getExtension(Locale locale, String key) {
if (locale.equals(defaultLocale)) {
locale = InternationalizationService.DEFAULT_LOCALE;
}
for (I18nExtension extension : extensions) {
if (extension.locale().equals(locale)
&& extension.keys().contains(key)) {
return extension;
}
}
return null;
}
/**
* A bundle is being added to the {@code BundleTracker}.
*
*
* This method is called before a bundle which matched the search parameters
* of the {@code BundleTracker} is added to the
* {@code BundleTracker}. This method should return the object to be
* tracked for the specified {@code Bundle}. The returned object is
* stored in the {@code BundleTracker} and is available from the
* {@link org.osgi.util.tracker.BundleTracker#getObject(org.osgi.framework.Bundle) getObject} method.
*
* @param bundle The {@code Bundle} being added to the
* {@code BundleTracker}.
* @param event The bundle event which caused this customizer method to be
* called or {@code null} if there is no bundle event associated
* with the call to this method.
* @return The object to be tracked for the specified {@code Bundle}
* object or {@code null} if the specified {@code Bundle}
* object should not be tracked.
*/
@Override
public List addingBundle(Bundle bundle, BundleEvent event) {
List list = ExtenderUtils.analyze("/i18n/", bundle);
if (list.isEmpty()) {
return null;
}
LOGGER.info(list.size() + " resource bundle(s) loaded from {} ({})", bundle.getSymbolicName(),
bundle.getBundleId());
extensions.addAll(list);
return list;
}
/**
* A bundle tracked by the {@code BundleTracker} has been modified.
*
*
* This method is called when a bundle being tracked by the
* {@code BundleTracker} has had its state modified.
*
* @param bundle The {@code Bundle} whose state has been modified.
* @param event The bundle event which caused this customizer method to be
* called or {@code null} if there is no bundle event associated
* with the call to this method.
* @param object The tracked object for the specified bundle.
*/
@Override
public void modifiedBundle(Bundle bundle, BundleEvent event, List object) {
// Not supported.
}
/**
* A bundle tracked by the {@code BundleTracker} has been removed.
*
*
* This method is called after a bundle is no longer being tracked by the
* {@code BundleTracker}.
*
* @param bundle The {@code Bundle} that has been removed.
* @param event The bundle event which caused this customizer method to be
* called or {@code null} if there is no bundle event associated
* with the call to this method.
* @param list The tracked object for the specified bundle.
*/
@Override
public void removedBundle(Bundle bundle, BundleEvent event, List list) {
for (I18nExtension extension : list) {
synchronized (this) {
extensions.remove(extension);
}
}
LOGGER.info("Bundle {} ({}) does not offer the {} resource bundle(s) anymore",
bundle.getSymbolicName(), bundle.getBundleId(), list.size());
}
}