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