/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.xwiki.localization.jar.internal;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Enumeration;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.apache.commons.collections.EnumerationUtils;
import org.xwiki.component.annotation.Component;
import org.xwiki.localization.TranslationBundleContext;
import org.xwiki.localization.internal.AbstractCachedTranslationBundle;
import org.xwiki.localization.internal.DefaultLocalizedTranslationBundle;
import org.xwiki.localization.internal.DefaultTranslation;
import org.xwiki.localization.internal.LocalizedTranslationBundle;
import org.xwiki.localization.message.TranslationMessage;
import org.xwiki.localization.message.TranslationMessageParser;
/**
* Provide translations coming from the root {@link ClassLoader}.
*
* @version $Id: ceecec30802ef07676521733b4576d26d9836d95 $
* @since 4.5M1
*/
@Component
@Named("rootclassloader")
@Singleton
public class RootClassLoaderTranslationBundle extends AbstractCachedTranslationBundle
{
/**
* The parser to use for each message.
*/
@Inject
@Named("messagetool/1.0")
private TranslationMessageParser parser;
/**
* Used to access the current bundles.
*/
@Inject
private TranslationBundleContext bundleContext;
@Override
protected LocalizedTranslationBundle createBundle(Locale locale)
{
Properties properties = getResourceProperties(locale);
if (properties == null) {
return LocalizedTranslationBundle.EMPTY;
}
// Convert to LocalBundle
DefaultLocalizedTranslationBundle localeBundle = new DefaultLocalizedTranslationBundle(this, locale);
for (Map.Entry<Object, Object> entry : properties.entrySet()) {
if (entry.getKey() instanceof String && entry.getValue() instanceof String) {
String key = (String) entry.getKey();
String message = (String) entry.getValue();
TranslationMessage translationMessage = this.parser.parse(message);
localeBundle.addTranslation(new DefaultTranslation(this.bundleContext, localeBundle, key,
translationMessage));
}
}
return localeBundle;
}
/**
* @param locale the locale to search for
* @return the content of all the resources files associated to the provided locale
*/
private Properties getResourceProperties(Locale locale)
{
String resourceName = "ApplicationResources";
if (!locale.equals(Locale.ROOT)) {
resourceName += "_" + locale;
}
resourceName += ".properties";
Enumeration<URL> urls;
try {
urls = getClass().getClassLoader().getResources(resourceName);
} catch (IOException e) {
this.logger.error("Failed to get resource URLs from class loader for name [{}]", resourceName, e);
return null;
}
if (!urls.hasMoreElements()) {
return null;
}
List<URL> urlList = EnumerationUtils.toList(urls);
Properties properties = new Properties();
// Load resources in reverse order to give priority to first found resources (follow ClassLoader#getResource
// behavior)
for (ListIterator<URL> it = urlList.listIterator(urlList.size()); it.hasPrevious();) {
URL url = it.previous();
try {
InputStream componentListStream = url.openStream();
try {
properties.load(componentListStream);
} finally {
componentListStream.close();
}
} catch (IOException e) {
this.logger.error("Failed to parse resource [{}] as translation budle", url, e);
}
}
return properties;
}
}