001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.http.header;
018
019import java.util.function.*;
020
021import org.apache.juneau.*;
022import org.apache.juneau.http.annotation.*;
023import org.apache.juneau.internal.*;
024
025/**
026 * Represents a parsed <l>Accept-Language</l> HTTP request header.
027 *
028 * <p>
029 * List of acceptable human languages for response.
030 *
031 * <h5 class='figure'>Example</h5>
032 * <p class='bcode'>
033 *    Accept-Language: en-US
034 * </p>
035 *
036 * <h5 class='topic'>RFC2616 Specification</h5>
037 *
038 * The Accept-Language request-header field is similar to Accept, but restricts the set of natural languages that are
039 * preferred as a response to the request.
040 * Language tags are defined in section 3.10.
041 *
042 * <p class='bcode'>
043 *    Accept-Language = "Accept-Language" ":"
044 *                      1#( language-range [ ";" "q" "=" qvalue ] )
045 *    language-range  = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
046 * </p>
047 *
048 * <p>
049 * Each language-range MAY be given an associated quality value which represents an estimate of the user's preference
050 * for the languages specified by that range.
051 * The quality value defaults to "q=1".
052 * For example...
053 * <p class='bcode'>
054 *    Accept-Language: da, en-gb;q=0.8, en;q=0.7
055 * </p>
056 * <p>
057 * ...would mean: "I prefer Danish, but will accept British English and other types of English."
058 *
059 * <p>
060 * A language-range matches a language-tag if it exactly equals the tag, or if it exactly equals a prefix of the tag
061 * such that the first tag character following the prefix is "-".
062 *
063 * <p>
064 * The special range "*", if present in the Accept-Language field, matches every tag not matched by any other range
065 * present in the Accept-Language field.
066 *
067 * <p>
068 * Note: This use of a prefix matching rule does not imply that language tags are assigned to languages in such a way
069 * that it is always true that if a user understands a language with a certain
070 * tag, then this user will also understand all languages with tags for which this tag is a prefix.
071 * The prefix rule simply allows the use of prefix tags if this is the case.
072 *
073 * <p>
074 * The language quality factor assigned to a language-tag by the Accept-Language field is the quality value of the
075 * longest language- range in the field that matches the language-tag.
076 *
077 * <p>
078 * If no language- range in the field matches the tag, the language quality factor assigned is 0.
079 *
080 * <p>
081 * If no Accept-Language header is present in the request, the server SHOULD assume that all languages are equally
082 * acceptable.
083 *
084 * <p>
085 * If an Accept-Language header is present, then all languages which are assigned a quality factor greater than 0 are
086 * acceptable.
087 *
088 * <p>
089 * It might be contrary to the privacy expectations of the user to send an Accept-Language header with the complete
090 * linguistic preferences of the user in every request.
091 * For a discussion of this issue, see section 15.1.4.
092 *
093 * <p>
094 * As intelligibility is highly dependent on the individual user, it is recommended that client applications make the
095 * choice of linguistic preference available to the user.
096 * If the choice is not made available, then the Accept-Language header field MUST NOT be given in the request.
097 *
098 * <p>
099 * Note: When making the choice of linguistic preference available to the user, we remind implementors of the fact that
100 * users are not familiar with the details of language matching as described above, and should provide appropriate
101 * guidance.
102 * As an example, users might assume that on selecting "en-gb", they will be served any kind of English document if
103 * British English is not available.
104 * A user agent might suggest in such a case to add "en" to get the best matching behavior.
105 *
106 * <h5 class='section'>See Also:</h5><ul>
107 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestCommonBasics">juneau-rest-common Basics</a>
108 *    <li class='extlink'><a class="doclink" href="https://www.w3.org/Protocols/rfc2616/rfc2616.html">Hypertext Transfer Protocol -- HTTP/1.1</a>
109 * </ul>
110 *
111 * @serial exclude
112 */
113@Header("Accept-Language")
114public class AcceptLanguage extends BasicStringRangesHeader {
115
116   //-----------------------------------------------------------------------------------------------------------------
117   // Static
118   //-----------------------------------------------------------------------------------------------------------------
119
120   private static final long serialVersionUID = 1L;
121   private static final String NAME = "Accept-Language";
122
123   private static final Cache<String,AcceptLanguage> CACHE = Cache.of(String.class, AcceptLanguage.class).build();
124
125   /**
126    * Static creator.
127    *
128    * @param value
129    *    The header value.
130    *    <br>Must be parsable by {@link StringRanges#of(String)}.
131    *    <br>Can be <jk>null</jk>.
132    * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>.
133    */
134   public static AcceptLanguage of(String value) {
135      return value == null ? null : CACHE.get(value, ()->new AcceptLanguage(value));
136   }
137
138   /**
139    * Static creator.
140    *
141    * @param value
142    *    The header value.
143    *    <br>Can be <jk>null</jk>.
144    * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>.
145    */
146   public static AcceptLanguage of(StringRanges value) {
147      return value == null ? null : new AcceptLanguage(value);
148   }
149
150   /**
151    * Static creator with delayed value.
152    *
153    * <p>
154    * Header value is re-evaluated on each call to {@link #getValue()}.
155    *
156    * @param value
157    *    The supplier of the header value.
158    *    <br>Can be <jk>null</jk>.
159    * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>.
160    */
161   public static AcceptLanguage of(Supplier<StringRanges> value) {
162      return value == null ? null : new AcceptLanguage(value);
163   }
164
165   //-----------------------------------------------------------------------------------------------------------------
166   // Instance
167   //-----------------------------------------------------------------------------------------------------------------
168
169   /**
170    * Constructor.
171    *
172    * @param value
173    *    The header value.
174    *    <br>Must be parsable by {@link StringRanges#of(String)}.
175    *    <br>Can be <jk>null</jk>.
176    */
177   public AcceptLanguage(String value) {
178      super(NAME, value);
179   }
180
181   /**
182    * Constructor.
183    *
184    * @param value
185    *    The header value.
186    *    <br>Can be <jk>null</jk>.
187    */
188   public AcceptLanguage(StringRanges value) {
189      super(NAME, value);
190   }
191
192   /**
193    * Constructor with delayed value.
194    *
195    * <p>
196    * Header value is re-evaluated on each call to {@link #getValue()}.
197    *
198    * @param value
199    *    The supplier of the header value.
200    *    <br>Can be <jk>null</jk>.
201    */
202   public AcceptLanguage(Supplier<StringRanges> value) {
203      super(NAME, value);
204   }
205}