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 }