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; 014 015import static org.apache.juneau.internal.StringUtils.*; 016import static org.apache.juneau.internal.ObjectUtils.*; 017 018import java.io.*; 019import java.util.*; 020import java.util.function.*; 021 022import org.apache.http.*; 023import org.apache.http.message.*; 024import org.apache.juneau.*; 025import org.apache.juneau.annotation.*; 026import org.apache.juneau.assertions.*; 027import org.apache.juneau.internal.*; 028import org.apache.juneau.reflect.*; 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@BeanIgnore 048public class BasicHeader implements Header, Cloneable, Serializable { 049 private static final long serialVersionUID = 1L; 050 051 private static final HeaderElement[] EMPTY_HEADER_ELEMENTS = new HeaderElement[] {}; 052 053 private final String name; 054 private final Object value; 055 private HeaderElement[] elements; 056 057 /** 058 * Convenience creator. 059 * 060 * @param name The parameter name. 061 * @param value 062 * The parameter value. 063 * <br>Any non-String value will be converted to a String using {@link Object#toString()}. 064 * @return A new {@link BasicHeader} object. 065 */ 066 public static BasicHeader of(String name, Object value) { 067 return new BasicHeader(name, value); 068 } 069 070 /** 071 * Creates a {@link Header} from a name/value pair string (e.g. <js>"Foo: bar"</js>) 072 * 073 * @param pair The pair string. 074 * @return A new {@link Header} object. 075 */ 076 public static BasicHeader ofPair(String pair) { 077 if (pair == null) 078 return null; 079 int i = pair.indexOf(':'); 080 if (i == -1) 081 return of(pair, ""); 082 return of(pair.substring(0,i).trim(), pair.substring(i+1).trim()); 083 } 084 085 /** 086 * Convenience creator. 087 * 088 * @param o The name value pair that makes up the header name and value. 089 * The parameter value. 090 * <br>Any non-String value will be converted to a String using {@link Object#toString()}. 091 * @return A new {@link BasicHeader} object. 092 */ 093 public static Header of(NameValuePair o) { 094 return new BasicHeader(o.getName(), o.getValue()); 095 } 096 097 /** 098 * Convenience creator using supplier. 099 * 100 * <p> 101 * Header value is re-evaluated on each call to {@link #getValue()}. 102 * 103 * @param name The parameter name. 104 * @param value 105 * The parameter value supplier. 106 * <br>Any non-String value will be converted to a String using {@link Object#toString()}. 107 * @return A new {@link BasicHeader} object. 108 */ 109 public static BasicHeader of(String name, Supplier<?> value) { 110 return new BasicHeader(name, value); 111 } 112 113 /** 114 * Utility method for converting an arbitrary object to a {@link Header}. 115 * 116 * @param o 117 * The object to cast or convert to a {@link Header}. 118 * @return Either the same object cast as a {@link Header} or converted to a {@link Header}. 119 */ 120 @SuppressWarnings("rawtypes") 121 public static Header cast(Object o) { 122 if (o instanceof Header) 123 return (Header)o; 124 if (o instanceof Headerable) 125 return ((Headerable)o).asHeader(); 126 if (o instanceof NameValuePair) 127 return BasicHeader.of((NameValuePair)o); 128 if (o instanceof NameValuePairable) 129 return BasicHeader.of(((NameValuePairable)o).asNameValuePair()); 130 if (o instanceof Map.Entry) { 131 Map.Entry e = (Map.Entry)o; 132 return BasicHeader.of(stringify(e.getKey()), e.getValue()); 133 } 134 throw new BasicRuntimeException("Object of type {0} could not be converted to a Header.", o == null ? null : o.getClass().getName()); 135 } 136 137 /** 138 * Returns <jk>true</jk> if the {@link #cast(Object)} method can be used on the specified object. 139 * 140 * @param o The object to check. 141 * @return <jk>true</jk> if the {@link #cast(Object)} method can be used on the specified object. 142 */ 143 public static boolean canCast(Object o) { 144 ClassInfo ci = ClassInfo.of(o); 145 return ci != null && ci.isChildOfAny(Header.class, Headerable.class, NameValuePair.class, NameValuePairable.class, Map.Entry.class); 146 } 147 148 /** 149 * Constructor. 150 * 151 * @param name The parameter name. 152 * @param value 153 * The parameter value. 154 * <br>Any non-String value will be converted to a String using {@link Object#toString()}. 155 * <br>Can also be an <l>Object</l> {@link Supplier}. 156 */ 157 public BasicHeader(String name, Object value) { 158 this.name = name; 159 this.value = value; 160 } 161 162 @Override /* Header */ 163 public String getName() { 164 return name; 165 } 166 167 @Override /* Header */ 168 public String getValue() { 169 return stringify(getRawValue()); 170 } 171 172 /** 173 * Returns the raw value of the header. 174 * 175 * @return The raw value of the header. 176 */ 177 protected Object getRawValue() { 178 return unwrap(value); 179 } 180 181 @Override 182 public HeaderElement[] getElements() throws ParseException { 183 if (elements == null) { 184 String s = getValue(); 185 HeaderElement[] x = s == null ? EMPTY_HEADER_ELEMENTS : BasicHeaderValueParser.parseElements(s, null); 186 if (value instanceof Supplier) 187 return x; 188 elements = x; 189 } 190 return elements; 191 } 192 193 /** 194 * Returns <jk>true</jk> if the specified value is the same using {@link String#equalsIgnoreCase(String)}. 195 * 196 * @param compare The value to compare against. 197 * @return <jk>true</jk> if the specified value is the same. 198 */ 199 protected boolean eqIC(String compare) { 200 return isEqualsIc(getValue(), compare); 201 } 202 203 /** 204 * Provides an object for performing assertions against the name of this header. 205 * 206 * @return An object for performing assertions against the name of this header. 207 */ 208 public FluentStringAssertion<BasicHeader> assertName() { 209 return new FluentStringAssertion<>(getName(), this); 210 } 211 212 /** 213 * Provides an object for performing assertions against the value of this header. 214 * 215 * @return An object for performing assertions against the value of this header. 216 */ 217 public FluentStringAssertion<BasicHeader> assertValue() { 218 return new FluentStringAssertion<>(getValue(), this); 219 } 220 221 /** 222 * Returns <jk>true</jk> if the specified object is a {@link Supplier}. 223 * 224 * @param o The object to check. 225 * @return <jk>true</jk> if the specified object is a {@link Supplier}. 226 */ 227 protected boolean isSupplier(Object o) { 228 return o instanceof Supplier; 229 } 230 231 /** 232 * If the specified object is a {@link Supplier}, returns the supplied value, otherwise the same value. 233 * 234 * @param o The object to unwrap. 235 * @return The unwrapped object. 236 */ 237 protected static Object unwrap(Object o) { 238 return ObjectUtils.unwrap(o); 239 } 240 241 @Override /* Object */ 242 public boolean equals(Object o) { 243 // Functionality provided for HttpRequest.removeHeader(). 244 // Not a perfect equality operator if using SVL vars. 245 if (! (o instanceof Header)) 246 return false; 247 return eq(this, (Header)o, (x,y)->eq(x.name,y.getName()) && eq(x.getValue(),y.getValue())); 248 } 249 250 @Override /* Object */ 251 public int hashCode() { 252 // Implemented since we override equals(Object). 253 return super.hashCode(); 254 } 255 256 @Override /* Object */ 257 public String toString() { 258 return name + ": " + getValue(); 259 } 260 261 // <FluentSetters> 262 263 // </FluentSetters> 264}