mirror of https://github.com/apache/jclouds.git
unwound a few stack traces by making DelegatesToInvocationFunction an invocation handler directly
This commit is contained in:
parent
f18d3b433f
commit
b07984435f
|
@ -32,8 +32,6 @@ import java.util.Arrays;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.jclouds.reflect.Invocation.Result;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Objects;
|
||||
|
@ -77,13 +75,13 @@ public final class FunctionalReflection {
|
|||
* @see com.google.common.reflect.AbstractInvocationHandler#invoke(Object, Method, Object[])
|
||||
* @see com.google.common.reflect.Reflection#newProxy(Class, java.lang.reflect.InvocationHandler)
|
||||
*/
|
||||
public static <T> T newProxy(TypeToken<T> enclosingType, Function<Invocation, Result> invocationFunction) {
|
||||
public static <T> T newProxy(TypeToken<T> enclosingType, Function<Invocation, Object> invocationFunction) {
|
||||
checkNotNull(enclosingType, "enclosingType");
|
||||
checkNotNull(invocationFunction, "invocationFunction");
|
||||
return newProxy(enclosingType.getRawType(), new FunctionalInvocationHandler<T>(enclosingType, invocationFunction));
|
||||
}
|
||||
|
||||
public static <T> T newProxy(Class<T> enclosingType, Function<Invocation, Result> invocationFunction) {
|
||||
public static <T> T newProxy(Class<T> enclosingType, Function<Invocation, Object> invocationFunction) {
|
||||
checkNotNull(invocationFunction, "invocationFunction");
|
||||
return newProxy(enclosingType,
|
||||
new FunctionalInvocationHandler<T>(TypeToken.of(enclosingType), invocationFunction));
|
||||
|
@ -100,9 +98,9 @@ public final class FunctionalReflection {
|
|||
private static final class FunctionalInvocationHandler<T> extends
|
||||
com.google.common.reflect.AbstractInvocationHandler {
|
||||
private final TypeToken<T> enclosingType;
|
||||
private final Function<Invocation, Result> invocationFunction;
|
||||
private final Function<Invocation, Object> invocationFunction;
|
||||
|
||||
private FunctionalInvocationHandler(TypeToken<T> enclosingType, Function<Invocation, Result> invocationFunction) {
|
||||
private FunctionalInvocationHandler(TypeToken<T> enclosingType, Function<Invocation, Object> invocationFunction) {
|
||||
this.enclosingType = enclosingType;
|
||||
this.invocationFunction = invocationFunction;
|
||||
}
|
||||
|
@ -117,17 +115,12 @@ public final class FunctionalReflection {
|
|||
Invokable<?, Object> invokable = Invokable.from(invoked);
|
||||
// not yet support the proxy arg
|
||||
Invocation invocation = Invocation.create(invokable, args);
|
||||
Result result;
|
||||
try {
|
||||
result = invocationFunction.apply(invocation);
|
||||
return invocationFunction.apply(invocation);
|
||||
} catch (RuntimeException e) {
|
||||
result = Result.fail(e);
|
||||
propagateIfPossible(e, invocation.getInvokable().getExceptionTypes());
|
||||
throw propagate(e);
|
||||
}
|
||||
if (result.getThrowable().isPresent()) {
|
||||
propagateIfPossible(result.getThrowable().get(), invocation.getInvokable().getExceptionTypes());
|
||||
throw propagate(result.getThrowable().get());
|
||||
}
|
||||
return result.getResult().orNull();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -23,11 +23,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.reflect.Invokable;
|
||||
|
||||
/**
|
||||
|
@ -90,63 +87,4 @@ public final class Invocation {
|
|||
public String toString() {
|
||||
return String.format("%s%s", invokable, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* result of an invocation which is either successful or failed, but not both.
|
||||
*/
|
||||
@Beta
|
||||
public final static class Result {
|
||||
public static Result success(@Nullable Object result) {
|
||||
return new Result(Optional.fromNullable(result), Optional.<Throwable> absent());
|
||||
}
|
||||
|
||||
public static Result fail(Throwable throwable) {
|
||||
return new Result(Optional.absent(), Optional.of(throwable));
|
||||
}
|
||||
|
||||
private final Optional<Object> result;
|
||||
private final Optional<Throwable> throwable;
|
||||
|
||||
private Result(Optional<Object> result, Optional<Throwable> throwable) {
|
||||
this.result = checkNotNull(result, "result");
|
||||
this.throwable = checkNotNull(throwable, "throwable");
|
||||
}
|
||||
|
||||
/**
|
||||
* result of{@link Invokable#invoke(Object, Object...)}
|
||||
*/
|
||||
public Optional<Object> getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* throwable received during {@link Invokable#invoke(Object, Object...)}
|
||||
*/
|
||||
public Optional<Throwable> getThrowable() {
|
||||
return throwable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
Result that = Result.class.cast(o);
|
||||
return equal(this.result.orNull(), that.result.orNull())
|
||||
&& equal(this.throwable.orNull(), that.throwable.orNull());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(result.orNull(), throwable.orNull());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toStringHelper("").omitNullValues().add("result", result.orNull())
|
||||
.add("throwable", throwable.orNull()).toString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,11 +18,12 @@
|
|||
*/
|
||||
package org.jclouds.rest.config;
|
||||
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.reflect.FunctionalReflection;
|
||||
import org.jclouds.rest.internal.DelegatingInvocationFunction;
|
||||
import org.jclouds.rest.internal.DelegatesToInvocationFunction;
|
||||
import org.jclouds.rest.internal.InvokeHttpMethod;
|
||||
|
||||
import com.google.inject.Provider;
|
||||
|
@ -35,10 +36,10 @@ import com.google.inject.TypeLiteral;
|
|||
@Singleton
|
||||
public class AsyncHttpApiProvider<A> implements Provider<A> {
|
||||
private final Class<? super A> asyncApiType;
|
||||
private final DelegatingInvocationFunction<A, A, InvokeHttpMethod<A, A>> httpInvoker;
|
||||
private final DelegatesToInvocationFunction<A, A, InvokeHttpMethod<A, A>> httpInvoker;
|
||||
|
||||
@Inject
|
||||
private AsyncHttpApiProvider(DelegatingInvocationFunction<A, A, InvokeHttpMethod<A, A>> httpInvoker,
|
||||
private AsyncHttpApiProvider(DelegatesToInvocationFunction<A, A, InvokeHttpMethod<A, A>> httpInvoker,
|
||||
TypeLiteral<A> asyncApiType) {
|
||||
this.httpInvoker = httpInvoker;
|
||||
this.asyncApiType = asyncApiType.getRawType();
|
||||
|
@ -47,7 +48,6 @@ public class AsyncHttpApiProvider<A> implements Provider<A> {
|
|||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public A get() {
|
||||
return (A) FunctionalReflection.newProxy(asyncApiType, httpInvoker);
|
||||
return (A) Proxy.newProxyInstance(asyncApiType.getClassLoader(), new Class<?>[] { asyncApiType }, httpInvoker);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,15 +18,16 @@
|
|||
*/
|
||||
package org.jclouds.rest.config;
|
||||
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.reflect.FunctionalReflection;
|
||||
import com.google.common.reflect.Invokable;
|
||||
import org.jclouds.rest.internal.DelegatingInvocationFunction;
|
||||
import org.jclouds.rest.internal.DelegatesToInvocationFunction;
|
||||
import org.jclouds.rest.internal.InvokeAndCallGetOnFutures;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.reflect.Invokable;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
|
@ -37,11 +38,11 @@ import com.google.inject.Provider;
|
|||
public class CallGetOnFuturesProvider<S, A> implements Provider<S> {
|
||||
|
||||
private final Class<? super S> apiType;
|
||||
private final DelegatingInvocationFunction<S, A, InvokeAndCallGetOnFutures<A>> syncInvoker;
|
||||
private final DelegatesToInvocationFunction<S, A, InvokeAndCallGetOnFutures<A>> syncInvoker;
|
||||
|
||||
@Inject
|
||||
private CallGetOnFuturesProvider(Cache<Invokable<?, ?>, Invokable<?, ?>> invokables,
|
||||
DelegatingInvocationFunction<S, A, InvokeAndCallGetOnFutures<A>> syncInvoker, Class<S> apiType,
|
||||
DelegatesToInvocationFunction<S, A, InvokeAndCallGetOnFutures<A>> syncInvoker, Class<S> apiType,
|
||||
Class<A> asyncApiType) {
|
||||
this.syncInvoker = syncInvoker;
|
||||
this.apiType = apiType;
|
||||
|
@ -52,6 +53,6 @@ public class CallGetOnFuturesProvider<S, A> implements Provider<S> {
|
|||
@Override
|
||||
@Singleton
|
||||
public S get() {
|
||||
return (S) FunctionalReflection.newProxy(apiType, syncInvoker);
|
||||
return (S) Proxy.newProxyInstance(apiType.getClassLoader(), new Class<?>[] { apiType }, syncInvoker);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,15 +18,16 @@
|
|||
*/
|
||||
package org.jclouds.rest.config;
|
||||
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.reflect.FunctionalReflection;
|
||||
import com.google.common.reflect.Invokable;
|
||||
import org.jclouds.rest.internal.DelegatingInvocationFunction;
|
||||
import org.jclouds.rest.internal.DelegatesToInvocationFunction;
|
||||
import org.jclouds.rest.internal.InvokeHttpMethod;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.reflect.Invokable;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
|
@ -37,11 +38,11 @@ import com.google.inject.Provider;
|
|||
@Singleton
|
||||
public class HttpApiProvider<S, A> implements Provider<S> {
|
||||
private final Class<? super S> apiType;
|
||||
private final DelegatingInvocationFunction<S, A, InvokeHttpMethod<S, A>> httpInvoker;
|
||||
private final DelegatesToInvocationFunction<S, A, InvokeHttpMethod<S, A>> httpInvoker;
|
||||
|
||||
@Inject
|
||||
private HttpApiProvider(Cache<Invokable<?, ?>, Invokable<?, ?>> invokables,
|
||||
DelegatingInvocationFunction<S, A, InvokeHttpMethod<S, A>> httpInvoker, Class<S> apiType, Class<A> asyncApiType) {
|
||||
DelegatesToInvocationFunction<S, A, InvokeHttpMethod<S, A>> httpInvoker, Class<S> apiType, Class<A> asyncApiType) {
|
||||
this.httpInvoker = httpInvoker;
|
||||
this.apiType = apiType;
|
||||
RestModule.putInvokables(TypeToken.of(apiType), TypeToken.of(asyncApiType), invokables);
|
||||
|
@ -51,7 +52,7 @@ public class HttpApiProvider<S, A> implements Provider<S> {
|
|||
@Override
|
||||
@Singleton
|
||||
public S get() {
|
||||
return (S) FunctionalReflection.newProxy(apiType, httpInvoker);
|
||||
return (S) Proxy.newProxyInstance(apiType.getClassLoader(), new Class<?>[] { apiType }, httpInvoker);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,7 +34,6 @@ import javax.inject.Named;
|
|||
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.reflect.Invocation;
|
||||
import org.jclouds.reflect.Invocation.Result;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
|
@ -46,7 +45,7 @@ import com.google.common.util.concurrent.UncheckedExecutionException;
|
|||
import com.google.common.util.concurrent.UncheckedTimeoutException;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
|
||||
public class BlockOnFuture implements Function<ListenableFuture<?>, Result> {
|
||||
public class BlockOnFuture implements Function<ListenableFuture<?>, Object> {
|
||||
|
||||
public static interface Factory {
|
||||
/**
|
||||
|
@ -73,19 +72,19 @@ public class BlockOnFuture implements Function<ListenableFuture<?>, Result> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Result apply(ListenableFuture<?> future) {
|
||||
public Object apply(ListenableFuture<?> future) {
|
||||
Optional<Long> timeoutNanos = timeoutInNanos(invocation.getInvokable(), timeouts);
|
||||
return block(future, timeoutNanos);
|
||||
}
|
||||
|
||||
private Result block(ListenableFuture<?> future, Optional<Long> timeoutNanos) {
|
||||
private Object block(ListenableFuture<?> future, Optional<Long> timeoutNanos) {
|
||||
try {
|
||||
if (timeoutNanos.isPresent()) {
|
||||
logger.debug(">> blocking on %s for %s", future, timeoutNanos);
|
||||
return Result.success(getUninterruptibly(future, timeoutNanos.get(), NANOSECONDS));
|
||||
return getUninterruptibly(future, timeoutNanos.get(), NANOSECONDS);
|
||||
} else {
|
||||
logger.debug(">> blocking on %s", future);
|
||||
return Result.success(getUninterruptibly(future));
|
||||
return getUninterruptibly(future);
|
||||
}
|
||||
} catch (ExecutionException e) {
|
||||
throw propagateCause(e);
|
||||
|
|
|
@ -19,25 +19,33 @@
|
|||
package org.jclouds.rest.internal;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Predicates.notNull;
|
||||
import static com.google.common.base.Throwables.propagate;
|
||||
import static com.google.common.collect.Iterables.all;
|
||||
import static com.google.common.collect.Iterables.find;
|
||||
import static com.google.inject.util.Types.newParameterizedType;
|
||||
import static org.jclouds.util.Optionals2.isReturnTypeOptional;
|
||||
import static org.jclouds.util.Optionals2.unwrapIfOptional;
|
||||
import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
|
||||
import static org.jclouds.util.Throwables2.propagateIfPossible;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Qualifier;
|
||||
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
import org.jclouds.reflect.FunctionalReflection;
|
||||
import org.jclouds.reflect.Invocation;
|
||||
import org.jclouds.reflect.Invocation.Result;
|
||||
import org.jclouds.reflect.InvocationSuccess;
|
||||
import com.google.common.reflect.Invokable;
|
||||
import org.jclouds.rest.AuthorizationException;
|
||||
import org.jclouds.rest.annotations.Delegate;
|
||||
import org.jclouds.rest.config.SetCaller;
|
||||
|
@ -49,6 +57,8 @@ import com.google.common.base.Optional;
|
|||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.reflect.AbstractInvocationHandler;
|
||||
import com.google.common.reflect.Invokable;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.inject.Binding;
|
||||
import com.google.inject.ConfigurationException;
|
||||
|
@ -60,7 +70,6 @@ import com.google.inject.TypeLiteral;
|
|||
import com.google.inject.util.Types;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param <S>
|
||||
* The enclosing type of the interface that a dynamic proxy like this implements
|
||||
* @param <A>
|
||||
|
@ -69,8 +78,67 @@ import com.google.inject.util.Types;
|
|||
* The function that implements this dynamic proxy
|
||||
*/
|
||||
@Beta
|
||||
public final class DelegatingInvocationFunction<S, A, F extends Function<Invocation, Result>> implements
|
||||
Function<Invocation, Result> {
|
||||
public final class DelegatesToInvocationFunction<S, A, F extends Function<Invocation, Object>> implements
|
||||
InvocationHandler {
|
||||
|
||||
private static final Object[] NO_ARGS = {};
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* <ul>
|
||||
* <li>{@code proxy.hashCode()} delegates to {@link AbstractInvocationHandler#hashCode}
|
||||
* <li>{@code proxy.toString()} delegates to {@link AbstractInvocationHandler#toString}
|
||||
* <li>{@code proxy.equals(argument)} returns true if:
|
||||
* <ul>
|
||||
* <li>{@code proxy} and {@code argument} are of the same type
|
||||
* <li>and {@link AbstractInvocationHandler#equals} returns true for the {@link InvocationHandler} of
|
||||
* {@code argument}
|
||||
* </ul>
|
||||
* <li>other method calls are dispatched to {@link #handleInvocation}.
|
||||
* </ul>
|
||||
* @throws Throwable
|
||||
*/
|
||||
@Override
|
||||
public final Object invoke(Object proxy, Method invoked, @Nullable Object[] argv) throws Throwable {
|
||||
if (argv == null) {
|
||||
argv = NO_ARGS;
|
||||
}
|
||||
if (argv.length == 0 && invoked.getName().equals("hashCode")) {
|
||||
return hashCode();
|
||||
}
|
||||
if (argv.length == 1 && invoked.getName().equals("equals") && invoked.getParameterTypes()[0] == Object.class) {
|
||||
Object arg = argv[0];
|
||||
return proxy.getClass().isInstance(arg) && equals(Proxy.getInvocationHandler(arg));
|
||||
}
|
||||
if (argv.length == 0 && invoked.getName().equals("toString")) {
|
||||
return toString();
|
||||
}
|
||||
List<Object> args = Arrays.asList(argv);
|
||||
if (all(args, notNull()))
|
||||
args = ImmutableList.copyOf(args);
|
||||
else
|
||||
args = Collections.unmodifiableList(args);
|
||||
Invokable<?, Object> invokable = Invokable.from(invoked);
|
||||
// not yet support the proxy arg
|
||||
Invocation invocation = Invocation.create(invokable, args);
|
||||
try {
|
||||
return handle(invocation);
|
||||
} catch (Throwable e) {
|
||||
propagateIfPossible(e, invocation.getInvokable().getExceptionTypes());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
protected Object handle(Invocation invocation) {
|
||||
if (invocation.getInvokable().isAnnotationPresent(Provides.class))
|
||||
return lookupValueFromGuice(invocation.getInvokable());
|
||||
else if (invocation.getInvokable().isAnnotationPresent(Delegate.class))
|
||||
return propagateContextToDelegate(invocation);
|
||||
return methodInvoker.apply(invocation);
|
||||
}
|
||||
|
||||
private final Injector injector;
|
||||
private final TypeToken<S> enclosingType;
|
||||
private final SetCaller setCaller;
|
||||
|
@ -80,7 +148,7 @@ public final class DelegatingInvocationFunction<S, A, F extends Function<Invocat
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Inject
|
||||
DelegatingInvocationFunction(Injector injector, SetCaller setCaller, Map<Class<?>, Class<?>> syncToAsync,
|
||||
DelegatesToInvocationFunction(Injector injector, SetCaller setCaller, Map<Class<?>, Class<?>> syncToAsync,
|
||||
TypeLiteral<S> enclosingType, Function<InvocationSuccess, Optional<Object>> optionalConverter, F methodInvoker) {
|
||||
this.injector = checkNotNull(injector, "injector");
|
||||
this.enclosingType = (TypeToken<S>) TypeToken.of(checkNotNull(enclosingType, "enclosingType").getType());
|
||||
|
@ -90,22 +158,13 @@ public final class DelegatingInvocationFunction<S, A, F extends Function<Invocat
|
|||
this.methodInvoker = checkNotNull(methodInvoker, "methodInvoker");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result apply(Invocation in) {
|
||||
if (in.getInvokable().isAnnotationPresent(Provides.class))
|
||||
return Result.success(lookupValueFromGuice(in.getInvokable()));
|
||||
else if (in.getInvokable().isAnnotationPresent(Delegate.class))
|
||||
return Result.success(propagateContextToDelegate(in));
|
||||
return methodInvoker.apply(in);
|
||||
}
|
||||
|
||||
private Object propagateContextToDelegate(Invocation caller) {
|
||||
Class<?> returnType = unwrapIfOptional(caller.getInvokable().getReturnType());
|
||||
Function<Invocation, Result> delegate;
|
||||
Function<Invocation, Object> delegate;
|
||||
setCaller.enter(enclosingType, caller);
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
Key<Function<Invocation, Result>> delegateType = (Key<Function<Invocation, Result>>) methodInvokerFor(returnType);
|
||||
Key<Function<Invocation, Object>> delegateType = (Key<Function<Invocation, Object>>) methodInvokerFor(returnType);
|
||||
delegate = injector.getInstance(delegateType);
|
||||
} finally {
|
||||
setCaller.exit();
|
|
@ -19,6 +19,8 @@
|
|||
package org.jclouds.rest.internal;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Throwables.propagate;
|
||||
import static com.google.common.util.concurrent.Futures.getUnchecked;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
|
@ -27,20 +29,18 @@ import javax.inject.Inject;
|
|||
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.reflect.Invocation;
|
||||
import org.jclouds.reflect.Invocation.Result;
|
||||
import com.google.common.reflect.Invokable;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.reflect.Invokable;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public final class InvokeAndCallGetOnFutures<R> implements Function<Invocation, Result> {
|
||||
public final class InvokeAndCallGetOnFutures<R> implements Function<Invocation, Object> {
|
||||
|
||||
@Resource
|
||||
private Logger logger = Logger.NULL;
|
||||
|
@ -62,7 +62,7 @@ public final class InvokeAndCallGetOnFutures<R> implements Function<Invocation,
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Result apply(Invocation in) {
|
||||
public Object apply(Invocation in) {
|
||||
@SuppressWarnings("rawtypes")
|
||||
Invokable target = checkNotNull(sync2AsyncInvokables.getIfPresent(in.getInvokable()), "invokable %s not in %s",
|
||||
in.getInvokable(), sync2AsyncInvokables);
|
||||
|
@ -70,13 +70,13 @@ public final class InvokeAndCallGetOnFutures<R> implements Function<Invocation,
|
|||
try {
|
||||
returnVal = target.invoke(receiver, in.getArgs().toArray());
|
||||
} catch (InvocationTargetException e) {
|
||||
return Result.fail(e);
|
||||
throw propagate(e.getCause());
|
||||
} catch (IllegalAccessException e) {
|
||||
return Result.fail(e);
|
||||
throw new Error("Method became inaccessible: " + toString(), e);
|
||||
}
|
||||
if (!isFuture(target))
|
||||
return Result.success(returnVal);
|
||||
return Result.success(Futures.getUnchecked(ListenableFuture.class.cast(returnVal)));
|
||||
return returnVal;
|
||||
return getUnchecked(ListenableFuture.class.cast(returnVal));
|
||||
}
|
||||
|
||||
private boolean isFuture(Invokable<?, ?> target) {
|
||||
|
|
|
@ -35,7 +35,6 @@ import org.jclouds.http.HttpCommandExecutorService;
|
|||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.reflect.Invocation;
|
||||
import org.jclouds.reflect.Invocation.Result;
|
||||
import org.jclouds.rest.InvocationContext;
|
||||
import org.jclouds.rest.annotations.Fallback;
|
||||
|
||||
|
@ -53,7 +52,7 @@ import com.google.common.util.concurrent.ListeningExecutorService;
|
|||
import com.google.inject.Injector;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
public class InvokeHttpMethod<S, A> implements Function<Invocation, Result> {
|
||||
public class InvokeHttpMethod<S, A> implements Function<Invocation, Object> {
|
||||
|
||||
@Resource
|
||||
private Logger logger = Logger.NULL;
|
||||
|
@ -98,9 +97,9 @@ public class InvokeHttpMethod<S, A> implements Function<Invocation, Result> {
|
|||
});
|
||||
|
||||
@Override
|
||||
public Result apply(Invocation in) {
|
||||
public Object apply(Invocation in) {
|
||||
if (isFuture(in.getInvokable())) {
|
||||
return Result.success(createFuture(in));
|
||||
return createFuture(in);
|
||||
}
|
||||
@SuppressWarnings("rawtypes")
|
||||
Invokable async = checkNotNull(sync2AsyncInvokables.getIfPresent(in.getInvokable()), "invokable %s not in %s",
|
||||
|
|
|
@ -27,9 +27,7 @@ import static org.testng.Assert.assertTrue;
|
|||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.jclouds.reflect.Invocation.Result;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
@ -45,8 +43,8 @@ public class FunctionalReflectionTest {
|
|||
@SuppressWarnings("unchecked")
|
||||
@Test(expectedExceptions = UnsupportedOperationException.class)
|
||||
public void testNullArgsAreAllowedAndUnmodifiable() {
|
||||
final Function<Invocation, Result> test = new Function<Invocation, Result>() {
|
||||
public Result apply(Invocation e) {
|
||||
final Function<Invocation, Object> test = new Function<Invocation, Object>() {
|
||||
public Object apply(Invocation e) {
|
||||
assertNotNull(e.getArgs());
|
||||
assertNull(e.getArgs().get(0));
|
||||
e.getArgs().add("foo");
|
||||
|
@ -59,8 +57,8 @@ public class FunctionalReflectionTest {
|
|||
@SuppressWarnings("unchecked")
|
||||
@Test(expectedExceptions = UnsupportedOperationException.class)
|
||||
public void testImmutableListWhenArgsAreNotNull() {
|
||||
final Function<Invocation, Result> test = new Function<Invocation, Result>() {
|
||||
public Result apply(Invocation e) {
|
||||
final Function<Invocation, Object> test = new Function<Invocation, Object>() {
|
||||
public Object apply(Invocation e) {
|
||||
assertNotNull(e.getArgs());
|
||||
assertTrue(e.getArgs() instanceof ImmutableList);
|
||||
assertEquals(e.getArgs().get(0), "foo");
|
||||
|
@ -73,9 +71,9 @@ public class FunctionalReflectionTest {
|
|||
|
||||
@Test(expectedExceptions = IOException.class, expectedExceptionsMessageRegExp = "io")
|
||||
public void testPropagatesDeclaredException() throws IOException {
|
||||
final Function<Invocation, Result> test = new Function<Invocation, Result>() {
|
||||
public Result apply(Invocation e) {
|
||||
return Result.fail(new IOException("io"));
|
||||
final Function<Invocation, Object> test = new Function<Invocation, Object>() {
|
||||
public Object apply(Invocation e) {
|
||||
throw new RuntimeException(new IOException("io"));
|
||||
}
|
||||
};
|
||||
Closeable closeable = FunctionalReflection.newProxy(Closeable.class, test);
|
||||
|
@ -87,21 +85,9 @@ public class FunctionalReflectionTest {
|
|||
*/
|
||||
@Test(expectedExceptions = AssertionError.class, expectedExceptionsMessageRegExp = "assert")
|
||||
public void testPropagatesError() throws IOException {
|
||||
final Function<Invocation, Result> test = new Function<Invocation, Result>() {
|
||||
public Result apply(Invocation e) {
|
||||
return Result.fail(new AssertionError("assert"));
|
||||
}
|
||||
};
|
||||
Closeable closeable = FunctionalReflection.newProxy(Closeable.class, test);
|
||||
closeable.close();
|
||||
}
|
||||
|
||||
// TODO: coerce things like this to UncheckedTimeoutException and friends
|
||||
@Test(expectedExceptions = RuntimeException.class, expectedExceptionsMessageRegExp = ".*timeout")
|
||||
public void testWrapsDeclaredException() throws IOException {
|
||||
final Function<Invocation, Result> test = new Function<Invocation, Result>() {
|
||||
public Result apply(Invocation e) {
|
||||
return Result.fail(new TimeoutException("timeout"));
|
||||
final Function<Invocation, Object> test = new Function<Invocation, Object>() {
|
||||
public Object apply(Invocation e) {
|
||||
throw new AssertionError("assert");
|
||||
}
|
||||
};
|
||||
Closeable closeable = FunctionalReflection.newProxy(Closeable.class, test);
|
||||
|
@ -109,9 +95,9 @@ public class FunctionalReflectionTest {
|
|||
}
|
||||
|
||||
public void testToStringEqualsFunction() {
|
||||
final Function<Invocation, Result> test = new Function<Invocation, Result>() {
|
||||
public Result apply(Invocation e) {
|
||||
return Result.success("foo");
|
||||
final Function<Invocation, Object> test = new Function<Invocation, Object>() {
|
||||
public Object apply(Invocation e) {
|
||||
return "foo";
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
|
@ -123,9 +109,9 @@ public class FunctionalReflectionTest {
|
|||
}
|
||||
|
||||
public void testHashCodeDifferentiatesOnInterface() {
|
||||
final Function<Invocation, Result> test = new Function<Invocation, Result>() {
|
||||
public Result apply(Invocation e) {
|
||||
return Result.success(null);
|
||||
final Function<Invocation, Object> test = new Function<Invocation, Object>() {
|
||||
public Object apply(Invocation e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
|
|
Loading…
Reference in New Issue