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.Utils.*;
020
021import java.util.*;
022import java.util.function.*;
023
024import org.apache.juneau.annotation.*;
025import org.apache.juneau.assertions.*;
026import org.apache.juneau.http.annotation.*;
027
028/**
029 * Category of headers that consist of a single boolean value.
030 *
031 * <p>
032 * <h5 class='figure'>Example</h5>
033 * <p class='bcode'>
034 *    Foo: true
035 * </p>
036 *
037 * <h5 class='section'>See Also:</h5><ul>
038 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestCommonBasics">juneau-rest-common Basics</a>
039 *    <li class='extlink'><a class="doclink" href="https://www.w3.org/Protocols/rfc2616/rfc2616.html">Hypertext Transfer Protocol -- HTTP/1.1</a>
040 * </ul>
041 *
042 * @serial exclude
043 */
044@Header
045@Schema(type = "boolean")
046public class BasicBooleanHeader 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 BasicBooleanHeader of(String name, Boolean value) {
060      return value == null ? null : new BasicBooleanHeader(name, value);
061   }
062
063   /**
064    * Static creator.
065    *
066    * @param name The header name.
067    * @param value
068    *    The header value.
069    *    <br>Must be parsable by {@link Boolean#parseBoolean(String)}.
070    *    <br>Can be <jk>null</jk>.
071    * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>.
072    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
073    */
074   public static BasicBooleanHeader of(String name, String value) {
075      return value == null ? null : new BasicBooleanHeader(name, value);
076   }
077
078   /**
079    * Static creator with delayed value.
080    *
081    * <p>
082    * Header value is re-evaluated on each call to {@link #getValue()}.
083    *
084    * @param name The header name.
085    * @param value
086    *    The supplier of the header value.
087    *    <br>Can be <jk>null</jk>.
088    * @return A new header bean, or <jk>null</jk> if the value is <jk>null</jk>.
089    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
090    */
091   public static BasicBooleanHeader of(String name, Supplier<Boolean> value) {
092      return value == null ? null : new BasicBooleanHeader(name, value);
093   }
094
095   private final Boolean value;
096   private final Supplier<Boolean> supplier;
097
098   /**
099    * Constructor.
100    *
101    * @param name The header name.
102    * @param value
103    *    The header value.
104    *    <br>Can be <jk>null</jk>.
105    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
106    */
107   public BasicBooleanHeader(String name, Boolean value) {
108      super(name, value);
109      this.value = value;
110      this.supplier = null;
111   }
112
113   /**
114    * Constructor.
115    *
116    * @param name The header name.
117    * @param value
118    *    The header value.
119    *    <br>Must be parsable by {@link Boolean#parseBoolean(String)}.
120    *    <br>Can be <jk>null</jk>.
121    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
122    */
123   public BasicBooleanHeader(String name, String value) {
124      super(name, value);
125      this.value = e(value) ? null : bool(value);
126      this.supplier = null;
127   }
128
129   /**
130    * Constructor with delayed value.
131    *
132    * <p>
133    * Header value is re-evaluated on each call to {@link #getValue()}.
134    *
135    * @param name The header name.
136    * @param value
137    *    The supplier of the header value.
138    *    <br>Can be <jk>null</jk>.
139    * @throws IllegalArgumentException If name is <jk>null</jk> or empty.
140    */
141   public BasicBooleanHeader(String name, Supplier<Boolean> value) {
142      super(name, null);
143      this.value = null;
144      supplier = value;
145   }
146
147   /**
148    * Returns the header value as a {@link Boolean} wrapped in an {@link Optional}.
149    *
150    * @return The header value as a {@link Boolean} wrapped in an {@link Optional}.  Never <jk>null</jk>.
151    */
152   public Optional<Boolean> asBoolean() {
153      return opt(value());
154   }
155
156   /**
157    * Provides the ability to perform fluent-style assertions on this header.
158    *
159    * <h5 class='section'>Examples:</h5>
160    * <p class='bjava'>
161    *    <jc>// Validates the response header Foo is true.</jc>
162    *    <jv>client</jv>
163    *       .get(<jsf>URL</jsf>)
164    *       .run()
165    *       .getHeader(<js>"Foo"</js>).asBooleanHeader().assertBoolean().isTrue();
166    * </p>
167    *
168    * @return A new fluent assertion object.
169    * @throws AssertionError If assertion failed.
170    */
171   public FluentBooleanAssertion<BasicBooleanHeader> assertBoolean() {
172      return new FluentBooleanAssertion<>(value(), this);
173   }
174
175   @Override /* Overridden from Header */
176   public String getValue() { return s(value()); }
177
178   /**
179    * Returns <jk>true</jk> if the header value is <jk>true</jk>.
180    *
181    * @return <jk>true</jk> if the header value is <jk>true</jk>.
182    */
183   public boolean isTrue() {
184      Boolean x = value();
185      return x == null ? value : x;
186   }
187
188   /**
189    * Return the value if present, otherwise return <c>other</c>.
190    *
191    * <p>
192    * This is a shortened form for calling <c>asBoolean().orElse(<jv>other</jv>)</c>.
193    *
194    * @param other The value to be returned if there is no value present, can be <jk>null</jk>.
195    * @return The value, if present, otherwise <c>other</c>.
196    */
197   public Boolean orElse(Boolean other) {
198      Boolean x = value();
199      return nn(x) ? x : other;
200   }
201
202   /**
203    * Returns the header value as a {@link Boolean}.
204    *
205    * @return The header value as a {@link Boolean}.  Can be <jk>null</jk>.
206    */
207   public Boolean toBoolean() {
208      return value();
209   }
210
211   private Boolean value() {
212      if (nn(supplier))
213         return supplier.get();
214      return value;
215   }
216}