/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library 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 library 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.
*/
package com.liferay.portal.language.extender.internal;
import com.liferay.osgi.util.ServiceTrackerFactory;
import com.liferay.portal.kernel.util.AggregateResourceBundle;
import com.liferay.portal.kernel.util.CacheResourceBundleLoader;
import com.liferay.portal.kernel.util.LocaleUtil;
import com.liferay.portal.kernel.util.ResourceBundleLoader;
import com.liferay.portal.kernel.util.ResourceBundleUtil;
import com.liferay.portal.kernel.util.Validator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import org.apache.felix.utils.extender.Extension;
import org.apache.felix.utils.log.Logger;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.wiring.BundleCapability;
import org.osgi.framework.wiring.BundleWiring;
import org.osgi.util.tracker.ServiceTracker;
/**
* @author Carlos Sierra Andrés
*/
public class LanguageExtension implements Extension {
public LanguageExtension(
BundleContext bundleContext, Bundle bundle,
List<BundleCapability> bundleCapabilities, Logger logger) {
_bundleContext = bundleContext;
_bundle = bundle;
_bundleCapabilities = bundleCapabilities;
_logger = logger;
}
@Override
public void destroy() throws Exception {
for (ServiceRegistration<ResourceBundleLoader> serviceRegistration :
_serviceRegistrations) {
serviceRegistration.unregister();
}
}
@Override
public void start() throws Exception {
BundleWiring bundleWiring = _bundle.adapt(BundleWiring.class);
for (BundleCapability capability : _bundleCapabilities) {
Map<String, Object> attributes = capability.getAttributes();
Object aggregate = attributes.get("resource.bundle.aggregate");
Object baseName = attributes.get("resource.bundle.base.name");
ResourceBundleLoader resourceBundleLoader = null;
if (aggregate instanceof String) {
resourceBundleLoader = processAggregate((String)aggregate);
}
else if (baseName instanceof String) {
resourceBundleLoader = processBaseName(
bundleWiring.getClassLoader(), (String)baseName);
}
if (resourceBundleLoader != null) {
registerResourceBundleLoader(attributes, resourceBundleLoader);
}
else {
_logger.log(
Logger.LOG_WARNING,
"Unable to handle " + capability + " in " +
_bundle.getSymbolicName());
}
}
}
protected ResourceBundleLoader processAggregate(String aggregate) {
String[] filterStrings = aggregate.split(",");
List<ServiceTracker<ResourceBundleLoader, ResourceBundleLoader>>
serviceTrackers = new ArrayList<>(filterStrings.length);
for (String filterString : filterStrings) {
filterString =
"(&(objectClass=" + ResourceBundleLoader.class.getName() + ")" +
filterString + ")";
ServiceTracker<ResourceBundleLoader, ResourceBundleLoader>
serviceTracker = ServiceTrackerFactory.open(
_bundleContext, filterString);
serviceTrackers.add(serviceTracker);
}
return new ServiceTrackerResourceBundleLoader(serviceTrackers);
}
protected ResourceBundleLoader processBaseName(
ClassLoader classLoader, String baseName) {
return new CacheResourceBundleLoader(
ResourceBundleUtil.getResourceBundleLoader(baseName, classLoader));
}
protected void registerResourceBundleLoader(
Map<String, Object> attributes,
ResourceBundleLoader resourceBundleLoader) {
Dictionary<String, Object> properties = new Hashtable<>(attributes);
if (Validator.isNull(properties.get("bundle.symbolic.name"))) {
properties.put("bundle.symbolic.name", _bundle.getSymbolicName());
}
if (Validator.isNull(properties.get("service.ranking"))) {
properties.put("service.ranking", Integer.MIN_VALUE);
}
_serviceRegistrations.add(
_bundleContext.registerService(
ResourceBundleLoader.class, resourceBundleLoader, properties));
}
private final Bundle _bundle;
private final List<BundleCapability> _bundleCapabilities;
private final BundleContext _bundleContext;
private final Logger _logger;
private final Collection<ServiceRegistration<ResourceBundleLoader>>
_serviceRegistrations = new ArrayList<>();
private static class ServiceTrackerResourceBundleLoader
implements ResourceBundleLoader {
public ServiceTrackerResourceBundleLoader(
List<ServiceTracker<ResourceBundleLoader, ResourceBundleLoader>>
serviceTrackers) {
_serviceTrackers = serviceTrackers;
}
@Override
public ResourceBundle loadResourceBundle(Locale locale) {
List<ResourceBundle> resourceBundles = new ArrayList<>();
for (ServiceTracker<ResourceBundleLoader, ResourceBundleLoader>
serviceTracker : _serviceTrackers) {
ResourceBundleLoader resourceBundleLoader =
serviceTracker.getService();
ResourceBundle resourceBundle =
resourceBundleLoader.loadResourceBundle(locale);
if (resourceBundle != null) {
resourceBundles.add(resourceBundle);
}
}
if (resourceBundles.isEmpty()) {
return null;
}
if (resourceBundles.size() == 1) {
return resourceBundles.get(0);
}
return new AggregateResourceBundle(
resourceBundles.toArray(
new ResourceBundle[resourceBundles.size()]));
}
/**
* @deprecated As of 2.0.0, replaced by {@link #loadResourceBundle(
* Locale)}
*/
@Deprecated
public ResourceBundle loadResourceBundle(String languageId) {
return loadResourceBundle(LocaleUtil.fromLanguageId(languageId));
}
private final
List<ServiceTracker<ResourceBundleLoader, ResourceBundleLoader>>
_serviceTrackers;
}
}