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