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}