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    }