| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
| ConcurrentUtils |
|
| 2.789473684210526;2.789 | ||||
| ConcurrentUtils$ConstantFuture |
|
| 2.789473684210526;2.789 |
| 1 | /* | |
| 2 | * Licensed to the Apache Software Foundation (ASF) under one or more | |
| 3 | * contributor license agreements. See the NOTICE file distributed with | |
| 4 | * this work for additional information regarding copyright ownership. | |
| 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 | |
| 6 | * (the "License"); you may not use this file except in compliance with | |
| 7 | * the License. You may obtain a copy of the License at | |
| 8 | * | |
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
| 10 | * | |
| 11 | * Unless required by applicable law or agreed to in writing, software | |
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 14 | * See the License for the specific language governing permissions and | |
| 15 | * limitations under the License. | |
| 16 | */ | |
| 17 | package org.apache.commons.lang3.concurrent; | |
| 18 | ||
| 19 | import java.util.concurrent.ConcurrentMap; | |
| 20 | import java.util.concurrent.ExecutionException; | |
| 21 | import java.util.concurrent.Future; | |
| 22 | import java.util.concurrent.TimeUnit; | |
| 23 | ||
| 24 | /** | |
| 25 | * <p> | |
| 26 | * An utility class providing functionality related to the {@code | |
| 27 | * java.util.concurrent} package. | |
| 28 | * </p> | |
| 29 | * | |
| 30 | * @since 3.0 | |
| 31 | * @version $Id: ConcurrentUtils.java 1436770 2013-01-22 07:09:45Z ggregory $ | |
| 32 | */ | |
| 33 | public class ConcurrentUtils { | |
| 34 | ||
| 35 | /** | |
| 36 | * Private constructor so that no instances can be created. This class | |
| 37 | * contains only static utility methods. | |
| 38 | */ | |
| 39 | 0 | private ConcurrentUtils() { |
| 40 | 0 | } |
| 41 | ||
| 42 | /** | |
| 43 | * Inspects the cause of the specified {@code ExecutionException} and | |
| 44 | * creates a {@code ConcurrentException} with the checked cause if | |
| 45 | * necessary. This method performs the following checks on the cause of the | |
| 46 | * passed in exception: | |
| 47 | * <ul> | |
| 48 | * <li>If the passed in exception is <b>null</b> or the cause is | |
| 49 | * <b>null</b>, this method returns <b>null</b>.</li> | |
| 50 | * <li>If the cause is a runtime exception, it is directly thrown.</li> | |
| 51 | * <li>If the cause is an error, it is directly thrown, too.</li> | |
| 52 | * <li>In any other case the cause is a checked exception. The method then | |
| 53 | * creates a {@link ConcurrentException}, initializes it with the cause, and | |
| 54 | * returns it.</li> | |
| 55 | * </ul> | |
| 56 | * | |
| 57 | * @param ex the exception to be processed | |
| 58 | * @return a {@code ConcurrentException} with the checked cause | |
| 59 | */ | |
| 60 | public static ConcurrentException extractCause(final ExecutionException ex) { | |
| 61 | 16 | if (ex == null || ex.getCause() == null) { |
| 62 | 4 | return null; |
| 63 | } | |
| 64 | ||
| 65 | 12 | throwCause(ex); |
| 66 | 5 | return new ConcurrentException(ex.getMessage(), ex.getCause()); |
| 67 | } | |
| 68 | ||
| 69 | /** | |
| 70 | * Inspects the cause of the specified {@code ExecutionException} and | |
| 71 | * creates a {@code ConcurrentRuntimeException} with the checked cause if | |
| 72 | * necessary. This method works exactly like | |
| 73 | * {@link #extractCause(ExecutionException)}. The only difference is that | |
| 74 | * the cause of the specified {@code ExecutionException} is extracted as a | |
| 75 | * runtime exception. This is an alternative for client code that does not | |
| 76 | * want to deal with checked exceptions. | |
| 77 | * | |
| 78 | * @param ex the exception to be processed | |
| 79 | * @return a {@code ConcurrentRuntimeException} with the checked cause | |
| 80 | */ | |
| 81 | public static ConcurrentRuntimeException extractCauseUnchecked( | |
| 82 | final ExecutionException ex) { | |
| 83 | 10 | if (ex == null || ex.getCause() == null) { |
| 84 | 4 | return null; |
| 85 | } | |
| 86 | ||
| 87 | 6 | throwCause(ex); |
| 88 | 2 | return new ConcurrentRuntimeException(ex.getMessage(), ex.getCause()); |
| 89 | } | |
| 90 | ||
| 91 | /** | |
| 92 | * Handles the specified {@code ExecutionException}. This method calls | |
| 93 | * {@link #extractCause(ExecutionException)} for obtaining the cause of the | |
| 94 | * exception - which might already cause an unchecked exception or an error | |
| 95 | * being thrown. If the cause is a checked exception however, it is wrapped | |
| 96 | * in a {@code ConcurrentException}, which is thrown. If the passed in | |
| 97 | * exception is <b>null</b> or has no cause, the method simply returns | |
| 98 | * without throwing an exception. | |
| 99 | * | |
| 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(final ExecutionException ex) | |
| 105 | throws ConcurrentException { | |
| 106 | 11 | final ConcurrentException cex = extractCause(ex); |
| 107 | ||
| 108 | 6 | if (cex != null) { |
| 109 | 4 | throw cex; |
| 110 | } | |
| 111 | 2 | } |
| 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(final ExecutionException ex) { | |
| 127 | 5 | final ConcurrentRuntimeException crex = extractCauseUnchecked(ex); |
| 128 | ||
| 129 | 3 | if (crex != null) { |
| 130 | 1 | throw crex; |
| 131 | } | |
| 132 | 2 | } |
| 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(final Throwable ex) { | |
| 144 | 18 | if (ex != null && !(ex instanceof RuntimeException) |
| 145 | && !(ex instanceof Error)) { | |
| 146 | 12 | return ex; |
| 147 | } else { | |
| 148 | 6 | 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(final ExecutionException ex) { | |
| 159 | 18 | if (ex.getCause() instanceof RuntimeException) { |
| 160 | 7 | throw (RuntimeException) ex.getCause(); |
| 161 | } | |
| 162 | ||
| 163 | 11 | if (ex.getCause() instanceof Error) { |
| 164 | 4 | throw (Error) ex.getCause(); |
| 165 | } | |
| 166 | 7 | } |
| 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(final ConcurrentInitializer<T> initializer) | |
| 183 | throws ConcurrentException { | |
| 184 | 5 | 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(final ConcurrentInitializer<T> initializer) { | |
| 201 | try { | |
| 202 | 3 | return initialize(initializer); |
| 203 | 1 | } catch (final ConcurrentException cex) { |
| 204 | 1 | 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(final ConcurrentMap<K, V> map, final K key, final V value) { | |
| 242 | 5 | if (map == null) { |
| 243 | 1 | return null; |
| 244 | } | |
| 245 | ||
| 246 | 4 | final V result = map.putIfAbsent(key, value); |
| 247 | 4 | 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(final ConcurrentMap<K, V> map, final K key, | |
| 271 | final ConcurrentInitializer<V> init) throws ConcurrentException { | |
| 272 | 6 | if (map == null || init == null) { |
| 273 | 2 | return null; |
| 274 | } | |
| 275 | ||
| 276 | 4 | final V value = map.get(key); |
| 277 | 4 | if (value == null) { |
| 278 | 3 | return putIfAbsent(map, key, init.get()); |
| 279 | } | |
| 280 | 1 | 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(final ConcurrentMap<K, V> map, | |
| 299 | final K key, final ConcurrentInitializer<V> init) { | |
| 300 | try { | |
| 301 | 2 | return createIfAbsent(map, key, init); |
| 302 | 1 | } catch (final ConcurrentException cex) { |
| 303 | 1 | 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(final T value) { | |
| 324 | 2 | 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 | 2 | ConstantFuture(final T value) { |
| 342 | 2 | this.value = value; |
| 343 | 2 | } |
| 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 | @Override | |
| 351 | public boolean isDone() { | |
| 352 | 2 | return true; |
| 353 | } | |
| 354 | ||
| 355 | /** | |
| 356 | * {@inheritDoc} This implementation just returns the constant value. | |
| 357 | */ | |
| 358 | @Override | |
| 359 | public T get() { | |
| 360 | 2 | return value; |
| 361 | } | |
| 362 | ||
| 363 | /** | |
| 364 | * {@inheritDoc} This implementation just returns the constant value; it | |
| 365 | * does not block, therefore the timeout has no meaning. | |
| 366 | */ | |
| 367 | @Override | |
| 368 | public T get(final long timeout, final TimeUnit unit) { | |
| 369 | 4 | return value; |
| 370 | } | |
| 371 | ||
| 372 | /** | |
| 373 | * {@inheritDoc} This implementation always returns <b>false</b>; there | |
| 374 | * is no background process which could be cancelled. | |
| 375 | */ | |
| 376 | @Override | |
| 377 | public boolean isCancelled() { | |
| 378 | 2 | return false; |
| 379 | } | |
| 380 | ||
| 381 | /** | |
| 382 | * {@inheritDoc} The cancel operation is not supported. This | |
| 383 | * implementation always returns <b>false</b>. | |
| 384 | */ | |
| 385 | @Override | |
| 386 | public boolean cancel(final boolean mayInterruptIfRunning) { | |
| 387 | 4 | return false; |
| 388 | } | |
| 389 | } | |
| 390 | ||
| 391 | } |