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 {@code null})
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 Thrown if the {@link Throwable} is not a checked exception.
108     */
109    static Throwable checkedException(final Throwable ex) {
110        Validate.isTrue(ExceptionUtils.isChecked(ex), "Not a checked exception: %s", ex);
111        return ex;
112    }
113
114    /**
115     * Gets an implementation of {@link Future} that is immediately done
116     * and returns the specified constant value.
117     *
118     * <p>
119     * This can be useful to return a simple constant immediately from the
120     * concurrent processing, perhaps as part of avoiding nulls.
121     * A constant future can also be useful in testing.
122     * </p>
123     *
124     * @param <T> The type of the value used by this {@link Future} object
125     * @param value  The constant value to return, may be null
126     * @return An instance of Future that will return the value, never null
127     */
128    public static <T> Future<T> constantFuture(final T value) {
129        return new ConstantFuture<>(value);
130    }
131
132    /**
133     * Checks if a concurrent map contains a key and creates a corresponding
134     * value if not. This method first checks the presence of the key in the
135     * given map. If it is already contained, its value is returned. Otherwise
136     * the {@code get()} method of the passed in {@link ConcurrentInitializer}
137     * is called. With the resulting object
138     * {@link #putIfAbsent(ConcurrentMap, Object, Object)} is called. This
139     * handles the case that in the meantime another thread has added the key to
140     * the map. Both the map and the initializer can be {@code null}; in this
141     * case this method simply returns {@code null}.
142     *
143     * @param <K> The type of the keys of the map
144     * @param <V> The type of the values of the map
145     * @param map The map to be modified
146     * @param key The key of the value to be added
147     * @param init The {@link ConcurrentInitializer} for creating the value
148     * @return The value stored in the map after this operation; this may or may
149     * not be the object created by the {@link ConcurrentInitializer}
150     * @throws ConcurrentException Thrown if the initializer throws an exception.
151     */
152    public static <K, V> V createIfAbsent(final ConcurrentMap<K, V> map, final K key,
153            final ConcurrentInitializer<V> init) throws ConcurrentException {
154        if (map == null || init == null) {
155            return null;
156        }
157
158        final V value = map.get(key);
159        if (value == null) {
160            return putIfAbsent(map, key, init.get());
161        }
162        return value;
163    }
164
165    /**
166     * Checks if a concurrent map contains a key and creates a corresponding
167     * value if not, suppressing checked exceptions. This method calls
168     * {@code createIfAbsent()}. If a {@link ConcurrentException} is thrown, it
169     * is caught and re-thrown as a {@link ConcurrentRuntimeException}.
170     *
171     * @param <K> The type of the keys of the map
172     * @param <V> The type of the values of the map
173     * @param map The map to be modified
174     * @param key The key of the value to be added
175     * @param init The {@link ConcurrentInitializer} for creating the value
176     * @return The value stored in the map after this operation; this may or may
177     * not be the object created by the {@link ConcurrentInitializer}
178     * @throws ConcurrentRuntimeException Thrown if the initializer throws an exception.
179     */
180    public static <K, V> V createIfAbsentUnchecked(final ConcurrentMap<K, V> map,
181            final K key, final ConcurrentInitializer<V> init) {
182        try {
183            return createIfAbsent(map, key, init);
184        } catch (final ConcurrentException cex) {
185            throw new ConcurrentRuntimeException(cex.getCause());
186        }
187    }
188
189    /**
190     * Inspects the cause of the specified {@link ExecutionException} and
191     * creates a {@link ConcurrentException} with the checked cause if
192     * necessary. This method performs the following checks on the cause of the
193     * passed in exception:
194     * <ul>
195     * <li>If the passed in exception is {@code null} or the cause is
196     * {@code null}, this method returns {@code null}.</li>
197     * <li>If the cause is a runtime exception, it is directly thrown.</li>
198     * <li>If the cause is an error, it is directly thrown, too.</li>
199     * <li>In any other case the cause is a checked exception. The method then
200     * creates a {@link ConcurrentException}, initializes it with the cause, and
201     * returns it.</li>
202     * </ul>
203     *
204     * @param ex The exception to be processed
205     * @return A {@link ConcurrentException} with the checked cause
206     */
207    public static ConcurrentException extractCause(final ExecutionException ex) {
208        if (ex == null || ex.getCause() == null) {
209            return null;
210        }
211        ExceptionUtils.throwUnchecked(ex.getCause());
212        return new ConcurrentException(ex.getMessage(), ex.getCause());
213    }
214
215    /**
216     * Inspects the cause of the specified {@link ExecutionException} and
217     * creates a {@link ConcurrentRuntimeException} with the checked cause if
218     * necessary. This method works exactly like
219     * {@link #extractCause(ExecutionException)}. The only difference is that
220     * the cause of the specified {@link ExecutionException} is extracted as a
221     * runtime exception. This is an alternative for client code that does not
222     * want to deal with checked exceptions.
223     *
224     * @param ex The exception to be processed
225     * @return A {@link ConcurrentRuntimeException} with the checked cause
226     */
227    public static ConcurrentRuntimeException extractCauseUnchecked(final ExecutionException ex) {
228        if (ex == null || ex.getCause() == null) {
229            return null;
230        }
231        ExceptionUtils.throwUnchecked(ex.getCause());
232        return new ConcurrentRuntimeException(ex.getMessage(), ex.getCause());
233    }
234
235    /**
236     * Handles the specified {@link ExecutionException}. This method calls
237     * {@link #extractCause(ExecutionException)} for obtaining the cause of the
238     * exception - which might already cause an unchecked exception or an error
239     * being thrown. If the cause is a checked exception however, it is wrapped
240     * in a {@link ConcurrentException}, which is thrown. If the passed in
241     * exception is {@code null} or has no cause, the method simply returns
242     * without throwing an exception.
243     *
244     * @param ex The exception to be handled
245     * @throws ConcurrentException Thrown if the cause of the {@code ExecutionException} is a checked exception.
246     */
247    public static void handleCause(final ExecutionException ex) throws ConcurrentException {
248        final ConcurrentException cause = extractCause(ex);
249        if (cause != null) {
250            throw cause;
251        }
252    }
253
254    /**
255     * Handles the specified {@link ExecutionException} and transforms it into a
256     * runtime exception. This method works exactly like
257     * {@link #handleCause(ExecutionException)}, but instead of a
258     * {@link ConcurrentException} it throws a
259     * {@link ConcurrentRuntimeException}. This is an alternative for client
260     * code that does not want to deal with checked exceptions.
261     *
262     * @param ex The exception to be handled
263     * @throws ConcurrentRuntimeException Thrown if the cause of the {@code ExecutionException} is a checked exception; this exception is then wrapped in the
264     *         thrown runtime exception.
265     */
266    public static void handleCauseUnchecked(final ExecutionException ex) {
267        final ConcurrentRuntimeException cause = extractCauseUnchecked(ex);
268        if (cause != null) {
269            throw cause;
270        }
271    }
272
273    /**
274     * Invokes the specified {@link ConcurrentInitializer} and returns the
275     * object produced by the initializer. This method just invokes the {@code
276     * get()} method of the given {@link ConcurrentInitializer}. It is
277     * {@code null}-safe: if the argument is {@code null}, result is also
278     * {@code null}.
279     *
280     * @param <T> The type of the object produced by the initializer
281     * @param initializer The {@link ConcurrentInitializer} to be invoked
282     * @return The object managed by the {@link ConcurrentInitializer}
283     * @throws ConcurrentException Thrown if the {@link ConcurrentInitializer} throws an exception.
284     */
285    public static <T> T initialize(final ConcurrentInitializer<T> initializer)
286            throws ConcurrentException {
287        return initializer != null ? initializer.get() : null;
288    }
289
290    /**
291     * Invokes the specified {@link ConcurrentInitializer} and transforms
292     * occurring exceptions to runtime exceptions. This method works like
293     * {@link #initialize(ConcurrentInitializer)}, but if the {@code
294     * ConcurrentInitializer} throws a {@link ConcurrentException}, it is
295     * caught, and the cause is wrapped in a {@link ConcurrentRuntimeException}.
296     * So client code does not have to deal with checked exceptions.
297     *
298     * @param <T> The type of the object produced by the initializer
299     * @param initializer The {@link ConcurrentInitializer} to be invoked
300     * @return The object managed by the {@link ConcurrentInitializer}
301     * @throws ConcurrentRuntimeException Thrown if the initializer throws an exception.
302     */
303    public static <T> T initializeUnchecked(final ConcurrentInitializer<T> initializer) {
304        try {
305            return initialize(initializer);
306        } catch (final ConcurrentException cex) {
307            throw new ConcurrentRuntimeException(cex.getCause());
308        }
309    }
310
311    /**
312     * Puts a value in the specified {@link ConcurrentMap} if the key is not yet
313     * present. This method works similar to the {@code putIfAbsent()} method of
314     * the {@link ConcurrentMap} interface, but the value returned is different.
315     * Basically, this method is equivalent to the following code fragment:
316     *
317     * <pre>
318     * if (!map.containsKey(key)) {
319     *     map.put(key, value);
320     *     return value;
321     * } else {
322     *     return map.get(key);
323     * }
324     * </pre>
325     *
326     * <p>
327     * except that the action is performed atomically. So this method always
328     * returns the value which is stored in the map.
329     * </p>
330     * <p>
331     * This method is {@code null}-safe: It accepts a {@code null} map as input
332     * without throwing an exception. In this case the return value is
333     * {@code null}, too.
334     * </p>
335     *
336     * @param <K> The type of the keys of the map
337     * @param <V> The type of the values of the map
338     * @param map The map to be modified
339     * @param key The key of the value to be added
340     * @param value The value to be added
341     * @return The value stored in the map after this operation
342     */
343    public static <K, V> V putIfAbsent(final ConcurrentMap<K, V> map, final K key, final V value) {
344        if (map == null) {
345            return null;
346        }
347        final V result = map.putIfAbsent(key, value);
348        return result != null ? result : value;
349    }
350
351    /**
352     * Private constructor so that no instances can be created. This class
353     * contains only static utility methods.
354     */
355    private ConcurrentUtils() {
356    }
357
358}