    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     */
    017    package org.apache.commons.lang3.concurrent;
    018
    019    import java.util.concurrent.Callable;
    020    import java.util.concurrent.ExecutionException;
    021    import java.util.concurrent.ExecutorService;
    022    import java.util.concurrent.Executors;
    023    import 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     *
    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     * <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     * @version $Id: BackgroundInitializer.java 1082044 2011-03-16 04:26:58Z bayard $
    084     * @param <T> the type of the object managed by this initializer class
    085     */
    086    public abstract class BackgroundInitializer<T> implements
    087            ConcurrentInitializer<T> {
    088        /** The external executor service for executing tasks. */
    089        private ExecutorService externalExecutor;
    090
    091        /** A reference to the executor service that is actually used. */
    092        private ExecutorService executor;
    093
    094        /** Stores the handle to the background task. */
    095        private Future<T> future;
    096
    097        /**
    098         * Creates a new instance of {@code BackgroundInitializer}. No external
    099         * {@code ExecutorService} is used.
    100         */
    101        protected BackgroundInitializer() {
    102            this(null);
    103        }
    104
    105        /**
    106         * Creates a new instance of {@code BackgroundInitializer} and initializes
    107         * it with the given {@code ExecutorService}. If the {@code ExecutorService}
    108         * is not null, the background task for initializing this object will be
    109         * scheduled at this service. Otherwise a new temporary {@code
    110         * ExecutorService} is created.
    111         *
    112         * @param exec an external {@code ExecutorService} to be used for task
    113         * execution
    114         */
    115        protected BackgroundInitializer(ExecutorService exec) {
    116            setExternalExecutor(exec);
    117        }
    118
    119        /**
    120         * Returns the external {@code ExecutorService} to be used by this class.
    121         *
    122         * @return the {@code ExecutorService}
    123         */
    124        public final synchronized ExecutorService getExternalExecutor() {
    125            return externalExecutor;
    126        }
    127
    128        /**
    129         * Returns a flag whether this {@code BackgroundInitializer} has already
    130         * been started.
    131         *
    132         * @return a flag whether the {@link #start()} method has already been
    133         * called
    134         */
    135        public synchronized boolean isStarted() {
    136            return future != null;
    137        }
    138
    139        /**
    140         * Sets an {@code ExecutorService} to be used by this class. The {@code
    141         * ExecutorService} passed to this method is used for executing the
    142         * background task. Thus it is possible to re-use an already existing
    143         * {@code ExecutorService} or to use a specially configured one. If no
    144         * {@code ExecutorService} is set, this instance creates a temporary one and
    145         * destroys it after background initialization is complete. Note that this
    146         * method must be called before {@link #start()}; otherwise an exception is
    147         * thrown.
    148         *
    149         * @param externalExecutor the {@code ExecutorService} to be used
    150         * @throws IllegalStateException if this initializer has already been
    151         * started
    152         */
    153        public final synchronized void setExternalExecutor(
    154                ExecutorService externalExecutor) {
    155            if (isStarted()) {
    156                throw new IllegalStateException(
    157                        "Cannot set ExecutorService after start()!");
    158            }
    159
    160            this.externalExecutor = externalExecutor;
    161        }
    162
    163        /**
    164         * Starts the background initialization. With this method the initializer
    165         * becomes active and invokes the {@link #initialize()} method in a
    166         * background task. A {@code BackgroundInitializer} can be started exactly
    167         * once. The return value of this method determines whether the start was
    168         * successful: only the first invocation of this method returns <b>true</b>,
    169         * following invocations will return <b>false</b>.
    170         *
    171         * @return a flag whether the initializer could be started successfully
    172         */
    173        public synchronized boolean start() {
    174            // Not yet started?
    175            if (!isStarted()) {
    176
    177                // Determine the executor to use and whether a temporary one has to
    178                // be created
    179                ExecutorService tempExec;
    180                executor = getExternalExecutor();
    181                if (executor == null) {
    182                    executor = tempExec = createExecutor();
    183                } else {
    184                    tempExec = null;
    185                }
    186
    187                future = executor.submit(createTask(tempExec));
    188
    189                return true;
    190            }
    191
    192            return false;
    193        }
    194
    195        /**
    196         * Returns the result of the background initialization. This method blocks
    197         * until initialization is complete. If the background processing caused a
    198         * runtime exception, it is directly thrown by this method. Checked
    199         * exceptions, including {@code InterruptedException} are wrapped in a
    200         * {@link ConcurrentException}. Calling this method before {@link #start()}
    201         * was called causes an {@code IllegalStateException} exception to be
    202         * thrown.
    203         *
    204         * @return the object produced by this initializer
    205         * @throws ConcurrentException if a checked exception occurred during
    206         * background processing
    207         * @throws IllegalStateException if {@link #start()} has not been called
    208         */
    209        public T get() throws ConcurrentException {
    210            try {
    211                return getFuture().get();
    212            } catch (ExecutionException execex) {
    213                ConcurrentUtils.handleCause(execex);
    214                return null; // should not be reached
    215            } catch (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 synchronized final 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(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            public InitializationTask(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            public T call() throws Exception {
    324                try {
    325                    return initialize();
    326                } finally {
    327                    if (execFinally != null) {
    328                        execFinally.shutdown();
    329                    }
    330                }
    331            }
    332        }
    333    }