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