1e829566cSChris Fraire /* 2e829566cSChris Fraire * The contents of this file are Copyright (c) 2014, 3e829566cSChris Fraire * https://programmingideaswithjake.wordpress.com/about/ made available under 4e829566cSChris Fraire * free license, 5e829566cSChris Fraire * https://programmingideaswithjake.wordpress.com/2014/10/05/java-functional-lazy-instantiation/ 6e829566cSChris Fraire * https://github.com/EZGames/functional-java/blob/master/LICENSE : 7e829566cSChris Fraire * "There is no license on this code. 8e829566cSChris Fraire * It's true open-ware. Do what you want with it. 9e829566cSChris Fraire * It's only meant to be helpful 10e829566cSChris Fraire * I'd prefer that you don't take credit for it, though. You don't have to give 11e829566cSChris Fraire * credit; just don't take it." 1234eac45cSChris Fraire * Portions Copyright (c) 2018, 2020, Chris Fraire <cfraire@me.com>. 13e829566cSChris Fraire */ 14e829566cSChris Fraire package org.opengrok.indexer.util; 15e829566cSChris Fraire 16e829566cSChris Fraire import java.util.function.Supplier; 17e829566cSChris Fraire 18e829566cSChris Fraire /** 19e829566cSChris Fraire * {@code LazilyInstantiate} is a quick class to make lazily instantiating 20e829566cSChris Fraire * objects easy. All you need to know for working with this class is its two 21e829566cSChris Fraire * public methods: one static factory for creating the object, and another for 22e829566cSChris Fraire * initiating the instantiation and retrieval of the object. 23e829566cSChris Fraire * <p> 24e829566cSChris Fraire * Also, another benefit is that it's thread safe, but only blocks when 25e829566cSChris Fraire * initially instantiating the object. After that, it stops blocking and removes 26e829566cSChris Fraire * unnecessary checks for whether the object is instantiated. 27e829566cSChris Fraire * <p> 28e829566cSChris Fraire * Here's an example of it being used for implementing a singleton: 29e829566cSChris Fraire * <code> 30e829566cSChris Fraire * public class Singleton<br> 31e829566cSChris Fraire * {<br> 32e829566cSChris Fraire * private static Supplier<Singleton> instance = 33e829566cSChris Fraire * LazilyInstantiate.using(() -> new Singleton());<br> 34e829566cSChris Fraire * //other fields<br> 35e829566cSChris Fraire * <br> 36e829566cSChris Fraire * public static getInstance()<br> 37e829566cSChris Fraire * {<br> 38e829566cSChris Fraire * instance.get();<br> 39e829566cSChris Fraire * }<br> 40e829566cSChris Fraire * <br> 41e829566cSChris Fraire * //other methods<br> 42e829566cSChris Fraire * <br> 43e829566cSChris Fraire * private Singleton()<br> 44e829566cSChris Fraire * {<br> 45e829566cSChris Fraire * //contructor stuff<br> 46e829566cSChris Fraire * }<br> 47e829566cSChris Fraire * }<br> 48e829566cSChris Fraire * </code> 49e829566cSChris Fraire * <p> 50e829566cSChris Fraire * So, here are the changes you'll need to apply in your code: 51e829566cSChris Fraire * <ul> 52e829566cSChris Fraire * <li>Change the type of the lazily instantiated object to a {@code Supplier} 53e829566cSChris Fraire * of that <i>type</i> 54e829566cSChris Fraire * <li>Have it set to LazilyInstantiate.using() where the argument is 55e829566cSChris Fraire * {@code () -> <instantiation code>} You could also use a method reference, 56e829566cSChris Fraire * which, for the example above, would be {@code Singleton::new} instead of 57e829566cSChris Fraire * {@code () -> new Singleton()}</li> 58e829566cSChris Fraire * <li>Whatever asks for the object, asks for the {@code Supplier} object, then 59e829566cSChris Fraire * {@code .get()}</li> 60e829566cSChris Fraire * </ul> 61e829566cSChris Fraire * 62e829566cSChris Fraire * @param <T> the type of object that you're trying to lazily instantiate 63e829566cSChris Fraire */ 64e829566cSChris Fraire public class LazilyInstantiate<T> implements Supplier<T> { 65e829566cSChris Fraire 66e829566cSChris Fraire private final Supplier<T> supplier; 67e829566cSChris Fraire private Supplier<T> current; 6834eac45cSChris Fraire private volatile boolean active; 69e829566cSChris Fraire using(Supplier<T> supplier)70e829566cSChris Fraire public static <T> LazilyInstantiate<T> using(Supplier<T> supplier) { 71e829566cSChris Fraire return new LazilyInstantiate<>(supplier); 72e829566cSChris Fraire } 73e829566cSChris Fraire 74e829566cSChris Fraire /** 75e829566cSChris Fraire * Executes the {@link #using(java.util.function.Supplier)} supplier in a 76e829566cSChris Fraire * thread-safe manner if it has not yet been executed, and keeps the result 77e829566cSChris Fraire * to provide to every caller of this method. 78e829566cSChris Fraire * @return the result of {@code supplier} 79e829566cSChris Fraire */ 80e829566cSChris Fraire @Override get()81e829566cSChris Fraire public T get() { 82e829566cSChris Fraire return current.get(); 83e829566cSChris Fraire } 84e829566cSChris Fraire 8534eac45cSChris Fraire /** 8634eac45cSChris Fraire * Gets a value indicating if the instance is active and no longer 8734eac45cSChris Fraire * technically lazy, since {@link #get()} has been called. 8834eac45cSChris Fraire */ isActive()8934eac45cSChris Fraire public boolean isActive() { 9034eac45cSChris Fraire return active; 9134eac45cSChris Fraire } 9234eac45cSChris Fraire LazilyInstantiate(Supplier<T> supplier)93e829566cSChris Fraire private LazilyInstantiate(Supplier<T> supplier) { 94e829566cSChris Fraire this.supplier = supplier; 9534eac45cSChris Fraire this.current = this::swapper; 96e829566cSChris Fraire } 97e829566cSChris Fraire 98e829566cSChris Fraire //swaps the itself out for a supplier of an instantiated object swapper()99e829566cSChris Fraire private synchronized T swapper() { 100*c6f0939bSAdam Hornacek if (!(current instanceof Factory)) { 101e829566cSChris Fraire T obj = supplier.get(); 102e829566cSChris Fraire current = new Factory<>(obj); 10334eac45cSChris Fraire active = true; 104e829566cSChris Fraire } 105e829566cSChris Fraire return current.get(); 106e829566cSChris Fraire } 107e829566cSChris Fraire 10834eac45cSChris Fraire private static class Factory<U> implements Supplier<U> { 109e829566cSChris Fraire 11034eac45cSChris Fraire private final U obj; 111e829566cSChris Fraire Factory(U obj)11234eac45cSChris Fraire Factory(U obj) { 113e829566cSChris Fraire this.obj = obj; 114e829566cSChris Fraire } 115e829566cSChris Fraire 116e829566cSChris Fraire @Override get()11734eac45cSChris Fraire public U get() { 118e829566cSChris Fraire return obj; 119e829566cSChris Fraire } 120e829566cSChris Fraire } 121e829566cSChris Fraire } 122