xref: /OpenGrok/opengrok-indexer/src/main/java/org/opengrok/indexer/util/LazilyInstantiate.java (revision c6f0939b1c668e9f8e1e276424439c3106b3a029)
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  * &nbsp; &nbsp; private static Supplier&lt;Singleton&gt; instance =
33e829566cSChris Fraire  * LazilyInstantiate.using(() -&gt; new Singleton());<br>
34e829566cSChris Fraire  * &nbsp; &nbsp; //other fields<br>
35e829566cSChris Fraire  * <br>
36e829566cSChris Fraire  * &nbsp; &nbsp; public static getInstance()<br>
37e829566cSChris Fraire  * &nbsp; &nbsp; {<br>
38e829566cSChris Fraire  * &nbsp; &nbsp; &nbsp; &nbsp; instance.get();<br>
39e829566cSChris Fraire  * &nbsp; &nbsp; }<br>
40e829566cSChris Fraire  * <br>
41e829566cSChris Fraire  * &nbsp; &nbsp; //other methods<br>
42e829566cSChris Fraire  * <br>
43e829566cSChris Fraire  * &nbsp; &nbsp; private Singleton()<br>
44e829566cSChris Fraire  * &nbsp; &nbsp; {<br>
45e829566cSChris Fraire  * &nbsp; &nbsp; &nbsp; &nbsp; //contructor stuff<br>
46e829566cSChris Fraire  * &nbsp; &nbsp; }<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