/**
* 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.servlet.filter.internal;
import com.liferay.osgi.util.ServiceTrackerFactory;
import com.liferay.portal.kernel.util.AggregateResourceBundle;
import com.liferay.portal.kernel.util.LocaleUtil;
import com.liferay.portal.kernel.util.ResourceBundleLoader;
import com.liferay.portal.kernel.util.ResourceBundleLoaderUtil;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.http.context.ServletContextHelper;
import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
/**
* @author Carlos Sierra Andrés
*/
@Component(immediate = true)
public class LanguageFilterTracker {
@Activate
protected void activate(final BundleContext bundleContext) {
_serviceTracker = new ServiceTracker<>(
bundleContext, ServletContextHelper.class,
new ServletContextHelperServiceTrackerCustomizer(bundleContext));
_serviceTracker.open();
}
@Deactivate
protected void deactivate() {
_serviceTracker.close();
}
private ServiceTracker<ServletContextHelper, ServiceTracker<?, ?>>
_serviceTracker;
private static class ServiceTrackerResourceBundleLoader
implements ResourceBundleLoader {
public ServiceTrackerResourceBundleLoader(
ServiceTracker<ResourceBundleLoader, ResourceBundleLoader>
serviceTracker) {
_serviceTracker = serviceTracker;
}
@Override
public ResourceBundle loadResourceBundle(Locale locale) {
ResourceBundleLoader resourceBundleLoader =
_serviceTracker.getService();
ResourceBundleLoader portalResourceBundleLoader =
ResourceBundleLoaderUtil.getPortalResourceBundleLoader();
if (resourceBundleLoader != null) {
ResourceBundle resourceBundle =
resourceBundleLoader.loadResourceBundle(locale);
if (resourceBundle != null) {
return new AggregateResourceBundle(
resourceBundle,
portalResourceBundleLoader.loadResourceBundle(locale));
}
}
return portalResourceBundleLoader.loadResourceBundle(locale);
}
/**
* @deprecated As of 2.0.0, replaced by {@link #loadResourceBundle(
* Locale)}
*/
@Deprecated
public ResourceBundle loadResourceBundle(String languageId) {
return loadResourceBundle(LocaleUtil.fromLanguageId(languageId));
}
private final ServiceTracker<ResourceBundleLoader, ResourceBundleLoader>
_serviceTracker;
}
private class ServletContextHelperServiceTrackerCustomizer
implements
ServiceTrackerCustomizer
<ServletContextHelper, ServiceTracker<?, ?>> {
public ServletContextHelperServiceTrackerCustomizer(
BundleContext bundleContext) {
_bundleContext = bundleContext;
}
@Override
public ServiceTracker<?, ?> addingService(
ServiceReference<ServletContextHelper> serviceReference) {
Bundle bundle = serviceReference.getBundle();
String filterString =
"(&(bundle.symbolic.name=" + bundle.getSymbolicName() +
")(objectClass=" + ResourceBundleLoader.class.getName() +
")(resource.bundle.base.name=*))";
Map<String, Object> properties = new HashMap<>();
properties.put("service.ranking", Integer.MIN_VALUE);
Object contextName = serviceReference.getProperty(
HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME);
properties.put("servlet.context.name", contextName);
return ServiceTrackerFactory.open(
bundle.getBundleContext(), filterString,
new ResourceBundleLoaderServiceTrackerCustomizer(
properties, filterString, contextName));
}
@Override
public void modifiedService(
ServiceReference<ServletContextHelper> serviceReference,
ServiceTracker<?, ?> serviceTracker) {
removedService(serviceReference, serviceTracker);
addingService(serviceReference);
}
@Override
public void removedService(
ServiceReference<ServletContextHelper> serviceReference,
ServiceTracker<?, ?> serviceTracker) {
serviceTracker.close();
}
private final BundleContext _bundleContext;
private class ResourceBundleLoaderServiceTrackerCustomizer
implements
ServiceTrackerCustomizer
<ResourceBundleLoader, TrackedServletContextHelper> {
public ResourceBundleLoaderServiceTrackerCustomizer(
Map<String, Object> properties, String filterString,
Object contextName) {
_properties = properties;
_filterString = filterString;
_contextName = contextName;
}
@Override
public TrackedServletContextHelper addingService(
ServiceReference<ResourceBundleLoader> serviceReference) {
List<ServiceRegistration<?>> serviceRegistrations =
new ArrayList<>();
Dictionary<String, Object> properties = new Hashtable<>(
_properties);
properties.put(
"resource.bundle.base.name",
serviceReference.getProperty("resource.bundle.base.name"));
ResourceBundleLoader resourceBundleLoader =
_bundleContext.getService(serviceReference);
serviceRegistrations.add(
_bundleContext.registerService(
ResourceBundleLoader.class, resourceBundleLoader,
properties));
ServiceTracker<ResourceBundleLoader, ResourceBundleLoader>
serviceTracker = ServiceTrackerFactory.open(
_bundleContext, _filterString);
Filter filter = new LanguageFilter(
new ServiceTrackerResourceBundleLoader(serviceTracker));
Dictionary<String, Object> filterProperties = new Hashtable<>();
filterProperties.put(
HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT,
_contextName);
filterProperties.put(
HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_DISPATCHER,
new String[] {
DispatcherType.ASYNC.toString(),
DispatcherType.FORWARD.toString(),
DispatcherType.INCLUDE.toString(),
DispatcherType.REQUEST.toString()
});
filterProperties.put(
HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_NAME,
LanguageFilter.class.getName());
filterProperties.put(
HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_PATTERN,
new String[] {"*.css", "*.js"});
serviceRegistrations.add(
_bundleContext.registerService(
Filter.class, filter, filterProperties));
return new TrackedServletContextHelper(
serviceTracker, serviceRegistrations);
}
@Override
public void modifiedService(
ServiceReference<ResourceBundleLoader> serviceReference,
TrackedServletContextHelper service) {
removedService(serviceReference, service);
addingService(serviceReference);
}
@Override
public void removedService(
ServiceReference<ResourceBundleLoader> serviceReference,
TrackedServletContextHelper trackedServletContextHelper) {
_bundleContext.ungetService(serviceReference);
trackedServletContextHelper.clean();
}
private final Object _contextName;
private final String _filterString;
private final Map<String, Object> _properties;
}
}
private class TrackedServletContextHelper {
public TrackedServletContextHelper(
ServiceTracker<?, ?> serviceTracker,
List<ServiceRegistration<?>> serviceRegistrations) {
_serviceTracker = serviceTracker;
_serviceRegistrations = serviceRegistrations;
}
public void clean() {
_serviceTracker.close();
for (ServiceRegistration<?> serviceRegistration :
_serviceRegistrations) {
serviceRegistration.unregister();
}
}
private final List<ServiceRegistration<?>> _serviceRegistrations;
private ServiceTracker<?, ?> _serviceTracker;
}
}