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.classic.header;
018
019import static org.apache.juneau.commons.utils.Shorts.*;
020
021import java.util.*;
022import java.util.function.*;
023
024import org.apache.http.*;
025import org.apache.juneau.bct.assertions.*;
026
027/**
028 * Category of headers that consist of a single string value.
029 *
030 * <p>
031 * <h5 class='figure'>Example</h5>
032 * <p class='bcode'>
033 *    Host: www.myhost.com:8080
034 * </p>
035 *
036 * <h5 class='section'>See Also:</h5><ul>
037 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestCommon">juneau-rest-common</a>
038 *    <li class='extlink'><a class="doclink" href="https://www.w3.org/Protocols/rfc2616/rfc2616.html">Hypertext Transfer Protocol -- HTTP/1.1</a>
039 * </ul>
040 *
041 * @serial exclude
042 */
043@SuppressWarnings({
044   "java:S2160" // equals() inherited from BasicHeader compares name+value; typed String field is accessed via getValue()
045})
046public class BasicStringHeader extends BasicHeader {
047   private static final long serialVersionUID = 1L;
048
049   /**
050    * Static creator.
051    *
052    * @param name The header name.
053    * @param value
054    *    The header value.
055    *    <br>Can be <jk>null</jk>.
056    * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>.
057    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
058    */
059   public static BasicStringHeader of(String name, String value) {
060      return value == null ? null : new BasicStringHeader(name, value);
061   }
062
063   /**
064    * Static creator with delayed value.
065    *
066    * <p>
067    * Header value is re-evaluated on each call to {@link #getValue()}.
068    *
069    * @param name The header name.
070    * @param value
071    *    The supplier of the header value.
072    *    <br>Can be <jk>null</jk>.
073    * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>.
074    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
075    */
076   public static BasicStringHeader of(String name, Supplier<String> value) {
077      return value == null ? null : new BasicStringHeader(name, value);
078   }
079
080   /**
081    * Creates a {@link Header} from a name/value pair string (e.g. <js>"Foo: bar"</js>)
082    *
083    * @param pair The pair string.
084    * @return A new header bean.
085    */
086   public static BasicStringHeader ofPair(String pair) {
087      if (pair == null)
088         return null;
089      var i = pair.indexOf(':');
090      if (i == -1)
091         i = pair.indexOf('=');
092      if (i == -1)
093         return of(pair, "");
094      return of(pair.substring(0, i).trim(), pair.substring(i + 1).trim());
095   }
096
097   private final String value;
098   private final transient Supplier<String> supplier;
099
100   /**
101    * Constructor.
102    *
103    * @param name The header name.
104    * @param value
105    *    The header value.
106    *    <br>Can be <jk>null</jk> to create a header with no value.
107    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
108    */
109   public BasicStringHeader(String name, String value) {
110      super(name, value);
111      this.value = value;
112      this.supplier = null;
113   }
114
115   /**
116    * Constructor with delayed value.
117    *
118    * <p>
119    * Header value is re-evaluated on each call to {@link #getValue()}.
120    *
121    * @param name The header name.
122    * @param value
123    *    The supplier of the header value.
124    *    <br>Can be <jk>null</jk> to create a header with no value.
125    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
126    */
127   public BasicStringHeader(String name, Supplier<String> value) {
128      super(name, null);
129      this.value = null;
130      supplier = value;
131   }
132
133   /**
134    * Provides the ability to perform fluent-style assertions on this header.
135    *
136    * <h5 class='section'>Examples:</h5>
137    * <p class='bjava'>
138    *    <jc>// Validates the content type header is provided.</jc>
139    *    <jv>client</jv>
140    *       .get(<jsf>URL</jsf>)
141    *       .run()
142    *       .getHeader(<js>"Content-Type"</js>).assertString().exists();
143    * </p>
144    *
145    * @return A new fluent assertion object.
146    * @throws AssertionError If assertion failed.
147    */
148   public FluentStringAssertion<BasicStringHeader> assertString() {
149      return new FluentStringAssertion<>(value(), this);
150   }
151
152   @Override /* Overridden from BasicHeader */
153   public Optional<String> asString() {
154      return o(value());
155   }
156
157   @Override /* Overridden from Header */
158   public String getValue() { return s(value()); }
159
160   /**
161    * Return the value if present, otherwise return <c>other</c>.
162    *
163    * <p>
164    * This is a shortened form for calling <c>asString().orElse(<jv>other</jv>)</c>.
165    *
166    * @param other The value to be returned if there is no value present, can be <jk>null</jk>.
167    * @return The value, if present, otherwise <c>other</c>.
168    */
169   @Override
170   public String orElse(String other) {
171      String x = value();
172      return nn(x) ? x : other;
173   }
174
175   private String value() {
176      if (nn(supplier))
177         return supplier.get();
178      return value;
179   }
180}