001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.http.header; 014 015import static org.apache.juneau.common.internal.StringUtils.*; 016import static org.apache.juneau.internal.CollectionUtils.*; 017 018import java.util.*; 019import java.util.function.*; 020 021import org.apache.juneau.*; 022 023/** 024 * Category of headers that consist of simple comma-delimited lists of strings with q-values. 025 * 026 * <p> 027 * <h5 class='figure'>Example</h5> 028 * <p class='bcode'> 029 * Accept-Encoding: compress;q=0.5, gzip;q=1.0 030 * </p> 031 * 032 * <h5 class='section'>See Also:</h5><ul> 033 * <li class='link'><a class="doclink" href="../../../../../index.html#juneau-rest-common">juneau-rest-common</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 * 037 * @serial exclude 038 */ 039public class BasicStringRangesHeader extends BasicHeader { 040 041 //----------------------------------------------------------------------------------------------------------------- 042 // Static 043 //----------------------------------------------------------------------------------------------------------------- 044 045 private static final long serialVersionUID = 1L; 046 047 /** 048 * Static creator. 049 * 050 * @param name The header name. 051 * @param value 052 * The header value. 053 * <br>Must be parsable by {@link StringRanges#of(String)}. 054 * <br>Can be <jk>null</jk>. 055 * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>. 056 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 057 */ 058 public static BasicStringRangesHeader of(String name, String value) { 059 return value == null ? null : new BasicStringRangesHeader(name, value); 060 } 061 062 /** 063 * Static creator. 064 * 065 * @param name The header name. 066 * @param value 067 * The header value. 068 * <br>Can be <jk>null</jk>. 069 * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>. 070 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 071 */ 072 public static BasicStringRangesHeader of(String name, StringRanges value) { 073 return value == null ? null : new BasicStringRangesHeader(name, value); 074 } 075 076 /** 077 * Static creator with delayed value. 078 * 079 * <p> 080 * Header value is re-evaluated on each call to {@link #getValue()}. 081 * 082 * @param name The header name. 083 * @param value 084 * The supplier of the header value. 085 * <br>Can be <jk>null</jk>. 086 * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>. 087 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 088 */ 089 public static BasicStringRangesHeader of(String name, Supplier<StringRanges> value) { 090 return value == null ? null : new BasicStringRangesHeader(name, value); 091 } 092 093 //----------------------------------------------------------------------------------------------------------------- 094 // Instance 095 //----------------------------------------------------------------------------------------------------------------- 096 097 private final String stringValue; 098 private final StringRanges value; 099 private final Supplier<StringRanges> supplier; 100 101 /** 102 * Constructor. 103 * 104 * @param name The header name. 105 * @param value 106 * The header value. 107 * <br>Must be parsable by {@link StringRanges#of(String)}. 108 * <br>Can be <jk>null</jk>. 109 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 110 */ 111 public BasicStringRangesHeader(String name, String value) { 112 super(name, value); 113 this.stringValue = value; 114 this.value = StringRanges.of(value); 115 this.supplier = null; 116 } 117 118 /** 119 * Constructor. 120 * 121 * @param name The header name. 122 * @param value 123 * The header value. 124 * <br>Can be <jk>null</jk>. 125 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 126 */ 127 public BasicStringRangesHeader(String name, StringRanges value) { 128 super(name, stringify(value)); 129 this.stringValue = null; 130 this.value = value; 131 this.supplier = null; 132 } 133 134 /** 135 * Constructor with delayed value. 136 * 137 * <p> 138 * Header value is re-evaluated on each call to {@link #getValue()}. 139 * 140 * @param name The header name. 141 * @param value 142 * The supplier of the header value. 143 * <br>Can be <jk>null</jk>. 144 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 145 */ 146 public BasicStringRangesHeader(String name, Supplier<StringRanges> value) { 147 super(name, null); 148 this.stringValue = null; 149 this.value = null; 150 this.supplier = value; 151 } 152 153 @Override /* Header */ 154 public String getValue() { 155 return stringValue != null ? stringValue : stringify(value()); 156 } 157 158 /** 159 * Returns the header value as a {@link StringRanges} wrapped in an {@link Optional}. 160 * 161 * @return The header value as a {@link StringRanges} wrapped in an {@link Optional}. Never <jk>null</jk>. 162 */ 163 public Optional<StringRanges> asStringRanges() { 164 return optional(value()); 165 } 166 167 /** 168 * Returns the header value as a {@link StringRanges}. 169 * 170 * @return The header value as a {@link StringRanges}. Can be <jk>null</jk>. 171 */ 172 public StringRanges toStringRanges() { 173 return value(); 174 } 175 176 /** 177 * Given a list of media types, returns the best match for this string range header. 178 * 179 * <p> 180 * Note that fuzzy matching is allowed on the media types where the string range header may 181 * contain additional subtype parts. 182 * <br>For example, given identical q-values and an string range value of <js>"text/json+activity"</js>, 183 * the media type <js>"text/json"</js> will match if <js>"text/json+activity"</js> or <js>"text/activity+json"</js> 184 * isn't found. 185 * <br>The purpose for this is to allow serializers to match when artifacts such as <c>id</c> properties are 186 * present in the header. 187 * 188 * <p> 189 * See <a class="doclink" href="https://www.w3.org/TR/activitypub/#retrieving-objects">ActivityPub / Retrieving Objects</a> 190 * 191 * @param names The names to match against. 192 * @return The index into the array of the best match, or <c>-1</c> if no suitable matches could be found. 193 */ 194 public int match(List<String> names) { 195 StringRanges x = value(); 196 return x == null ? -1 : x.match(names); 197 } 198 199 /** 200 * Returns the {@link MediaRange} at the specified index. 201 * 202 * @param index The index position of the media range. 203 * @return The {@link MediaRange} at the specified index or <jk>null</jk> if the index is out of range. 204 */ 205 public StringRange getRange(int index) { 206 StringRanges x = value(); 207 return x == null ? null : x.getRange(index); 208 } 209 210 /** 211 * Return the value if present, otherwise return <c>other</c>. 212 * 213 * <p> 214 * This is a shortened form for calling <c>asArray().orElse(<jv>other</jv>)</c>. 215 * 216 * @param other The value to be returned if there is no value present, can be <jk>null</jk>. 217 * @return The value, if present, otherwise <c>other</c>. 218 */ 219 public StringRanges orElse(StringRanges other) { 220 StringRanges x = value(); 221 return x != null ? x : other; 222 } 223 224 private StringRanges value() { 225 if (supplier != null) 226 return supplier.get(); 227 return value; 228 } 229}