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