    001// Copyright 2006, 2007, 2009, 2010, 2012 The Apache Software Foundation
    002//
    003// Licensed under the Apache License, Version 2.0 (the "License");
    004// you may not use this file except in compliance with the License.
    005// You may obtain a copy of the License at
    006//
    007// http://www.apache.org/licenses/LICENSE-2.0
    008//
    009// Unless required by applicable law or agreed to in writing, software
    010// distributed under the License is distributed on an "AS IS" BASIS,
    011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    012// See the License for the specific language governing permissions and
    013// limitations under the License.
    014
    015package org.apache.tapestry5.internal.services;
    016
    017import java.util.Collections;
    018import java.util.List;
    019import java.util.Locale;
    020import java.util.Map;
    021import java.util.Set;
    022
    023import org.apache.tapestry5.OptionModel;
    024import org.apache.tapestry5.SelectModel;
    025import org.apache.tapestry5.SymbolConstants;
    026import org.apache.tapestry5.commons.util.CollectionFactory;
    027import org.apache.tapestry5.http.services.Request;
    028import org.apache.tapestry5.internal.OptionModelImpl;
    029import org.apache.tapestry5.internal.SelectModelImpl;
    030import org.apache.tapestry5.internal.TapestryInternalUtils;
    031import org.apache.tapestry5.ioc.annotations.Symbol;
    032import org.apache.tapestry5.ioc.services.ThreadLocale;
    033import org.apache.tapestry5.services.LocalizationSetter;
    034import org.apache.tapestry5.services.PersistentLocale;
    035
    036/**
    037 * Given a set of supported locales, for a specified desired locale, sets the current thread's locale to a supported
    038 * locale that is closest to the desired.
    039 */
    040public class LocalizationSetterImpl implements LocalizationSetter
    041{
    042    private final Request request;
    043
    044    private final ThreadLocale threadLocale;
    045
    046    private final Locale defaultLocale;
    047
    048    private final Set<String> supportedLocaleNames;
    049
    050    private final List<Locale> supportedLocales;
    051
    052    private final Map<String, Locale> localeCache = CollectionFactory.newConcurrentMap();
    053
    054    private final PersistentLocale persistentLocale;
    055
    056    public LocalizationSetterImpl(Request request,
    057
    058    PersistentLocale persistentLocale,
    059
    060    ThreadLocale threadLocale,
    061
    062    @Symbol(SymbolConstants.SUPPORTED_LOCALES)
    063    String localeNames)
    064    {
    065        this.request = request;
    066
    067        this.persistentLocale = persistentLocale;
    068        this.threadLocale = threadLocale;
    069
    070        this.supportedLocaleNames = CollectionFactory.newSet();
    071
    072        String[] names = TapestryInternalUtils.splitAtCommas(localeNames);
    073
    074        for (String name : names)
    075        {
    076            supportedLocaleNames.add(name.toLowerCase());
    077        }
    078
    079        supportedLocales = parseNames(names);
    080
    081        defaultLocale = supportedLocales.get(0);
    082    }
    083
    084    private List<Locale> parseNames(String[] localeNames)
    085    {
    086        List<Locale> list = CollectionFactory.newList();
    087
    088        for (String name : localeNames)
    089        {
    090            list.add(toLocale(name));
    091        }
    092
    093        return Collections.unmodifiableList(list);
    094    }
    095
    096    public Locale toLocale(String localeName)
    097    {
    098        Locale result = localeCache.get(localeName);
    099
    100        if (result == null)
    101        {
    102            result = constructLocale(localeName);
    103            localeCache.put(localeName, result);
    104        }
    105
    106        return result;
    107    }
    108
    109    private Locale constructLocale(String name)
    110    {
    111        String[] terms = name.split("_");
    112
    113        switch (terms.length)
    114        {
    115            case 1:
    116                return new Locale(terms[0], "");
    117
    118            case 2:
    119                return new Locale(terms[0], terms[1]);
    120
    121            case 3:
    122
    123                return new Locale(terms[0], terms[1], terms[2]);
    124
    125            default:
    126
    127                throw new IllegalArgumentException();
    128        }
    129    }
    130
    131    public boolean setLocaleFromLocaleName(String localeName)
    132    {
    133        boolean supported = isSupportedLocaleName(localeName);
    134
    135        if (supported)
    136        {
    137            Locale locale = findClosestSupportedLocale(toLocale(localeName));
    138
    139            persistentLocale.set(locale);
    140
    141            threadLocale.setLocale(locale);
    142        }
    143        else
    144        {
    145            Locale requestLocale = request.getLocale();
    146
    147            Locale supportedLocale = findClosestSupportedLocale(requestLocale);
    148
    149            threadLocale.setLocale(supportedLocale);
    150        }
    151
    152        return supported;
    153    }
    154
    155    public void setNonPersistentLocaleFromLocaleName(String localeName)
    156    {
    157        Locale requested = toLocale(localeName);
    158
    159        Locale supported = findClosestSupportedLocale(requested);
    160
    161        threadLocale.setLocale(supported);
    162    }
    163
    164    public void setNonPersistentLocaleFromRequest(Request request)
    165    {
    166        Locale locale = request.getLocale();
    167        setNonPersistentLocaleFromLocaleName(locale.toString());
    168    }
    169
    170    private Locale findClosestSupportedLocale(Locale desiredLocale)
    171    {
    172        String localeName = desiredLocale.toString();
    173
    174        while (true)
    175        {
    176            if (isSupportedLocaleName(localeName))
    177                return toLocale(localeName);
    178
    179            localeName = stripTerm(localeName);
    180
    181            if (localeName.length() == 0)
    182                break;
    183        }
    184
    185        return defaultLocale;
    186    }
    187
    188    static String stripTerm(String localeName)
    189    {
    190        int scorex = localeName.lastIndexOf('_');
    191
    192        return scorex < 0 ? "" : localeName.substring(0, scorex);
    193    }
    194
    195    public List<Locale> getSupportedLocales()
    196    {
    197        return supportedLocales;
    198    }
    199
    200    public boolean isSupportedLocaleName(String localeName)
    201    {
    202        return supportedLocaleNames.contains(localeName.toLowerCase());
    203    }
    204
    205    public SelectModel getSupportedLocalesModel()
    206    {
    207        List<OptionModel> options = CollectionFactory.newList();
    208
    209        for (Locale l : supportedLocales)
    210        {
    211            options.add(new OptionModelImpl(l.getDisplayName(l), l));
    212        }
    213
    214        return new SelectModelImpl(null, options);
    215    }
    216
    217}