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}