    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    }