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