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 (the
006 * "License"); you may not use this file except in compliance with the
007 * 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;
018import static org.apache.juneau.commons.utils.Shorts.*;
019
020import java.util.*;
021import java.util.function.*;
022
023import org.apache.juneau.commons.utils.*;
024
025/**
026 * Base for boolean headers.
027 *
028 * @since 9.2.1
029 */
030@SuppressWarnings({
031   "java:S2160", // equals() on HttpHeaderBean uses name + getValue(); typed state is reflected in getValue()
032   "java:S9149", // Public Juneau DSL factory; hiding parent of()/create() is intentional.
033   "unchecked" // Supplier<?> branches cast to typed suppliers after lazy-mode check
034})
035public class HttpBooleanHeader extends HttpHeaderBean {
036
037   public static final int LAZY_WIRE_STRING = 0;
038   public static final int LAZY_BOOLEAN = 1;
039
040   private final Boolean value;
041   private final Supplier<?> lazySupplier;
042   private final int lazyMode;
043
044   /**
045    * Creates an {@link HttpBooleanHeader} by parsing the given wire-format value.
046    *
047    * @param name Header name. Must not be {@code null}.
048    * @param wireValue Wire value (e.g. {@code "true"}). May be {@code null}.
049    * @return A new instance. Never {@code null}.
050    */
051   public static HttpBooleanHeader of(String name, String wireValue) {
052      return new HttpBooleanHeader(name, wireValue);
053   }
054
055   /**
056    * Creates an {@link HttpBooleanHeader} with the given typed value.
057    *
058    * @param name Header name. Must not be {@code null}.
059    * @param typedValue The boolean value. May be {@code null}.
060    * @return A new instance. Never {@code null}.
061    */
062   public static HttpBooleanHeader of(String name, Boolean typedValue) {
063      return new HttpBooleanHeader(name, typedValue);
064   }
065
066   /**
067    * Constructor.
068    *
069    * @param name Header name. Must not be <jk>null</jk>.
070    * @param wireValue Wire value (e.g. {@code "true"}). Can be <jk>null</jk> or empty, in which case the parsed value is <jk>null</jk>.
071    */
072   protected HttpBooleanHeader(String name, String wireValue) {
073      super(name, wireValue);
074      this.value = ie(wireValue) ? null : Boolean.valueOf(b(wireValue));
075      this.lazySupplier = null;
076      this.lazyMode = -1;
077   }
078
079   /**
080    * Constructor.
081    *
082    * @param name Header name. Must not be <jk>null</jk>.
083    * @param typedValue The boolean value. Can be <jk>null</jk>, in which case the parsed value is <jk>null</jk>.
084    */
085   protected HttpBooleanHeader(String name, Boolean typedValue) {
086      super(name, s(typedValue));
087      this.value = typedValue;
088      this.lazySupplier = null;
089      this.lazyMode = -1;
090   }
091
092   /**
093    * Constructor with lazy value supplier.
094    *
095    * @param name Header name. Must not be <jk>null</jk>.
096    * @param supplier The lazy value supplier. Must not be <jk>null</jk>.
097    * @param lazyMode Either {@link #LAZY_WIRE_STRING} or {@link #LAZY_BOOLEAN}.
098    */
099   protected HttpBooleanHeader(String name, Supplier<?> supplier, int lazyMode) {
100      super(name, lazyMode == LAZY_WIRE_STRING
101         ? ((Supplier<String>) supplier)::get
102         : () -> s(((Supplier<Boolean>) supplier).get()));
103      this.value = null;
104      this.lazySupplier = supplier;
105      this.lazyMode = lazyMode;
106   }
107
108   public Optional<Boolean> asBoolean() {
109      return o(toBoolean());
110   }
111
112   /**
113    * Returns the wire-format value of this header.
114    *
115    * @return The wire value, or <jk>null</jk> if the value is unset.
116    */
117   @Override
118   public String getValue() {
119      return s(toBoolean());
120   }
121
122   /**
123    * Returns <jk>true</jk> if the parsed value is <jk>true</jk>.
124    *
125    * @return <jk>true</jk> if the parsed value is <jk>true</jk>; <jk>false</jk> if it is <jk>false</jk> or unset.
126    */
127   public boolean isTrue() {
128      return ObjectUtils.isTrue(toBoolean());
129   }
130
131   /**
132    * Returns the parsed value of this header, or the specified default if unset.
133    *
134    * @param other The default value. Can be <jk>null</jk> to allow a <jk>null</jk> result when the header is unset.
135    * @return The parsed value, or <c>other</c> if the value is unset. Can be <jk>null</jk> if <c>other</c> is <jk>null</jk>.
136    */
137   public Boolean orElse(Boolean other) {
138      var x = toBoolean();
139      return nn(x) ? x : other;
140   }
141
142   /**
143    * Returns the parsed value of this header.
144    *
145    * @return The parsed value, or <jk>null</jk> if the value is unset.
146    */
147   public Boolean toBoolean() {
148      if (lazyMode == LAZY_BOOLEAN)
149         return ((Supplier<Boolean>) lazySupplier).get();
150      if (value != null)
151         return value;
152      var v = super.getValue();
153      return ie(v) ? null : Boolean.valueOf(b(v));
154   }
155}