    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.ExecutionException;
    020    import java.util.concurrent.Future;
    021    import java.util.concurrent.TimeUnit;
    022
    023    /**
    024     * <p>
    025     * An utility class providing functionality related to the {@code
    026     * java.util.concurrent} package.
    027     * </p>
    028     *
    029     * @author Apache Software Foundation
    030     * @version $Id: ConcurrentUtils.java 929189 2010-03-30 16:49:22Z oheger $
    031     */
    032    public class ConcurrentUtils {
    033
    034        /**
    035         * Private constructor so that no instances can be created. This class
    036         * contains only static utility methods.
    037         */
    038        private ConcurrentUtils() {
    039        }
    040
    041        /**
    042         * Inspects the cause of the specified {@code ExecutionException} and
    043         * creates a {@code ConcurrentException} with the checked cause if
    044         * necessary. This method performs the following checks on the cause of the
    045         * passed in exception:
    046         * <ul>
    047         * <li>If the passed in exception is <b>null</b> or the cause is
    048         * <b>null</b>, this method returns <b>null</b>.</li>
    049         * <li>If the cause is a runtime exception, it is directly thrown.</li>
    050         * <li>If the cause is an error, it is directly thrown, too.</li>
    051         * <li>In any other case the cause is a checked exception. The method then
    052         * creates a {@link ConcurrentException}, initializes it with the cause, and
    053         * returns it.</li>
    054         * </ul>
    055         *
    056         * @param ex the exception to be processed
    057         * @return a {@code ConcurrentException} with the checked cause
    058         */
    059        public static ConcurrentException extractCause(ExecutionException ex) {
    060            if (ex == null || ex.getCause() == null) {
    061                return null;
    062            }
    063
    064            throwCause(ex);
    065            return new ConcurrentException(ex.getMessage(), ex.getCause());
    066        }
    067
    068        /**
    069         * Inspects the cause of the specified {@code ExecutionException} and
    070         * creates a {@code ConcurrentRuntimeException} with the checked cause if
    071         * necessary. This method works exactly like
    072         * {@link #extractCause(ExecutionException)}. The only difference is that
    073         * the cause of the specified {@code ExecutionException} is extracted as a
    074         * runtime exception. This is an alternative for client code that does not
    075         * want to deal with checked exceptions.
    076         *
    077         * @param ex the exception to be processed
    078         * @return a {@code ConcurrentRuntimeException} with the checked cause
    079         */
    080        public static ConcurrentRuntimeException extractCauseUnchecked(
    081                ExecutionException ex) {
    082            if (ex == null || ex.getCause() == null) {
    083                return null;
    084            }
    085
    086            throwCause(ex);
    087            return new ConcurrentRuntimeException(ex.getMessage(), ex.getCause());
    088        }
    089
    090        /**
    091         * Handles the specified {@code ExecutionException}. This method calls
    092         * {@link #extractCause(ExecutionException)} for obtaining the cause of the
    093         * exception - which might already cause an unchecked exception or an error
    094         * being thrown. If the cause is a checked exception however, it is wrapped
    095         * in a {@code ConcurrentException}, which is thrown. If the passed in
    096         * exception is <b>null</b> or has no cause, the method simply returns
    097         * without throwing an exception.
    098         *
    099         * @param ex the exception to be handled
    100         * @throws ConcurrentException if the cause of the {@code
    101         * ExecutionException} is a checked exception
    102         */
    103        public static void handleCause(ExecutionException ex)
    104                throws ConcurrentException {
    105            ConcurrentException cex = extractCause(ex);
    106
    107            if (cex != null) {
    108                throw cex;
    109            }
    110        }
    111
    112        /**
    113         * Handles the specified {@code ExecutionException} and transforms it into a
    114         * runtime exception. This method works exactly like
    115         * {@link #handleCause(ExecutionException)}, but instead of a
    116         * {@link ConcurrentException} it throws a
    117         * {@link ConcurrentRuntimeException}. This is an alternative for client
    118         * code that does not want to deal with checked exceptions.
    119         *
    120         * @param ex the exception to be handled
    121         * @throws ConcurrentRuntimeException if the cause of the {@code
    122         * ExecutionException} is a checked exception; this exception is then
    123         * wrapped in the thrown runtime exception
    124         */
    125        public static void handleCauseUnchecked(ExecutionException ex) {
    126            ConcurrentRuntimeException crex = extractCauseUnchecked(ex);
    127
    128            if (crex != null) {
    129                throw crex;
    130            }
    131        }
    132
    133        /**
    134         * Tests whether the specified {@code Throwable} is a checked exception. If
    135         * not, an exception is thrown.
    136         *
    137         * @param ex the {@code Throwable} to check
    138         * @return a flag whether the passed in exception is a checked exception
    139         * @throws IllegalArgumentException if the {@code Throwable} is not a
    140         * checked exception
    141         */
    142        static Throwable checkedException(Throwable ex) {
    143            if (ex != null && !(ex instanceof RuntimeException)
    144                    && !(ex instanceof Error)) {
    145                return ex;
    146            } else {
    147                throw new IllegalArgumentException("Not a checked exception: " + ex);
    148            }
    149        }
    150
    151        /**
    152         * Tests whether the cause of the specified {@code ExecutionException}
    153         * should be thrown and does it if necessary.
    154         *
    155         * @param ex the exception in question
    156         */
    157        private static void throwCause(ExecutionException ex) {
    158            if (ex.getCause() instanceof RuntimeException) {
    159                throw (RuntimeException) ex.getCause();
    160            }
    161
    162            if (ex.getCause() instanceof Error) {
    163                throw (Error) ex.getCause();
    164            }
    165        }
    166
    167        //-----------------------------------------------------------------------
    168        /**
    169         * Invokes the specified {@code ConcurrentInitializer} and returns the
    170         * object produced by the initializer. This method just invokes the {@code
    171         * get()} method of the given {@code ConcurrentInitializer}. It is
    172         * <b>null</b>-safe: if the argument is <b>null</b>, result is also
    173         * <b>null</b>.
    174         *
    175         * @param <T> the type of the object produced by the initializer
    176         * @param initializer the {@code ConcurrentInitializer} to be invoked
    177         * @return the object managed by the {@code ConcurrentInitializer}
    178         * @throws ConcurrentException if the {@code ConcurrentInitializer} throws
    179         * an exception
    180         */
    181        public static <T> T initialize(ConcurrentInitializer<T> initializer)
    182                throws ConcurrentException {
    183            return (initializer != null) ? initializer.get() : null;
    184        }
    185
    186        /**
    187         * Invokes the specified {@code ConcurrentInitializer} and transforms
    188         * occurring exceptions to runtime exceptions. This method works like
    189         * {@link #initialize(ConcurrentInitializer)}, but if the {@code
    190         * ConcurrentInitializer} throws a {@link ConcurrentException}, it is
    191         * caught, and the cause is wrapped in a {@link ConcurrentRuntimeException}.
    192         * So client code does not have to deal with checked exceptions.
    193         *
    194         * @param <T> the type of the object produced by the initializer
    195         * @param initializer the {@code ConcurrentInitializer} to be invoked
    196         * @return the object managed by the {@code ConcurrentInitializer}
    197         * @throws ConcurrentRuntimeException if the initializer throws an exception
    198         */
    199        public static <T> T initializeUnchecked(ConcurrentInitializer<T> initializer) {
    200            try {
    201                return initialize(initializer);
    202            } catch (ConcurrentException cex) {
    203                throw new ConcurrentRuntimeException(cex.getCause());
    204            }
    205        }
    206
    207        //-----------------------------------------------------------------------
    208        /**
    209         * <p>
    210         * Gets an implementation of <code>Future</code> that is immediately done
    211         * and returns the specified constant value.
    212         * </p>
    213         * <p>
    214         * This can be useful to return a simple constant immediately from the
    215         * concurrent processing, perhaps as part of avoiding nulls.
    216         * A constant future can also be useful in testing.
    217         * </p>
    218         *
    219         * @param value  the constant value to return, may be null
    220         * @return an instance of Future that will return the value, never null
    221         */
    222        public static <T> Future<T> constantFuture(T value) {
    223            return new ConstantFuture<T>(value);
    224        }
    225
    226        static final class ConstantFuture<T> implements Future<T> {
    227            /** The constant value. */
    228            private final T value;
    229
    230            ConstantFuture(T value) {
    231                this.value = value;
    232            }
    233
    234            public boolean isDone() {
    235                return true;
    236            }
    237
    238            public T get() {
    239                return value;
    240            }
    241
    242            public T get(long timeout, TimeUnit unit) {
    243                return value;
    244            }
    245
    246            public boolean isCancelled() {
    247                return false;
    248            }
    249
    250            public boolean cancel(boolean mayInterruptIfRunning) {
    251                return false;
    252            }
    253        }
    254
    255    }