    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     * @version $Id: BackgroundInitializer.java 929189 2010-03-30 16:49:22Z oheger $
    083     * @param <T> the type of the object managed by this initializer class
    084     */
    085    public abstract class BackgroundInitializer<T> implements
    086            ConcurrentInitializer<T> {
    087        /** The external executor service for executing tasks. */
    088        private ExecutorService externalExecutor;
    089
    090        /** A reference to the executor service that is actually used. */
    091        private ExecutorService executor;
    092
    093        /** Stores the handle to the background task. */
    094        private Future<T> future;
    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(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                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        public T get() throws ConcurrentException {
    209            try {
    210                return getFuture().get();
    211            } catch (ExecutionException execex) {
    212                ConcurrentUtils.handleCause(execex);
    213                return null; // should not be reached
    214            } catch (InterruptedException iex) {
    215                // reset interrupted state
    216                Thread.currentThread().interrupt();
    217                throw new ConcurrentException(iex);
    218            }
    219        }
    220
    221        /**
    222         * Returns the {@code 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 {@code 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 {@code 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 {@code ExecutorService} for executing the background task
    245         */
    246        protected synchronized final 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 {@code 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 {@code Callable}
    279         * object returned by this method is passed to the {@code ExecutorService}.
    280         * This implementation returns a task that invokes the {@link #initialize()}
    281         * method. If a temporary {@code ExecutorService} is used, it is destroyed
    282         * at the end of the task.
    283         *
    284         * @param execDestroy the {@code ExecutorService} to be destroyed by the
    285         * task
    286         * @return a task for the background initialization
    287         */
    288        private Callable<T> createTask(ExecutorService execDestroy) {
    289            return new InitializationTask(execDestroy);
    290        }
    291
    292        /**
    293         * Creates the {@code ExecutorService} to be used. This method is called if
    294         * no {@code ExecutorService} was provided at construction time.
    295         *
    296         * @return the {@code 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 {@code InitializationTask} and initializes
    308             * it with the {@code ExecutorService} to be destroyed at the end.
    309             *
    310             * @param exec the {@code ExecutorService}
    311             */
    312            public InitializationTask(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            public T call() throws Exception {
    323                try {
    324                    return initialize();
    325                } finally {
    326                    if (execFinally != null) {
    327                        execFinally.shutdown();
    328                    }
    329                }
    330            }
    331        }
    332    }