    001    // Copyright 2006, 2007, 2009, 2010 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
    015    package org.apache.tapestry5.internal.services;
    016
    017    import java.util.Collections;
    018    import java.util.List;
    019    import java.util.Locale;
    020    import java.util.Map;
    021    import java.util.Set;
    022
    023    import org.apache.tapestry5.OptionModel;
    024    import org.apache.tapestry5.SelectModel;
    025    import org.apache.tapestry5.SymbolConstants;
    026    import org.apache.tapestry5.internal.OptionModelImpl;
    027    import org.apache.tapestry5.internal.SelectModelImpl;
    028    import org.apache.tapestry5.internal.TapestryInternalUtils;
    029    import org.apache.tapestry5.ioc.annotations.Symbol;
    030    import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
    031    import org.apache.tapestry5.ioc.services.ThreadLocale;
    032    import org.apache.tapestry5.services.LocalizationSetter;
    033    import org.apache.tapestry5.services.PersistentLocale;
    034    import org.apache.tapestry5.services.Request;
    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     */
    040    public 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 setNonPeristentLocaleFromLocaleName(String localeName)
    156        {
    157            Locale requested = toLocale(localeName);
    158
    159            Locale supported = findClosestSupportedLocale(requested);
    160
    161            threadLocale.setLocale(supported);
    162        }
    163
    164        private Locale findClosestSupportedLocale(Locale desiredLocale)
    165        {
    166            String localeName = desiredLocale.toString();
    167
    168            while (true)
    169            {
    170                if (isSupportedLocaleName(localeName))
    171                    return toLocale(localeName);
    172
    173                localeName = stripTerm(localeName);
    174
    175                if (localeName.length() == 0)
    176                    break;
    177            }
    178
    179            return defaultLocale;
    180        }
    181
    182        static String stripTerm(String localeName)
    183        {
    184            int scorex = localeName.lastIndexOf('_');
    185
    186            return scorex < 0 ? "" : localeName.substring(0, scorex);
    187        }
    188
    189        public List<Locale> getSupportedLocales()
    190        {
    191            return supportedLocales;
    192        }
    193
    194        public boolean isSupportedLocaleName(String localeName)
    195        {
    196            return supportedLocaleNames.contains(localeName.toLowerCase());
    197        }
    198
    199        public SelectModel getSupportedLocalesModel()
    200        {
    201            List<OptionModel> options = CollectionFactory.newList();
    202
    203            for (Locale l : supportedLocales)
    204            {
    205                options.add(new OptionModelImpl(l.getDisplayName(l), l));
    206            }
    207
    208            return new SelectModelImpl(null, options);
    209        }
    210
    211    }