mirror of https://github.com/apache/jclouds.git
Cleaned up scoping of delegated methods
This commit is contained in:
parent
436037c7be
commit
891484a2aa
|
@ -0,0 +1,38 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* 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 org.jclouds.rest.annotations;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import javax.inject.Qualifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply this to implementation classes when you want Access to items from the
|
||||||
|
* scope of a delegate.
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Target( { ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER , ElementType.FIELD})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Qualifier
|
||||||
|
public @interface Caller {
|
||||||
|
}
|
|
@ -51,15 +51,15 @@ public class RestClientModule<S, A> extends AbstractModule {
|
||||||
protected final Map<Class<?>, Class<?>> delegates;
|
protected final Map<Class<?>, Class<?>> delegates;
|
||||||
|
|
||||||
public RestClientModule(Class<S> syncClientType, Class<A> asyncClientType,
|
public RestClientModule(Class<S> syncClientType, Class<A> asyncClientType,
|
||||||
Map<Class<?>, Class<?>> delegates) {
|
Map<Class<?>, Class<?>> delegates) {
|
||||||
this.asyncClientType = asyncClientType;
|
this.asyncClientType = asyncClientType;
|
||||||
this.syncClientType = syncClientType;
|
this.syncClientType = syncClientType;
|
||||||
this.delegates = delegates;
|
this.delegates = delegates;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RestClientModule(Class<S> syncClientType, Class<A> asyncClientType) {
|
public RestClientModule(Class<S> syncClientType, Class<A> asyncClientType) {
|
||||||
this(syncClientType, asyncClientType, ImmutableMap.<Class<?>, Class<?>> of(syncClientType,
|
this(syncClientType, asyncClientType, ImmutableMap
|
||||||
asyncClientType));
|
.<Class<?>, Class<?>> of(syncClientType, asyncClientType));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -68,8 +68,9 @@ public class RestClientModule<S, A> extends AbstractModule {
|
||||||
// Ensures the restcontext can be looked up without generic types.
|
// Ensures the restcontext can be looked up without generic types.
|
||||||
bind(new TypeLiteral<RestContext>() {
|
bind(new TypeLiteral<RestContext>() {
|
||||||
}).to(
|
}).to(
|
||||||
(TypeLiteral) TypeLiteral.get(Types.newParameterizedType(RestContextImpl.class,
|
(TypeLiteral) TypeLiteral.get(Types.newParameterizedType(
|
||||||
syncClientType, asyncClientType))).in(Scopes.SINGLETON);
|
RestContextImpl.class, syncClientType, asyncClientType))).in(
|
||||||
|
Scopes.SINGLETON);
|
||||||
bindAsyncClient();
|
bindAsyncClient();
|
||||||
bindClient();
|
bindClient();
|
||||||
bindErrorHandlers();
|
bindErrorHandlers();
|
||||||
|
@ -82,8 +83,10 @@ public class RestClientModule<S, A> extends AbstractModule {
|
||||||
* ex.
|
* ex.
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
* bind(HttpRetryHandler.class).annotatedWith(Redirection.class).to(AWSRedirectionRetryHandler.class);
|
* bind(HttpRetryHandler.class).annotatedWith(Redirection.class).to(
|
||||||
* bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(AWSClientErrorRetryHandler.class);
|
* AWSRedirectionRetryHandler.class);
|
||||||
|
* bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(
|
||||||
|
* AWSClientErrorRetryHandler.class);
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -96,9 +99,12 @@ public class RestClientModule<S, A> extends AbstractModule {
|
||||||
* ex.
|
* ex.
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
* bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(ParseAWSErrorFromXmlContent.class);
|
* bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(
|
||||||
* bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(ParseAWSErrorFromXmlContent.class);
|
* ParseAWSErrorFromXmlContent.class);
|
||||||
* bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(ParseAWSErrorFromXmlContent.class);
|
* bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(
|
||||||
|
* ParseAWSErrorFromXmlContent.class);
|
||||||
|
* bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(
|
||||||
|
* ParseAWSErrorFromXmlContent.class);
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
|
@ -111,14 +117,16 @@ public class RestClientModule<S, A> extends AbstractModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void bindClient() {
|
protected void bindClient() {
|
||||||
BinderUtils.bindClient(binder(), syncClientType, asyncClientType, delegates);
|
BinderUtils.bindClient(binder(), syncClientType, asyncClientType,
|
||||||
|
delegates);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
@Named("sync")
|
@Named("sync")
|
||||||
ConcurrentMap<ClassMethodArgs, Object> provideSyncDelegateMap(
|
ConcurrentMap<ClassMethodArgs, Object> provideSyncDelegateMap(
|
||||||
CreateClientForCaller createClientForCaller) {
|
CreateClientForCaller createClientForCaller) {
|
||||||
createClientForCaller.sync2Async = delegates;
|
createClientForCaller.sync2Async = delegates;
|
||||||
return new MapMaker().makeComputingMap(createClientForCaller);
|
return new MapMaker().makeComputingMap(createClientForCaller);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,9 +18,9 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.rest.config;
|
package org.jclouds.rest.config;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
import javax.ws.rs.core.UriBuilder;
|
import javax.ws.rs.core.UriBuilder;
|
||||||
|
@ -36,6 +36,7 @@ import org.jclouds.internal.ClassMethodArgs;
|
||||||
import org.jclouds.rest.AsyncClientFactory;
|
import org.jclouds.rest.AsyncClientFactory;
|
||||||
import org.jclouds.rest.HttpAsyncClient;
|
import org.jclouds.rest.HttpAsyncClient;
|
||||||
import org.jclouds.rest.HttpClient;
|
import org.jclouds.rest.HttpClient;
|
||||||
|
import org.jclouds.rest.annotations.Caller;
|
||||||
import org.jclouds.rest.internal.AsyncRestClientProxy;
|
import org.jclouds.rest.internal.AsyncRestClientProxy;
|
||||||
import org.jclouds.rest.internal.RestAnnotationProcessor;
|
import org.jclouds.rest.internal.RestAnnotationProcessor;
|
||||||
|
|
||||||
|
@ -43,8 +44,10 @@ import com.google.common.base.Function;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.MapMaker;
|
import com.google.common.collect.MapMaker;
|
||||||
import com.google.inject.AbstractModule;
|
import com.google.inject.AbstractModule;
|
||||||
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Injector;
|
import com.google.inject.Injector;
|
||||||
import com.google.inject.Key;
|
import com.google.inject.Key;
|
||||||
|
import com.google.inject.Module;
|
||||||
import com.google.inject.Provides;
|
import com.google.inject.Provides;
|
||||||
import com.google.inject.Scopes;
|
import com.google.inject.Scopes;
|
||||||
import com.google.inject.TypeLiteral;
|
import com.google.inject.TypeLiteral;
|
||||||
|
@ -61,58 +64,99 @@ public class RestModule extends AbstractModule {
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
install(new ParserModule());
|
install(new ParserModule());
|
||||||
bind(UriBuilder.class).to(UriBuilderImpl.class);
|
bind(UriBuilder.class).to(UriBuilderImpl.class);
|
||||||
bind(AsyncRestClientProxy.Factory.class).to(Factory.class).in(Scopes.SINGLETON);
|
bind(AsyncRestClientProxy.Factory.class).to(Factory.class).in(
|
||||||
|
Scopes.SINGLETON);
|
||||||
BinderUtils.bindAsyncClient(binder(), HttpAsyncClient.class);
|
BinderUtils.bindAsyncClient(binder(), HttpAsyncClient.class);
|
||||||
BinderUtils.bindClient(binder(), HttpClient.class, HttpAsyncClient.class, ImmutableMap
|
BinderUtils.bindClient(binder(), HttpClient.class, HttpAsyncClient.class,
|
||||||
.<Class<?>, Class<?>> of(HttpClient.class, HttpAsyncClient.class));
|
ImmutableMap.<Class<?>, Class<?>> of(HttpClient.class,
|
||||||
|
HttpAsyncClient.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
@Named("async")
|
@Named("async")
|
||||||
ConcurrentMap<ClassMethodArgs, Object> provideAsyncDelegateMap(
|
ConcurrentMap<ClassMethodArgs, Object> provideAsyncDelegateMap(
|
||||||
CreateAsyncClientForCaller createAsyncClientForCaller) {
|
CreateAsyncClientForCaller createAsyncClientForCaller) {
|
||||||
return new MapMaker().makeComputingMap(createAsyncClientForCaller);
|
return new MapMaker().makeComputingMap(createAsyncClientForCaller);
|
||||||
}
|
}
|
||||||
|
|
||||||
static class CreateAsyncClientForCaller implements Function<ClassMethodArgs, Object> {
|
static class CreateAsyncClientForCaller implements
|
||||||
|
Function<ClassMethodArgs, Object> {
|
||||||
private final Injector injector;
|
private final Injector injector;
|
||||||
private final AsyncRestClientProxy.Factory factory;
|
private final AsyncRestClientProxy.Factory factory;
|
||||||
|
|
||||||
|
@Caller
|
||||||
|
@Inject(optional = true)
|
||||||
|
Module callerModule = new CallerScopedBindingModule();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
CreateAsyncClientForCaller(Injector injector, AsyncRestClientProxy.Factory factory) {
|
CreateAsyncClientForCaller(Injector injector,
|
||||||
|
AsyncRestClientProxy.Factory factory) {
|
||||||
this.injector = injector;
|
this.injector = injector;
|
||||||
this.factory = factory;
|
this.factory = factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public Object apply(ClassMethodArgs from) {
|
public Object apply(final ClassMethodArgs from) {
|
||||||
Class clazz = from.getAsyncClass();
|
Class clazz = from.getAsyncClass();
|
||||||
TypeLiteral typeLiteral = TypeLiteral.get(clazz);
|
TypeLiteral typeLiteral = TypeLiteral.get(clazz);
|
||||||
RestAnnotationProcessor util = (RestAnnotationProcessor) injector.getInstance(Key
|
Injector injector = this.injector.createChildInjector(callerModule,
|
||||||
.get(TypeLiteral.get(Types.newParameterizedType(RestAnnotationProcessor.class,
|
new AbstractModule() {
|
||||||
clazz))));
|
|
||||||
util.setCaller(from);
|
|
||||||
|
|
||||||
ConcurrentMap<ClassMethodArgs, Object> delegateMap = injector.getInstance(Key.get(
|
@Override
|
||||||
new TypeLiteral<ConcurrentMap<ClassMethodArgs, Object>>() {
|
protected void configure() {
|
||||||
}, Names.named("async")));
|
bind(ClassMethodArgs.class).annotatedWith(Caller.class)
|
||||||
AsyncRestClientProxy proxy = new AsyncRestClientProxy(injector, factory, util,
|
.toInstance(from);
|
||||||
typeLiteral, delegateMap);
|
install(callerModule);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
RestAnnotationProcessor util = (RestAnnotationProcessor) injector
|
||||||
|
.getInstance(Key.get(TypeLiteral.get(Types.newParameterizedType(
|
||||||
|
RestAnnotationProcessor.class, clazz))));
|
||||||
|
// not sure why we have to go back and re-inject this...
|
||||||
|
injector.injectMembers(util);
|
||||||
|
ConcurrentMap<ClassMethodArgs, Object> delegateMap = injector
|
||||||
|
.getInstance(Key.get(
|
||||||
|
new TypeLiteral<ConcurrentMap<ClassMethodArgs, Object>>() {
|
||||||
|
}, Names.named("async")));
|
||||||
|
AsyncRestClientProxy proxy = new AsyncRestClientProxy(injector,
|
||||||
|
factory, util, typeLiteral, delegateMap);
|
||||||
injector.injectMembers(proxy);
|
injector.injectMembers(proxy);
|
||||||
return AsyncClientFactory.create(clazz, proxy);
|
return AsyncClientFactory.create(clazz, proxy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
public static class CallerScopedBindingModule extends AbstractModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Caller
|
||||||
|
URI provideCallerScopedURI(Injector injector, @Caller ClassMethodArgs args) {
|
||||||
|
try {
|
||||||
|
return RestAnnotationProcessor.getEndpointFor(args.getMethod(),
|
||||||
|
args.getArgs(), injector);
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static class Factory implements AsyncRestClientProxy.Factory {
|
private static class Factory implements AsyncRestClientProxy.Factory {
|
||||||
@Inject
|
@Inject
|
||||||
private TransformingHttpCommandExecutorService executorService;
|
private TransformingHttpCommandExecutorService executorService;
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public TransformingHttpCommand<?> create(HttpRequest request,
|
public TransformingHttpCommand<?> create(HttpRequest request,
|
||||||
Function<HttpResponse, ?> transformer) {
|
Function<HttpResponse, ?> transformer) {
|
||||||
return new TransformingHttpCommandImpl(executorService, request, transformer);
|
return new TransformingHttpCommandImpl(executorService, request,
|
||||||
|
transformer);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue