001 // Copyright 2004, 2005 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.tapestry.services.impl;
016
017 import java.util.Arrays;
018 import java.util.HashMap;
019 import java.util.HashSet;
020 import java.util.Locale;
021 import java.util.Map;
022 import java.util.Set;
023
024 import org.apache.hivemind.service.ThreadLocale;
025 import org.apache.tapestry.TapestryConstants;
026 import org.apache.tapestry.TapestryUtils;
027 import org.apache.tapestry.services.CookieSource;
028 import org.apache.tapestry.services.RequestLocaleManager;
029 import org.apache.tapestry.web.WebRequest;
030
031 /**
032 * Service tapestry.request.RequestLocaleManager. Identifies the Locale provided by the client
033 * (either in a Tapestry-specific cookie, or interpolated from the HTTP header.
034 *
035 * @author Howard Lewis Ship
036 * @since 4.0
037 */
038 public class RequestLocaleManagerImpl implements RequestLocaleManager
039 {
040 private WebRequest _request;
041
042 /**
043 * Extracted at start of request, and used at end of request to see if locale has changed.
044 * Because of this thread-specific state, the service must use the threaded service lifecycle
045 * model.
046 */
047
048 private Locale _requestLocale;
049
050 private CookieSource _cookieSource;
051
052 private ThreadLocale _threadLocale;
053
054 /**
055 * Set from symbol org.apache.tapestry.accepted-locales, a comma-seperated list of locale names.
056 * The first name is the default for requests that can't be matched against the other locale
057 * names. May also be blank, in which case, whatever locale was provided in the request is
058 * accepted (which is Tapestry 3.0 behavior).
059 */
060
061 private String _acceptedLocales;
062
063 private Locale _defaultLocale;
064
065 /**
066 * Set of locale names. Incoming requests will be matched to one of these locales.
067 */
068
069 private Set _acceptedLocaleNamesSet = new HashSet();
070
071 /**
072 * Cache of Locales, keyed on locale name.
073 */
074
075 private Map _localeCache = new HashMap();
076
077 public void initializeService()
078 {
079 String[] names = TapestryUtils.split(_acceptedLocales);
080
081 if (names.length == 0)
082 return;
083
084 _defaultLocale = getLocale(names[0]);
085
086 _acceptedLocaleNamesSet.addAll(Arrays.asList(names));
087
088 }
089
090 public Locale extractLocaleForCurrentRequest()
091 {
092 String localeName = _cookieSource.readCookieValue(TapestryConstants.LOCALE_COOKIE_NAME);
093
094 String requestedLocale = (localeName != null) ? localeName : _request.getLocale()
095 .toString();
096
097 _requestLocale = filterRequestedLocale(requestedLocale);
098
099 _threadLocale.setLocale(_requestLocale);
100
101 return _requestLocale;
102 }
103
104 /**
105 * Converts the request locale name into a Locale instance; applies filters (based on
106 * acceptedLocales) if enabled.
107 */
108
109 Locale filterRequestedLocale(String localeName)
110 {
111 if (_acceptedLocaleNamesSet.isEmpty())
112 return getLocale(localeName);
113
114 while (true)
115 {
116 if (_acceptedLocaleNamesSet.contains(localeName))
117 return getLocale(localeName);
118
119 localeName = stripTerm(localeName);
120
121 if (localeName.length() == 0)
122 return _defaultLocale;
123 }
124 }
125
126 private String stripTerm(String localeName)
127 {
128 int scorex = localeName.lastIndexOf('_');
129
130 return scorex < 0 ? "" : localeName.substring(0, scorex);
131 }
132
133 public void persistLocale()
134 {
135 Locale locale = _threadLocale.getLocale();
136
137 if (locale.equals(_requestLocale))
138 return;
139
140 _cookieSource.writeCookieValue(TapestryConstants.LOCALE_COOKIE_NAME, locale.toString());
141 }
142
143 Locale getLocale(String name)
144 {
145 Locale result = (Locale) _localeCache.get(name);
146
147 if (result == null)
148 {
149 result = constructLocale(name);
150 _localeCache.put(name, result);
151 }
152
153 return result;
154 }
155
156 private Locale constructLocale(String name)
157 {
158 String[] terms = TapestryUtils.split(name, '_');
159
160 switch (terms.length)
161 {
162 case 1:
163 return new Locale(terms[0], "");
164
165 case 2:
166 return new Locale(terms[0], terms[1]);
167
168 case 3:
169
170 return new Locale(terms[0], terms[1], terms[2]);
171
172 default:
173
174 throw new IllegalArgumentException();
175 }
176 }
177
178 public void setCookieSource(CookieSource source)
179 {
180 _cookieSource = source;
181 }
182
183 public void setRequest(WebRequest request)
184 {
185 _request = request;
186 }
187
188 public void setThreadLocale(ThreadLocale threadLocale)
189 {
190 _threadLocale = threadLocale;
191 }
192
193 public void setAcceptedLocales(String acceptedLocales)
194 {
195 _acceptedLocales = acceptedLocales;
196 }
197 }