| // Copyright 2004, 2005 The Apache Software Foundation |
| // |
| // Licensed 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.tapestry.services.impl; |
| |
| import org.apache.hivemind.service.ThreadLocale; |
| import org.apache.tapestry.TapestryConstants; |
| import org.apache.tapestry.TapestryUtils; |
| import org.apache.tapestry.services.CookieSource; |
| import org.apache.tapestry.services.RequestLocaleManager; |
| import org.apache.tapestry.web.WebRequest; |
| |
| import java.util.*; |
| |
| /** |
| * Service tapestry.request.RequestLocaleManager. Identifies the Locale provided by the client |
| * (either in a Tapestry-specific cookie, or interpolated from the HTTP header. |
| * |
| * @author Howard Lewis Ship |
| * @since 4.0 |
| */ |
| public class RequestLocaleManagerImpl implements RequestLocaleManager |
| { |
| private WebRequest _request; |
| |
| /** |
| * Extracted at start of request, and used at end of request to see if locale has changed. |
| * Because of this thread-specific state, the service must use the threaded service lifecycle |
| * model. |
| */ |
| |
| private Locale _requestLocale; |
| |
| private CookieSource _cookieSource; |
| |
| private ThreadLocale _threadLocale; |
| |
| /** |
| * Set from symbol org.apache.tapestry.accepted-locales, a comma-seperated list of locale names. |
| * The first name is the default for requests that can't be matched against the other locale |
| * names. May also be blank, in which case, whatever locale was provided in the request is |
| * accepted (which is Tapestry 3.0 behavior). |
| */ |
| |
| private String _acceptedLocales; |
| |
| private Locale _defaultLocale; |
| |
| /** |
| * Set of locale names. Incoming requests will be matched to one of these locales. |
| */ |
| |
| private Set _acceptedLocaleNamesSet = new HashSet(); |
| |
| /** |
| * Cache of Locales, keyed on locale name. |
| */ |
| |
| private Map _localeCache = new HashMap(); |
| |
| /** |
| * Reference to last persisted locale, if any. Used to prevent |
| * duplicate cookie writes of the same locale. |
| */ |
| private Locale _lastPersisted; |
| |
| public void initializeService() |
| { |
| String[] names = TapestryUtils.split(_acceptedLocales); |
| |
| if (names.length == 0) |
| return; |
| |
| _defaultLocale = getLocale(names[0]); |
| |
| _acceptedLocaleNamesSet.addAll(Arrays.asList(names)); |
| } |
| |
| public Locale extractLocaleForCurrentRequest() |
| { |
| String localeName = _cookieSource.readCookieValue(TapestryConstants.LOCALE_COOKIE_NAME); |
| |
| String requestedLocale = (localeName != null) ? localeName : _request.getLocale().toString(); |
| |
| _requestLocale = filterRequestedLocale(requestedLocale); |
| |
| _threadLocale.setLocale(_requestLocale); |
| |
| return _requestLocale; |
| } |
| |
| /** |
| * Converts the request locale name into a Locale instance; applies filters (based on |
| * acceptedLocales) if enabled. |
| */ |
| |
| Locale filterRequestedLocale(String localeName) |
| { |
| String requestLocaleName = localeName; |
| if (_acceptedLocaleNamesSet.isEmpty()) |
| return getLocale(requestLocaleName); |
| |
| while (requestLocaleName.length() > 0) |
| { |
| if (_acceptedLocaleNamesSet.contains(requestLocaleName)) |
| return getLocale(requestLocaleName); |
| |
| requestLocaleName = stripTerm(requestLocaleName); |
| } |
| |
| // now try "best match" |
| |
| for (Iterator it = _acceptedLocaleNamesSet.iterator(); it.hasNext();) |
| { |
| String locale = (String) it.next(); |
| |
| if (locale.startsWith(localeName)) |
| return getLocale(locale); |
| } |
| |
| return _defaultLocale; |
| } |
| |
| private String stripTerm(String localeName) |
| { |
| int scorex = localeName.lastIndexOf('_'); |
| |
| return scorex < 0 ? "" : localeName.substring(0, scorex); |
| } |
| |
| public void persistLocale() |
| { |
| Locale locale = _threadLocale.getLocale(); |
| |
| if (locale.equals(_requestLocale) |
| || _lastPersisted != null && locale.equals(_lastPersisted)) |
| return; |
| |
| _cookieSource.writeCookieValue(TapestryConstants.LOCALE_COOKIE_NAME, locale.toString()); |
| _lastPersisted = locale; |
| } |
| |
| Locale getLocale(String name) |
| { |
| Locale result = (Locale) _localeCache.get(name); |
| |
| if (result == null) |
| { |
| result = constructLocale(name); |
| _localeCache.put(name, result); |
| } |
| |
| return result; |
| } |
| |
| private Locale constructLocale(String name) |
| { |
| String[] terms = TapestryUtils.split(name, '_'); |
| |
| switch (terms.length) |
| { |
| case 1: |
| return new Locale(terms[0], ""); |
| |
| case 2: |
| return new Locale(terms[0], terms[1]); |
| |
| case 3: |
| |
| return new Locale(terms[0], terms[1], terms[2]); |
| |
| default: |
| |
| throw new IllegalArgumentException(); |
| } |
| } |
| |
| public void setCookieSource(CookieSource source) |
| { |
| _cookieSource = source; |
| } |
| |
| public void setRequest(WebRequest request) |
| { |
| _request = request; |
| } |
| |
| public void setThreadLocale(ThreadLocale threadLocale) |
| { |
| _threadLocale = threadLocale; |
| } |
| |
| public void setAcceptedLocales(String acceptedLocales) |
| { |
| _acceptedLocales = acceptedLocales; |
| } |
| } |