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 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.utils.*; 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="https://juneau.apache.org/docs/topics/JuneauRestCommonBasics">juneau-rest-common Basics</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@BeanIgnore 055public class BasicHeader implements Header, Cloneable, Serializable { 056 057 //----------------------------------------------------------------------------------------------------------------- 058 // Static 059 //----------------------------------------------------------------------------------------------------------------- 060 061 private static final long serialVersionUID = 1L; 062 private static final HeaderElement[] EMPTY_HEADER_ELEMENTS = {}; 063 064 /** 065 * Static creator. 066 * 067 * @param name The parameter name. 068 * @param value 069 * The parameter value. 070 * <br>Can be <jk>null</jk>. 071 * @return A new header bean, or <jk>null</jk> if value is <jk>null</jk>. 072 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 073 */ 074 public static BasicHeader of(String name, Object value) { 075 return value == null ? null : new BasicHeader(name, value); 076 } 077 078 /** 079 * Static creator. 080 * 081 * @param o The name value pair that makes up the header name and value. 082 * The parameter value. 083 * <br>Any non-String value will be converted to a String using {@link Object#toString()}. 084 * @return A new header bean. 085 */ 086 public static BasicHeader of(NameValuePair o) { 087 return new BasicHeader(o.getName(), o.getValue()); 088 } 089 090 //----------------------------------------------------------------------------------------------------------------- 091 // Instance 092 //----------------------------------------------------------------------------------------------------------------- 093 094 private final String name; 095 private final String stringValue; 096 097 private final Object value; 098 private final Supplier<Object> supplier; 099 100 private HeaderElement[] elements; 101 102 /** 103 * Constructor. 104 * 105 * @param name The parameter name. 106 * @param value 107 * The parameter value. 108 * <br>Any non-String value will be converted to a String using {@link Object#toString()}. 109 * <br>Can also be an <l>Object</l> {@link Supplier}. 110 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 111 */ 112 public BasicHeader(String name, Object value) { 113 Utils.assertArg(Utils.isNotEmpty(name), "Name cannot be empty on header."); 114 this.name = name; 115 this.value = value instanceof Supplier ? null : value; 116 this.stringValue = Utils.s(value); 117 this.supplier = Utils.cast(Supplier.class, value); 118 } 119 120 /** 121 * Constructor with delayed value. 122 * 123 * <p> 124 * Header value is re-evaluated on each call to {@link #getValue()}. 125 * 126 * @param name The header name. 127 * @param value 128 * The supplier of the header value. 129 * <br>Can be <jk>null</jk>. 130 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 131 */ 132 public BasicHeader(String name, Supplier<Object> value) { 133 Utils.assertArg(Utils.isNotEmpty(name), "Name cannot be empty on header."); 134 this.name = name; 135 this.value = null; 136 this.stringValue = null; 137 this.supplier = value; 138 } 139 140 /** 141 * Copy constructor. 142 * 143 * @param copyFrom The object to copy. 144 */ 145 protected BasicHeader(BasicHeader copyFrom) { 146 this.name = copyFrom.name; 147 this.value = copyFrom.value; 148 this.stringValue = copyFrom.stringValue; 149 this.supplier = copyFrom.supplier; 150 } 151 152 @Override /* Header */ 153 public String getName() { 154 return name; 155 } 156 157 @Override /* Header */ 158 public String getValue() { 159 if (supplier != null) 160 return Utils.s(supplier.get()); 161 return stringValue; 162 } 163 164 @Override 165 public HeaderElement[] getElements() throws ParseException { 166 if (elements == null) { 167 String s = getValue(); 168 HeaderElement[] x = s == null ? EMPTY_HEADER_ELEMENTS : BasicHeaderValueParser.parseElements(s, null); 169 if (supplier == null) 170 elements = x; 171 return x; 172 } 173 return elements; 174 } 175 176 /** 177 * Returns <jk>true</jk> if the specified value is the same using {@link String#equalsIgnoreCase(String)}. 178 * 179 * @param compare The value to compare against. 180 * @return <jk>true</jk> if the specified value is the same. 181 */ 182 public boolean equalsIgnoreCase(String compare) { 183 return Utils.eqic(getValue(), compare); 184 } 185 186 /** 187 * Provides an object for performing assertions against the name of this header. 188 * 189 * @return An object for performing assertions against the name of this header. 190 */ 191 public FluentStringAssertion<BasicHeader> assertName() { 192 return new FluentStringAssertion<>(getName(), this); 193 } 194 195 /** 196 * Provides an object for performing assertions against the value of this header. 197 * 198 * @return An object for performing assertions against the value of this header. 199 */ 200 public FluentStringAssertion<BasicHeader> assertStringValue() { 201 return new FluentStringAssertion<>(getValue(), this); 202 } 203 204 /** 205 * Returns the value of this header as a string. 206 * 207 * @return The value of this header as a string, or {@link Optional#empty()} if the value is <jk>null</jk> 208 */ 209 public Optional<String> asString() { 210 return Utils.opt(getValue()); 211 } 212 213 /** 214 * Returns <jk>true</jk> if the value exists. 215 * 216 * <p> 217 * This is a shortcut for calling <c>asString().isPresent()</c>. 218 * 219 * @return <jk>true</jk> if the value exists. 220 */ 221 public boolean isPresent() { 222 return asString().isPresent(); 223 } 224 225 /** 226 * Returns <jk>true</jk> if the value exists and is not empty. 227 * 228 * <p> 229 * This is a shortcut for calling <c>!asString().orElse(<js>""</js>).isEmpty()</c>. 230 * 231 * @return <jk>true</jk> if the value exists and is not empty. 232 */ 233 public boolean isNotEmpty() { 234 return ! asString().orElse("").isEmpty(); 235 } 236 237 /** 238 * If a value is present, returns the value, otherwise throws {@link NoSuchElementException}. 239 * 240 * <p> 241 * This is a shortcut for calling <c>asString().get()</c>. 242 * 243 * @return The value if present. 244 */ 245 public String get() { 246 return asString().get(); 247 } 248 249 /** 250 * If a value is present, returns the value, otherwise returns other. 251 * 252 * <p> 253 * This is a shortcut for calling <c>asString().orElse(<jv>other</jv>)</c>. 254 * 255 * @param other The other value. 256 * @return The value if present or the other value if not. 257 */ 258 public String orElse(String other) { 259 return asString().orElse(other); 260 } 261 262 @Override /* Object */ 263 public boolean equals(Object o) { 264 // Functionality provided for HttpRequest.removeHeader(). 265 // Not a perfect equality operator if using SVL vars. 266 if (! (o instanceof Header)) 267 return false; 268 return Utils.eq(this, (Header)o, (x,y)->Utils.eq(x.name, y.getName()) && Utils.eq(x.getValue(), y.getValue())); 269 } 270 271 @Override /* Object */ 272 public int hashCode() { 273 // Implemented since we override equals(Object). 274 return super.hashCode(); 275 } 276 277 @Override /* Object */ 278 public String toString() { 279 return getName() + ": " + getValue(); 280 } 281}