001/* 002 * Licensed under the Apache License, Version 2.0 (the "License"); 003 * you may not use this file except in compliance with the License. 004 * You may obtain a copy of the License at 005 * 006 * http://www.apache.org/licenses/LICENSE-2.0 007 * 008 * Unless required by applicable law or agreed to in writing, software 009 * distributed under the License is distributed on an "AS IS" BASIS, 010 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 011 * See the License for the specific language governing permissions and 012 * limitations under the License. 013 */ 014package org.gbif.ws.server.provider; 015 016import java.util.Arrays; 017import java.util.Collections; 018import java.util.List; 019import java.util.Locale; 020import java.util.Map; 021 022import org.apache.commons.lang3.StringUtils; 023import org.springframework.http.HttpHeaders; 024import org.springframework.web.context.request.WebRequest; 025 026import static org.gbif.ws.util.CommonWsUtils.getFirst; 027 028/** 029 * Provider class that extracts the requested locale based on http header or language query parameter. 030 * This allows resources to access a locale context very easily while keeping all logic in this class. 031 * The accept any language value * will be converted into a null locale. 032 * Example resource use: 033 * <pre> 034 * {@code 035 * public String getVernacularName(Locale locale) { 036 * return "this is the " + locale + " vernacular name: xyz"); 037 * } 038 * } 039 * </pre> 040 */ 041public class LocaleProvider implements ContextProvider<Locale> { 042 043 private static final String LANGUAGE_PARAM = "language"; 044 private static final String ANY_LANGUAGE = "*"; 045 046 @Override 047 public Locale getValue(WebRequest webRequest) { 048 return getLocale(webRequest); 049 } 050 051 public static Locale getLocale(WebRequest webRequest) { 052 Map<String, String[]> params = webRequest.getParameterMap(); 053 054 // try language parameter first 055 String languageParam = getFirst(params, LANGUAGE_PARAM); 056 if (languageParam != null) { 057 String lang = languageParam.trim().toLowerCase(); 058 // iso language has to be 2 lower case letters! 059 if (StringUtils.isNotEmpty(lang) && lang.length() == 2) { 060 return new Locale(lang); 061 } 062 } 063 064 // try headers next 065 String[] acceptLanguageHeaderValues = webRequest.getHeaderValues(HttpHeaders.ACCEPT_LANGUAGE); 066 067 List<String> languages = 068 acceptLanguageHeaderValues != null 069 ? Arrays.asList(acceptLanguageHeaderValues) 070 : Collections.emptyList(); 071 072 for (String lang : languages) { 073 // ignore accept any language value: * and non iso 2-letter codes 074 if (StringUtils.isNotEmpty(lang) 075 && !ANY_LANGUAGE.equalsIgnoreCase(lang) 076 && lang.length() == 2) { 077 return Locale.forLanguageTag(lang); 078 } 079 } 080 081 return null; 082 } 083}