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 }