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}