| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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.apache.sling.cms.core.i18n.impl; |
| |
| import java.util.Locale; |
| import java.util.Map; |
| import java.util.Optional; |
| import java.util.ResourceBundle; |
| import java.util.TreeMap; |
| |
| import javax.jcr.RepositoryException; |
| import javax.jcr.Value; |
| |
| import org.apache.sling.api.SlingHttpServletRequest; |
| import org.apache.sling.api.resource.ResourceResolver; |
| import org.apache.sling.cms.AuthorizableWrapper; |
| import org.apache.sling.cms.i18n.I18NDictionary; |
| import org.apache.sling.cms.i18n.I18NProvider; |
| import org.apache.sling.commons.osgi.Order; |
| import org.apache.sling.commons.osgi.ServiceUtil; |
| import org.apache.sling.i18n.DefaultLocaleResolver; |
| import org.apache.sling.i18n.LocaleResolver; |
| import org.apache.sling.i18n.RequestLocaleResolver; |
| import org.apache.sling.i18n.ResourceBundleProvider; |
| import org.osgi.service.component.annotations.Component; |
| import org.osgi.service.component.annotations.Reference; |
| import org.osgi.service.component.annotations.ReferenceCardinality; |
| import org.osgi.service.component.annotations.ReferencePolicy; |
| import org.osgi.service.component.annotations.ReferencePolicyOption; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| @SuppressWarnings("deprecation") |
| @Component(service = I18NProvider.class) |
| public class I18NProviderImpl implements I18NProvider { |
| /** |
| * Provider that goes through a list of registered providers and takes the first |
| * non-null responses |
| */ |
| private class CombinedBundleProvider implements ResourceBundleProvider { |
| |
| @Override |
| public Locale getDefaultLocale() { |
| // ask all registered providers, use the first one that returns |
| final ResourceBundleProvider[] sp = sortedProviders; |
| for (int i = sp.length - 1; i >= 0; i--) { |
| final ResourceBundleProvider provider = sp[i]; |
| final Locale locale = provider.getDefaultLocale(); |
| if (locale != null) { |
| log.trace("Found default locale {}", locale); |
| return locale; |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public ResourceBundle getResourceBundle(final Locale locale) { |
| return getResourceBundle(null, locale); |
| } |
| |
| @Override |
| public ResourceBundle getResourceBundle(final String baseName, final Locale locale) { |
| log.debug("Retrieving resource bundle for {}", locale); |
| // ask all registered providers, use the first one that returns |
| final ResourceBundleProvider[] sp = sortedProviders; |
| for (int i = sp.length - 1; i >= 0; i--) { |
| final ResourceBundleProvider provider = sp[i]; |
| final ResourceBundle bundle = baseName != null ? provider.getResourceBundle(baseName, locale) |
| : provider.getResourceBundle(locale); |
| if (bundle != null) { |
| log.trace("Using bundle {}", bundle); |
| return bundle; |
| } |
| } |
| return null; |
| } |
| } |
| |
| private static final Logger log = LoggerFactory.getLogger(I18NProviderImpl.class); |
| |
| private final DefaultLocaleResolver defaultLocaleResolver = new DefaultLocaleResolver(); |
| |
| private LocaleResolver localeResolver = defaultLocaleResolver; |
| |
| private final Map<Object, ResourceBundleProvider> providers = new TreeMap<>(); |
| |
| private RequestLocaleResolver requestLocaleResolver = defaultLocaleResolver; |
| |
| private ResourceBundleProvider[] sortedProviders = new ResourceBundleProvider[0]; |
| |
| @Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY) |
| protected void bindLocaleResolver(final LocaleResolver resolver) { |
| this.localeResolver = resolver; |
| } |
| |
| @Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY) |
| protected void bindRequestLocaleResolver(final RequestLocaleResolver resolver) { |
| this.requestLocaleResolver = resolver; |
| } |
| |
| @Reference(service = ResourceBundleProvider.class, cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC) |
| protected void bindResourceBundleProvider(final ResourceBundleProvider provider, final Map<String, Object> props) { |
| synchronized (this.providers) { |
| this.providers.put(ServiceUtil.getComparableForServiceRanking(props, Order.ASCENDING), provider); |
| this.sortedProviders = this.providers.values().toArray(new ResourceBundleProvider[this.providers.size()]); |
| } |
| } |
| |
| @Override |
| public I18NDictionary getDictionary(ResourceResolver resolver) { |
| AuthorizableWrapper wrapper = resolver.adaptTo(AuthorizableWrapper.class); |
| Locale locale = Optional.ofNullable(wrapper).map(AuthorizableWrapper::getAuthorizable).map(a -> { |
| try { |
| Value[] val = a.getProperty("profile/locale"); |
| if (val != null && val.length == 0) { |
| return val[0].getString(); |
| } else { |
| return Locale.ENGLISH.toLanguageTag(); |
| } |
| } catch (RepositoryException e) { |
| return Locale.ENGLISH.toLanguageTag(); |
| } |
| }).map(Locale::forLanguageTag).orElse(Locale.ENGLISH); |
| CombinedBundleProvider cbp = new CombinedBundleProvider(); |
| return new I18NDictionaryImpl(cbp.getResourceBundle(locale)); |
| } |
| |
| @Override |
| public I18NDictionary getDictionary(SlingHttpServletRequest request) { |
| return getDictionary(request.getResourceResolver()); |
| } |
| |
| protected void unbindLocaleResolver(final LocaleResolver resolver) { |
| if (this.localeResolver == resolver) { |
| this.localeResolver = defaultLocaleResolver; |
| } |
| } |
| |
| protected void unbindRequestLocaleResolver(final RequestLocaleResolver resolver) { |
| if (this.requestLocaleResolver == resolver) { |
| this.requestLocaleResolver = defaultLocaleResolver; |
| } |
| } |
| |
| // ---------- internal ----------------------------------------------------- |
| |
| protected void unbindResourceBundleProvider(final ResourceBundleProvider provider, |
| final Map<String, Object> props) { |
| synchronized (this.providers) { |
| this.providers.remove(ServiceUtil.getComparableForServiceRanking(props, Order.ASCENDING)); |
| this.sortedProviders = this.providers.values().toArray(new ResourceBundleProvider[this.providers.size()]); |
| } |
| } |
| |
| } |