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 static org.apache.juneau.commons.utils.Utils.*; 020 021import java.util.*; 022import java.util.function.*; 023 024import org.apache.juneau.*; 025 026/** 027 * Category of headers that consist of simple comma-delimited lists of strings with q-values. 028 * 029 * <p> 030 * <h5 class='figure'>Example</h5> 031 * <p class='bcode'> 032 * Accept-Encoding: compress;q=0.5, gzip;q=1.0 033 * </p> 034 * 035 * <h5 class='section'>See Also:</h5><ul> 036 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestCommonBasics">juneau-rest-common Basics</a> 037 * <li class='extlink'><a class="doclink" href="https://www.w3.org/Protocols/rfc2616/rfc2616.html">Hypertext Transfer Protocol -- HTTP/1.1</a> 038 * </ul> 039 * 040 * @serial exclude 041 */ 042public class BasicStringRangesHeader extends BasicHeader { 043 private static final long serialVersionUID = 1L; 044 045 /** 046 * Static creator. 047 * 048 * @param name The header name. 049 * @param value 050 * The header value. 051 * <br>Must be parsable by {@link StringRanges#of(String)}. 052 * <br>Can be <jk>null</jk>. 053 * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>. 054 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 055 */ 056 public static BasicStringRangesHeader of(String name, String value) { 057 return value == null ? null : new BasicStringRangesHeader(name, value); 058 } 059 060 /** 061 * Static creator. 062 * 063 * @param name The header name. 064 * @param value 065 * The header value. 066 * <br>Can be <jk>null</jk>. 067 * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>. 068 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 069 */ 070 public static BasicStringRangesHeader of(String name, StringRanges value) { 071 return value == null ? null : new BasicStringRangesHeader(name, value); 072 } 073 074 /** 075 * Static creator with delayed value. 076 * 077 * <p> 078 * Header value is re-evaluated on each call to {@link #getValue()}. 079 * 080 * @param name The header name. 081 * @param value 082 * The supplier of the header value. 083 * <br>Can be <jk>null</jk>. 084 * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>. 085 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 086 */ 087 public static BasicStringRangesHeader of(String name, Supplier<StringRanges> value) { 088 return value == null ? null : new BasicStringRangesHeader(name, value); 089 } 090 091 private final String stringValue; 092 private final StringRanges value; 093 private final Supplier<StringRanges> supplier; 094 095 /** 096 * Constructor. 097 * 098 * @param name The header name. 099 * @param value 100 * The header value. 101 * <br>Must be parsable by {@link StringRanges#of(String)}. 102 * <br>Can be <jk>null</jk>. 103 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 104 */ 105 public BasicStringRangesHeader(String name, String value) { 106 super(name, value); 107 stringValue = value; 108 this.value = StringRanges.of(value); 109 this.supplier = null; 110 } 111 112 /** 113 * Constructor. 114 * 115 * @param name The header name. 116 * @param value 117 * The header value. 118 * <br>Can be <jk>null</jk>. 119 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 120 */ 121 public BasicStringRangesHeader(String name, StringRanges value) { 122 super(name, s(value)); 123 this.stringValue = null; 124 this.value = value; 125 this.supplier = null; 126 } 127 128 /** 129 * Constructor with delayed value. 130 * 131 * <p> 132 * Header value is re-evaluated on each call to {@link #getValue()}. 133 * 134 * @param name The header name. 135 * @param value 136 * The supplier of the header value. 137 * <br>Can be <jk>null</jk>. 138 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 139 */ 140 public BasicStringRangesHeader(String name, Supplier<StringRanges> value) { 141 super(name, null); 142 this.stringValue = null; 143 this.value = null; 144 supplier = value; 145 } 146 147 /** 148 * Returns the header value as a {@link StringRanges} wrapped in an {@link Optional}. 149 * 150 * @return The header value as a {@link StringRanges} wrapped in an {@link Optional}. Never <jk>null</jk>. 151 */ 152 public Optional<StringRanges> asStringRanges() { 153 return opt(value()); 154 } 155 156 /** 157 * Returns the {@link MediaRange} at the specified index. 158 * 159 * @param index The index position of the media range. 160 * @return The {@link MediaRange} at the specified index or <jk>null</jk> if the index is out of range. 161 */ 162 public StringRange getRange(int index) { 163 StringRanges x = value(); 164 return x == null ? null : x.getRange(index); 165 } 166 167 @Override /* Overridden from Header */ 168 public String getValue() { return nn(stringValue) ? stringValue : s(value()); } 169 170 /** 171 * Given a list of media types, returns the best match for this string range header. 172 * 173 * <p> 174 * Note that fuzzy matching is allowed on the media types where the string range header may 175 * contain additional subtype parts. 176 * <br>For example, given identical q-values and an string range value of <js>"text/json+activity"</js>, 177 * the media type <js>"text/json"</js> will match if <js>"text/json+activity"</js> or <js>"text/activity+json"</js> 178 * isn't found. 179 * <br>The purpose for this is to allow serializers to match when artifacts such as <c>id</c> properties are 180 * present in the header. 181 * 182 * <p> 183 * See <a class="doclink" href="https://www.w3.org/TR/activitypub/#retrieving-objects">ActivityPub / Retrieving Objects</a> 184 * 185 * @param names The names to match against. 186 * @return The index into the array of the best match, or <c>-1</c> if no suitable matches could be found. 187 */ 188 public int match(List<String> names) { 189 StringRanges x = value(); 190 return x == null ? -1 : x.match(names); 191 } 192 193 /** 194 * Return the value if present, otherwise return <c>other</c>. 195 * 196 * <p> 197 * This is a shortened form for calling <c>asArray().orElse(<jv>other</jv>)</c>. 198 * 199 * @param other The value to be returned if there is no value present, can be <jk>null</jk>. 200 * @return The value, if present, otherwise <c>other</c>. 201 */ 202 public StringRanges orElse(StringRanges other) { 203 StringRanges x = value(); 204 return nn(x) ? x : other; 205 } 206 207 /** 208 * Returns the header value as a {@link StringRanges}. 209 * 210 * @return The header value as a {@link StringRanges}. Can be <jk>null</jk>. 211 */ 212 public StringRanges toStringRanges() { 213 return value(); 214 } 215 216 private StringRanges value() { 217 if (nn(supplier)) 218 return supplier.get(); 219 return value; 220 } 221}