updated to employ Reflection.newProxy + AbstractInvocationHandler

This commit is contained in:
Adrian Cole 2012-12-02 12:27:57 -08:00
parent 4d2124bada
commit c30fedec20
9 changed files with 31 additions and 94 deletions

View File

@ -62,11 +62,11 @@ public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensio
org.jclouds.openstack.v2_0.services.Extension.class)); org.jclouds.openstack.v2_0.services.Extension.class));
if (ext.isPresent()) { if (ext.isPresent()) {
URI namespace = URI.create(ext.get().namespace()); URI namespace = URI.create(ext.get().namespace());
if (input.getArgs() == null || input.getArgs().length == 0) { if (input.getArgs().length == 0) {
if (Iterables.any(extensions.getUnchecked(""), if (Iterables.any(extensions.getUnchecked(""),
ExtensionPredicates.namespaceOrAliasEquals(namespace, aliases.get(namespace)))) ExtensionPredicates.namespaceOrAliasEquals(namespace, aliases.get(namespace))))
return Optional.of(input.getReturnVal()); return Optional.of(input.getReturnVal());
} else if (input.getArgs() != null && input.getArgs().length == 1) { } else if (input.getArgs().length == 1) {
if (Iterables.any(extensions.getUnchecked(checkNotNull(input.getArgs()[0], "arg[0] in %s", input).toString()), if (Iterables.any(extensions.getUnchecked(checkNotNull(input.getArgs()[0], "arg[0] in %s", input).toString()),
ExtensionPredicates.namespaceOrAliasEquals(namespace, aliases.get(namespace)))) ExtensionPredicates.namespaceOrAliasEquals(namespace, aliases.get(namespace))))
return Optional.of(input.getReturnVal()); return Optional.of(input.getReturnVal());

View File

@ -63,7 +63,7 @@ public abstract class CallerArg0ToPagedIterable<T, I extends CallerArg0ToPagedIt
return PagedIterables.of(input); return PagedIterables.of(input);
Optional<String> arg0Option = Optional.absent(); Optional<String> arg0Option = Optional.absent();
if (request.getCaller().get().getArgs() != null && request.getCaller().get().getArgs().length > 0) { if (request.getCaller().get().getArgs().length > 0) {
Object arg0 = request.getCaller().get().getArgs()[0]; Object arg0 = request.getCaller().get().getArgs()[0];
if (arg0 != null) if (arg0 != null)
arg0Option = Optional.of(arg0.toString()); arg0Option = Optional.of(arg0.toString());

View File

@ -19,11 +19,10 @@
package org.jclouds.concurrent.internal; package org.jclouds.concurrent.internal;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
import static com.google.common.reflect.Reflection.newProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays; import java.util.Arrays;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -46,6 +45,7 @@ import com.google.common.base.Throwables;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.AbstractInvocationHandler;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.ProvisionException; import com.google.inject.ProvisionException;
@ -54,15 +54,13 @@ import com.google.inject.ProvisionException;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public class SyncProxy implements InvocationHandler { public class SyncProxy extends AbstractInvocationHandler {
@SuppressWarnings("unchecked")
public static <T> T proxy(Function<ClassMethodArgsAndReturnVal, Optional<Object>> optionalConverter, Class<T> clazz, Object async, public static <T> T proxy(Function<ClassMethodArgsAndReturnVal, Optional<Object>> optionalConverter, Class<T> clazz, Object async,
@Named("sync") LoadingCache<ClassMethodArgs, Object> delegateMap, @Named("sync") LoadingCache<ClassMethodArgs, Object> delegateMap,
Map<Class<?>, Class<?>> sync2Async, Map<String, Long> timeouts) throws IllegalArgumentException, SecurityException, Map<Class<?>, Class<?>> sync2Async, Map<String, Long> timeouts) throws IllegalArgumentException, SecurityException,
NoSuchMethodException { NoSuchMethodException {
return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[] { clazz }, return newProxy(clazz, new SyncProxy(optionalConverter, clazz, async, delegateMap, sync2Async, timeouts));
new SyncProxy(optionalConverter, clazz, async, delegateMap, sync2Async, timeouts));
} }
private final Function<ClassMethodArgsAndReturnVal, Optional<Object>> optionalConverter; private final Function<ClassMethodArgsAndReturnVal, Optional<Object>> optionalConverter;
@ -134,14 +132,9 @@ public class SyncProxy implements InvocationHandler {
return methodNanos; return methodNanos;
} }
public Object invoke(Object o, Method method, Object[] args) throws Exception { @Override
if (method.getName().equals("equals")) { protected Object handleInvocation(Object o, Method method, Object[] args) throws Exception {
return this.equals(o); if (method.isAnnotationPresent(Delegate.class)) {
} else if (method.getName().equals("hashCode")) {
return this.hashCode();
} else if (method.getName().equals("toString")) {
return this.toString();
} else if (method.isAnnotationPresent(Delegate.class)) {
Class<?> syncClass = Optionals2.returnTypeOrTypeOfOptional(method); Class<?> syncClass = Optionals2.returnTypeOrTypeOfOptional(method);
// get the return type of the asynchronous class associated with this client // get the return type of the asynchronous class associated with this client
// ex. FloatingIPClient is associated with FloatingIPAsyncClient // ex. FloatingIPClient is associated with FloatingIPAsyncClient
@ -191,24 +184,8 @@ public class SyncProxy implements InvocationHandler {
} }
return timeout != null ? TimeUnit.MILLISECONDS.toNanos(timeout) : null; return timeout != null ? TimeUnit.MILLISECONDS.toNanos(timeout) : null;
} }
@Override @Override
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof SyncProxy))
return false;
SyncProxy other = (SyncProxy) obj;
if (other == this)
return true;
if (other.declaring != this.declaring)
return false;
return super.equals(obj);
}
@Override
public int hashCode() {
return declaring.hashCode();
}
public String toString() { public String toString() {
return "Sync Proxy for: " + delegate.getClass().getSimpleName(); return "Sync Proxy for: " + delegate.getClass().getSimpleName();
} }

View File

@ -24,8 +24,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays; import java.util.Arrays;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper; import com.google.common.base.Objects.ToStringHelper;
@ -48,7 +46,7 @@ public class ClassMethodArgs {
public abstract static class Builder<B extends Builder<B>> { public abstract static class Builder<B extends Builder<B>> {
private Class<?> clazz; private Class<?> clazz;
private Method method; private Method method;
private Object[] args; private Object[] args = {};
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected B self() { protected B self() {
@ -96,10 +94,10 @@ public class ClassMethodArgs {
this(builder.clazz, builder.method, builder.args); this(builder.clazz, builder.method, builder.args);
} }
public ClassMethodArgs(Class<?> clazz, Method method, @Nullable Object[] args) { public ClassMethodArgs(Class<?> clazz, Method method, Object[] args) {
this.clazz = checkNotNull(clazz, "clazz"); this.clazz = checkNotNull(clazz, "clazz");
this.method = checkNotNull(method, "method"); this.method = checkNotNull(method, "method");
this.args = args; this.args = checkNotNull(args, "args");
} }
public Class<?> getClazz() { public Class<?> getClazz() {
@ -110,7 +108,7 @@ public class ClassMethodArgs {
return method; return method;
} }
@Nullable public Object[] getArgs() { public Object[] getArgs() {
return args; return args;
} }
@ -136,6 +134,6 @@ public class ClassMethodArgs {
protected ToStringHelper string() { protected ToStringHelper string() {
return Objects.toStringHelper("").omitNullValues().add("clazz", clazz).add("method", method) return Objects.toStringHelper("").omitNullValues().add("clazz", clazz).add("method", method)
.add("args", args != null ? Arrays.asList(args) : null); .add("args", args.length != 0 ? Arrays.asList(args) : null);
} }
} }

View File

@ -22,8 +22,6 @@ import static com.google.common.base.Objects.equal;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper; import com.google.common.base.Objects.ToStringHelper;
@ -68,7 +66,7 @@ public class ClassMethodArgsAndReturnVal extends ClassMethodArgs {
private final Object returnVal; private final Object returnVal;
public ClassMethodArgsAndReturnVal(Class<?> clazz, Method method, @Nullable Object[] args, Object returnVal) { public ClassMethodArgsAndReturnVal(Class<?> clazz, Method method, Object[] args, Object returnVal) {
super(clazz, method, args); super(clazz, method, args);
this.returnVal = returnVal; this.returnVal = returnVal;
} }

View File

@ -18,7 +18,8 @@
*/ */
package org.jclouds.rest; package org.jclouds.rest;
import java.lang.reflect.Proxy; import static com.google.common.reflect.Reflection.newProxy;
import static com.google.inject.util.Types.newParameterizedType;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
@ -28,7 +29,6 @@ import org.jclouds.rest.internal.AsyncRestClientProxy;
import com.google.inject.Injector; import com.google.inject.Injector;
import com.google.inject.Key; import com.google.inject.Key;
import com.google.inject.TypeLiteral; import com.google.inject.TypeLiteral;
import com.google.inject.util.Types;
/** /**
* *
@ -45,12 +45,9 @@ public class AsyncClientFactory {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> T create(Class<T> clazz) { public <T> T create(Class<T> clazz) {
return (T) create(clazz, (AsyncRestClientProxy<T>) injector.getInstance(Key.get(TypeLiteral Key<AsyncRestClientProxy<T>> key = (Key<AsyncRestClientProxy<T>>) Key.get(TypeLiteral.get(newParameterizedType(
.get(Types.newParameterizedType(AsyncRestClientProxy.class, clazz))))); AsyncRestClientProxy.class, clazz)));
return newProxy(clazz, injector.getInstance(key));
} }
@SuppressWarnings("unchecked")
public static <T> T create(Class<T> clazz, AsyncRestClientProxy<T> proxy) {
return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[] { clazz }, proxy);
}
} }

View File

@ -94,15 +94,4 @@ public class BinderUtils {
binder.bind(asyncClientType).toProvider(asyncProvider); binder.bind(asyncClientType).toProvider(asyncProvider);
} }
@SuppressWarnings("unchecked")
public static <T> T newNullProxy(Class<T> clazz) {
return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[] { clazz }, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
return null;
}
});
}
} }

View File

@ -18,6 +18,7 @@
*/ */
package org.jclouds.rest.config; package org.jclouds.rest.config;
import static com.google.common.reflect.Reflection.newProxy;
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX; import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -40,7 +41,6 @@ import org.jclouds.internal.ClassMethodArgs;
import org.jclouds.internal.FilterStringsBoundToInjectorByName; import org.jclouds.internal.FilterStringsBoundToInjectorByName;
import org.jclouds.json.config.GsonModule; import org.jclouds.json.config.GsonModule;
import org.jclouds.location.config.LocationModule; import org.jclouds.location.config.LocationModule;
import org.jclouds.rest.AsyncClientFactory;
import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.HttpAsyncClient; import org.jclouds.rest.HttpAsyncClient;
import org.jclouds.rest.HttpClient; import org.jclouds.rest.HttpClient;
@ -178,15 +178,14 @@ public class RestModule extends AbstractModule {
TypeLiteral typeLiteral = TypeLiteral.get(clazz); TypeLiteral typeLiteral = TypeLiteral.get(clazz);
RestAnnotationProcessor util = (RestAnnotationProcessor) injector.getInstance(Key.get(TypeLiteral.get(Types RestAnnotationProcessor util = (RestAnnotationProcessor) injector.getInstance(Key.get(TypeLiteral.get(Types
.newParameterizedType(RestAnnotationProcessor.class, clazz)))); .newParameterizedType(RestAnnotationProcessor.class, clazz))));
// cannot use child injectors due to the super coarse guice lock on // cannot use child injectors due to the super coarse guice lock on Singleton
// Singleton
util.setCaller(from); util.setCaller(from);
LoadingCache<ClassMethodArgs, Object> delegateMap = injector.getInstance(Key.get( LoadingCache<ClassMethodArgs, Object> delegateMap = injector.getInstance(Key.get(
new TypeLiteral<LoadingCache<ClassMethodArgs, Object>>() { new TypeLiteral<LoadingCache<ClassMethodArgs, Object>>() {
}, Names.named("async"))); }, Names.named("async")));
AsyncRestClientProxy proxy = new AsyncRestClientProxy(injector, factory, util, typeLiteral, delegateMap); AsyncRestClientProxy proxy = new AsyncRestClientProxy(injector, factory, util, typeLiteral, delegateMap);
injector.injectMembers(proxy); injector.injectMembers(proxy);
return AsyncClientFactory.create(clazz, proxy); return newProxy(clazz, proxy);
} }
} }

View File

@ -19,7 +19,6 @@
package org.jclouds.rest.internal; package org.jclouds.rest.internal;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -28,6 +27,7 @@ import javax.annotation.Resource;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Qualifier; import javax.inject.Qualifier;
import javax.inject.Singleton; import javax.inject.Singleton;
import javax.ws.rs.Path;
import org.jclouds.Constants; import org.jclouds.Constants;
import org.jclouds.concurrent.ExceptionParsingListenableFuture; import org.jclouds.concurrent.ExceptionParsingListenableFuture;
@ -51,6 +51,7 @@ import com.google.common.base.Throwables;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.reflect.AbstractInvocationHandler;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.Binding; import com.google.inject.Binding;
@ -88,7 +89,7 @@ import com.google.inject.util.Types;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Singleton @Singleton
public class AsyncRestClientProxy<T> implements InvocationHandler { public class AsyncRestClientProxy<T> extends AbstractInvocationHandler {
public Class<T> getDeclaring() { public Class<T> getDeclaring() {
return declaring; return declaring;
} }
@ -133,14 +134,9 @@ public class AsyncRestClientProxy<T> implements InvocationHandler {
}; };
public Object invoke(Object o, Method method, Object[] args) throws ExecutionException { @Override
if (method.getName().equals("equals")) { protected Object handleInvocation(Object proxy, Method method, Object[] args) throws ExecutionException {
return this.equals(o); if (method.isAnnotationPresent(Provides.class)) {
} else if (method.getName().equals("toString")) {
return this.toString();
} else if (method.getName().equals("hashCode")) {
return this.hashCode();
} else if (method.isAnnotationPresent(Provides.class)) {
return lookupValueFromGuice(method); return lookupValueFromGuice(method);
} else if (method.isAnnotationPresent(Delegate.class)) { } else if (method.isAnnotationPresent(Delegate.class)) {
return propagateContextToDelegate(method, args); return propagateContextToDelegate(method, args);
@ -279,23 +275,6 @@ public class AsyncRestClientProxy<T> implements InvocationHandler {
public TransformingHttpCommand<?> create(HttpRequest request, Function<HttpResponse, ?> transformer); public TransformingHttpCommand<?> create(HttpRequest request, Function<HttpResponse, ?> transformer);
} }
@Override
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof AsyncRestClientProxy<?>))
return false;
AsyncRestClientProxy<?> other = (AsyncRestClientProxy<?>) obj;
if (other == this)
return true;
if (other.declaring != this.declaring)
return false;
return super.equals(obj);
}
@Override
public int hashCode() {
return declaring.hashCode();
}
public String toString() { public String toString() {
return "Client Proxy for :" + declaring.getName(); return "Client Proxy for :" + declaring.getName();
} }