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.commons.collections.*;
023import org.apache.juneau.http.annotation.*;
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   private static final long serialVersionUID = 1L;
116   private static final String NAME = "Accept-Language";
117
118   private static final Cache<String,AcceptLanguage> CACHE = Cache.of(String.class, AcceptLanguage.class).build();
119
120   /**
121    * Static creator.
122    *
123    * @param value
124    *    The header value.
125    *    <br>Must be parsable by {@link StringRanges#of(String)}.
126    *    <br>Can be <jk>null</jk>.
127    * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>.
128    */
129   public static AcceptLanguage of(String value) {
130      return value == null ? null : CACHE.get(value, () -> new AcceptLanguage(value));
131   }
132
133   /**
134    * Static creator.
135    *
136    * @param value
137    *    The header value.
138    *    <br>Can be <jk>null</jk>.
139    * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>.
140    */
141   public static AcceptLanguage of(StringRanges value) {
142      return value == null ? null : new AcceptLanguage(value);
143   }
144
145   /**
146    * Static creator with delayed value.
147    *
148    * <p>
149    * Header value is re-evaluated on each call to {@link #getValue()}.
150    *
151    * @param value
152    *    The supplier of the header value.
153    *    <br>Can be <jk>null</jk>.
154    * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>.
155    */
156   public static AcceptLanguage of(Supplier<StringRanges> value) {
157      return value == null ? null : new AcceptLanguage(value);
158   }
159
160   /**
161    * Constructor.
162    *
163    * @param value
164    *    The header value.
165    *    <br>Must be parsable by {@link StringRanges#of(String)}.
166    *    <br>Can be <jk>null</jk>.
167    */
168   public AcceptLanguage(String value) {
169      super(NAME, value);
170   }
171
172   /**
173    * Constructor.
174    *
175    * @param value
176    *    The header value.
177    *    <br>Can be <jk>null</jk>.
178    */
179   public AcceptLanguage(StringRanges value) {
180      super(NAME, value);
181   }
182
183   /**
184    * Constructor with delayed value.
185    *
186    * <p>
187    * Header value is re-evaluated on each call to {@link #getValue()}.
188    *
189    * @param value
190    *    The supplier of the header value.
191    *    <br>Can be <jk>null</jk>.
192    */
193   public AcceptLanguage(Supplier<StringRanges> value) {
194      super(NAME, value);
195   }
196}