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.concurrent;
018
019import static org.apache.juneau.commons.utils.Shorts.*;
020
021import java.util.*;
022import java.util.concurrent.atomic.*;
023import java.util.function.*;
024
025/**
026 * A thread-safe reference that combines {@link AtomicReference} with {@link Optional}-like functionality.
027 *
028 * <p>
029 * This class extends {@link AtomicReference} to provide both atomic reference operations and Optional-like
030 * convenience methods for working with potentially null values. It is thread-safe and can be used in
031 * concurrent environments where you need to atomically update a reference while also having Optional-like
032 * operations.
033 *
034 * <h5 class='section'>Features:</h5>
035 * <ul class='spaced-list'>
036 *    <li>Extends AtomicReference - inherits all atomic operations (get, set, compareAndSet, etc.)
037 *    <li>Optional-like API - provides isPresent(), isEmpty(), map(), orElse(), etc.
038 *    <li>Thread-safe - all operations are atomic
039 *    <li>Null-safe - handles null values gracefully (null represents "empty")
040 * </ul>
041 *
042 * <h5 class='section'>Usage:</h5>
043 * <p class='bjava'>
044 *    <jc>// Create an empty reference</jc>
045 *    NullableReference&lt;String&gt; <jv>ref</jv> = NullableReference.<jsm>empty</jsm>();
046 *
047 *    <jc>// Set a value atomically</jc>
048 *    <jv>ref</jv>.set(<js>"value"</js>);
049 *
050 *    <jc>// Check if value is present</jc>
051 *    <jk>if</jk> (<jv>ref</jv>.isPresent()) {
052 *       String <jv>value</jv> = <jv>ref</jv>.get();
053 *    }
054 *
055 *    <jc>// Use Optional-like methods</jc>
056 *    String <jv>result</jv> = <jv>ref</jv>.map(String::toUpperCase).orElse(<js>"default"</js>);
057 *
058 *    <jc>// Atomic update</jc>
059 *    <jv>ref</jv>.compareAndSet(<js>"value"</js>, <js>"newValue"</js>);
060 * </p>
061 *
062 * <h5 class='section'>Thread Safety:</h5>
063 * <p>
064 * This class is thread-safe. All operations inherit thread-safety from {@link AtomicReference}.
065 * Multiple threads can safely call methods like {@link #get()}, {@link #set(Object)}, {@link #compareAndSet(Object, Object)},
066 * and the Optional-like methods concurrently.
067 *
068 * <h5 class='section'>See Also:</h5><ul>
069 *    <li class='jc'>{@link AtomicReference} - Base class providing atomic operations
070 *    <li class='jc'>{@link Optional} - Java's Optional class
071 *    <li class='jc'>{@link org.apache.juneau.commons.function.NullableSupplier} - Similar functionality for suppliers
072 * </ul>
073 *
074 * @param <V> The type of value held by this reference.
075 */
076@SuppressWarnings({
077   "java:S1192" // Duplicated literals (argument/property names) read more clearly inline than as constants
078})
079public class NullableReference<V> extends AtomicReference<V> {
080
081   private static final long serialVersionUID = 1L;
082
083   /**
084    * Creates an empty NullableReference with an initial value of <jk>null</jk>.
085    *
086    * @param <V> The value type.
087    * @return A new empty NullableReference.
088    */
089   public static <V> NullableReference<V> empty() {
090      return new NullableReference<>(null);
091   }
092
093   /**
094    * Creates an NullableReference with the specified initial value.
095    *
096    * @param <V> The value type.
097    * @param initialValue The initial value. Can be <jk>null</jk>.
098    * @return A new NullableReference with the specified value.
099    */
100   public static <V> NullableReference<V> of(V initialValue) {
101      return new NullableReference<>(initialValue);
102   }
103
104   /**
105    * Creates an NullableReference with the specified initial value (alias for {@link #of(Object)}).
106    *
107    * @param <V> The value type.
108    * @param initialValue The initial value. Can be <jk>null</jk>.
109    * @return A new NullableReference with the specified value.
110    */
111   public static <V> NullableReference<V> ofNullable(V initialValue) {
112      return new NullableReference<>(initialValue);
113   }
114
115   /**
116    * Constructor with initial value.
117    *
118    * @param initialValue The initial value. Can be <jk>null</jk>.
119    */
120   public NullableReference(V initialValue) {
121      super(initialValue);
122   }
123
124   /**
125    * Default constructor (initializes to <jk>null</jk>).
126    */
127   public NullableReference() {
128      super();
129   }
130
131   /**
132    * Returns <jk>true</jk> if the current value is not <jk>null</jk>.
133    *
134    * @return <jk>true</jk> if the current value is not <jk>null</jk>.
135    */
136   public boolean isPresent() {
137      return nn(get());
138   }
139
140   /**
141    * Returns <jk>true</jk> if the current value is <jk>null</jk>.
142    *
143    * @return <jk>true</jk> if the current value is <jk>null</jk>.
144    */
145   public boolean isEmpty() {
146      return !isPresent();
147   }
148
149   /**
150    * If a value is present, applies the provided mapping function to it and returns an NullableReference describing the result.
151    *
152    * @param <U> The type of the result of the mapping function.
153    * @param mapper A mapping function to apply to the value, if present. Must not be <jk>null</jk>.
154    * @return An NullableReference describing the result of applying a mapping function to the value, if a value is present, otherwise an empty NullableReference.
155    */
156   public <U> NullableReference<U> map(Function<? super V,? extends U> mapper) {
157      reqnn("mapper", mapper);
158      V value = get();
159      return nn(value) ? NullableReference.of(mapper.apply(value)) : NullableReference.empty();
160   }
161
162   /**
163    * If a value is present, returns the result of applying the given NullableReference-bearing mapping function to the value, otherwise returns an empty NullableReference.
164    *
165    * @param <U> The type parameter to the NullableReference returned by the mapping function.
166    * @param mapper A mapping function to apply to the value, if present. Must not be <jk>null</jk>.
167    * @return The result of applying an NullableReference-bearing mapping function to the value, if a value is present, otherwise an empty NullableReference.
168    */
169   public <U> NullableReference<U> flatMap(Function<? super V,? extends NullableReference<? extends U>> mapper) {
170      reqnn("mapper", mapper);
171      V value = get();
172      if (nn(value)) {
173         NullableReference<? extends U> result = mapper.apply(value);
174         return result != null ? NullableReference.ofNullable(result.get()) : NullableReference.empty();
175      }
176      return NullableReference.empty();
177   }
178
179   /**
180    * If a value is present, and the value matches the given predicate, returns an NullableReference describing the value, otherwise returns an empty NullableReference.
181    *
182    * @param predicate A predicate to apply to the value, if present. Must not be <jk>null</jk>.
183    * @return An NullableReference describing the value if a value is present and the value matches the given predicate, otherwise an empty NullableReference.
184    */
185   public NullableReference<V> filter(Predicate<? super V> predicate) {
186      reqnn("predicate", predicate);
187      V value = get();
188      return (nn(value) && predicate.test(value)) ? NullableReference.of(value) : NullableReference.empty();
189   }
190
191   /**
192    * If a value is present, returns the value, otherwise returns <jk>other</jk>.
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 <jk>other</jk>.
196    */
197   public V orElse(V other) {
198      V value = get();
199      return nn(value) ? value : other;
200   }
201
202   /**
203    * If a value is present, returns the value, otherwise returns the result produced by the supplying function.
204    *
205    * @param other A {@link Supplier} whose result is returned if no value is present. Must not be <jk>null</jk>.
206    * @return The value, if present, otherwise the result of <jk>other.get()</jk>.
207    */
208   public V orElseGet(Supplier<? extends V> other) {
209      reqnn("other", other);
210      V value = get();
211      return nn(value) ? value : other.get();
212   }
213
214   /**
215    * If a value is present, returns the value, otherwise throws an exception produced by the exception supplying function.
216    *
217    * @param <X> Type of the exception to be thrown.
218    * @param exceptionSupplier The supplying function that produces an exception to be thrown. Must not be <jk>null</jk>.
219    * @return The value, if present.
220    * @throws X If no value is present.
221    */
222   public <X extends Throwable> V orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
223      reqnn("exceptionSupplier", exceptionSupplier);
224      V value = get();
225      if (nn(value))
226         return value;
227      throw exceptionSupplier.get();
228   }
229
230   /**
231    * If a value is present, performs the given action with the value, otherwise does nothing.
232    *
233    * @param action The action to be performed, if a value is present. Must not be <jk>null</jk>.
234    */
235   public void ifPresent(Consumer<? super V> action) {
236      reqnn("action", action);
237      V value = get();
238      if (nn(value))
239         action.accept(value);
240   }
241
242   /**
243    * If a value is present, performs the given action with the value, otherwise performs the given empty-based action.
244    *
245    * @param action The action to be performed, if a value is present. Must not be <jk>null</jk>.
246    * @param emptyAction The empty-based action to be performed, if no value is present. Must not be <jk>null</jk>.
247    */
248   public void ifPresentOrElse(Consumer<? super V> action, Runnable emptyAction) {
249      reqnn("action", action);
250      reqnn("emptyAction", emptyAction);
251      V value = get();
252      if (nn(value))
253         action.accept(value);
254      else
255         emptyAction.run();
256   }
257
258   /**
259    * Converts this NullableReference to an {@link Optional}.
260    *
261    * @return An Optional containing the value if present, otherwise an empty Optional.
262    */
263   public Optional<V> toOptional() {
264      return o(get());
265   }
266}