|
Java example source code file (FuturesGetChecked.java)
This example Java source code file (FuturesGetChecked.java) is included in the alvinalexander.com
"Java Source Code
Warehouse" project. The intent of this project is to help you "Learn
Java by Example" TM.
Learn more about this Java project at its project page.
The FuturesGetChecked.java Java example source code
/*
* Copyright (C) 2006 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.util.concurrent;
import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.Thread.currentThread;
import static java.util.Arrays.asList;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.collect.Ordering;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.j2objc.annotations.J2ObjCIncompatible;
import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement;
import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.annotation.Nullable;
/**
* Static methods used to implement {@link Futures#getChecked(Future, Class)}.
*/
@GwtIncompatible
final class FuturesGetChecked {
@CanIgnoreReturnValue
static <V, X extends Exception> V getChecked(Future future, Class exceptionClass) throws X {
return getChecked(bestGetCheckedTypeValidator(), future, exceptionClass);
}
/**
* Implementation of {@link Futures#getChecked(Future, Class)}.
*/
@CanIgnoreReturnValue
@VisibleForTesting
static <V, X extends Exception> V getChecked(
GetCheckedTypeValidator validator, Future<V> future, Class exceptionClass) throws X {
validator.validateClass(exceptionClass);
try {
return future.get();
} catch (InterruptedException e) {
currentThread().interrupt();
throw newWithCause(exceptionClass, e);
} catch (ExecutionException e) {
wrapAndThrowExceptionOrError(e.getCause(), exceptionClass);
throw new AssertionError();
}
}
/**
* Implementation of {@link Futures#getChecked(Future, Class, long, TimeUnit)}.
*/
@CanIgnoreReturnValue
static <V, X extends Exception> V getChecked(
Future<V> future, Class exceptionClass, long timeout, TimeUnit unit) throws X {
// TODO(cpovirk): benchmark a version of this method that accepts a GetCheckedTypeValidator
bestGetCheckedTypeValidator().validateClass(exceptionClass);
try {
return future.get(timeout, unit);
} catch (InterruptedException e) {
currentThread().interrupt();
throw newWithCause(exceptionClass, e);
} catch (TimeoutException e) {
throw newWithCause(exceptionClass, e);
} catch (ExecutionException e) {
wrapAndThrowExceptionOrError(e.getCause(), exceptionClass);
throw new AssertionError();
}
}
@VisibleForTesting
interface GetCheckedTypeValidator {
void validateClass(Class<? extends Exception> exceptionClass);
}
private static GetCheckedTypeValidator bestGetCheckedTypeValidator() {
return GetCheckedTypeValidatorHolder.BEST_VALIDATOR;
}
@VisibleForTesting
static GetCheckedTypeValidator weakSetValidator() {
return GetCheckedTypeValidatorHolder.WeakSetValidator.INSTANCE;
}
@J2ObjCIncompatible // ClassValue
@VisibleForTesting
static GetCheckedTypeValidator classValueValidator() {
return GetCheckedTypeValidatorHolder.ClassValueValidator.INSTANCE;
}
/**
* Provides a check of whether an exception type is valid for use with
* {@link FuturesGetChecked#getChecked(Future, Class)}, possibly using caching.
*
* <p>Uses reflection to gracefully fall back to when certain implementations aren't available.
*/
@VisibleForTesting
static class GetCheckedTypeValidatorHolder {
static final String CLASS_VALUE_VALIDATOR_NAME =
GetCheckedTypeValidatorHolder.class.getName() + "$ClassValueValidator";
static final GetCheckedTypeValidator BEST_VALIDATOR = getBestValidator();
@IgnoreJRERequirement // getChecked falls back to another implementation if necessary
@J2ObjCIncompatible // ClassValue
enum ClassValueValidator implements GetCheckedTypeValidator {
INSTANCE;
/*
* Static final fields are presumed to be fastest, based on our experience with
* UnsignedBytesBenchmark. TODO(cpovirk): benchmark this
*/
private static final ClassValue<Boolean> isValidClass =
new ClassValue<Boolean>() {
@Override
protected Boolean computeValue(Class<?> type) {
checkExceptionClassValidity(type.asSubclass(Exception.class));
return true;
}
};
@Override
public void validateClass(Class<? extends Exception> exceptionClass) {
isValidClass.get(exceptionClass); // throws if invalid; returns safely (and caches) if valid
}
}
enum WeakSetValidator implements GetCheckedTypeValidator {
INSTANCE;
/*
* Static final fields are presumed to be fastest, based on our experience with
* UnsignedBytesBenchmark. TODO(cpovirk): benchmark this
*/
/*
* A CopyOnWriteArraySet<WeakReference> is faster than a newSetFromMap of a MapMaker map with
* weakKeys() and concurrencyLevel(1), even up to at least 12 cached exception types.
*/
private static final Set<WeakReference> validClasses =
new CopyOnWriteArraySet<WeakReference>();
@Override
public void validateClass(Class<? extends Exception> exceptionClass) {
for (WeakReference<Class extends Exception>> knownGood : validClasses) {
if (exceptionClass.equals(knownGood.get())) {
return;
}
// TODO(cpovirk): if reference has been cleared, remove it?
}
checkExceptionClassValidity(exceptionClass);
/*
* It's very unlikely that any loaded Futures class will see getChecked called with more
* than a handful of exceptions. But it seems prudent to set a cap on how many we'll cache.
* This avoids out-of-control memory consumption, and it keeps the cache from growing so
* large that doing the lookup is noticeably slower than redoing the work would be.
*
* Ideally we'd have a real eviction policy, but until we see a problem in practice, I hope
* that this will suffice. I have not even benchmarked with different size limits.
*/
if (validClasses.size() > 1000) {
validClasses.clear();
}
validClasses.add(new WeakReference<Class extends Exception>>(exceptionClass));
}
}
/**
* Returns the ClassValue-using validator, or falls back to the "weak Set" implementation if
* unable to do so.
*/
static GetCheckedTypeValidator getBestValidator() {
try {
Class<?> theClass = Class.forName(CLASS_VALUE_VALIDATOR_NAME);
return (GetCheckedTypeValidator) theClass.getEnumConstants()[0];
} catch (Throwable t) { // ensure we really catch *everything*
return weakSetValidator();
}
}
}
// TODO(cpovirk): change parameter order to match other helper methods (Class, Throwable)?
private static <X extends Exception> void wrapAndThrowExceptionOrError(
Throwable cause, Class<X> exceptionClass) throws X {
if (cause instanceof Error) {
throw new ExecutionError((Error) cause);
}
if (cause instanceof RuntimeException) {
throw new UncheckedExecutionException(cause);
}
throw newWithCause(exceptionClass, cause);
}
/*
* TODO(user): FutureChecker interface for these to be static methods on? If so, refer to it in
* the (static-method) Futures.getChecked documentation
*/
private static boolean hasConstructorUsableByGetChecked(
Class<? extends Exception> exceptionClass) {
try {
Exception unused = newWithCause(exceptionClass, new Exception());
return true;
} catch (Exception e) {
return false;
}
}
private static <X extends Exception> X newWithCause(Class exceptionClass, Throwable cause) {
// getConstructors() guarantees this as long as we don't modify the array.
@SuppressWarnings({"unchecked", "rawtypes"})
List<Constructor constructors = (List) Arrays.asList(exceptionClass.getConstructors());
for (Constructor<X> constructor : preferringStrings(constructors)) {
@Nullable X instance = newFromConstructor(constructor, cause);
if (instance != null) {
if (instance.getCause() == null) {
instance.initCause(cause);
}
return instance;
}
}
throw new IllegalArgumentException(
"No appropriate constructor for exception of type "
+ exceptionClass
+ " in response to chained exception",
cause);
}
private static <X extends Exception> List> preferringStrings(
List<Constructor constructors) {
return WITH_STRING_PARAM_FIRST.sortedCopy(constructors);
}
private static final Ordering<Constructor>> WITH_STRING_PARAM_FIRST =
Ordering.natural()
.onResultOf(
new Function<Constructor>, Boolean>() {
@Override
public Boolean apply(Constructor<?> input) {
return asList(input.getParameterTypes()).contains(String.class);
}
})
.reverse();
@Nullable
private static <X> X newFromConstructor(Constructor constructor, Throwable cause) {
Class<?>[] paramTypes = constructor.getParameterTypes();
Object[] params = new Object[paramTypes.length];
for (int i = 0; i < paramTypes.length; i++) {
Class<?> paramType = paramTypes[i];
if (paramType.equals(String.class)) {
params[i] = cause.toString();
} else if (paramType.equals(Throwable.class)) {
params[i] = cause;
} else {
return null;
}
}
try {
return constructor.newInstance(params);
} catch (IllegalArgumentException e) {
return null;
} catch (InstantiationException e) {
return null;
} catch (IllegalAccessException e) {
return null;
} catch (InvocationTargetException e) {
return null;
}
}
@VisibleForTesting
static boolean isCheckedException(Class<? extends Exception> type) {
return !RuntimeException.class.isAssignableFrom(type);
}
@VisibleForTesting
static void checkExceptionClassValidity(Class<? extends Exception> exceptionClass) {
checkArgument(
isCheckedException(exceptionClass),
"Futures.getChecked exception type (%s) must not be a RuntimeException",
exceptionClass);
checkArgument(
hasConstructorUsableByGetChecked(exceptionClass),
"Futures.getChecked exception type (%s) must be an accessible class with an accessible "
+ "constructor whose parameters (if any) must be of type String and/or Throwable",
exceptionClass);
}
private FuturesGetChecked() {}
}
Other Java examples (source code examples)
Here is a short list of links related to this Java FuturesGetChecked.java source code file:
|