001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  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 implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.lang3.concurrent;
018
019import java.util.concurrent.Callable;
020import java.util.concurrent.CancellationException;
021import java.util.concurrent.ExecutionException;
022import java.util.concurrent.ExecutorService;
023import java.util.concurrent.Executors;
024import java.util.concurrent.Future;
025
026import org.apache.commons.lang3.function.FailableConsumer;
027import org.apache.commons.lang3.function.FailableSupplier;
028
029/**
030 * A class that allows complex initialization operations in a background task.
031 *
032 * <p>
033 * Applications often have to do some expensive initialization steps when they
034 * are started, e.g. constructing a connection to a database, reading a
035 * configuration file, etc. Doing these things in parallel can enhance
036 * performance as the CPU load can be improved. However, when access to the
037 * resources initialized in a background thread is actually required,
038 * synchronization has to be performed to ensure that their initialization is
039 * complete.
040 * </p>
041 * <p>
042 * This abstract base class provides support for this use case. A concrete
043 * subclass must implement the {@link #initialize()} method. Here an arbitrary
044 * initialization can be implemented, and a result object can be returned. With
045 * this method in place the basic usage of this class is as follows (where
046 * {@code MyBackgroundInitializer} is a concrete subclass):
047 * </p>
048 *
049 * <pre>
050 * MyBackgroundInitializer initializer = new MyBackgroundInitializer();
051 * initializer.start();
052 * // Now do some other things. Initialization runs in a parallel thread
053 * ...
054 * // Wait for the end of initialization and access the result object
055 * Object result = initializer.get();
056 * </pre>
057 *
058 * <p>
059 * After the construction of a {@link BackgroundInitializer} object its
060 * {@link #start()} method has to be called. This starts the background
061 * processing. The application can now continue to do other things. When it
062 * needs access to the object produced by the {@link BackgroundInitializer} it
063 * calls its {@link #get()} method. If initialization is already complete,
064 * {@link #get()} returns the result object immediately. Otherwise it blocks
065 * until the result object is fully constructed.
066 * </p>
067 * <p>
068 * {@link BackgroundInitializer} is a thin wrapper around a {@link Future}
069 * object and uses an {@link ExecutorService} for running the background
070 * initialization task. It is possible to pass in an {@link ExecutorService} at
071 * construction time or set one using {@code setExternalExecutor()} before
072 * {@code start()} was called. Then this object is used to spawn the background
073 * task. If no {@link ExecutorService} has been provided, {@code
074 * BackgroundInitializer} creates a temporary {@link ExecutorService} and
075 * destroys it when initialization is complete.
076 * </p>
077 * <p>
078 * The methods provided by {@link BackgroundInitializer} provide for minimal
079 * interaction with the wrapped {@link Future} object. It is also possible to
080 * obtain the {@link Future} object directly. Then the enhanced functionality
081 * offered by {@link Future} can be used, e.g. to check whether the background
082 * operation is complete or to cancel the operation.
083 * </p>
084 *
085 * @since 3.0
086 * @param <T> the type of the object managed by this initializer class
087 */
088public class BackgroundInitializer<T> extends AbstractConcurrentInitializer<T, Exception> {
089
090    /**
091     * Builds a new instance.
092     *
093     * @param <T> the type of the object managed by the initializer.
094     * @param <I> the type of the initializer managed by this builder.
095     * @since 3.14.0
096     */
097    public static class Builder<I extends BackgroundInitializer<T>, T> extends AbstractBuilder<I, T, Builder<I, T>, Exception> {
098
099        /**
100         * The external executor service for executing tasks. null is a permitted value.
101         */
102        private ExecutorService externalExecutor;
103
104        /**
105         * Constructs a new instance.
106         */
107        public Builder() {
108            // empty
109        }
110
111        @SuppressWarnings("unchecked")
112        @Override
113        public I get() {
114            return (I) new BackgroundInitializer(getInitializer(), getCloser(), externalExecutor);
115        }
116
117        /**
118         * Sets the external executor service for executing tasks. null is a permitted value.
119         *
120         * @see org.apache.commons.lang3.concurrent.BackgroundInitializer#setExternalExecutor(ExecutorService)
121         *
122         * @param externalExecutor the {@link ExecutorService} to be used.
123         * @return {@code this} instance.
124         */
125        public Builder<I, T> setExternalExecutor(final ExecutorService externalExecutor) {
126            this.externalExecutor = externalExecutor;
127            return asThis();
128        }
129
130    }
131
132    private final class InitializationTask implements Callable<T> {
133        /** Stores the executor service to be destroyed at the end. */
134        private final ExecutorService execFinally;
135
136        /**
137         * Creates a new instance of {@link InitializationTask} and initializes
138         * it with the {@link ExecutorService} to be destroyed at the end.
139         *
140         * @param exec the {@link ExecutorService}
141         */
142        InitializationTask(final ExecutorService exec) {
143            execFinally = exec;
144        }
145
146        /**
147         * Initiates initialization and returns the result.
148         *
149         * @return the result object
150         * @throws Exception if an error occurs
151         */
152        @Override
153        public T call() throws Exception {
154            try {
155                return initialize();
156            } finally {
157                if (execFinally != null) {
158                    execFinally.shutdown();
159                }
160            }
161        }
162    }
163
164    /**
165     * Creates a new builder.
166     *
167     * @param <T> the type of object to build.
168     * @return a new builder.
169     * @since 3.14.0
170     */
171    public static <T> Builder<BackgroundInitializer<T>, T> builder() {
172        return new Builder<>();
173    }
174
175    /** The external executor service for executing tasks. */
176    private ExecutorService externalExecutor; // @GuardedBy("this")
177
178    /** A reference to the executor service that is actually used. */
179    private ExecutorService executor; // @GuardedBy("this")
180
181    /** Stores the handle to the background task. */
182    private Future<T> future;  // @GuardedBy("this")
183
184    /**
185     * Creates a new instance of {@link BackgroundInitializer}. No external
186     * {@link ExecutorService} is used.
187     */
188    protected BackgroundInitializer() {
189        this(null);
190    }
191
192    /**
193     * Creates a new instance of {@link BackgroundInitializer} and initializes
194     * it with the given {@link ExecutorService}. If the {@link ExecutorService}
195     * is not null, the background task for initializing this object will be
196     * scheduled at this service. Otherwise a new temporary {@code
197     * ExecutorService} is created.
198     *
199     * @param exec an external {@link ExecutorService} to be used for task
200     * execution
201     */
202    protected BackgroundInitializer(final ExecutorService exec) {
203        setExternalExecutor(exec);
204    }
205
206    /**
207     * Constructs a new instance.
208     *
209     * @param initializer the initializer supplier called by {@link #initialize()}.
210     * @param closer the closer consumer called by {@link #close()}.
211     * @param exec the {@link ExecutorService} to be used @see #setExternalExecutor(ExecutorService)
212     */
213    private BackgroundInitializer(final FailableSupplier<T, ConcurrentException> initializer, final FailableConsumer<T, ConcurrentException> closer, final ExecutorService exec) {
214        super(initializer, closer);
215        setExternalExecutor(exec);
216    }
217
218    /**
219     * Creates the {@link ExecutorService} to be used. This method is called if
220     * no {@link ExecutorService} was provided at construction time.
221     *
222     * @return the {@link ExecutorService} to be used
223     */
224    private ExecutorService createExecutor() {
225        return Executors.newFixedThreadPool(getTaskCount());
226    }
227
228    /**
229     * Creates a task for the background initialization. The {@link Callable}
230     * object returned by this method is passed to the {@link ExecutorService}.
231     * This implementation returns a task that invokes the {@link #initialize()}
232     * method. If a temporary {@link ExecutorService} is used, it is destroyed
233     * at the end of the task.
234     *
235     * @param execDestroy the {@link ExecutorService} to be destroyed by the
236     * task
237     * @return a task for the background initialization
238     */
239    private Callable<T> createTask(final ExecutorService execDestroy) {
240        return new InitializationTask(execDestroy);
241    }
242
243    /**
244     * Returns the result of the background initialization. This method blocks
245     * until initialization is complete. If the background processing caused a
246     * runtime exception, it is directly thrown by this method. Checked
247     * exceptions, including {@link InterruptedException} are wrapped in a
248     * {@link ConcurrentException}. Calling this method before {@link #start()}
249     * was called causes an {@link IllegalStateException} exception to be
250     * thrown.
251     *
252     * @return the object produced by this initializer
253     * @throws ConcurrentException if a checked exception occurred during
254     * background processing
255     * @throws IllegalStateException if {@link #start()} has not been called
256     */
257    @Override
258    public T get() throws ConcurrentException {
259        try {
260            return getFuture().get();
261        } catch (final ExecutionException execex) {
262            ConcurrentUtils.handleCause(execex);
263            return null; // should not be reached
264        } catch (final InterruptedException iex) {
265            // reset interrupted state
266            Thread.currentThread().interrupt();
267            throw new ConcurrentException(iex);
268        }
269    }
270
271    /**
272     * Returns the {@link ExecutorService} that is actually used for executing
273     * the background task. This method can be called after {@link #start()}
274     * (before {@code start()} it returns <b>null</b>). If an external executor
275     * was set, this is also the active executor. Otherwise this method returns
276     * the temporary executor that was created by this object.
277     *
278     * @return the {@link ExecutorService} for executing the background task
279     */
280    protected final synchronized ExecutorService getActiveExecutor() {
281        return executor;
282    }
283
284    /**
285     * Returns the external {@link ExecutorService} to be used by this class.
286     *
287     * @return the {@link ExecutorService}
288     */
289    public final synchronized ExecutorService getExternalExecutor() {
290        return externalExecutor;
291    }
292
293    /**
294     * Returns the {@link Future} object that was created when {@link #start()}
295     * was called. Therefore this method can only be called after {@code
296     * start()}.
297     *
298     * @return the {@link Future} object wrapped by this initializer
299     * @throws IllegalStateException if {@link #start()} has not been called
300     */
301    public synchronized Future<T> getFuture() {
302        if (future == null) {
303            throw new IllegalStateException("start() must be called first!");
304        }
305
306        return future;
307    }
308
309    /**
310     * Returns the number of background tasks to be created for this
311     * initializer. This information is evaluated when a temporary {@code
312     * ExecutorService} is created. This base implementation returns 1. Derived
313     * classes that do more complex background processing can override it. This
314     * method is called from a synchronized block by the {@link #start()}
315     * method. Therefore overriding methods should be careful with obtaining
316     * other locks and return as fast as possible.
317     *
318     * @return the number of background tasks required by this initializer
319     */
320    protected int getTaskCount() {
321        return 1;
322    }
323
324    /**
325     * {@inheritDoc}
326     */
327    @Override
328    protected Exception getTypedException(final Exception e) {
329        //This Exception object will be used for type comparison in AbstractConcurrentInitializer.initialize but not thrown
330        return new Exception(e);
331    }
332
333    /**
334     * Tests whether this instance is initialized. Once initialized, always returns true.
335     * If initialization failed then the failure will be cached and this will never return
336     * true.
337     *
338     * @return true if initialization completed successfully, otherwise false
339     * @since 3.14.0
340     */
341    @Override
342    public synchronized boolean isInitialized() {
343        if (future == null || ! future.isDone() ) {
344            return false;
345        }
346
347        try {
348            future.get();
349            return true;
350        } catch (CancellationException | ExecutionException | InterruptedException e) {
351            return false;
352        }
353    }
354
355    /**
356     * Returns a flag whether this {@link BackgroundInitializer} has already
357     * been started.
358     *
359     * @return a flag whether the {@link #start()} method has already been
360     * called
361     */
362    public synchronized boolean isStarted() {
363        return future != null;
364    }
365
366    /**
367     * Sets an {@link ExecutorService} to be used by this class. The {@code
368     * ExecutorService} passed to this method is used for executing the
369     * background task. Thus it is possible to re-use an already existing
370     * {@link ExecutorService} or to use a specially configured one. If no
371     * {@link ExecutorService} is set, this instance creates a temporary one and
372     * destroys it after background initialization is complete. Note that this
373     * method must be called before {@link #start()}; otherwise an exception is
374     * thrown.
375     *
376     * @param externalExecutor the {@link ExecutorService} to be used
377     * @throws IllegalStateException if this initializer has already been
378     * started
379     */
380    public final synchronized void setExternalExecutor(
381            final ExecutorService externalExecutor) {
382        if (isStarted()) {
383            throw new IllegalStateException(
384                    "Cannot set ExecutorService after start()!");
385        }
386
387        this.externalExecutor = externalExecutor;
388    }
389
390    /**
391     * Starts the background initialization. With this method the initializer
392     * becomes active and invokes the {@link #initialize()} method in a
393     * background task. A {@link BackgroundInitializer} can be started exactly
394     * once. The return value of this method determines whether the start was
395     * successful: only the first invocation of this method returns <b>true</b>,
396     * following invocations will return <b>false</b>.
397     *
398     * @return a flag whether the initializer could be started successfully
399     */
400    public synchronized boolean start() {
401        // Not yet started?
402        if (!isStarted()) {
403
404            // Determine the executor to use and whether a temporary one has to
405            // be created
406            final ExecutorService tempExec;
407            executor = getExternalExecutor();
408            if (executor == null) {
409                executor = tempExec = createExecutor();
410            } else {
411                tempExec = null;
412            }
413
414            future = executor.submit(createTask(tempExec));
415
416            return true;
417        }
418
419        return false;
420    }
421}