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.common.utils.Utils.*; 020 021import java.util.*; 022import java.util.function.*; 023 024import org.apache.http.*; 025import org.apache.http.message.*; 026 027 028/** 029 * Describes a single type used in content negotiation between an HTTP client and server, as described in 030 * Section 14.1 and 14.7 of RFC2616 (the HTTP/1.1 specification). 031 * 032 * <h5 class='section'>See Also:</h5><ul> 033 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestCommonBasics">juneau-rest-common Basics</a> 034 * <li class='extlink'><a class="doclink" href="https://www.w3.org/Protocols/rfc2616/rfc2616.html">Hypertext Transfer Protocol -- HTTP/1.1</a> 035 * </ul> 036 */ 037public class MediaRange extends MediaType { 038 039 private final NameValuePair[] extensions; 040 private final Float qValue; 041 private final String string; 042 043 /** 044 * Constructor. 045 * 046 * @param e The parsed media range element. 047 */ 048 public MediaRange(HeaderElement e) { 049 super(e); 050 051 Float qValue = 1f; 052 053 // The media type consists of everything up to the q parameter. 054 // The q parameter and stuff after is part of the range. 055 List<NameValuePair> extensions = list(); 056 boolean foundQ = false; 057 for (NameValuePair p : e.getParameters()) { 058 if (p.getName().equals("q")) { 059 qValue = Float.parseFloat(p.getValue()); 060 foundQ = true; 061 } else if (foundQ) { 062 extensions.add(new BasicNameValuePair(p.getName(), p.getValue())); 063 } 064 } 065 066 this.qValue = qValue; 067 this.extensions = extensions.toArray(new NameValuePair[extensions.size()]); 068 069 StringBuffer sb = new StringBuffer().append(super.toString()); 070 071 // '1' is equivalent to specifying no qValue. If there's no extensions, then we won't include a qValue. 072 if (qValue.floatValue() == 1.0) { 073 if (this.extensions.length > 0) { 074 sb.append(";q=").append(qValue); 075 extensions.forEach(x -> sb.append(';').append(x.getName()).append('=').append(x.getValue())); 076 } 077 } else { 078 sb.append(";q=").append(qValue); 079 extensions.forEach(x -> sb.append(';').append(x.getName()).append('=').append(x.getValue())); 080 } 081 string = sb.toString(); 082 } 083 084 /** 085 * Returns the <js>'q'</js> (quality) value for this type, as described in Section 3.9 of RFC2616. 086 * 087 * <p> 088 * The quality value is a float between <c>0.0</c> (unacceptable) and <c>1.0</c> (most acceptable). 089 * 090 * <p> 091 * If 'q' value doesn't make sense for the context (e.g. this range was extracted from a <js>"content-*"</js> 092 * header, as opposed to <js>"accept-*"</js> header, its value will always be <js>"1"</js>. 093 * 094 * @return The 'q' value for this type, never <jk>null</jk>. 095 */ 096 public Float getQValue() { 097 return qValue; 098 } 099 100 /** 101 * Returns the optional set of custom extensions defined for this type. 102 * 103 * <p> 104 * Values are lowercase and never <jk>null</jk>. 105 * 106 * @return The optional list of extensions, never <jk>null</jk>. 107 */ 108 public List<NameValuePair> getExtensions() { 109 return u(alist(extensions)); 110 } 111 112 /** 113 * Performs an action on the optional set of custom extensions defined for this type. 114 * 115 * <p> 116 * Values are lowercase and never <jk>null</jk>. 117 * 118 * @param action The action to perform. 119 * @return This object. 120 */ 121 public MediaRange forEachExtension(Consumer<NameValuePair> action) { 122 for (NameValuePair r : extensions) 123 action.accept(r); 124 return this; 125 } 126 127 @Override /* Object */ 128 public String toString() { 129 return string; 130 } 131}