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;
|
||||
|
||||
public RestClientModule(Class<S> syncClientType, Class<A> asyncClientType,
|
||||
Map<Class<?>, Class<?>> delegates) {
|
||||
Map<Class<?>, Class<?>> delegates) {
|
||||
this.asyncClientType = asyncClientType;
|
||||
this.syncClientType = syncClientType;
|
||||
this.delegates = delegates;
|
||||
}
|
||||
|
||||
public RestClientModule(Class<S> syncClientType, Class<A> asyncClientType) {
|
||||
this(syncClientType, asyncClientType, ImmutableMap.<Class<?>, Class<?>> of(syncClientType,
|
||||
asyncClientType));
|
||||
this(syncClientType, asyncClientType, ImmutableMap
|
||||
.<Class<?>, Class<?>> of(syncClientType, asyncClientType));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -68,8 +68,9 @@ public class RestClientModule<S, A> extends AbstractModule {
|
|||
// Ensures the restcontext can be looked up without generic types.
|
||||
bind(new TypeLiteral<RestContext>() {
|
||||
}).to(
|
||||
(TypeLiteral) TypeLiteral.get(Types.newParameterizedType(RestContextImpl.class,
|
||||
syncClientType, asyncClientType))).in(Scopes.SINGLETON);
|
||||
(TypeLiteral) TypeLiteral.get(Types.newParameterizedType(
|
||||
RestContextImpl.class, syncClientType, asyncClientType))).in(
|
||||
Scopes.SINGLETON);
|
||||
bindAsyncClient();
|
||||
bindClient();
|
||||
bindErrorHandlers();
|
||||
|
@ -82,8 +83,10 @@ public class RestClientModule<S, A> extends AbstractModule {
|
|||
* ex.
|
||||
*
|
||||
* <pre>
|
||||
* bind(HttpRetryHandler.class).annotatedWith(Redirection.class).to(AWSRedirectionRetryHandler.class);
|
||||
* bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(AWSClientErrorRetryHandler.class);
|
||||
* bind(HttpRetryHandler.class).annotatedWith(Redirection.class).to(
|
||||
* AWSRedirectionRetryHandler.class);
|
||||
* bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(
|
||||
* AWSClientErrorRetryHandler.class);
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
|
@ -96,9 +99,12 @@ public class RestClientModule<S, A> extends AbstractModule {
|
|||
* ex.
|
||||
*
|
||||
* <pre>
|
||||
* bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(ParseAWSErrorFromXmlContent.class);
|
||||
* bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(ParseAWSErrorFromXmlContent.class);
|
||||
* bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(ParseAWSErrorFromXmlContent.class);
|
||||
* bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(
|
||||
* ParseAWSErrorFromXmlContent.class);
|
||||
* bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(
|
||||
* ParseAWSErrorFromXmlContent.class);
|
||||
* bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(
|
||||
* ParseAWSErrorFromXmlContent.class);
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
|
@ -111,14 +117,16 @@ public class RestClientModule<S, A> extends AbstractModule {
|
|||
}
|
||||
|
||||
protected void bindClient() {
|
||||
BinderUtils.bindClient(binder(), syncClientType, asyncClientType, delegates);
|
||||
BinderUtils.bindClient(binder(), syncClientType, asyncClientType,
|
||||
delegates);
|
||||
}
|
||||
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Named("sync")
|
||||
ConcurrentMap<ClassMethodArgs, Object> provideSyncDelegateMap(
|
||||
CreateClientForCaller createClientForCaller) {
|
||||
CreateClientForCaller createClientForCaller) {
|
||||
createClientForCaller.sync2Async = delegates;
|
||||
return new MapMaker().makeComputingMap(createClientForCaller);
|
||||
}
|
||||
|
|
|
@ -18,9 +18,9 @@
|
|||
*/
|
||||
package org.jclouds.rest.config;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
|
@ -36,6 +36,7 @@ import org.jclouds.internal.ClassMethodArgs;
|
|||
import org.jclouds.rest.AsyncClientFactory;
|
||||
import org.jclouds.rest.HttpAsyncClient;
|
||||
import org.jclouds.rest.HttpClient;
|
||||
import org.jclouds.rest.annotations.Caller;
|
||||
import org.jclouds.rest.internal.AsyncRestClientProxy;
|
||||
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.MapMaker;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Key;
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.Scopes;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
@ -61,58 +64,99 @@ public class RestModule extends AbstractModule {
|
|||
protected void configure() {
|
||||
install(new ParserModule());
|
||||
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.bindClient(binder(), HttpClient.class, HttpAsyncClient.class, ImmutableMap
|
||||
.<Class<?>, Class<?>> of(HttpClient.class, HttpAsyncClient.class));
|
||||
BinderUtils.bindClient(binder(), HttpClient.class, HttpAsyncClient.class,
|
||||
ImmutableMap.<Class<?>, Class<?>> of(HttpClient.class,
|
||||
HttpAsyncClient.class));
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Named("async")
|
||||
ConcurrentMap<ClassMethodArgs, Object> provideAsyncDelegateMap(
|
||||
CreateAsyncClientForCaller createAsyncClientForCaller) {
|
||||
CreateAsyncClientForCaller 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 AsyncRestClientProxy.Factory factory;
|
||||
|
||||
@Caller
|
||||
@Inject(optional = true)
|
||||
Module callerModule = new CallerScopedBindingModule();
|
||||
|
||||
@Inject
|
||||
CreateAsyncClientForCaller(Injector injector, AsyncRestClientProxy.Factory factory) {
|
||||
CreateAsyncClientForCaller(Injector injector,
|
||||
AsyncRestClientProxy.Factory factory) {
|
||||
this.injector = injector;
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Object apply(ClassMethodArgs from) {
|
||||
public Object apply(final ClassMethodArgs from) {
|
||||
Class clazz = from.getAsyncClass();
|
||||
TypeLiteral typeLiteral = TypeLiteral.get(clazz);
|
||||
RestAnnotationProcessor util = (RestAnnotationProcessor) injector.getInstance(Key
|
||||
.get(TypeLiteral.get(Types.newParameterizedType(RestAnnotationProcessor.class,
|
||||
clazz))));
|
||||
util.setCaller(from);
|
||||
Injector injector = this.injector.createChildInjector(callerModule,
|
||||
new AbstractModule() {
|
||||
|
||||
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);
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(ClassMethodArgs.class).annotatedWith(Caller.class)
|
||||
.toInstance(from);
|
||||
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);
|
||||
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 {
|
||||
@Inject
|
||||
private TransformingHttpCommandExecutorService executorService;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public TransformingHttpCommand<?> create(HttpRequest request,
|
||||
Function<HttpResponse, ?> transformer) {
|
||||
return new TransformingHttpCommandImpl(executorService, request, transformer);
|
||||
Function<HttpResponse, ?> transformer) {
|
||||
return new TransformingHttpCommandImpl(executorService, request,
|
||||
transformer);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue