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.ArgUtils.*; 016import static org.apache.juneau.common.internal.StringUtils.*; 017import static org.apache.juneau.internal.CollectionUtils.*; 018import static org.apache.juneau.internal.ObjectUtils.*; 019import java.io.*; 020import java.util.*; 021import java.util.function.*; 022 023import org.apache.http.*; 024import org.apache.http.message.*; 025import org.apache.juneau.annotation.*; 026import org.apache.juneau.assertions.*; 027import org.apache.juneau.common.internal.*; 028import org.apache.juneau.internal.*; 029 030/** 031 * Superclass of all headers defined in this package. 032 * 033 * Provides the following features: 034 * <ul class='spaced-list'> 035 * <li> 036 * Default support for various streams and readers. 037 * <li> 038 * Content from {@link Supplier Suppliers}. 039 * <li> 040 * Caching. 041 * <li> 042 * Fluent setters. 043 * <li> 044 * Fluent assertions. 045 * </ul> 046 * 047 * <h5 class='section'>See Also:</h5><ul> 048 * <li class='link'><a class="doclink" href="../../../../../index.html#juneau-rest-common">juneau-rest-common</a> 049 * <li class='extlink'><a class="doclink" href="https://www.w3.org/Protocols/rfc2616/rfc2616.html">Hypertext Transfer Protocol -- HTTP/1.1</a> 050 * </ul> 051 * 052 * @serial exclude 053 */ 054@FluentSetters 055@BeanIgnore 056public class BasicHeader implements Header, Cloneable, Serializable { 057 058 //----------------------------------------------------------------------------------------------------------------- 059 // Static 060 //----------------------------------------------------------------------------------------------------------------- 061 062 private static final long serialVersionUID = 1L; 063 private static final HeaderElement[] EMPTY_HEADER_ELEMENTS = new HeaderElement[] {}; 064 065 /** 066 * Static creator. 067 * 068 * @param name The parameter name. 069 * @param value 070 * The parameter value. 071 * <br>Can be <jk>null</jk>. 072 * @return A new header bean, or <jk>null</jk> if value is <jk>null</jk>. 073 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 074 */ 075 public static BasicHeader of(String name, Object value) { 076 return value == null ? null : new BasicHeader(name, value); 077 } 078 079 /** 080 * Static creator. 081 * 082 * @param o The name value pair that makes up the header name and value. 083 * The parameter value. 084 * <br>Any non-String value will be converted to a String using {@link Object#toString()}. 085 * @return A new header bean. 086 */ 087 public static BasicHeader of(NameValuePair o) { 088 return new BasicHeader(o.getName(), o.getValue()); 089 } 090 091 //----------------------------------------------------------------------------------------------------------------- 092 // Instance 093 //----------------------------------------------------------------------------------------------------------------- 094 095 private final String name; 096 private final String stringValue; 097 098 private final Object value; 099 private final Supplier<Object> supplier; 100 101 private HeaderElement[] elements; 102 103 /** 104 * Constructor. 105 * 106 * @param name The parameter name. 107 * @param value 108 * The parameter value. 109 * <br>Any non-String value will be converted to a String using {@link Object#toString()}. 110 * <br>Can also be an <l>Object</l> {@link Supplier}. 111 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 112 */ 113 public BasicHeader(String name, Object value) { 114 assertArg(StringUtils.isNotEmpty(name), "Name cannot be empty on header."); 115 this.name = name; 116 this.value = value instanceof Supplier ? null : value; 117 this.stringValue = stringify(value); 118 this.supplier = cast(Supplier.class, value); 119 } 120 121 /** 122 * Constructor with delayed value. 123 * 124 * <p> 125 * Header value is re-evaluated on each call to {@link #getValue()}. 126 * 127 * @param name The header name. 128 * @param value 129 * The supplier of the header value. 130 * <br>Can be <jk>null</jk>. 131 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 132 */ 133 public BasicHeader(String name, Supplier<Object> value) { 134 assertArg(StringUtils.isNotEmpty(name), "Name cannot be empty on header."); 135 this.name = name; 136 this.value = null; 137 this.stringValue = null; 138 this.supplier = value; 139 } 140 141 /** 142 * Copy constructor. 143 * 144 * @param copyFrom The object to copy. 145 */ 146 protected BasicHeader(BasicHeader copyFrom) { 147 this.name = copyFrom.name; 148 this.value = copyFrom.value; 149 this.stringValue = copyFrom.stringValue; 150 this.supplier = copyFrom.supplier; 151 } 152 153 @Override /* Header */ 154 public String getName() { 155 return name; 156 } 157 158 @Override /* Header */ 159 public String getValue() { 160 if (supplier != null) 161 return stringify(supplier.get()); 162 return stringValue; 163 } 164 165 @Override 166 public HeaderElement[] getElements() throws ParseException { 167 if (elements == null) { 168 String s = getValue(); 169 HeaderElement[] x = s == null ? EMPTY_HEADER_ELEMENTS : BasicHeaderValueParser.parseElements(s, null); 170 if (supplier == null) 171 elements = x; 172 return x; 173 } 174 return elements; 175 } 176 177 /** 178 * Returns <jk>true</jk> if the specified value is the same using {@link String#equalsIgnoreCase(String)}. 179 * 180 * @param compare The value to compare against. 181 * @return <jk>true</jk> if the specified value is the same. 182 */ 183 public boolean equalsIgnoreCase(String compare) { 184 return eqic(getValue(), compare); 185 } 186 187 /** 188 * Provides an object for performing assertions against the name of this header. 189 * 190 * @return An object for performing assertions against the name of this header. 191 */ 192 public FluentStringAssertion<BasicHeader> assertName() { 193 return new FluentStringAssertion<>(getName(), this); 194 } 195 196 /** 197 * Provides an object for performing assertions against the value of this header. 198 * 199 * @return An object for performing assertions against the value of this header. 200 */ 201 public FluentStringAssertion<BasicHeader> assertStringValue() { 202 return new FluentStringAssertion<>(getValue(), this); 203 } 204 205 /** 206 * Returns the value of this header as a string. 207 * 208 * @return The value of this header as a string, or {@link Optional#empty()} if the value is <jk>null</jk> 209 */ 210 public Optional<String> asString() { 211 return optional(getValue()); 212 } 213 214 /** 215 * Returns <jk>true</jk> if the value exists. 216 * 217 * <p> 218 * This is a shortcut for calling <c>asString().isPresent()</c>. 219 * 220 * @return <jk>true</jk> if the value exists. 221 */ 222 public boolean isPresent() { 223 return asString().isPresent(); 224 } 225 226 /** 227 * Returns <jk>true</jk> if the value exists and is not empty. 228 * 229 * <p> 230 * This is a shortcut for calling <c>!asString().orElse(<js>""</js>).isEmpty()</c>. 231 * 232 * @return <jk>true</jk> if the value exists and is not empty. 233 */ 234 public boolean isNotEmpty() { 235 return ! asString().orElse("").isEmpty(); 236 } 237 238 /** 239 * If a value is present, returns the value, otherwise throws {@link NoSuchElementException}. 240 * 241 * <p> 242 * This is a shortcut for calling <c>asString().get()</c>. 243 * 244 * @return The value if present. 245 */ 246 public String get() { 247 return asString().get(); 248 } 249 250 /** 251 * If a value is present, returns the value, otherwise returns other. 252 * 253 * <p> 254 * This is a shortcut for calling <c>asString().orElse(<jv>other</jv>)</c>. 255 * 256 * @param other The other value. 257 * @return The value if present or the other value if not. 258 */ 259 public String orElse(String other) { 260 return asString().orElse(other); 261 } 262 263 @Override /* Object */ 264 public boolean equals(Object o) { 265 // Functionality provided for HttpRequest.removeHeader(). 266 // Not a perfect equality operator if using SVL vars. 267 if (! (o instanceof Header)) 268 return false; 269 return eq(this, (Header)o, (x,y)->eq(x.name,y.getName()) && eq(x.getValue(),y.getValue())); 270 } 271 272 @Override /* Object */ 273 public int hashCode() { 274 // Implemented since we override equals(Object). 275 return super.hashCode(); 276 } 277 278 @Override /* Object */ 279 public String toString() { 280 return getName() + ": " + getValue(); 281 } 282 283 // <FluentSetters> 284 285 // </FluentSetters> 286}