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 }