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}