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.commons.lang;
018
019import static org.apache.juneau.commons.utils.Shorts.*;
020
021import java.util.concurrent.atomic.*;
022
023import org.apache.juneau.commons.utils.*;
024
025/**
026 * A simple mutable boolean value.
027 *
028 * <p>
029 * This class extends {@link Holder}&lt;{@link Boolean}&gt; and provides a convenient way to pass mutable
030 * boolean references to lambdas, inner classes, or methods. Unlike {@link Flag}, this class supports three
031 * states: <c>true</c>, <c>false</c>, and <c>null</c>.
032 *
033 * <h5 class='section'>Notes:</h5><ul>
034 *    <li class='note'>
035 *       This class is <b>not thread-safe</b>. For concurrent access, use {@link AtomicBoolean} instead.
036 *    <li class='note'>
037 *       This class supports three states (<c>true</c>, <c>false</c>, <c>null</c>). If you only need
038 *       two states (<c>true</c>/<c>false</c>), consider using {@link Flag} instead.
039 * </ul>
040 *
041 * <h5 class='section'>Example:</h5>
042 * <p class='bjava'>
043 *    <jc>// Create a boolean value to track if a condition was met</jc>
044 *    BooleanHolder <jv>found</jv> = BooleanHolder.<jsm>create</jsm>();
045 *
046 *    <jc>// Use in a lambda</jc>
047 *    list.forEach(<jv>x</jv> -&gt; {
048 *       <jk>if</jk> (<jv>x</jv>.matches(criteria)) {
049 *          <jv>found</jv>.set(<jk>true</jk>);
050 *       }
051 *    });
052 *
053 *    <jk>if</jk> (<jv>found</jv>.isTrue()) {
054 *       <jsm>log</jsm>(<js>"Match found!"</js>);
055 *    }
056 * </p>
057 *
058 * <h5 class='section'>See Also:</h5><ul>
059 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommonsLang">Lang Package</a>
060 *    <li class='jc'>{@link Flag}
061 * </ul>
062 */
063@SuppressWarnings({
064   "java:S1192" // Duplicated literals (argument/property names) read more clearly inline than as constants
065})
066public class BooleanHolder extends Holder<Boolean> {
067
068   /**
069    * Creates a new boolean value initialized to <c>false</c>.
070    *
071    * <h5 class='section'>Example:</h5>
072    * <p class='bjava'>
073    *    BooleanHolder <jv>value</jv> = BooleanHolder.<jsm>create</jsm>();
074    *    <jsm>assertEquals</jsm>(<jk>false</jk>, <jv>value</jv>.get());
075    * </p>
076    *
077    * @return A new boolean value.
078    */
079   public static BooleanHolder create() {
080      return of(false);
081   }
082
083   /**
084    * Creates a new boolean value with the specified initial value.
085    *
086    * <h5 class='section'>Example:</h5>
087    * <p class='bjava'>
088    *    BooleanHolder <jv>value</jv> = BooleanHolder.<jsm>of</jsm>(<jk>true</jk>);
089    *    <jsm>assertEquals</jsm>(<jk>true</jk>, <jv>value</jv>.get());
090    * </p>
091    *
092    * @param value The initial value.  Can be <jk>null</jk>.
093    * @return A new boolean value.
094    */
095   public static BooleanHolder of(Boolean value) {
096      return new BooleanHolder(value);
097   }
098
099   /**
100    * Constructor.
101    *
102    * @param value The initial value.  Can be <jk>null</jk>.
103    */
104   public BooleanHolder(Boolean value) {
105      super(value);
106   }
107
108   /**
109    * Checks if the current value is equal to the specified value.
110    *
111    * <p>
112    * Uses {@link Shorts#eq(Object, Object)} for deep equality comparison, which handles nulls safely.
113    *
114    * <h5 class='section'>Example:</h5>
115    * <p class='bjava'>
116    *    BooleanHolder <jv>value</jv> = BooleanHolder.<jsm>of</jsm>(<jk>true</jk>);
117    *    <jsm>assertTrue</jsm>(<jv>value</jv>.is(<jk>true</jk>));
118    *    <jsm>assertFalse</jsm>(<jv>value</jv>.is(<jk>false</jk>));
119    *
120    *    <jc>// Handles null safely</jc>
121    *    BooleanHolder <jv>empty</jv> = BooleanHolder.<jsm>of</jsm>(<jk>null</jk>);
122    *    <jsm>assertTrue</jsm>(<jv>empty</jv>.is(<jk>null</jk>));
123    * </p>
124    *
125    * @param value The value to compare to.  Can be <jk>null</jk>.
126    * @return <jk>true</jk> if the current value is equal to the specified value.
127    */
128   @Override
129   public boolean is(Boolean value) {
130      return eq(get(), value);
131   }
132
133   /**
134    * Checks if the current value matches any of the specified values.
135    *
136    * <p>
137    * Uses {@link Shorts#eq(Object, Object)} for deep equality comparison of each value.
138    *
139    * <h5 class='section'>Example:</h5>
140    * <p class='bjava'>
141    *    BooleanHolder <jv>value</jv> = BooleanHolder.<jsm>of</jsm>(<jk>true</jk>);
142    *    <jsm>assertTrue</jsm>(<jv>value</jv>.isAny(<jk>true</jk>, <jk>null</jk>));
143    *    <jsm>assertFalse</jsm>(<jv>value</jv>.isAny(<jk>false</jk>));
144    * </p>
145    *
146    * @param values The values to compare to.  Must not be <jk>null</jk>.
147    * @return <jk>true</jk> if the current value matches any of the specified values.
148    */
149   public boolean isAny(Boolean...values) {
150      reqnn("values", values);
151      var current = get();
152      for (var value : values)
153         if (eq(current, value))
154            return true;
155      return false;
156   }
157
158   /**
159    * Returns <c>true</c> if the value is not set to <c>true</c> (i.e., it's <c>false</c> or <c>null</c>).
160    *
161    * <h5 class='section'>Example:</h5>
162    * <p class='bjava'>
163    *    BooleanHolder <jv>value</jv> = BooleanHolder.<jsm>of</jsm>(<jk>false</jk>);
164    *    <jk>if</jk> (<jv>value</jv>.isNotTrue()) {
165    *       <jsm>log</jsm>(<js>"Value is not true"</js>);
166    *    }
167    * </p>
168    *
169    * @return <c>true</c> if the value is not set to <c>true</c>, <c>false</c> otherwise.
170    */
171   public boolean isNotTrue() { return ! isTrue(); }
172
173   /**
174    * Returns <c>true</c> if the value is set to <c>true</c>.
175    *
176    * <h5 class='section'>Example:</h5>
177    * <p class='bjava'>
178    *    BooleanHolder <jv>value</jv> = BooleanHolder.<jsm>of</jsm>(<jk>true</jk>);
179    *    <jk>if</jk> (<jv>value</jv>.isTrue()) {
180    *       <jsm>log</jsm>(<js>"Value is true"</js>);
181    *    }
182    * </p>
183    *
184    * @return <c>true</c> if the value is set to <c>true</c>, <c>false</c> otherwise (including when <c>null</c>).
185    */
186   public boolean isTrue() { return ObjectUtils.isTrue(get()); }
187}