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; 018 019import static org.apache.juneau.commons.utils.CollectionUtils.*; 020 021import java.util.*; 022import java.util.function.*; 023 024import org.apache.http.*; 025import org.apache.http.message.*; 026 027/** 028 * Describes a single type used in content negotiation between an HTTP client and server, as described in 029 * Section 14.1 and 14.7 of RFC2616 (the HTTP/1.1 specification). 030 * 031 * <h5 class='section'>See Also:</h5><ul> 032 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestCommonBasics">juneau-rest-common Basics</a> 033 * <li class='extlink'><a class="doclink" href="https://www.w3.org/Protocols/rfc2616/rfc2616.html">Hypertext Transfer Protocol -- HTTP/1.1</a> 034 * </ul> 035 */ 036public class MediaRange extends MediaType { 037 038 private final NameValuePair[] extensions; 039 private final Float qValue; 040 private final String string; 041 042 /** 043 * Constructor. 044 * 045 * @param e The parsed media range element. 046 */ 047 public MediaRange(HeaderElement e) { 048 super(e); 049 050 Float qValue = 1f; 051 052 // The media type consists of everything up to the q parameter. 053 // The q parameter and stuff after is part of the range. 054 List<NameValuePair> extensions = list(); 055 boolean foundQ = false; 056 for (var p : e.getParameters()) { 057 if (p.getName().equals("q")) { 058 qValue = Float.parseFloat(p.getValue()); 059 foundQ = true; 060 } else if (foundQ) { 061 extensions.add(new BasicNameValuePair(p.getName(), p.getValue())); 062 } 063 } 064 065 this.qValue = qValue; 066 this.extensions = extensions.toArray(new NameValuePair[extensions.size()]); 067 068 var sb = new StringBuffer().append(super.toString()); 069 070 // '1' is equivalent to specifying no qValue. If there's no extensions, then we won't include a qValue. 071 if (qValue.floatValue() == 1.0) { 072 if (this.extensions.length > 0) { 073 sb.append(";q=").append(qValue); 074 extensions.forEach(x -> sb.append(';').append(x.getName()).append('=').append(x.getValue())); 075 } 076 } else { 077 sb.append(";q=").append(qValue); 078 extensions.forEach(x -> sb.append(';').append(x.getName()).append('=').append(x.getValue())); 079 } 080 string = sb.toString(); 081 } 082 083 /** 084 * Performs an action on the optional set of custom extensions defined for this type. 085 * 086 * <p> 087 * Values are lowercase and never <jk>null</jk>. 088 * 089 * @param action The action to perform. 090 * @return This object. 091 */ 092 public MediaRange forEachExtension(Consumer<NameValuePair> action) { 093 for (var r : extensions) 094 action.accept(r); 095 return this; 096 } 097 098 @Override /* Overridden from MediaType */ 099 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}