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}