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