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 * @version $Id: BackgroundInitializer.java 1583482 2014-03-31 22:54:57Z niallp $
084 * @param <T> the type of the object managed by this initializer class
085 */
086public abstract class BackgroundInitializer<T> implements
087        ConcurrentInitializer<T> {
088    /** The external executor service for executing tasks. */
089    private ExecutorService externalExecutor; // @GuardedBy("this")
090
091    /** A reference to the executor service that is actually used. */
092    private ExecutorService executor; // @GuardedBy("this")
093
094    /** Stores the handle to the background task. */
095    private Future<T> future;  // @GuardedBy("this")
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(final 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            final 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    @Override
210    public T get() throws ConcurrentException {
211        try {
212            return getFuture().get();
213        } catch (final ExecutionException execex) {
214            ConcurrentUtils.handleCause(execex);
215            return null; // should not be reached
216        } catch (final InterruptedException iex) {
217            // reset interrupted state
218            Thread.currentThread().interrupt();
219            throw new ConcurrentException(iex);
220        }
221    }
222
223    /**
224     * Returns the {@code Future} object that was created when {@link #start()}
225     * was called. Therefore this method can only be called after {@code
226     * start()}.
227     *
228     * @return the {@code Future} object wrapped by this initializer
229     * @throws IllegalStateException if {@link #start()} has not been called
230     */
231    public synchronized Future<T> getFuture() {
232        if (future == null) {
233            throw new IllegalStateException("start() must be called first!");
234        }
235
236        return future;
237    }
238
239    /**
240     * Returns the {@code ExecutorService} that is actually used for executing
241     * the background task. This method can be called after {@link #start()}
242     * (before {@code start()} it returns <b>null</b>). If an external executor
243     * was set, this is also the active executor. Otherwise this method returns
244     * the temporary executor that was created by this object.
245     *
246     * @return the {@code ExecutorService} for executing the background task
247     */
248    protected synchronized final ExecutorService getActiveExecutor() {
249        return executor;
250    }
251
252    /**
253     * Returns the number of background tasks to be created for this
254     * initializer. This information is evaluated when a temporary {@code
255     * ExecutorService} is created. This base implementation returns 1. Derived
256     * classes that do more complex background processing can override it. This
257     * method is called from a synchronized block by the {@link #start()}
258     * method. Therefore overriding methods should be careful with obtaining
259     * other locks and return as fast as possible.
260     *
261     * @return the number of background tasks required by this initializer
262     */
263    protected int getTaskCount() {
264        return 1;
265    }
266
267    /**
268     * Performs the initialization. This method is called in a background task
269     * when this {@code BackgroundInitializer} is started. It must be
270     * implemented by a concrete subclass. An implementation is free to perform
271     * arbitrary initialization. The object returned by this method can be
272     * queried using the {@link #get()} method.
273     *
274     * @return a result object
275     * @throws Exception if an error occurs
276     */
277    protected abstract T initialize() throws Exception;
278
279    /**
280     * Creates a task for the background initialization. The {@code Callable}
281     * object returned by this method is passed to the {@code ExecutorService}.
282     * This implementation returns a task that invokes the {@link #initialize()}
283     * method. If a temporary {@code ExecutorService} is used, it is destroyed
284     * at the end of the task.
285     *
286     * @param execDestroy the {@code ExecutorService} to be destroyed by the
287     * task
288     * @return a task for the background initialization
289     */
290    private Callable<T> createTask(final ExecutorService execDestroy) {
291        return new InitializationTask(execDestroy);
292    }
293
294    /**
295     * Creates the {@code ExecutorService} to be used. This method is called if
296     * no {@code ExecutorService} was provided at construction time.
297     *
298     * @return the {@code ExecutorService} to be used
299     */
300    private ExecutorService createExecutor() {
301        return Executors.newFixedThreadPool(getTaskCount());
302    }
303
304    private class InitializationTask implements Callable<T> {
305        /** Stores the executor service to be destroyed at the end. */
306        private final ExecutorService execFinally;
307
308        /**
309         * Creates a new instance of {@code InitializationTask} and initializes
310         * it with the {@code ExecutorService} to be destroyed at the end.
311         *
312         * @param exec the {@code ExecutorService}
313         */
314        public InitializationTask(final ExecutorService exec) {
315            execFinally = exec;
316        }
317
318        /**
319         * Initiates initialization and returns the result.
320         *
321         * @return the result object
322         * @throws Exception if an error occurs
323         */
324        @Override
325        public T call() throws Exception {
326            try {
327                return initialize();
328            } finally {
329                if (execFinally != null) {
330                    execFinally.shutdown();
331                }
332            }
333        }
334    }
335}