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.ConcurrentMap;
020    import java.util.concurrent.ExecutionException;
021    import java.util.concurrent.Future;
022    import java.util.concurrent.TimeUnit;
023    
024    /**
025     * <p>
026     * An utility class providing functionality related to the {@code
027     * java.util.concurrent} package.
028     * </p>
029     *
030     * @since 3.0
031     * @version $Id: ConcurrentUtils.java 1199894 2011-11-09 17:53:59Z ggregory $
032     */
033    public class ConcurrentUtils {
034    
035        /**
036         * Private constructor so that no instances can be created. This class
037         * contains only static utility methods.
038         */
039        private ConcurrentUtils() {
040        }
041    
042        /**
043         * Inspects the cause of the specified {@code ExecutionException} and
044         * creates a {@code ConcurrentException} with the checked cause if
045         * necessary. This method performs the following checks on the cause of the
046         * passed in exception:
047         * <ul>
048         * <li>If the passed in exception is <b>null</b> or the cause is
049         * <b>null</b>, this method returns <b>null</b>.</li>
050         * <li>If the cause is a runtime exception, it is directly thrown.</li>
051         * <li>If the cause is an error, it is directly thrown, too.</li>
052         * <li>In any other case the cause is a checked exception. The method then
053         * creates a {@link ConcurrentException}, initializes it with the cause, and
054         * returns it.</li>
055         * </ul>
056         *
057         * @param ex the exception to be processed
058         * @return a {@code ConcurrentException} with the checked cause
059         */
060        public static ConcurrentException extractCause(ExecutionException ex) {
061            if (ex == null || ex.getCause() == null) {
062                return null;
063            }
064    
065            throwCause(ex);
066            return new ConcurrentException(ex.getMessage(), ex.getCause());
067        }
068    
069        /**
070         * Inspects the cause of the specified {@code ExecutionException} and
071         * creates a {@code ConcurrentRuntimeException} with the checked cause if
072         * necessary. This method works exactly like
073         * {@link #extractCause(ExecutionException)}. The only difference is that
074         * the cause of the specified {@code ExecutionException} is extracted as a
075         * runtime exception. This is an alternative for client code that does not
076         * want to deal with checked exceptions.
077         *
078         * @param ex the exception to be processed
079         * @return a {@code ConcurrentRuntimeException} with the checked cause
080         */
081        public static ConcurrentRuntimeException extractCauseUnchecked(
082                ExecutionException ex) {
083            if (ex == null || ex.getCause() == null) {
084                return null;
085            }
086    
087            throwCause(ex);
088            return new ConcurrentRuntimeException(ex.getMessage(), ex.getCause());
089        }
090    
091        /**
092         * Handles the specified {@code ExecutionException}. This method calls
093         * {@link #extractCause(ExecutionException)} for obtaining the cause of the
094         * exception - which might already cause an unchecked exception or an error
095         * being thrown. If the cause is a checked exception however, it is wrapped
096         * in a {@code ConcurrentException}, which is thrown. If the passed in
097         * exception is <b>null</b> or has no cause, the method simply returns
098         * without throwing an exception.
099         *
100         * @param ex the exception to be handled
101         * @throws ConcurrentException if the cause of the {@code
102         * ExecutionException} is a checked exception
103         */
104        public static void handleCause(ExecutionException ex)
105                throws ConcurrentException {
106            ConcurrentException cex = extractCause(ex);
107    
108            if (cex != null) {
109                throw cex;
110            }
111        }
112    
113        /**
114         * Handles the specified {@code ExecutionException} and transforms it into a
115         * runtime exception. This method works exactly like
116         * {@link #handleCause(ExecutionException)}, but instead of a
117         * {@link ConcurrentException} it throws a
118         * {@link ConcurrentRuntimeException}. This is an alternative for client
119         * code that does not want to deal with checked exceptions.
120         *
121         * @param ex the exception to be handled
122         * @throws ConcurrentRuntimeException if the cause of the {@code
123         * ExecutionException} is a checked exception; this exception is then
124         * wrapped in the thrown runtime exception
125         */
126        public static void handleCauseUnchecked(ExecutionException ex) {
127            ConcurrentRuntimeException crex = extractCauseUnchecked(ex);
128    
129            if (crex != null) {
130                throw crex;
131            }
132        }
133    
134        /**
135         * Tests whether the specified {@code Throwable} is a checked exception. If
136         * not, an exception is thrown.
137         *
138         * @param ex the {@code Throwable} to check
139         * @return a flag whether the passed in exception is a checked exception
140         * @throws IllegalArgumentException if the {@code Throwable} is not a
141         * checked exception
142         */
143        static Throwable checkedException(Throwable ex) {
144            if (ex != null && !(ex instanceof RuntimeException)
145                    && !(ex instanceof Error)) {
146                return ex;
147            } else {
148                throw new IllegalArgumentException("Not a checked exception: " + ex);
149            }
150        }
151    
152        /**
153         * Tests whether the cause of the specified {@code ExecutionException}
154         * should be thrown and does it if necessary.
155         *
156         * @param ex the exception in question
157         */
158        private static void throwCause(ExecutionException ex) {
159            if (ex.getCause() instanceof RuntimeException) {
160                throw (RuntimeException) ex.getCause();
161            }
162    
163            if (ex.getCause() instanceof Error) {
164                throw (Error) ex.getCause();
165            }
166        }
167    
168        //-----------------------------------------------------------------------
169        /**
170         * Invokes the specified {@code ConcurrentInitializer} and returns the
171         * object produced by the initializer. This method just invokes the {@code
172         * get()} method of the given {@code ConcurrentInitializer}. It is
173         * <b>null</b>-safe: if the argument is <b>null</b>, result is also
174         * <b>null</b>.
175         *
176         * @param <T> the type of the object produced by the initializer
177         * @param initializer the {@code ConcurrentInitializer} to be invoked
178         * @return the object managed by the {@code ConcurrentInitializer}
179         * @throws ConcurrentException if the {@code ConcurrentInitializer} throws
180         * an exception
181         */
182        public static <T> T initialize(ConcurrentInitializer<T> initializer)
183                throws ConcurrentException {
184            return initializer != null ? initializer.get() : null;
185        }
186    
187        /**
188         * Invokes the specified {@code ConcurrentInitializer} and transforms
189         * occurring exceptions to runtime exceptions. This method works like
190         * {@link #initialize(ConcurrentInitializer)}, but if the {@code
191         * ConcurrentInitializer} throws a {@link ConcurrentException}, it is
192         * caught, and the cause is wrapped in a {@link ConcurrentRuntimeException}.
193         * So client code does not have to deal with checked exceptions.
194         *
195         * @param <T> the type of the object produced by the initializer
196         * @param initializer the {@code ConcurrentInitializer} to be invoked
197         * @return the object managed by the {@code ConcurrentInitializer}
198         * @throws ConcurrentRuntimeException if the initializer throws an exception
199         */
200        public static <T> T initializeUnchecked(ConcurrentInitializer<T> initializer) {
201            try {
202                return initialize(initializer);
203            } catch (ConcurrentException cex) {
204                throw new ConcurrentRuntimeException(cex.getCause());
205            }
206        }
207    
208        //-----------------------------------------------------------------------
209        /**
210         * <p>
211         * Puts a value in the specified {@code ConcurrentMap} if the key is not yet
212         * present. This method works similar to the {@code putIfAbsent()} method of
213         * the {@code ConcurrentMap} interface, but the value returned is different.
214         * Basically, this method is equivalent to the following code fragment:
215         *
216         * <pre>
217         * if (!map.containsKey(key)) {
218         *     map.put(key, value);
219         *     return value;
220         * } else {
221         *     return map.get(key);
222         * }
223         * </pre>
224         *
225         * except that the action is performed atomically. So this method always
226         * returns the value which is stored in the map.
227         * </p>
228         * <p>
229         * This method is <b>null</b>-safe: It accepts a <b>null</b> map as input
230         * without throwing an exception. In this case the return value is
231         * <b>null</b>, too.
232         * </p>
233         *
234         * @param <K> the type of the keys of the map
235         * @param <V> the type of the values of the map
236         * @param map the map to be modified
237         * @param key the key of the value to be added
238         * @param value the value to be added
239         * @return the value stored in the map after this operation
240         */
241        public static <K, V> V putIfAbsent(ConcurrentMap<K, V> map, K key, V value) {
242            if (map == null) {
243                return null;
244            }
245    
246            V result = map.putIfAbsent(key, value);
247            return result != null ? result : value;
248        }
249    
250        /**
251         * Checks if a concurrent map contains a key and creates a corresponding
252         * value if not. This method first checks the presence of the key in the
253         * given map. If it is already contained, its value is returned. Otherwise
254         * the {@code get()} method of the passed in {@link ConcurrentInitializer}
255         * is called. With the resulting object
256         * {@link #putIfAbsent(ConcurrentMap, Object, Object)} is called. This
257         * handles the case that in the meantime another thread has added the key to
258         * the map. Both the map and the initializer can be <b>null</b>; in this
259         * case this method simply returns <b>null</b>.
260         *
261         * @param <K> the type of the keys of the map
262         * @param <V> the type of the values of the map
263         * @param map the map to be modified
264         * @param key the key of the value to be added
265         * @param init the {@link ConcurrentInitializer} for creating the value
266         * @return the value stored in the map after this operation; this may or may
267         * not be the object created by the {@link ConcurrentInitializer}
268         * @throws ConcurrentException if the initializer throws an exception
269         */
270        public static <K, V> V createIfAbsent(ConcurrentMap<K, V> map, K key,
271                ConcurrentInitializer<V> init) throws ConcurrentException {
272            if (map == null || init == null) {
273                return null;
274            }
275    
276            V value = map.get(key);
277            if (value == null) {
278                return putIfAbsent(map, key, init.get());
279            }
280            return value;
281        }
282    
283        /**
284         * Checks if a concurrent map contains a key and creates a corresponding
285         * value if not, suppressing checked exceptions. This method calls
286         * {@code createIfAbsent()}. If a {@link ConcurrentException} is thrown, it
287         * is caught and re-thrown as a {@link ConcurrentRuntimeException}.
288         *
289         * @param <K> the type of the keys of the map
290         * @param <V> the type of the values of the map
291         * @param map the map to be modified
292         * @param key the key of the value to be added
293         * @param init the {@link ConcurrentInitializer} for creating the value
294         * @return the value stored in the map after this operation; this may or may
295         * not be the object created by the {@link ConcurrentInitializer}
296         * @throws ConcurrentRuntimeException if the initializer throws an exception
297         */
298        public static <K, V> V createIfAbsentUnchecked(ConcurrentMap<K, V> map,
299                K key, ConcurrentInitializer<V> init) {
300            try {
301                return createIfAbsent(map, key, init);
302            } catch (ConcurrentException cex) {
303                throw new ConcurrentRuntimeException(cex.getCause());
304            }
305        }
306    
307        //-----------------------------------------------------------------------
308        /**
309         * <p>
310         * Gets an implementation of <code>Future</code> that is immediately done
311         * and returns the specified constant value.
312         * </p>
313         * <p>
314         * This can be useful to return a simple constant immediately from the
315         * concurrent processing, perhaps as part of avoiding nulls.
316         * A constant future can also be useful in testing.
317         * </p>
318         *
319         * @param <T> the type of the value used by this {@code Future} object
320         * @param value  the constant value to return, may be null
321         * @return an instance of Future that will return the value, never null
322         */
323        public static <T> Future<T> constantFuture(T value) {
324            return new ConstantFuture<T>(value);
325        }
326    
327        /**
328         * A specialized {@code Future} implementation which wraps a constant value.
329         * @param <T> the type of the value wrapped by this class
330         */
331        static final class ConstantFuture<T> implements Future<T> {
332            /** The constant value. */
333            private final T value;
334    
335            /**
336             * Creates a new instance of {@code ConstantFuture} and initializes it
337             * with the constant value.
338             *
339             * @param value the value (may be <b>null</b>)
340             */
341            ConstantFuture(T value) {
342                this.value = value;
343            }
344    
345            /**
346             * {@inheritDoc} This implementation always returns <b>true</b> because
347             * the constant object managed by this {@code Future} implementation is
348             * always available.
349             */
350            public boolean isDone() {
351                return true;
352            }
353    
354            /**
355             * {@inheritDoc} This implementation just returns the constant value.
356             */
357            public T get() {
358                return value;
359            }
360    
361            /**
362             * {@inheritDoc} This implementation just returns the constant value; it
363             * does not block, therefore the timeout has no meaning.
364             */
365            public T get(long timeout, TimeUnit unit) {
366                return value;
367            }
368    
369            /**
370             * {@inheritDoc} This implementation always returns <b>false</b>; there
371             * is no background process which could be cancelled.
372             */
373            public boolean isCancelled() {
374                return false;
375            }
376    
377            /**
378             * {@inheritDoc} The cancel operation is not supported. This
379             * implementation always returns <b>false</b>.
380             */
381            public boolean cancel(boolean mayInterruptIfRunning) {
382                return false;
383            }
384        }
385    
386    }