001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau;
014
015import java.lang.reflect.*;
016import java.util.*;
017import java.util.function.*;
018
019import org.apache.juneau.reflect.*;
020
021/**
022 * Represents a simple settable value.
023 *
024 * <p>
025 * Similar to an {@link Optional} but mutable.
026 *
027 * <h5 class='section'>Notes:</h5><ul>
028 *    <li class='warn'>This class is not thread safe.
029 * </ul>
030 *
031 * <h5 class='section'>See Also:</h5><ul>
032 * </ul>
033 *
034 * @param <T> The value type.
035 */
036public class Value<T> {
037
038   //-----------------------------------------------------------------------------------------------------------------
039   // Static
040   //-----------------------------------------------------------------------------------------------------------------
041
042   /**
043    * Static creator.
044    *
045    * @param <T> The value type.
046    * @param object The object being wrapped.
047    * @return A new {@link Value} object.
048    */
049   public static <T> Value<T> of(T object) {
050      return new Value<>(object);
051   }
052
053   /**
054    * Static creator.
055    *
056    * @param <T> The value type.
057    * @return An empty {@link Value} object.
058    */
059   public static <T> Value<T> empty() {
060      return new Value<>(null);
061   }
062
063   /**
064    * Returns the generic parameter type of the Value type.
065    *
066    * @param t The type to find the parameter type of.
067    * @return The parameter type of the value, or <jk>null</jk> if the type is not a subclass of <c>Value</c>.
068    */
069   public static Type getParameterType(Type t) {
070      if (t instanceof ParameterizedType) {
071         ParameterizedType pt = (ParameterizedType)t;
072         if (pt.getRawType() == Value.class) {
073            Type[] ta = pt.getActualTypeArguments();
074            if (ta.length > 0)
075               return ta[0];
076         }
077      } else if (t instanceof Class) {
078         Class<?> c = (Class<?>)t;
079         if (Value.class.isAssignableFrom(c)) {
080            return ClassInfo.of(c).getParameterType(0, Value.class);
081         }
082      }
083
084      return null;
085   }
086
087   /**
088    * Returns the unwrapped type.
089    *
090    * @param t The type to unwrap.
091    * @return The unwrapped type, or the same type if the type isn't {@link Value}.
092    */
093   public static Type unwrap(Type t) {
094      Type x = getParameterType(t);
095      return x != null ? x : t;
096   }
097
098   /**
099    * Convenience method for checking if the specified type is this class.
100    *
101    * @param t The type to check.
102    * @return <jk>true</jk> if the specified type is this class.
103    */
104   public static boolean isType(Type t) {
105      return
106         (t instanceof ParameterizedType && ((ParameterizedType)t).getRawType() == Value.class)
107         || (t instanceof Class && Value.class.isAssignableFrom((Class<?>)t));
108   }
109
110   //-----------------------------------------------------------------------------------------------------------------
111   // Implementation
112   //-----------------------------------------------------------------------------------------------------------------
113
114
115   private T t;
116   private ValueListener<T> listener;
117
118   /**
119    * Constructor.
120    */
121   public Value() {}
122
123   /**
124    * Constructor.
125    *
126    * @param t Initial value.
127    */
128   public Value(T t) {
129      set(t);
130   }
131
132   /**
133    * Adds a listener for this value.
134    *
135    * @param listener The new listener for this value.
136    * @return This object.
137    */
138   public Value<T> listener(ValueListener<T> listener) {
139      this.listener = listener;
140      return this;
141   }
142
143   /**
144    * Sets the value.
145    *
146    * @param t The new value.
147    * @return This object.
148    */
149   public Value<T> set(T t) {
150      this.t = t;
151      if (listener != null)
152         listener.onSet(t);
153      return this;
154   }
155
156   /**
157    * Sets the value if it's not already set.
158    *
159    * @param t The new value.
160    * @return This object.
161    */
162   public Value<T> setIfEmpty(T t) {
163      if (isEmpty())
164         set(t);
165      return this;
166   }
167
168   /**
169    * Returns the value.
170    *
171    * @return The value, or <jk>null</jk> if it is not set.
172    */
173   public T get() {
174      return t;
175   }
176
177   /**
178    * Returns the value and then unsets it.
179    *
180    * @return The value before it was unset.
181    */
182   public T getAndUnset() {
183      T t2 = t;
184      t = null;
185      return t2;
186   }
187
188   /**
189    * Returns <jk>true</jk> if the value is set.
190    *
191    * @return <jk>true</jk> if the value is set.
192    */
193   public boolean isPresent() {
194      return get() != null;
195   }
196
197   /**
198    * If a value is present, invoke the specified consumer with the value, otherwise do nothing.
199    *
200    * @param consumer Block to be executed if a value is present.
201    */
202   public void ifPresent(Consumer<? super T> consumer) {
203      if (t != null)
204         consumer.accept(t);
205   }
206
207   /**
208    * Applies a mapping function against the contents of this value.
209    *
210    * @param <T2> The mapped value type.
211    * @param mapper The mapping function.
212    * @return The mapped value.
213    */
214   public <T2> Value<T2> map(Function<? super T, T2> mapper) {
215      if (t != null)
216         return Value.of(mapper.apply(t));
217      return Value.empty();
218   }
219
220   /**
221    * Returns the contents of this value or the default value if <jk>null</jk>.
222    *
223    * @param def The default value.
224    * @return The contents of this value or the default value if <jk>null</jk>.
225    */
226   public T orElse(T def) {
227      return t == null ? def : t;
228   }
229   /**
230    * Returns <jk>true</jk> if the value is empty.
231    *
232    * @return <jk>true</jk> if the value is empty.
233    */
234   public boolean isEmpty() {
235      return t == null;
236   }
237
238   /**
239    * Return the value if present, otherwise invoke {@code other} and return
240    * the result of that invocation.
241    *
242    * @param other a {@code Supplier} whose result is returned if no value
243    * is present
244    * @return the value if present otherwise the result of {@code other.get()}
245    * @throws NullPointerException if value is not present and {@code other} is
246    * null
247    */
248   public T orElseGet(Supplier<? extends T> other) {
249      return t != null ? t : other.get();
250   }
251
252   /**
253    * Return the contained value, if present, otherwise throw an exception
254    * to be created by the provided supplier.
255    *
256    * @param <X> The exception type.
257    * @param exceptionSupplier The supplier which will return the exception to
258    * be thrown
259    * @return the present value
260    * @throws X if there is no value present
261    * @throws NullPointerException if no value is present and
262    * {@code exceptionSupplier} is null
263    */
264   public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
265      if (t != null)
266         return t;
267      throw exceptionSupplier.get();
268   }
269
270   @Override /* Object */
271   public String toString() {
272      return "Value("+t+")";
273   }
274}