    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 an permitted value.
    101         */
    102        private ExecutorService externalExecutor;
    103
    104        @SuppressWarnings("unchecked")
    105        @Override
    106        public I get() {
    107            return (I) new BackgroundInitializer(getInitializer(), getCloser(), externalExecutor);
    108        }
    109
    110        /**
    111         * Sets the external executor service for executing tasks. null is an permitted value.
    112         *
    113         * @see org.apache.commons.lang3.concurrent.BackgroundInitializer#setExternalExecutor(ExecutorService)
    114         *
    115         * @param externalExecutor the {@link ExecutorService} to be used.
    116         * @return this
    117         */
    118        public Builder<I, T> setExternalExecutor(final ExecutorService externalExecutor) {
    119            this.externalExecutor = externalExecutor;
    120            return asThis();
    121        }
    122
    123    }
    124
    125    private final class InitializationTask implements Callable<T> {
    126        /** Stores the executor service to be destroyed at the end. */
    127        private final ExecutorService execFinally;
    128
    129        /**
    130         * Creates a new instance of {@link InitializationTask} and initializes
    131         * it with the {@link ExecutorService} to be destroyed at the end.
    132         *
    133         * @param exec the {@link ExecutorService}
    134         */
    135        InitializationTask(final ExecutorService exec) {
    136            execFinally = exec;
    137        }
    138
    139        /**
    140         * Initiates initialization and returns the result.
    141         *
    142         * @return the result object
    143         * @throws Exception if an error occurs
    144         */
    145        @Override
    146        public T call() throws Exception {
    147            try {
    148                return initialize();
    149            } finally {
    150                if (execFinally != null) {
    151                    execFinally.shutdown();
    152                }
    153            }
    154        }
    155    }
    156
    157    /**
    158     * Creates a new builder.
    159     *
    160     * @param <T> the type of object to build.
    161     * @return a new builder.
    162     * @since 3.14.0
    163     */
    164    public static <T> Builder<BackgroundInitializer<T>, T> builder() {
    165        return new Builder<>();
    166    }
    167
    168    /** The external executor service for executing tasks. */
    169    private ExecutorService externalExecutor; // @GuardedBy("this")
    170
    171    /** A reference to the executor service that is actually used. */
    172    private ExecutorService executor; // @GuardedBy("this")
    173
    174    /** Stores the handle to the background task. */
    175    private Future<T> future;  // @GuardedBy("this")
    176
    177    /**
    178     * Creates a new instance of {@link BackgroundInitializer}. No external
    179     * {@link ExecutorService} is used.
    180     */
    181    protected BackgroundInitializer() {
    182        this(null);
    183    }
    184
    185    /**
    186     * Creates a new instance of {@link BackgroundInitializer} and initializes
    187     * it with the given {@link ExecutorService}. If the {@link ExecutorService}
    188     * is not null, the background task for initializing this object will be
    189     * scheduled at this service. Otherwise a new temporary {@code
    190     * ExecutorService} is created.
    191     *
    192     * @param exec an external {@link ExecutorService} to be used for task
    193     * execution
    194     */
    195    protected BackgroundInitializer(final ExecutorService exec) {
    196        setExternalExecutor(exec);
    197    }
    198
    199    /**
    200     * Constructs a new instance.
    201     *
    202     * @param initializer the initializer supplier called by {@link #initialize()}.
    203     * @param closer the closer consumer called by {@link #close()}.
    204     * @param exec the {@link ExecutorService} to be used @see #setExternalExecutor(ExecutorService)
    205     */
    206    private BackgroundInitializer(final FailableSupplier<T, ConcurrentException> initializer, final FailableConsumer<T, ConcurrentException> closer, final ExecutorService exec) {
    207        super(initializer, closer);
    208        setExternalExecutor(exec);
    209    }
    210
    211    /**
    212     * Creates the {@link ExecutorService} to be used. This method is called if
    213     * no {@link ExecutorService} was provided at construction time.
    214     *
    215     * @return the {@link ExecutorService} to be used
    216     */
    217    private ExecutorService createExecutor() {
    218        return Executors.newFixedThreadPool(getTaskCount());
    219    }
    220
    221    /**
    222     * Creates a task for the background initialization. The {@link Callable}
    223     * object returned by this method is passed to the {@link ExecutorService}.
    224     * This implementation returns a task that invokes the {@link #initialize()}
    225     * method. If a temporary {@link ExecutorService} is used, it is destroyed
    226     * at the end of the task.
    227     *
    228     * @param execDestroy the {@link ExecutorService} to be destroyed by the
    229     * task
    230     * @return a task for the background initialization
    231     */
    232    private Callable<T> createTask(final ExecutorService execDestroy) {
    233        return new InitializationTask(execDestroy);
    234    }
    235
    236    /**
    237     * Returns the result of the background initialization. This method blocks
    238     * until initialization is complete. If the background processing caused a
    239     * runtime exception, it is directly thrown by this method. Checked
    240     * exceptions, including {@link InterruptedException} are wrapped in a
    241     * {@link ConcurrentException}. Calling this method before {@link #start()}
    242     * was called causes an {@link IllegalStateException} exception to be
    243     * thrown.
    244     *
    245     * @return the object produced by this initializer
    246     * @throws ConcurrentException if a checked exception occurred during
    247     * background processing
    248     * @throws IllegalStateException if {@link #start()} has not been called
    249     */
    250    @Override
    251    public T get() throws ConcurrentException {
    252        try {
    253            return getFuture().get();
    254        } catch (final ExecutionException execex) {
    255            ConcurrentUtils.handleCause(execex);
    256            return null; // should not be reached
    257        } catch (final InterruptedException iex) {
    258            // reset interrupted state
    259            Thread.currentThread().interrupt();
    260            throw new ConcurrentException(iex);
    261        }
    262    }
    263
    264    /**
    265     * Returns the {@link ExecutorService} that is actually used for executing
    266     * the background task. This method can be called after {@link #start()}
    267     * (before {@code start()} it returns <b>null</b>). If an external executor
    268     * was set, this is also the active executor. Otherwise this method returns
    269     * the temporary executor that was created by this object.
    270     *
    271     * @return the {@link ExecutorService} for executing the background task
    272     */
    273    protected final synchronized ExecutorService getActiveExecutor() {
    274        return executor;
    275    }
    276
    277    /**
    278     * Returns the external {@link ExecutorService} to be used by this class.
    279     *
    280     * @return the {@link ExecutorService}
    281     */
    282    public final synchronized ExecutorService getExternalExecutor() {
    283        return externalExecutor;
    284    }
    285
    286    /**
    287     * Returns the {@link Future} object that was created when {@link #start()}
    288     * was called. Therefore this method can only be called after {@code
    289     * start()}.
    290     *
    291     * @return the {@link Future} object wrapped by this initializer
    292     * @throws IllegalStateException if {@link #start()} has not been called
    293     */
    294    public synchronized Future<T> getFuture() {
    295        if (future == null) {
    296            throw new IllegalStateException("start() must be called first!");
    297        }
    298
    299        return future;
    300    }
    301
    302    /**
    303     * Returns the number of background tasks to be created for this
    304     * initializer. This information is evaluated when a temporary {@code
    305     * ExecutorService} is created. This base implementation returns 1. Derived
    306     * classes that do more complex background processing can override it. This
    307     * method is called from a synchronized block by the {@link #start()}
    308     * method. Therefore overriding methods should be careful with obtaining
    309     * other locks and return as fast as possible.
    310     *
    311     * @return the number of background tasks required by this initializer
    312     */
    313    protected int getTaskCount() {
    314        return 1;
    315    }
    316
    317    /**
    318     * {@inheritDoc}
    319     */
    320    @Override
    321    protected Exception getTypedException(Exception e) {
    322        //This Exception object will be used for type comparison in AbstractConcurrentInitializer.initialize but not thrown
    323        return new Exception(e);
    324    }
    325
    326    /**
    327     * Tests whether this instance is initialized. Once initialized, always returns true.
    328     * If initialization failed then the failure will be cached and this will never return
    329     * true.
    330     *
    331     * @return true if initialization completed successfully, otherwise false
    332     * @since 3.14.0
    333     */
    334    @Override
    335    public synchronized boolean isInitialized() {
    336        if (future == null || ! future.isDone() ) {
    337            return false;
    338        }
    339
    340        try {
    341            future.get();
    342            return true;
    343        } catch (CancellationException | ExecutionException | InterruptedException e) {
    344            return false;
    345        }
    346    }
    347
    348    /**
    349     * Returns a flag whether this {@link BackgroundInitializer} has already
    350     * been started.
    351     *
    352     * @return a flag whether the {@link #start()} method has already been
    353     * called
    354     */
    355    public synchronized boolean isStarted() {
    356        return future != null;
    357    }
    358
    359    /**
    360     * Sets an {@link ExecutorService} to be used by this class. The {@code
    361     * ExecutorService} passed to this method is used for executing the
    362     * background task. Thus it is possible to re-use an already existing
    363     * {@link ExecutorService} or to use a specially configured one. If no
    364     * {@link ExecutorService} is set, this instance creates a temporary one and
    365     * destroys it after background initialization is complete. Note that this
    366     * method must be called before {@link #start()}; otherwise an exception is
    367     * thrown.
    368     *
    369     * @param externalExecutor the {@link ExecutorService} to be used
    370     * @throws IllegalStateException if this initializer has already been
    371     * started
    372     */
    373    public final synchronized void setExternalExecutor(
    374            final ExecutorService externalExecutor) {
    375        if (isStarted()) {
    376            throw new IllegalStateException(
    377                    "Cannot set ExecutorService after start()!");
    378        }
    379
    380        this.externalExecutor = externalExecutor;
    381    }
    382
    383    /**
    384     * Starts the background initialization. With this method the initializer
    385     * becomes active and invokes the {@link #initialize()} method in a
    386     * background task. A {@link BackgroundInitializer} can be started exactly
    387     * once. The return value of this method determines whether the start was
    388     * successful: only the first invocation of this method returns <b>true</b>,
    389     * following invocations will return <b>false</b>.
    390     *
    391     * @return a flag whether the initializer could be started successfully
    392     */
    393    public synchronized boolean start() {
    394        // Not yet started?
    395        if (!isStarted()) {
    396
    397            // Determine the executor to use and whether a temporary one has to
    398            // be created
    399            final ExecutorService tempExec;
    400            executor = getExternalExecutor();
    401            if (executor == null) {
    402                executor = tempExec = createExecutor();
    403            } else {
    404                tempExec = null;
    405            }
    406
    407            future = executor.submit(createTask(tempExec));
    408
    409            return true;
    410        }
    411
    412        return false;
    413    }
    414}