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     * @since 3.0
083     * @version $Id: BackgroundInitializer.java 1082044 2011-03-16 04:26:58Z bayard $
084     * @param <T> the type of the object managed by this initializer class
085     */
086    public abstract class BackgroundInitializer<T> implements
087            ConcurrentInitializer<T> {
088        /** The external executor service for executing tasks. */
089        private ExecutorService externalExecutor;
090    
091        /** A reference to the executor service that is actually used. */
092        private ExecutorService executor;
093    
094        /** Stores the handle to the background task. */
095        private Future<T> future;
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(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                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        public T get() throws ConcurrentException {
210            try {
211                return getFuture().get();
212            } catch (ExecutionException execex) {
213                ConcurrentUtils.handleCause(execex);
214                return null; // should not be reached
215            } catch (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 synchronized final 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(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            public InitializationTask(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            public T call() throws Exception {
324                try {
325                    return initialize();
326                } finally {
327                    if (execFinally != null) {
328                        execFinally.shutdown();
329                    }
330                }
331            }
332        }
333    }