View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.juneau;
18  
19  import static org.apache.juneau.commons.utils.CollectionUtils.*;
20  
21  import java.util.*;
22  import java.util.function.*;
23  
24  import org.apache.http.*;
25  import org.apache.http.message.*;
26  
27  /**
28   * Describes a single type used in content negotiation between an HTTP client and server, as described in
29   * Section 14.1 and 14.7 of RFC2616 (the HTTP/1.1 specification).
30   *
31   * <h5 class='section'>See Also:</h5><ul>
32   * 	<li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestCommonBasics">juneau-rest-common Basics</a>
33   * 	<li class='extlink'><a class="doclink" href="https://www.w3.org/Protocols/rfc2616/rfc2616.html">Hypertext Transfer Protocol -- HTTP/1.1</a>
34   * </ul>
35   */
36  public class MediaRange extends MediaType {
37  
38  	private final NameValuePair[] extensions;
39  	private final Float qValue;
40  	private final String string;
41  
42  	/**
43  	 * Constructor.
44  	 *
45  	 * @param e The parsed media range element.
46  	 */
47  	public MediaRange(HeaderElement e) {
48  		super(e);
49  
50  		Float qValue = 1f;
51  
52  		// The media type consists of everything up to the q parameter.
53  		// The q parameter and stuff after is part of the range.
54  		List<NameValuePair> extensions = list();
55  		boolean foundQ = false;
56  		for (var p : e.getParameters()) {
57  			if (p.getName().equals("q")) {
58  				qValue = Float.parseFloat(p.getValue());
59  				foundQ = true;
60  			} else if (foundQ) {
61  				extensions.add(new BasicNameValuePair(p.getName(), p.getValue()));
62  			}
63  		}
64  
65  		this.qValue = qValue;
66  		this.extensions = extensions.toArray(new NameValuePair[extensions.size()]);
67  
68  		var sb = new StringBuffer().append(super.toString());
69  
70  		// '1' is equivalent to specifying no qValue. If there's no extensions, then we won't include a qValue.
71  		if (qValue.floatValue() == 1.0) {
72  			if (this.extensions.length > 0) {
73  				sb.append(";q=").append(qValue);
74  				extensions.forEach(x -> sb.append(';').append(x.getName()).append('=').append(x.getValue()));
75  			}
76  		} else {
77  			sb.append(";q=").append(qValue);
78  			extensions.forEach(x -> sb.append(';').append(x.getName()).append('=').append(x.getValue()));
79  		}
80  		string = sb.toString();
81  	}
82  
83  	/**
84  	 * Performs an action on the optional set of custom extensions defined for this type.
85  	 *
86  	 * <p>
87  	 * Values are lowercase and never <jk>null</jk>.
88  	 *
89  	 * @param action The action to perform.
90  	 * @return This object.
91  	 */
92  	public MediaRange forEachExtension(Consumer<NameValuePair> action) {
93  		for (var r : extensions)
94  			action.accept(r);
95  		return this;
96  	}
97  
98  	@Override /* Overridden from MediaType */
99  	public MediaRange forEachParameter(Consumer<NameValuePair> action) {
100 		super.forEachParameter(action);
101 		return this;
102 	}
103 
104 	/**
105 	 * Returns the optional set of custom extensions defined for this type.
106 	 *
107 	 * <p>
108 	 * Values are lowercase and never <jk>null</jk>.
109 	 *
110 	 * @return The optional list of extensions, never <jk>null</jk>.
111 	 */
112 	public List<NameValuePair> getExtensions() { return u(l(extensions)); }
113 
114 	/**
115 	 * Returns the <js>'q'</js> (quality) value for this type, as described in Section 3.9 of RFC2616.
116 	 *
117 	 * <p>
118 	 * The quality value is a float between <c>0.0</c> (unacceptable) and <c>1.0</c> (most acceptable).
119 	 *
120 	 * <p>
121 	 * If 'q' value doesn't make sense for the context (e.g. this range was extracted from a <js>"content-*"</js>
122 	 * header, as opposed to <js>"accept-*"</js> header, its value will always be <js>"1"</js>.
123 	 *
124 	 * @return The 'q' value for this type, never <jk>null</jk>.
125 	 */
126 	public Float getQValue() { return qValue; }
127 
128 	@Override /* Overridden from Object */
129 	public String toString() {
130 		return string;
131 	}
132 }