    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.ExecutionException;
    021import java.util.concurrent.ExecutorService;
    022import java.util.concurrent.Executors;
    023import java.util.concurrent.Future;
    024
    025/**
    026 * A class that allows complex initialization operations in a background task.
    027 *
    028 * <p>
    029 * Applications often have to do some expensive initialization steps when they
    030 * are started, e.g. constructing a connection to a database, reading a
    031 * configuration file, etc. Doing these things in parallel can enhance
    032 * performance as the CPU load can be improved. However, when access to the
    033 * resources initialized in a background thread is actually required,
    034 * synchronization has to be performed to ensure that their initialization is
    035 * complete.
    036 * </p>
    037 * <p>
    038 * This abstract base class provides support for this use case. A concrete
    039 * subclass must implement the {@link #initialize()} method. Here an arbitrary
    040 * initialization can be implemented, and a result object can be returned. With
    041 * this method in place the basic usage of this class is as follows (where
    042 * {@code MyBackgroundInitializer} is a concrete subclass):
    043 * </p>
    044 *
    045 * <pre>
    046 * MyBackgroundInitializer initializer = new MyBackgroundInitializer();
    047 * initializer.start();
    048 * // Now do some other things. Initialization runs in a parallel thread
    049 * ...
    050 * // Wait for the end of initialization and access the result object
    051 * Object result = initializer.get();
    052 * </pre>
    053 *
    054 * <p>
    055 * After the construction of a {@link BackgroundInitializer} object its
    056 * {@link #start()} method has to be called. This starts the background
    057 * processing. The application can now continue to do other things. When it
    058 * needs access to the object produced by the {@link BackgroundInitializer} it
    059 * calls its {@link #get()} method. If initialization is already complete,
    060 * {@link #get()} returns the result object immediately. Otherwise it blocks
    061 * until the result object is fully constructed.
    062 * </p>
    063 * <p>
    064 * {@link BackgroundInitializer} is a thin wrapper around a {@link Future}
    065 * object and uses an {@link ExecutorService} for running the background
    066 * initialization task. It is possible to pass in an {@link ExecutorService} at
    067 * construction time or set one using {@code setExternalExecutor()} before
    068 * {@code start()} was called. Then this object is used to spawn the background
    069 * task. If no {@link ExecutorService} has been provided, {@code
    070 * BackgroundInitializer} creates a temporary {@link ExecutorService} and
    071 * destroys it when initialization is complete.
    072 * </p>
    073 * <p>
    074 * The methods provided by {@link BackgroundInitializer} provide for minimal
    075 * interaction with the wrapped {@link Future} object. It is also possible to
    076 * obtain the {@link Future} object directly. Then the enhanced functionality
    077 * offered by {@link Future} can be used, e.g. to check whether the background
    078 * operation is complete or to cancel the operation.
    079 * </p>
    080 *
    081 * @since 3.0
    082 * @param <T> the type of the object managed by this initializer class
    083 */
    084public abstract class BackgroundInitializer<T> implements
    085        ConcurrentInitializer<T> {
    086    /** The external executor service for executing tasks. */
    087    private ExecutorService externalExecutor; // @GuardedBy("this")
    088
    089    /** A reference to the executor service that is actually used. */
    090    private ExecutorService executor; // @GuardedBy("this")
    091
    092    /** Stores the handle to the background task. */
    093    private Future<T> future;  // @GuardedBy("this")
    094
    095    /**
    096     * Creates a new instance of {@link BackgroundInitializer}. No external
    097     * {@link ExecutorService} is used.
    098     */
    099    protected BackgroundInitializer() {
    100        this(null);
    101    }
    102
    103    /**
    104     * Creates a new instance of {@link BackgroundInitializer} and initializes
    105     * it with the given {@link ExecutorService}. If the {@link ExecutorService}
    106     * is not null, the background task for initializing this object will be
    107     * scheduled at this service. Otherwise a new temporary {@code
    108     * ExecutorService} is created.
    109     *
    110     * @param exec an external {@link ExecutorService} to be used for task
    111     * execution
    112     */
    113    protected BackgroundInitializer(final ExecutorService exec) {
    114        setExternalExecutor(exec);
    115    }
    116
    117    /**
    118     * Returns the external {@link ExecutorService} to be used by this class.
    119     *
    120     * @return the {@link ExecutorService}
    121     */
    122    public final synchronized ExecutorService getExternalExecutor() {
    123        return externalExecutor;
    124    }
    125
    126    /**
    127     * Returns a flag whether this {@link BackgroundInitializer} has already
    128     * been started.
    129     *
    130     * @return a flag whether the {@link #start()} method has already been
    131     * called
    132     */
    133    public synchronized boolean isStarted() {
    134        return future != null;
    135    }
    136
    137    /**
    138     * Sets an {@link ExecutorService} to be used by this class. The {@code
    139     * ExecutorService} passed to this method is used for executing the
    140     * background task. Thus it is possible to re-use an already existing
    141     * {@link ExecutorService} or to use a specially configured one. If no
    142     * {@link ExecutorService} is set, this instance creates a temporary one and
    143     * destroys it after background initialization is complete. Note that this
    144     * method must be called before {@link #start()}; otherwise an exception is
    145     * thrown.
    146     *
    147     * @param externalExecutor the {@link ExecutorService} to be used
    148     * @throws IllegalStateException if this initializer has already been
    149     * started
    150     */
    151    public final synchronized void setExternalExecutor(
    152            final ExecutorService externalExecutor) {
    153        if (isStarted()) {
    154            throw new IllegalStateException(
    155                    "Cannot set ExecutorService after start()!");
    156        }
    157
    158        this.externalExecutor = externalExecutor;
    159    }
    160
    161    /**
    162     * Starts the background initialization. With this method the initializer
    163     * becomes active and invokes the {@link #initialize()} method in a
    164     * background task. A {@link BackgroundInitializer} can be started exactly
    165     * once. The return value of this method determines whether the start was
    166     * successful: only the first invocation of this method returns <b>true</b>,
    167     * following invocations will return <b>false</b>.
    168     *
    169     * @return a flag whether the initializer could be started successfully
    170     */
    171    public synchronized boolean start() {
    172        // Not yet started?
    173        if (!isStarted()) {
    174
    175            // Determine the executor to use and whether a temporary one has to
    176            // be created
    177            final ExecutorService tempExec;
    178            executor = getExternalExecutor();
    179            if (executor == null) {
    180                executor = tempExec = createExecutor();
    181            } else {
    182                tempExec = null;
    183            }
    184
    185            future = executor.submit(createTask(tempExec));
    186
    187            return true;
    188        }
    189
    190        return false;
    191    }
    192
    193    /**
    194     * Returns the result of the background initialization. This method blocks
    195     * until initialization is complete. If the background processing caused a
    196     * runtime exception, it is directly thrown by this method. Checked
    197     * exceptions, including {@link InterruptedException} are wrapped in a
    198     * {@link ConcurrentException}. Calling this method before {@link #start()}
    199     * was called causes an {@link IllegalStateException} exception to be
    200     * thrown.
    201     *
    202     * @return the object produced by this initializer
    203     * @throws ConcurrentException if a checked exception occurred during
    204     * background processing
    205     * @throws IllegalStateException if {@link #start()} has not been called
    206     */
    207    @Override
    208    public T get() throws ConcurrentException {
    209        try {
    210            return getFuture().get();
    211        } catch (final ExecutionException execex) {
    212            ConcurrentUtils.handleCause(execex);
    213            return null; // should not be reached
    214        } catch (final InterruptedException iex) {
    215            // reset interrupted state
    216            Thread.currentThread().interrupt();
    217            throw new ConcurrentException(iex);
    218        }
    219    }
    220
    221    /**
    222     * Returns the {@link Future} object that was created when {@link #start()}
    223     * was called. Therefore this method can only be called after {@code
    224     * start()}.
    225     *
    226     * @return the {@link Future} object wrapped by this initializer
    227     * @throws IllegalStateException if {@link #start()} has not been called
    228     */
    229    public synchronized Future<T> getFuture() {
    230        if (future == null) {
    231            throw new IllegalStateException("start() must be called first!");
    232        }
    233
    234        return future;
    235    }
    236
    237    /**
    238     * Returns the {@link ExecutorService} that is actually used for executing
    239     * the background task. This method can be called after {@link #start()}
    240     * (before {@code start()} it returns <b>null</b>). If an external executor
    241     * was set, this is also the active executor. Otherwise this method returns
    242     * the temporary executor that was created by this object.
    243     *
    244     * @return the {@link ExecutorService} for executing the background task
    245     */
    246    protected final synchronized ExecutorService getActiveExecutor() {
    247        return executor;
    248    }
    249
    250    /**
    251     * Returns the number of background tasks to be created for this
    252     * initializer. This information is evaluated when a temporary {@code
    253     * ExecutorService} is created. This base implementation returns 1. Derived
    254     * classes that do more complex background processing can override it. This
    255     * method is called from a synchronized block by the {@link #start()}
    256     * method. Therefore overriding methods should be careful with obtaining
    257     * other locks and return as fast as possible.
    258     *
    259     * @return the number of background tasks required by this initializer
    260     */
    261    protected int getTaskCount() {
    262        return 1;
    263    }
    264
    265    /**
    266     * Performs the initialization. This method is called in a background task
    267     * when this {@link BackgroundInitializer} is started. It must be
    268     * implemented by a concrete subclass. An implementation is free to perform
    269     * arbitrary initialization. The object returned by this method can be
    270     * queried using the {@link #get()} method.
    271     *
    272     * @return a result object
    273     * @throws Exception if an error occurs
    274     */
    275    protected abstract T initialize() throws Exception;
    276
    277    /**
    278     * Creates a task for the background initialization. The {@link Callable}
    279     * object returned by this method is passed to the {@link ExecutorService}.
    280     * This implementation returns a task that invokes the {@link #initialize()}
    281     * method. If a temporary {@link ExecutorService} is used, it is destroyed
    282     * at the end of the task.
    283     *
    284     * @param execDestroy the {@link ExecutorService} to be destroyed by the
    285     * task
    286     * @return a task for the background initialization
    287     */
    288    private Callable<T> createTask(final ExecutorService execDestroy) {
    289        return new InitializationTask(execDestroy);
    290    }
    291
    292    /**
    293     * Creates the {@link ExecutorService} to be used. This method is called if
    294     * no {@link ExecutorService} was provided at construction time.
    295     *
    296     * @return the {@link ExecutorService} to be used
    297     */
    298    private ExecutorService createExecutor() {
    299        return Executors.newFixedThreadPool(getTaskCount());
    300    }
    301
    302    private class InitializationTask implements Callable<T> {
    303        /** Stores the executor service to be destroyed at the end. */
    304        private final ExecutorService execFinally;
    305
    306        /**
    307         * Creates a new instance of {@link InitializationTask} and initializes
    308         * it with the {@link ExecutorService} to be destroyed at the end.
    309         *
    310         * @param exec the {@link ExecutorService}
    311         */
    312        InitializationTask(final ExecutorService exec) {
    313            execFinally = exec;
    314        }
    315
    316        /**
    317         * Initiates initialization and returns the result.
    318         *
    319         * @return the result object
    320         * @throws Exception if an error occurs
    321         */
    322        @Override
    323        public T call() throws Exception {
    324            try {
    325                return initialize();
    326            } finally {
    327                if (execFinally != null) {
    328                    execFinally.shutdown();
    329                }
    330            }
    331        }
    332    }
    333}