001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
002 *
003 * Copyright © 2019–2020 microBean™.
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * 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
014 * implied.  See the License for the specific language governing
015 * permissions and limitations under the License.
016 */
017package org.microbean.settings;
018
019import java.lang.annotation.Annotation;
020
021import java.util.Collections;
022import java.util.HashSet;
023import java.util.Objects;
024import java.util.Set;
025
026import java.util.function.Supplier;
027
028/**
029 * A {@link Supplier} of {@link String}s and hence an abstraction of a
030 * (definitionally) {@link String}-typed <a
031 * href="{@docRoot}/overview-summary.html#setting_value">setting
032 * value</a>, additionally encompassing the <a
033 * href="{@docRoot}/overview-summary.html#setting_name">setting
034 * name</a> for which it is applicable and the {@link Source} whence
035 * it originated.
036 *
037 * @author <a href="https://about.me/lairdnelson"
038 * target="_parent">Laird Nelson</a>
039 *
040 * @threadsafety Instances of this class are safe for concurrent use
041 * by multiple threads.
042 *
043 * @see Settings
044 *
045 * @see Source
046 *
047 * @see Source#getValue(String, Set)
048 */
049public class Value implements Supplier<String> {
050
051
052  /*
053   * Instance fields.
054   */
055
056
057  private final Source source;
058
059  private final String name;
060
061  private final Set<Annotation> qualifiers;
062
063  private final boolean authoritative;
064
065  private final Supplier<? extends String> valueSupplier;
066
067
068  /*
069   * Constructors.
070   */
071
072
073  /**
074   * Creates a new {@link Value}.
075   *
076   * @param other the {@link Value} to copy; must not be {@code null}
077   *
078   * @exception NullPointerException if {@code other} is {@code null}
079   */
080  public Value(final Value other) {
081    this(other.getSource(),
082         other.getName(),
083         other.getQualifiers(),
084         other.isAuthoritative(),
085         other::get);
086  }
087
088  /**
089   * Creates a new {@link Value}.
090   *
091   * @param other the {@link Value} to copy; must not be {@code null}
092   *
093   * @param value the {@link String} to be returned by the {@link
094   * #get()} method; may be {@code null}
095   *
096   * @exception NullPointerException if {@code other} is {@code null}
097   */
098  public Value(final Value other,
099               final String value) {
100    this(other.getSource(),
101         other.getName(),
102         other.getQualifiers(),
103         other.isAuthoritative(),
104         () -> value);
105  }
106
107  /**
108   * Creates a new {@link Value}.
109   *
110   * @param other the {@link Value} to copy; must not be {@code null}
111   *
112   * @param valueSupplier a {@link Supplier} of {@link String}s whose
113   * {@link Supplier#get()} method will be called by this {@link
114   * Value}'s {@link #get()} method; may be {@code null}; if
115   * non-{@code null}, must be safe for concurrent access by multiple
116   * threads
117   *
118   * @exception NullPointerException if {@code other} is {@code null}
119   */
120  public Value(final Value other,
121               final Supplier<? extends String> valueSupplier) {
122    this(other.getSource(),
123         other.getName(),
124         other.getQualifiers(),
125         other.isAuthoritative(),
126         valueSupplier);
127  }
128
129  /**
130   * Creates a new {@link Value}.
131   *
132   * @param source the {@link Source} that created this {@link Value};
133   * may be {@code null} to indicate that the {@link Value} was
134   * synthesized
135   *
136   * @param name the <a
137   * href="{@docRoot}/overview-summary.html#setting_name">name of the
138   * setting</a> for which this is a {@link Value}; must not be {@code
139   * null}
140   *
141   * @param qualifiers a {@link Set} of {@link Annotation}s <a
142   * href="{@docRoot}/overview-summary.html#qualifiers">qualifying</a>
143   * this {@link Value}; may be {@code null}; will be iterated over by
144   * this constructor without any extra synchronization; will be
145   * copied shallowly by this constructor if it is non-{@code null}
146   *
147   * @param value the {@link String} to be returned by the {@link
148   * #get()} method; may be {@code null}
149   *
150   * @exception NullPointerException if {@code name} is {@code null}
151   */
152  public Value(final Source source,
153               final String name,
154               final Set<Annotation> qualifiers,
155               final String value) {
156    this(source, name, qualifiers, false, () -> value);
157  }
158
159  /**
160   * Creates a new {@link Value}.
161   *
162   * @param source the {@link Source} that created this {@link Value};
163   * may be {@code null} to indicate that the {@link Value} was
164   * synthesized
165   *
166   * @param name the <a
167   * href="{@docRoot}/overview-summary.html#setting_name">name of the
168   * setting</a> for which this is a {@link Value}; must not be {@code
169   * null}
170   *
171   * @param qualifiers a {@link Set} of {@link Annotation}s <a
172   * href="{@docRoot}/overview-summary.html#qualifiers">qualifying</a>
173   * this {@link Value}; may be {@code null}; will be iterated over by
174   * this constructor without any extra synchronization; will be
175   * copied shallowly by this constructor if it is non-{@code null}
176   *
177   * @param valueSupplier a {@link Supplier} of {@link String}s whose
178   * {@link Supplier#get()} method will be called by this {@link
179   * Value}'s {@link #get()} method; may be {@code null}; if
180   * non-{@code null}, must be safe for concurrent access by multiple
181   * threads
182   *
183   * @exception NullPointerException if {@code name} is {@code null}
184   */
185  public Value(final Source source,
186               final String name,
187               final Set<Annotation> qualifiers,
188               final Supplier<? extends String> valueSupplier) {
189    this(source, name, qualifiers, false, valueSupplier);
190  }
191
192  /**
193   * Creates a new {@link Value}.
194   *
195   * @param source the {@link Source} that created this {@link Value};
196   * may be {@code null} to indicate that the {@link Value} was
197   * synthesized
198   *
199   * @param name the <a
200   * href="{@docRoot}/overview-summary.html#setting_name">name of the
201   * setting</a> for which this is a {@link Value}; must not be {@code
202   * null}
203   *
204   * @param qualifiers a {@link Set} of {@link Annotation}s <a
205   * href="{@docRoot}/overview-summary.html#qualifiers">qualifying</a>
206   * this {@link Value}; may be {@code null}; will be iterated over by
207   * this constructor without any extra synchronization; will be
208   * copied shallowly by this constructor if it is non-{@code null}
209   *
210   * @param authoritative whether this {@link Value} is to be treated
211   * as coming from an authoritative source
212   *
213   * @param value the {@link String} to be returned by the {@link
214   * #get()} method; may be {@code null}
215   *
216   * @exception NullPointerException if {@code name} is {@code null}
217   */
218  public Value(final Source source,
219               final String name,
220               final Set<Annotation> qualifiers,
221               final boolean authoritative,
222               final String value) {
223    this(source, name, qualifiers, authoritative, () -> value);
224  }
225
226  /**
227   * Creates a new {@link Value}.
228   *
229   * @param source the {@link Source} that created this {@link Value};
230   * may be {@code null} to indicate that the {@link Value} was
231   * synthesized
232   *
233   * @param name the <a
234   * href="{@docRoot}/overview-summary.html#setting_name">name of the
235   * setting</a> for which this is a {@link Value}; must not be {@code
236   * null}
237   *
238   * @param qualifiers a {@link Set} of {@link Annotation}s <a
239   * href="{@docRoot}/overview-summary.html#qualifiers">qualifying</a>
240   * this {@link Value}; may be {@code null}; will be iterated over by
241   * this constructor without any extra synchronization; will be
242   * copied shallowly by this constructor if it is non-{@code null}
243   *
244   * @param authoritative whether this {@link Value} is to be treated
245   * as coming from an authoritative source
246   *
247   * @param valueSupplier a {@link Supplier} of {@link String}s whose
248   * {@link Supplier#get()} method will be called by this {@link
249   * Value}'s {@link #get()} method; may be {@code null}; if
250   * non-{@code null}, must be safe for concurrent access by multiple
251   * threads
252   *
253   * @exception NullPointerException if {@code name} is {@code null}
254   */
255  public Value(final Source source,
256               final String name,
257               final Set<Annotation> qualifiers,
258               final boolean authoritative,
259               final Supplier<? extends String> valueSupplier) {
260    super();
261    this.source = source;
262    if (qualifiers == null || qualifiers.isEmpty()) {
263      this.qualifiers = Collections.emptySet();
264    } else if (qualifiers.size() == 1) {
265      this.qualifiers = Collections.singleton(qualifiers.iterator().next());
266    } else {
267      this.qualifiers = Collections.unmodifiableSet(new HashSet<>(qualifiers));
268    }
269    this.name = Objects.requireNonNull(name);
270    this.authoritative = authoritative;
271    if (valueSupplier == null) {
272      this.valueSupplier = Value::returnNull;
273    } else {
274      this.valueSupplier = valueSupplier;
275    }
276  }
277
278
279  /*
280   * Instance methods.
281   */
282
283
284  /**
285   * Returns the {@link String} representation of this {@link Value}.
286   *
287   * @return the {@link String} representation of this {@link Value},
288   * which may be {@code null}
289   *
290   * @nullability This method may return {@code null}.
291   *
292   * @idempotency No guarantees are made with respect to the
293   * idempotency of this method.
294   *
295   * @threadsafety This method is safe for concurrent use by multiple
296   * threads.
297   */
298  @Override
299  public final String get() {
300    return this.valueSupplier.get();
301  }
302
303  /**
304   * Returns {@code true} if this {@link Value} is to be treated as
305   * coming from an authoritative source.
306   *
307   * @return {@code true} if this {@link Value} is to be treated as
308   * coming from an authoritative source; {@code false} otherwise
309   *
310   * @idempotency This method is idempotent.
311   *
312   * @threadsafety This method is safe for concurrent use by multiple
313   * threads.
314   */
315  public final boolean isAuthoritative() {
316    return this.authoritative;
317  }
318
319  /**
320   * Returns the {@link Source} that created this {@link Value}.
321   *
322   * @return the {@link Source} that created this {@link Value}, which
323   * may be {@code null}
324   *
325   * @nullability This method may return {@code null}.
326   *
327   * @idempotency This method is idempotent.
328   *
329   * @threadsafety This method is safe for concurrent use by multiple
330   * threads.
331   */
332  public final Source getSource() {
333    return this.source;
334  }
335
336  /**
337   * Returns the <a
338   * href="{@docRoot}/overview-summary.html#setting_name">name of the
339   * setting</a> for which this is a {@link Value}.
340   *
341   * @return the <a
342   * href="{@docRoot}/overview-summary.html#setting_name">name of the
343   * setting</a> for which this is a {@link Value}; never {@code null}
344   *
345   * @nullability This method never returns {@code null}.
346   *
347   * @idempotency This method is idempotent.
348   *
349   * @threadsafety This method is safe for concurrent use by multiple
350   * threads.
351   */
352  public final String getName() {
353    return this.name;
354  }
355
356  /**
357   * Returns a non-{@code null}, {@linkplain
358   * Collections#unmodifiableSet(Set) unmodifiable <code>Set</code>}
359   * of {@link Annotation}s <a
360   * href="{@docRoot}/overview-summary.html#qualifiers">qualifying</a>
361   * this {@link Value}.
362   *
363   * @return a non-{@code null}, {@linkplain
364   * Collections#unmodifiableSet(Set) unmodifiable <code>Set</code>}
365   * of {@link Annotation}s <a
366   * href="{@docRoot}/overview-summary.html#qualifiers">qualifying</a>
367   * this {@link Value}
368   *
369   * @nullability This method never returns {@code null}.
370   *
371   * @idempotency This method is idempotent.
372   *
373   * @threadsafety This method is safe for concurrent use by multiple
374   * threads.
375   */
376  public final Set<Annotation> getQualifiers() {
377    return this.qualifiers;
378  }
379
380  /**
381   * Returns a hashcode for this {@link Value} based off the return
382   * value of the {@link #get()} method and nothing else.
383   *
384   * <p>Note that because the return value of invocations of a {@link
385   * Value}'s {@link #get()} method can change over time, in general
386   * {@link Value} hashcodes should be treated with great care.</p>
387   *
388   * @return a hashcode for this {@link Value}
389   *
390   * @idempotency No guarantees are made with respect to the
391   * idempotency of this method.
392   *
393   * @threadsafety This method is and overrides must be safe for
394   * concurrent use by multiple threads.
395   *
396   * @see #equals(Object)
397   */
398  @Override
399  public int hashCode() {
400    final Object value = this.get();
401    return value == null ? 0 : value.hashCode();
402  }
403
404  /**
405   * Returns {@code true} if the supplied {@link Object} is a {@link
406   * Value} and has a {@link #get()} method implementation that
407   * returns a value equal to the return value of an invocation of
408   * this {@link Value}'s {@link #get()} method.
409   *
410   * <p>Note that because the return value of invocations of a {@link
411   * Value}'s {@link #get()} method can change over time, in general
412   * {@link Value} equality comparisons should be treated with great
413   * care.</p>
414   *
415   * @param other the {@link Object} to compare; may be {@code null}
416   *
417   * @return {@code true} if the supplied {@link Object} is a {@link
418   * Value} and has a {@link #get()} method implementation that
419   * returns a value equal to the return value of an invocation of
420   * this {@link Value}'s {@link #get()} method; {@code false}
421   * otherwise
422   *
423   * @idempotency No guarantees are made with respect to the
424   * idempotency of this method.
425   *
426   * @threadsafety This method is and overrides must be safe for
427   * concurrent use by multiple threads.
428   *
429   * @see #hashCode()
430   */
431  @Override
432  public boolean equals(final Object other) {
433    if (other == this) {
434      return true;
435    } else if (other instanceof Value) {
436      final Value her = (Value)other;
437
438      final Object value = this.get();
439      if (value == null) {
440        if (her.get() != null) {
441          return false;
442        }
443      } else if (!value.equals(her.get())) {
444        return false;
445      }
446
447      return true;
448
449    } else {
450      return false;
451    }
452  }
453
454  /**
455   * Returns a {@link String} representation of this {@link Value} as
456   * of the current moment by returning the result of invoking the
457   * {@link #get()} method.
458   *
459   * <p>This method may return {@code null}.</p>
460   *
461   * @return a {@link String} representation of this {@link Value} as
462   * of the current moment, or {@code null}
463   *
464   * @nullability This method and its overrides may return {@code
465   * null}.
466   *
467   * @idempotency No guarantees are made with respect to the
468   * idempotency of this method.
469   *
470   * @threadsafety This method is and its overrides must be safe for
471   * concurrent use by multiple threads.
472   *
473   * @see #get()
474   */
475  @Override
476  public String toString() {
477    return this.get();
478  }
479
480
481  /*
482   * Static methods.
483   */
484  
485
486  /**
487   * A static method that exists only to be referred to internally by
488   * a method reference.
489   *
490   * @return {@code null} when invoked
491   */
492  private static final String returnNull() {
493    return null;
494  }
495
496}