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