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 {
|
||||
}
|
|
@ -58,8 +58,8 @@ public class RestClientModule<S, A> extends AbstractModule {
|
|||
}
|
||||
|
||||
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,9 +117,11 @@ 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")
|
||||
|
|
|
@ -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,10 +64,12 @@ 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
|
||||
|
@ -75,36 +80,74 @@ public class RestModule extends AbstractModule {
|
|||
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(
|
||||
@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);
|
||||
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;
|
||||
|
@ -112,7 +155,8 @@ public class RestModule extends AbstractModule {
|
|||
@SuppressWarnings("unchecked")
|
||||
public TransformingHttpCommand<?> create(HttpRequest request,
|
||||
Function<HttpResponse, ?> transformer) {
|
||||
return new TransformingHttpCommandImpl(executorService, request, transformer);
|
||||
return new TransformingHttpCommandImpl(executorService, request,
|
||||
transformer);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,8 +20,6 @@ package org.jclouds.rest.internal;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.collect.Collections2.filter;
|
||||
import static com.google.common.collect.Collections2.transform;
|
||||
import static com.google.common.collect.Iterables.concat;
|
||||
import static com.google.common.collect.Lists.newArrayList;
|
||||
import static com.google.common.collect.Lists.newLinkedList;
|
||||
import static com.google.common.collect.Maps.filterValues;
|
||||
|
@ -37,8 +35,6 @@ import static org.jclouds.http.HttpUtils.makeQueryLine;
|
|||
import static org.jclouds.http.HttpUtils.parseQueryToMap;
|
||||
import static org.jclouds.http.HttpUtils.urlEncode;
|
||||
import static org.jclouds.http.Payloads.newPayload;
|
||||
import static org.jclouds.http.Payloads.newStringPayload;
|
||||
import static org.jclouds.http.Payloads.newUrlEncodedFormPayload;
|
||||
import static org.jclouds.util.Utils.replaceTokens;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
@ -76,6 +72,7 @@ import org.jclouds.http.HttpResponse;
|
|||
import org.jclouds.http.HttpUtils;
|
||||
import org.jclouds.http.Payload;
|
||||
import org.jclouds.http.PayloadEnclosing;
|
||||
import org.jclouds.http.Payloads;
|
||||
import org.jclouds.http.functions.ParseSax;
|
||||
import org.jclouds.http.functions.ParseURIFromListOrLocationHeaderIf20x;
|
||||
import org.jclouds.http.functions.ReleasePayloadAndReturn;
|
||||
|
@ -93,6 +90,7 @@ import org.jclouds.rest.Binder;
|
|||
import org.jclouds.rest.InputParamValidator;
|
||||
import org.jclouds.rest.InvocationContext;
|
||||
import org.jclouds.rest.annotations.BinderParam;
|
||||
import org.jclouds.rest.annotations.Caller;
|
||||
import org.jclouds.rest.annotations.Delegate;
|
||||
import org.jclouds.rest.annotations.Endpoint;
|
||||
import org.jclouds.rest.annotations.EndpointParam;
|
||||
|
@ -116,6 +114,7 @@ import org.jclouds.rest.functions.MapHttp4xxCodesToExceptions;
|
|||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.LinkedHashMultimap;
|
||||
import com.google.common.collect.LinkedListMultimap;
|
||||
import com.google.common.collect.MapMaker;
|
||||
|
@ -136,51 +135,48 @@ public class RestAnnotationProcessor<T> {
|
|||
@Resource
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
ClassMethodArgs caller;
|
||||
|
||||
@Inject(optional = true)
|
||||
public void setCaller(@Named("caller") ClassMethodArgs caller) {
|
||||
seedCache(caller.getMethod().getDeclaringClass());
|
||||
this.caller = caller;
|
||||
}
|
||||
|
||||
private final Class<T> declaring;
|
||||
|
||||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToDecoratorParamAnnotation = createMethodToIndexOfParamToAnnotation(BinderParam.class);
|
||||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToHeaderParamAnnotations = createMethodToIndexOfParamToAnnotation(HeaderParam.class);
|
||||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToEndpointAnnotations = createMethodToIndexOfParamToAnnotation(Endpoint.class);
|
||||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToEndpointParamAnnotations = createMethodToIndexOfParamToAnnotation(EndpointParam.class);
|
||||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToMatrixParamAnnotations = createMethodToIndexOfParamToAnnotation(MatrixParam.class);
|
||||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToFormParamAnnotations = createMethodToIndexOfParamToAnnotation(FormParam.class);
|
||||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToQueryParamAnnotations = createMethodToIndexOfParamToAnnotation(QueryParam.class);
|
||||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToPathParamAnnotations = createMethodToIndexOfParamToAnnotation(PathParam.class);
|
||||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToPostParamAnnotations = createMethodToIndexOfParamToAnnotation(MapPayloadParam.class);
|
||||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToPartParamAnnotations = createMethodToIndexOfParamToAnnotation(PartParam.class);
|
||||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToParamParserAnnotations = createMethodToIndexOfParamToAnnotation(ParamParser.class);
|
||||
private final Map<MethodKey, Method> delegationMap = newHashMap();
|
||||
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToDecoratorParamAnnotation = createMethodToIndexOfParamToAnnotation(BinderParam.class);
|
||||
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToHeaderParamAnnotations = createMethodToIndexOfParamToAnnotation(HeaderParam.class);
|
||||
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToEndpointAnnotations = createMethodToIndexOfParamToAnnotation(Endpoint.class);
|
||||
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToEndpointParamAnnotations = createMethodToIndexOfParamToAnnotation(EndpointParam.class);
|
||||
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToMatrixParamAnnotations = createMethodToIndexOfParamToAnnotation(MatrixParam.class);
|
||||
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToFormParamAnnotations = createMethodToIndexOfParamToAnnotation(FormParam.class);
|
||||
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToQueryParamAnnotations = createMethodToIndexOfParamToAnnotation(QueryParam.class);
|
||||
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToPathParamAnnotations = createMethodToIndexOfParamToAnnotation(PathParam.class);
|
||||
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToPostParamAnnotations = createMethodToIndexOfParamToAnnotation(MapPayloadParam.class);
|
||||
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToPartParamAnnotations = createMethodToIndexOfParamToAnnotation(PartParam.class);
|
||||
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToParamParserAnnotations = createMethodToIndexOfParamToAnnotation(ParamParser.class);
|
||||
static final Map<MethodKey, Method> delegationMap = newHashMap();
|
||||
|
||||
static Map<Method, Map<Integer, Set<Annotation>>> createMethodToIndexOfParamToAnnotation(
|
||||
final Class<? extends Annotation> annotation) {
|
||||
return new MapMaker().makeComputingMap(new Function<Method, Map<Integer, Set<Annotation>>>() {
|
||||
return new MapMaker()
|
||||
.makeComputingMap(new Function<Method, Map<Integer, Set<Annotation>>>() {
|
||||
public Map<Integer, Set<Annotation>> apply(final Method method) {
|
||||
return new MapMaker().makeComputingMap(new GetAnnotationsForMethodParameterIndex(
|
||||
return new MapMaker()
|
||||
.makeComputingMap(new GetAnnotationsForMethodParameterIndex(
|
||||
method, annotation));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static class GetAnnotationsForMethodParameterIndex implements Function<Integer, Set<Annotation>> {
|
||||
static class GetAnnotationsForMethodParameterIndex implements
|
||||
Function<Integer, Set<Annotation>> {
|
||||
private final Method method;
|
||||
private final Class<?> clazz;
|
||||
|
||||
protected GetAnnotationsForMethodParameterIndex(Method method, Class<?> clazz) {
|
||||
protected GetAnnotationsForMethodParameterIndex(Method method,
|
||||
Class<?> clazz) {
|
||||
this.method = method;
|
||||
this.clazz = clazz;
|
||||
}
|
||||
|
||||
public Set<Annotation> apply(final Integer index) {
|
||||
Set<Annotation> keys = new HashSet<Annotation>();
|
||||
List<Annotation> parameterAnnotations = newArrayList(method.getParameterAnnotations()[index]);
|
||||
List<Annotation> parameterAnnotations = newArrayList(method
|
||||
.getParameterAnnotations()[index]);
|
||||
Collection<Annotation> filtered = filter(parameterAnnotations,
|
||||
new Predicate<Annotation>() {
|
||||
public boolean apply(Annotation input) {
|
||||
|
@ -231,13 +227,15 @@ public class RestAnnotationProcessor<T> {
|
|||
private InputParamValidator inputParamValidator;
|
||||
|
||||
@VisibleForTesting
|
||||
Function<HttpResponse, ?> createResponseParser(Method method, HttpRequest request) {
|
||||
Function<HttpResponse, ?> createResponseParser(Method method,
|
||||
HttpRequest request) {
|
||||
return createResponseParser(parserFactory, injector, method, request);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static Function<HttpResponse, ?> createResponseParser(ParseSax.Factory parserFactory,
|
||||
Injector injector, Method method, HttpRequest request) {
|
||||
public static Function<HttpResponse, ?> createResponseParser(
|
||||
ParseSax.Factory parserFactory, Injector injector, Method method,
|
||||
HttpRequest request) {
|
||||
Function<HttpResponse, ?> transformer;
|
||||
Class<? extends HandlerWithResult<?>> handler = getSaxResponseParserClassOrNull(method);
|
||||
if (handler != null) {
|
||||
|
@ -246,7 +244,8 @@ public class RestAnnotationProcessor<T> {
|
|||
transformer = injector.getInstance(getParserOrThrowException(method));
|
||||
}
|
||||
if (transformer instanceof InvocationContext) {
|
||||
((InvocationContext) transformer).setContext((GeneratedHttpRequest<?>) request);
|
||||
((InvocationContext) transformer)
|
||||
.setContext((GeneratedHttpRequest<?>) request);
|
||||
}
|
||||
return transformer;
|
||||
}
|
||||
|
@ -254,7 +253,8 @@ public class RestAnnotationProcessor<T> {
|
|||
@VisibleForTesting
|
||||
Function<Exception, ?> createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(
|
||||
Method method) {
|
||||
return createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(injector, method);
|
||||
return createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(
|
||||
injector, method);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
|
@ -269,8 +269,9 @@ public class RestAnnotationProcessor<T> {
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Inject
|
||||
public RestAnnotationProcessor(Injector injector, ParseSax.Factory parserFactory,
|
||||
HttpUtils utils, TypeLiteral<T> typeLiteral) {
|
||||
public RestAnnotationProcessor(Injector injector,
|
||||
ParseSax.Factory parserFactory, HttpUtils utils,
|
||||
TypeLiteral<T> typeLiteral) {
|
||||
this.declaring = (Class<T>) typeLiteral.getRawType();
|
||||
this.injector = injector;
|
||||
this.parserFactory = parserFactory;
|
||||
|
@ -294,17 +295,27 @@ public class RestAnnotationProcessor<T> {
|
|||
for (Method method : methods) {
|
||||
if (isHttpMethod(method)) {
|
||||
for (int index = 0; index < method.getParameterTypes().length; index++) {
|
||||
methodToIndexOfParamToDecoratorParamAnnotation.get(method).get(index);
|
||||
methodToIndexOfParamToHeaderParamAnnotations.get(method).get(index);
|
||||
methodToIndexOfParamToMatrixParamAnnotations.get(method).get(index);
|
||||
methodToIndexOfParamToFormParamAnnotations.get(method).get(index);
|
||||
methodToIndexOfParamToQueryParamAnnotations.get(method).get(index);
|
||||
methodToIndexOfParamToDecoratorParamAnnotation.get(method).get(
|
||||
index);
|
||||
methodToIndexOfParamToHeaderParamAnnotations.get(method).get(
|
||||
index);
|
||||
methodToIndexOfParamToMatrixParamAnnotations.get(method).get(
|
||||
index);
|
||||
methodToIndexOfParamToFormParamAnnotations.get(method)
|
||||
.get(index);
|
||||
methodToIndexOfParamToQueryParamAnnotations.get(method).get(
|
||||
index);
|
||||
methodToIndexOfParamToEndpointAnnotations.get(method).get(index);
|
||||
methodToIndexOfParamToEndpointParamAnnotations.get(method).get(index);
|
||||
methodToIndexOfParamToPathParamAnnotations.get(method).get(index);
|
||||
methodToIndexOfParamToPostParamAnnotations.get(method).get(index);
|
||||
methodToIndexOfParamToParamParserAnnotations.get(method).get(index);
|
||||
methodToIndexOfParamToPartParamAnnotations.get(method).get(index);
|
||||
methodToIndexOfParamToEndpointParamAnnotations.get(method).get(
|
||||
index);
|
||||
methodToIndexOfParamToPathParamAnnotations.get(method)
|
||||
.get(index);
|
||||
methodToIndexOfParamToPostParamAnnotations.get(method)
|
||||
.get(index);
|
||||
methodToIndexOfParamToParamParserAnnotations.get(method).get(
|
||||
index);
|
||||
methodToIndexOfParamToPartParamAnnotations.get(method)
|
||||
.get(index);
|
||||
methodToIndexesOfOptions.get(method);
|
||||
}
|
||||
delegationMap.put(new MethodKey(method), method);
|
||||
|
@ -315,7 +326,9 @@ public class RestAnnotationProcessor<T> {
|
|||
} else if (method.isAnnotationPresent(Delegate.class)) {
|
||||
logger.debug("skipping delegate method %s", method);
|
||||
} else if (!method.getName().startsWith("new")) {
|
||||
logger.trace("Method is not annotated as either http or constant: %s", method);
|
||||
logger.trace(
|
||||
"Method is not annotated as either http or constant: %s",
|
||||
method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -362,19 +375,26 @@ public class RestAnnotationProcessor<T> {
|
|||
|
||||
final Injector injector;
|
||||
|
||||
ClassMethodArgs caller;
|
||||
|
||||
@Inject(optional = true)
|
||||
public void setCaller(@Caller ClassMethodArgs caller) {
|
||||
seedCache(caller.getMethod().getDeclaringClass());
|
||||
this.caller = caller;
|
||||
}
|
||||
|
||||
@Inject(optional = true)
|
||||
@Caller
|
||||
@Nullable
|
||||
URI callerEndpoint;
|
||||
|
||||
public GeneratedHttpRequest<T> createRequest(Method method, Object... args) {
|
||||
inputParamValidator.validateMethodParametersOrThrow(method, args);
|
||||
URI endpoint;
|
||||
URI endpoint = callerEndpoint;
|
||||
|
||||
try {
|
||||
if (caller != null) {
|
||||
try {
|
||||
endpoint = getEndpointFor(caller.getMethod(), caller.getArgs());
|
||||
} catch (IllegalStateException e) {
|
||||
endpoint = getEndpointFor(method, args);
|
||||
}
|
||||
} else {
|
||||
endpoint = getEndpointFor(method, args);
|
||||
}
|
||||
if (endpoint == null)
|
||||
endpoint = getEndpointFor(method, args, injector);
|
||||
} catch (IllegalStateException e) {
|
||||
endpoint = injector.getInstance(Key.get(URI.class,
|
||||
org.jclouds.rest.annotations.Provider.class));
|
||||
|
@ -386,34 +406,44 @@ public class RestAnnotationProcessor<T> {
|
|||
Multimap<String, String> tokenValues = LinkedHashMultimap.create();
|
||||
|
||||
if (caller != null) {
|
||||
builder.path(getPath(caller.getMethod().getDeclaringClass(), caller.getMethod(), caller
|
||||
.getArgs()));
|
||||
builder.path(getPath(caller.getMethod().getDeclaringClass(), caller
|
||||
.getMethod(), caller.getArgs()));
|
||||
}
|
||||
tokenValues.putAll(addPathAndGetTokens(declaring, method, args, builder));
|
||||
|
||||
Multimap<String, String> formParams = addFormParams(tokenValues.entries(), method, args);
|
||||
Multimap<String, String> queryParams = addQueryParams(tokenValues.entries(), method, args);
|
||||
Multimap<String, String> formParams = addFormParams(
|
||||
tokenValues.entries(), method, args);
|
||||
Multimap<String, String> queryParams = addQueryParams(tokenValues
|
||||
.entries(), method, args);
|
||||
|
||||
addMatrixParams(builder, tokenValues.entries(), method, args);
|
||||
|
||||
Multimap<String, String> headers = buildHeaders(tokenValues.entries(), method, args);
|
||||
Multimap<String, String> headers = buildHeaders(tokenValues.entries(),
|
||||
method, args);
|
||||
|
||||
Payload payload = null;
|
||||
HttpRequestOptions options = findOptionsIn(method, args);
|
||||
if (options != null) {
|
||||
injector.injectMembers(options);// TODO test case
|
||||
for (Entry<String, String> header : options.buildRequestHeaders().entries()) {
|
||||
headers.put(header.getKey(), replaceTokens(header.getValue(), tokenValues.entries()));
|
||||
for (Entry<String, String> header : options.buildRequestHeaders()
|
||||
.entries()) {
|
||||
headers.put(header.getKey(), replaceTokens(header.getValue(),
|
||||
tokenValues.entries()));
|
||||
}
|
||||
for (Entry<String, String> matrix : options.buildMatrixParameters().entries()) {
|
||||
builder.matrixParam(matrix.getKey(), replaceTokens(matrix.getValue(), tokenValues
|
||||
.entries()));
|
||||
for (Entry<String, String> matrix : options.buildMatrixParameters()
|
||||
.entries()) {
|
||||
builder.matrixParam(matrix.getKey(), replaceTokens(matrix
|
||||
.getValue(), tokenValues.entries()));
|
||||
}
|
||||
for (Entry<String, String> query : options.buildQueryParameters().entries()) {
|
||||
queryParams.put(query.getKey(), replaceTokens(query.getValue(), tokenValues.entries()));
|
||||
for (Entry<String, String> query : options.buildQueryParameters()
|
||||
.entries()) {
|
||||
queryParams.put(query.getKey(), replaceTokens(query.getValue(),
|
||||
tokenValues.entries()));
|
||||
}
|
||||
for (Entry<String, String> form : options.buildFormParameters().entries()) {
|
||||
formParams.put(form.getKey(), replaceTokens(form.getValue(), tokenValues.entries()));
|
||||
for (Entry<String, String> form : options.buildFormParameters()
|
||||
.entries()) {
|
||||
formParams.put(form.getKey(), replaceTokens(form.getValue(),
|
||||
tokenValues.entries()));
|
||||
}
|
||||
|
||||
String pathSuffix = options.buildPathSuffix();
|
||||
|
@ -422,7 +452,7 @@ public class RestAnnotationProcessor<T> {
|
|||
}
|
||||
String stringPayload = options.buildStringPayload();
|
||||
if (stringPayload != null)
|
||||
payload = newStringPayload(stringPayload);
|
||||
payload = Payloads.newStringPayload(stringPayload);
|
||||
}
|
||||
|
||||
if (queryParams.size() > 0) {
|
||||
|
@ -437,22 +467,24 @@ public class RestAnnotationProcessor<T> {
|
|||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
GeneratedHttpRequest<T> request = new GeneratedHttpRequest<T>(httpMethod, endpoint, skips,
|
||||
declaring, method, args);
|
||||
addHostHeaderIfAnnotatedWithVirtualHost(headers, request.getEndpoint().getHost(), method);
|
||||
GeneratedHttpRequest<T> request = new GeneratedHttpRequest<T>(httpMethod,
|
||||
endpoint, skips, declaring, method, args);
|
||||
addHostHeaderIfAnnotatedWithVirtualHost(headers, request.getEndpoint()
|
||||
.getHost(), method);
|
||||
addFiltersIfAnnotated(method, request);
|
||||
|
||||
if (payload == null)
|
||||
payload = findPayloadInArgs(args);
|
||||
List<? extends Part> parts = getParts(method, args, concat(tokenValues.entries(), formParams
|
||||
.entries()));
|
||||
List<? extends Part> parts = getParts(method, args, Iterables.concat(
|
||||
tokenValues.entries(), formParams.entries()));
|
||||
if (parts.size() > 0) {
|
||||
if (formParams.size() > 0) {
|
||||
parts = newLinkedList(concat(transform(formParams.entries(), ENTRY_TO_PART), parts));
|
||||
parts = newLinkedList(Iterables.concat(Iterables.transform(
|
||||
formParams.entries(), ENTRY_TO_PART), parts));
|
||||
}
|
||||
payload = new MultipartForm(BOUNDARY, parts);
|
||||
} else if (formParams.size() > 0) {
|
||||
payload = newUrlEncodedFormPayload(formParams, skips);
|
||||
payload = Payloads.newUrlEncodedFormPayload(formParams, skips);
|
||||
}
|
||||
if (payload != null) {
|
||||
request.setPayload(payload);
|
||||
|
@ -469,11 +501,12 @@ public class RestAnnotationProcessor<T> {
|
|||
builder.path(clazz);
|
||||
builder.path(method);
|
||||
return builder.buildFromEncodedMap(
|
||||
convertUnsafe(encodeValues(getPathParamKeyValues(method, args), skips))).getPath();
|
||||
convertUnsafe(encodeValues(getPathParamKeyValues(method, args),
|
||||
skips))).getPath();
|
||||
}
|
||||
|
||||
private Multimap<String, String> addPathAndGetTokens(Class<?> clazz, Method method,
|
||||
Object[] args, UriBuilder builder) {
|
||||
private Multimap<String, String> addPathAndGetTokens(Class<?> clazz,
|
||||
Method method, Object[] args, UriBuilder builder) {
|
||||
if (clazz.isAnnotationPresent(Path.class))
|
||||
builder.path(clazz);
|
||||
builder.path(method);
|
||||
|
@ -485,15 +518,18 @@ public class RestAnnotationProcessor<T> {
|
|||
return replaceQuery(uriBuilderProvider, in, newQuery, sorter, skips);
|
||||
}
|
||||
|
||||
public static URI replaceQuery(Provider<UriBuilder> uriBuilderProvider, URI in, String newQuery,
|
||||
public static URI replaceQuery(Provider<UriBuilder> uriBuilderProvider,
|
||||
URI in, String newQuery,
|
||||
@Nullable Comparator<Entry<String, String>> sorter, char... skips) {
|
||||
UriBuilder builder = uriBuilderProvider.get().uri(in);
|
||||
builder.replaceQuery(makeQueryLine(parseQueryToMap(newQuery), sorter, skips));
|
||||
builder.replaceQuery(makeQueryLine(parseQueryToMap(newQuery), sorter,
|
||||
skips));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private void addMatrixParams(UriBuilder builder, Collection<Entry<String, String>> tokenValues,
|
||||
Method method, Object... args) {
|
||||
private void addMatrixParams(UriBuilder builder,
|
||||
Collection<Entry<String, String>> tokenValues, Method method,
|
||||
Object... args) {
|
||||
if (declaring.isAnnotationPresent(MatrixParams.class)) {
|
||||
MatrixParams matrix = declaring.getAnnotation(MatrixParams.class);
|
||||
addMatrix(builder, matrix, tokenValues);
|
||||
|
@ -504,13 +540,16 @@ public class RestAnnotationProcessor<T> {
|
|||
addMatrix(builder, matrix, tokenValues);
|
||||
}
|
||||
|
||||
for (Entry<String, String> matrix : getMatrixParamKeyValues(method, args).entries()) {
|
||||
builder.matrixParam(matrix.getKey(), replaceTokens(matrix.getValue(), tokenValues));
|
||||
for (Entry<String, String> matrix : getMatrixParamKeyValues(method, args)
|
||||
.entries()) {
|
||||
builder.matrixParam(matrix.getKey(), replaceTokens(matrix.getValue(),
|
||||
tokenValues));
|
||||
}
|
||||
}
|
||||
|
||||
private Multimap<String, String> addFormParams(Collection<Entry<String, String>> tokenValues,
|
||||
Method method, Object... args) {
|
||||
private Multimap<String, String> addFormParams(
|
||||
Collection<Entry<String, String>> tokenValues, Method method,
|
||||
Object... args) {
|
||||
Multimap<String, String> formMap = LinkedListMultimap.create();
|
||||
if (declaring.isAnnotationPresent(FormParams.class)) {
|
||||
FormParams form = declaring.getAnnotation(FormParams.class);
|
||||
|
@ -522,14 +561,17 @@ public class RestAnnotationProcessor<T> {
|
|||
addForm(formMap, form, tokenValues);
|
||||
}
|
||||
|
||||
for (Entry<String, String> form : getFormParamKeyValues(method, args).entries()) {
|
||||
formMap.put(form.getKey(), replaceTokens(form.getValue(), tokenValues));
|
||||
for (Entry<String, String> form : getFormParamKeyValues(method, args)
|
||||
.entries()) {
|
||||
formMap
|
||||
.put(form.getKey(), replaceTokens(form.getValue(), tokenValues));
|
||||
}
|
||||
return formMap;
|
||||
}
|
||||
|
||||
private Multimap<String, String> addQueryParams(Collection<Entry<String, String>> tokenValues,
|
||||
Method method, Object... args) {
|
||||
private Multimap<String, String> addQueryParams(
|
||||
Collection<Entry<String, String>> tokenValues, Method method,
|
||||
Object... args) {
|
||||
Multimap<String, String> queryMap = LinkedListMultimap.create();
|
||||
if (declaring.isAnnotationPresent(QueryParams.class)) {
|
||||
QueryParams query = declaring.getAnnotation(QueryParams.class);
|
||||
|
@ -541,8 +583,10 @@ public class RestAnnotationProcessor<T> {
|
|||
addQuery(queryMap, query, tokenValues);
|
||||
}
|
||||
|
||||
for (Entry<String, String> query : getQueryParamKeyValues(method, args).entries()) {
|
||||
queryMap.put(query.getKey(), replaceTokens(query.getValue(), tokenValues));
|
||||
for (Entry<String, String> query : getQueryParamKeyValues(method, args)
|
||||
.entries()) {
|
||||
queryMap.put(query.getKey(), replaceTokens(query.getValue(),
|
||||
tokenValues));
|
||||
}
|
||||
return queryMap;
|
||||
}
|
||||
|
@ -554,19 +598,21 @@ public class RestAnnotationProcessor<T> {
|
|||
formParams.removeAll(form.keys()[i]);
|
||||
formParams.put(form.keys()[i], null);
|
||||
} else {
|
||||
formParams.put(form.keys()[i], replaceTokens(form.values()[i], tokenValues));
|
||||
formParams.put(form.keys()[i], replaceTokens(form.values()[i],
|
||||
tokenValues));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addQuery(Multimap<String, String> queryParams, QueryParams query,
|
||||
Collection<Entry<String, String>> tokenValues) {
|
||||
private void addQuery(Multimap<String, String> queryParams,
|
||||
QueryParams query, Collection<Entry<String, String>> tokenValues) {
|
||||
for (int i = 0; i < query.keys().length; i++) {
|
||||
if (query.values()[i].equals(QueryParams.NULL)) {
|
||||
queryParams.removeAll(query.keys()[i]);
|
||||
queryParams.put(query.keys()[i], null);
|
||||
} else {
|
||||
queryParams.put(query.keys()[i], replaceTokens(query.values()[i], tokenValues));
|
||||
queryParams.put(query.keys()[i], replaceTokens(query.values()[i],
|
||||
tokenValues));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -577,56 +623,82 @@ public class RestAnnotationProcessor<T> {
|
|||
if (matrix.values()[i].equals(MatrixParams.NULL)) {
|
||||
builder.replaceMatrix(matrix.keys()[i]);
|
||||
} else {
|
||||
builder.matrixParam(matrix.keys()[i], replaceTokens(matrix.values()[i], tokenValues));
|
||||
builder.matrixParam(matrix.keys()[i], replaceTokens(
|
||||
matrix.values()[i], tokenValues));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addFiltersIfAnnotated(Method method, HttpRequest request) {
|
||||
if (declaring.isAnnotationPresent(RequestFilters.class)) {
|
||||
for (Class<? extends HttpRequestFilter> clazz : declaring.getAnnotation(
|
||||
RequestFilters.class).value()) {
|
||||
for (Class<? extends HttpRequestFilter> clazz : declaring
|
||||
.getAnnotation(RequestFilters.class).value()) {
|
||||
HttpRequestFilter instance = injector.getInstance(clazz);
|
||||
request.getFilters().add(instance);
|
||||
logger.trace("%s - adding filter %s from annotation on %s", request, instance,
|
||||
declaring.getName());
|
||||
logger.trace("%s - adding filter %s from annotation on %s",
|
||||
request, instance, declaring.getName());
|
||||
}
|
||||
}
|
||||
if (method.isAnnotationPresent(RequestFilters.class)) {
|
||||
if (method.isAnnotationPresent(OverrideRequestFilters.class))
|
||||
request.getFilters().clear();
|
||||
for (Class<? extends HttpRequestFilter> clazz : method.getAnnotation(RequestFilters.class)
|
||||
.value()) {
|
||||
for (Class<? extends HttpRequestFilter> clazz : method.getAnnotation(
|
||||
RequestFilters.class).value()) {
|
||||
HttpRequestFilter instance = injector.getInstance(clazz);
|
||||
request.getFilters().add(instance);
|
||||
logger.trace("%s - adding filter %s from annotation on %s", request, instance, method
|
||||
.getName());
|
||||
logger.trace("%s - adding filter %s from annotation on %s",
|
||||
request, instance, method.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
URI getEndpointInParametersOrNull(Method method, Object... args) {
|
||||
Map<Integer, Set<Annotation>> map = indexWithOnlyOneAnnotation(method, "@EndpointParam",
|
||||
methodToIndexOfParamToEndpointParamAnnotations);
|
||||
public static URI getEndpointInParametersOrNull(Method method,
|
||||
Object[] args, Injector injector) {
|
||||
Map<Integer, Set<Annotation>> map = RestAnnotationProcessor
|
||||
.indexWithOnlyOneAnnotation(
|
||||
method,
|
||||
"@EndpointParam",
|
||||
RestAnnotationProcessor.methodToIndexOfParamToEndpointParamAnnotations);
|
||||
if (map.size() == 1 && args.length > 0) {
|
||||
EndpointParam annotation = (EndpointParam) map.values().iterator().next().iterator()
|
||||
.next();
|
||||
EndpointParam annotation = (EndpointParam) map.values().iterator()
|
||||
.next().iterator().next();
|
||||
int index = map.keySet().iterator().next();
|
||||
Function<Object, URI> parser = injector.getInstance(annotation.parser());
|
||||
Function<Object, URI> parser = injector.getInstance(annotation
|
||||
.parser());
|
||||
try {
|
||||
URI returnVal = parser.apply(args[index]);
|
||||
checkArgument(returnVal != null, String.format(
|
||||
"endpoint for [%s] not configured for %s", args[index], method));
|
||||
"endpoint for [%s] not configured for %s", args[index],
|
||||
method));
|
||||
return returnVal;
|
||||
} catch (NullPointerException e) {
|
||||
logger.error("argument at index %d on method %s", index, method);
|
||||
throw e;
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"argument at index %d on method %s", index, method), e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static URI getEndpointFor(Method method, Object[] args, Injector injector) {
|
||||
URI endpoint = getEndpointInParametersOrNull(method, args, injector);
|
||||
if (endpoint == null) {
|
||||
Endpoint annotation;
|
||||
if (method.isAnnotationPresent(Endpoint.class)) {
|
||||
annotation = method.getAnnotation(Endpoint.class);
|
||||
} else if (method.getDeclaringClass().isAnnotationPresent(
|
||||
Endpoint.class)) {
|
||||
annotation = method.getDeclaringClass().getAnnotation(
|
||||
Endpoint.class);
|
||||
} else {
|
||||
throw new IllegalStateException(
|
||||
"no annotations on class or method: " + method);
|
||||
}
|
||||
return injector.getInstance(Key.get(URI.class, annotation.value()));
|
||||
}
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
public static final TypeLiteral<ListenableFuture<Boolean>> futureBooleanLiteral = new TypeLiteral<ListenableFuture<Boolean>>() {
|
||||
};
|
||||
|
||||
|
@ -640,43 +712,52 @@ public class RestAnnotationProcessor<T> {
|
|||
public static final TypeLiteral<ListenableFuture<InputStream>> futureInputStreamLiteral = new TypeLiteral<ListenableFuture<InputStream>>() {
|
||||
};
|
||||
|
||||
public static Class<? extends Function<HttpResponse, ?>> getParserOrThrowException(Method method) {
|
||||
public static Class<? extends Function<HttpResponse, ?>> getParserOrThrowException(
|
||||
Method method) {
|
||||
ResponseParser annotation = method.getAnnotation(ResponseParser.class);
|
||||
if (annotation == null) {
|
||||
if (method.getReturnType().equals(boolean.class)
|
||||
|| method.getReturnType().equals(Boolean.class)
|
||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureBooleanLiteral)) {
|
||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(
|
||||
futureBooleanLiteral)) {
|
||||
return ReturnTrueIf2xx.class;
|
||||
} else if (method.getReturnType().equals(String.class)
|
||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureStringLiteral)) {
|
||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(
|
||||
futureStringLiteral)) {
|
||||
return ReturnStringIf2xx.class;
|
||||
} else if (method.getReturnType().equals(void.class)
|
||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureVoidLiteral)) {
|
||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(
|
||||
futureVoidLiteral)) {
|
||||
return ReleasePayloadAndReturn.class;
|
||||
} else if (method.getReturnType().equals(URI.class)
|
||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureURILiteral)) {
|
||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(
|
||||
futureURILiteral)) {
|
||||
return ParseURIFromListOrLocationHeaderIf20x.class;
|
||||
} else if (method.getReturnType().equals(InputStream.class)
|
||||
|| TypeLiteral.get(method.getGenericReturnType())
|
||||
.equals(futureInputStreamLiteral)) {
|
||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(
|
||||
futureInputStreamLiteral)) {
|
||||
return ReturnInputStream.class;
|
||||
} else {
|
||||
throw new IllegalStateException(
|
||||
"You must specify a ResponseTransformer annotation on: " + method.toString());
|
||||
"You must specify a ResponseTransformer annotation on: "
|
||||
+ method.toString());
|
||||
}
|
||||
}
|
||||
return annotation.value();
|
||||
}
|
||||
|
||||
public static Class<? extends HandlerWithResult<?>> getSaxResponseParserClassOrNull(Method method) {
|
||||
XMLResponseParser annotation = method.getAnnotation(XMLResponseParser.class);
|
||||
public static Class<? extends HandlerWithResult<?>> getSaxResponseParserClassOrNull(
|
||||
Method method) {
|
||||
XMLResponseParser annotation = method
|
||||
.getAnnotation(XMLResponseParser.class);
|
||||
if (annotation != null) {
|
||||
return annotation.value();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public org.jclouds.rest.MapBinder getMapPayloadBinderOrNull(Method method, Object... args) {
|
||||
public org.jclouds.rest.MapBinder getMapPayloadBinderOrNull(Method method,
|
||||
Object... args) {
|
||||
if (args != null) {
|
||||
for (Object arg : args) {
|
||||
if (arg instanceof Object[]) {
|
||||
|
@ -712,16 +793,19 @@ public class RestAnnotationProcessor<T> {
|
|||
private Multimap<String, String> constants = LinkedHashMultimap.create();
|
||||
|
||||
public boolean isHttpMethod(Method method) {
|
||||
return method.isAnnotationPresent(Path.class) || IsHttpMethod.getHttpMethods(method) != null;
|
||||
return method.isAnnotationPresent(Path.class)
|
||||
|| IsHttpMethod.getHttpMethods(method) != null;
|
||||
}
|
||||
|
||||
public boolean isConstantDeclaration(Method method) {
|
||||
return method.isAnnotationPresent(PathParam.class) && method.isAnnotationPresent(Named.class);
|
||||
return method.isAnnotationPresent(PathParam.class)
|
||||
&& method.isAnnotationPresent(Named.class);
|
||||
}
|
||||
|
||||
public void bindConstant(Method method) {
|
||||
String key = method.getAnnotation(PathParam.class).value();
|
||||
String value = injector.getInstance(Key.get(String.class, method.getAnnotation(Named.class)));
|
||||
String value = injector.getInstance(Key.get(String.class, method
|
||||
.getAnnotation(Named.class)));
|
||||
constants.put(key, value);
|
||||
}
|
||||
|
||||
|
@ -735,18 +819,20 @@ public class RestAnnotationProcessor<T> {
|
|||
return requests.iterator().next();
|
||||
}
|
||||
|
||||
public void addHostHeaderIfAnnotatedWithVirtualHost(Multimap<String, String> headers,
|
||||
String host, Method method) {
|
||||
public void addHostHeaderIfAnnotatedWithVirtualHost(
|
||||
Multimap<String, String> headers, String host, Method method) {
|
||||
if (declaring.isAnnotationPresent(VirtualHost.class)
|
||||
|| method.isAnnotationPresent(VirtualHost.class)) {
|
||||
headers.put(HOST, host);
|
||||
}
|
||||
}
|
||||
|
||||
public void decorateRequest(GeneratedHttpRequest<T> request, Multimap<String, String> headers) {
|
||||
org.jclouds.rest.MapBinder mapBinder = getMapPayloadBinderOrNull(request.getJavaMethod(),
|
||||
public void decorateRequest(GeneratedHttpRequest<T> request,
|
||||
Multimap<String, String> headers) {
|
||||
org.jclouds.rest.MapBinder mapBinder = getMapPayloadBinderOrNull(request
|
||||
.getJavaMethod(), request.getArgs());
|
||||
Map<String, String> mapParams = buildPostParams(request.getJavaMethod(),
|
||||
request.getArgs());
|
||||
Map<String, String> mapParams = buildPostParams(request.getJavaMethod(), request.getArgs());
|
||||
// MapPayloadBinder is only useful if there are parameters. We guard here
|
||||
// in case the
|
||||
// MapPayloadBinder is also an PayloadBinder. If so, it can be used with
|
||||
|
@ -756,31 +842,37 @@ public class RestAnnotationProcessor<T> {
|
|||
mapBinder.bindToRequest(request, mapParams);
|
||||
} else {
|
||||
OUTER: for (Entry<Integer, Set<Annotation>> entry : filterValues(
|
||||
methodToIndexOfParamToDecoratorParamAnnotation.get(request.getJavaMethod()),
|
||||
new Predicate<Set<Annotation>>() {
|
||||
methodToIndexOfParamToDecoratorParamAnnotation.get(request
|
||||
.getJavaMethod()), new Predicate<Set<Annotation>>() {
|
||||
public boolean apply(Set<Annotation> input) {
|
||||
return input.size() >= 1;
|
||||
}
|
||||
}).entrySet()) {
|
||||
boolean shouldBreak = false;
|
||||
BinderParam payloadAnnotation = (BinderParam) entry.getValue().iterator().next();
|
||||
BinderParam payloadAnnotation = (BinderParam) entry.getValue()
|
||||
.iterator().next();
|
||||
Binder binder = injector.getInstance(payloadAnnotation.value());
|
||||
if (request.getArgs().length >= entry.getKey() + 1
|
||||
&& request.getArgs()[entry.getKey()] != null) {
|
||||
Object input;
|
||||
Class<?> parameterType = request.getJavaMethod().getParameterTypes()[entry.getKey()];
|
||||
Class<? extends Object> argType = request.getArgs()[entry.getKey()].getClass();
|
||||
Class<?> parameterType = request.getJavaMethod()
|
||||
.getParameterTypes()[entry.getKey()];
|
||||
Class<? extends Object> argType = request.getArgs()[entry
|
||||
.getKey()].getClass();
|
||||
if (!argType.isArray() && request.getJavaMethod().isVarArgs()
|
||||
&& parameterType.isArray()) {
|
||||
int arrayLength = request.getArgs().length
|
||||
- request.getJavaMethod().getParameterTypes().length + 1;
|
||||
- request.getJavaMethod().getParameterTypes().length
|
||||
+ 1;
|
||||
if (arrayLength == 0)
|
||||
break OUTER;
|
||||
input = (Object[]) Array.newInstance(
|
||||
request.getArgs()[entry.getKey()].getClass(), arrayLength);
|
||||
System.arraycopy(request.getArgs(), entry.getKey(), input, 0, arrayLength);
|
||||
input = (Object[]) Array.newInstance(request.getArgs()[entry
|
||||
.getKey()].getClass(), arrayLength);
|
||||
System.arraycopy(request.getArgs(), entry.getKey(), input, 0,
|
||||
arrayLength);
|
||||
shouldBreak = true;
|
||||
} else if (argType.isArray() && request.getJavaMethod().isVarArgs()
|
||||
} else if (argType.isArray()
|
||||
&& request.getJavaMethod().isVarArgs()
|
||||
&& parameterType.isArray()) {
|
||||
input = request.getArgs()[entry.getKey()];
|
||||
} else {
|
||||
|
@ -801,19 +893,23 @@ public class RestAnnotationProcessor<T> {
|
|||
utils.setPayloadPropertiesFromHeaders(headers, request);
|
||||
}
|
||||
|
||||
protected Map<Integer, Set<Annotation>> indexWithOnlyOneAnnotation(Method method,
|
||||
String description, Map<Method, Map<Integer, Set<Annotation>>> toRefine) {
|
||||
Map<Integer, Set<Annotation>> indexToPayloadAnnotation = filterValues(toRefine.get(method),
|
||||
new Predicate<Set<Annotation>>() {
|
||||
public static Map<Integer, Set<Annotation>> indexWithOnlyOneAnnotation(
|
||||
Method method, String description,
|
||||
Map<Method, Map<Integer, Set<Annotation>>> toRefine) {
|
||||
Map<Integer, Set<Annotation>> indexToPayloadAnnotation = filterValues(
|
||||
toRefine.get(method), new Predicate<Set<Annotation>>() {
|
||||
public boolean apply(Set<Annotation> input) {
|
||||
return input.size() == 1;
|
||||
}
|
||||
});
|
||||
|
||||
if (indexToPayloadAnnotation.size() > 1) {
|
||||
throw new IllegalStateException(String.format(
|
||||
"You must not specify more than one %s annotation on: %s; found %s", description,
|
||||
method.toString(), indexToPayloadAnnotation));
|
||||
throw new IllegalStateException(
|
||||
String
|
||||
.format(
|
||||
"You must not specify more than one %s annotation on: %s; found %s",
|
||||
description, method.toString(),
|
||||
indexToPayloadAnnotation));
|
||||
}
|
||||
return indexToPayloadAnnotation;
|
||||
}
|
||||
|
@ -845,13 +941,15 @@ public class RestAnnotationProcessor<T> {
|
|||
return null;
|
||||
}
|
||||
|
||||
public Multimap<String, String> buildHeaders(Collection<Entry<String, String>> tokenValues,
|
||||
Method method, final Object... args) {
|
||||
public Multimap<String, String> buildHeaders(
|
||||
Collection<Entry<String, String>> tokenValues, Method method,
|
||||
final Object... args) {
|
||||
Multimap<String, String> headers = LinkedHashMultimap.create();
|
||||
addHeaderIfAnnotationPresentOnMethod(headers, method, tokenValues);
|
||||
Map<Integer, Set<Annotation>> indexToHeaderParam = methodToIndexOfParamToHeaderParamAnnotations
|
||||
.get(method);
|
||||
for (Entry<Integer, Set<Annotation>> entry : indexToHeaderParam.entrySet()) {
|
||||
for (Entry<Integer, Set<Annotation>> entry : indexToHeaderParam
|
||||
.entrySet()) {
|
||||
for (Annotation key : entry.getValue()) {
|
||||
String value = args[entry.getKey()].toString();
|
||||
value = replaceTokens(value, tokenValues);
|
||||
|
@ -863,7 +961,8 @@ public class RestAnnotationProcessor<T> {
|
|||
return headers;
|
||||
}
|
||||
|
||||
void addConsumesIfPresentOnTypeOrMethod(Multimap<String, String> headers, Method method) {
|
||||
void addConsumesIfPresentOnTypeOrMethod(Multimap<String, String> headers,
|
||||
Method method) {
|
||||
if (declaring.isAnnotationPresent(Consumes.class)) {
|
||||
Consumes header = declaring.getAnnotation(Consumes.class);
|
||||
headers.replaceValues(ACCEPT, asList(header.value()));
|
||||
|
@ -874,7 +973,8 @@ public class RestAnnotationProcessor<T> {
|
|||
}
|
||||
}
|
||||
|
||||
void addProducesIfPresentOnTypeOrMethod(Multimap<String, String> headers, Method method) {
|
||||
void addProducesIfPresentOnTypeOrMethod(Multimap<String, String> headers,
|
||||
Method method) {
|
||||
if (declaring.isAnnotationPresent(Produces.class)) {
|
||||
Produces header = declaring.getAnnotation(Produces.class);
|
||||
headers.replaceValues(CONTENT_TYPE, asList(header.value()));
|
||||
|
@ -885,8 +985,9 @@ public class RestAnnotationProcessor<T> {
|
|||
}
|
||||
}
|
||||
|
||||
public void addHeaderIfAnnotationPresentOnMethod(Multimap<String, String> headers,
|
||||
Method method, Collection<Entry<String, String>> tokenValues) {
|
||||
public void addHeaderIfAnnotationPresentOnMethod(
|
||||
Multimap<String, String> headers, Method method,
|
||||
Collection<Entry<String, String>> tokenValues) {
|
||||
if (declaring.isAnnotationPresent(Headers.class)) {
|
||||
Headers header = declaring.getAnnotation(Headers.class);
|
||||
addHeader(headers, header, tokenValues);
|
||||
|
@ -928,7 +1029,8 @@ public class RestAnnotationProcessor<T> {
|
|||
options.contentType(param.contentType());
|
||||
if (!PartParam.NO_FILENAME.equals(param.filename()))
|
||||
options.filename(replaceTokens(param.filename(), iterable));
|
||||
Part part = Part.create(param.name(), newPayload(args[entry.getKey()]), options);
|
||||
Part part = Part.create(param.name(), newPayload(args[entry
|
||||
.getKey()]), options);
|
||||
parts.add(part);
|
||||
}
|
||||
}
|
||||
|
@ -946,7 +1048,8 @@ public class RestAnnotationProcessor<T> {
|
|||
return null;
|
||||
}
|
||||
|
||||
private Multimap<String, String> getPathParamKeyValues(Method method, Object... args) {
|
||||
private Multimap<String, String> getPathParamKeyValues(Method method,
|
||||
Object... args) {
|
||||
Multimap<String, String> pathParamValues = LinkedHashMultimap.create();
|
||||
pathParamValues.putAll(constants);
|
||||
Map<Integer, Set<Annotation>> indexToPathParam = methodToIndexOfParamToPathParamAnnotations
|
||||
|
@ -956,12 +1059,15 @@ public class RestAnnotationProcessor<T> {
|
|||
.get(method);
|
||||
for (Entry<Integer, Set<Annotation>> entry : indexToPathParam.entrySet()) {
|
||||
for (Annotation key : entry.getValue()) {
|
||||
Set<Annotation> extractors = indexToParamExtractor.get(entry.getKey());
|
||||
Set<Annotation> extractors = indexToParamExtractor.get(entry
|
||||
.getKey());
|
||||
String paramKey = ((PathParam) key).value();
|
||||
String paramValue;
|
||||
if (extractors != null && extractors.size() > 0) {
|
||||
ParamParser extractor = (ParamParser) extractors.iterator().next();
|
||||
paramValue = injector.getInstance(extractor.value()).apply(args[entry.getKey()]);
|
||||
ParamParser extractor = (ParamParser) extractors.iterator()
|
||||
.next();
|
||||
paramValue = injector.getInstance(extractor.value()).apply(
|
||||
args[entry.getKey()]);
|
||||
} else {
|
||||
paramValue = args[entry.getKey()].toString();
|
||||
}
|
||||
|
@ -972,15 +1078,16 @@ public class RestAnnotationProcessor<T> {
|
|||
if (method.isAnnotationPresent(PathParam.class)
|
||||
&& method.isAnnotationPresent(ParamParser.class)) {
|
||||
String paramKey = method.getAnnotation(PathParam.class).value();
|
||||
String paramValue = injector.getInstance(method.getAnnotation(ParamParser.class).value())
|
||||
.apply(args);
|
||||
String paramValue = injector.getInstance(
|
||||
method.getAnnotation(ParamParser.class).value()).apply(args);
|
||||
pathParamValues.put(paramKey, paramValue);
|
||||
|
||||
}
|
||||
return pathParamValues;
|
||||
}
|
||||
|
||||
private Multimap<String, String> encodeValues(Multimap<String, String> unencoded, char... skips) {
|
||||
private Multimap<String, String> encodeValues(
|
||||
Multimap<String, String> unencoded, char... skips) {
|
||||
Multimap<String, String> encoded = LinkedHashMultimap.create();
|
||||
for (Entry<String, String> entry : unencoded.entries()) {
|
||||
encoded.put(entry.getKey(), urlEncode(entry.getValue(), skips));
|
||||
|
@ -988,7 +1095,8 @@ public class RestAnnotationProcessor<T> {
|
|||
return encoded;
|
||||
}
|
||||
|
||||
private Multimap<String, String> getMatrixParamKeyValues(Method method, Object... args) {
|
||||
private Multimap<String, String> getMatrixParamKeyValues(Method method,
|
||||
Object... args) {
|
||||
Multimap<String, String> matrixParamValues = LinkedHashMultimap.create();
|
||||
matrixParamValues.putAll(constants);
|
||||
Map<Integer, Set<Annotation>> indexToMatrixParam = methodToIndexOfParamToMatrixParamAnnotations
|
||||
|
@ -996,14 +1104,18 @@ public class RestAnnotationProcessor<T> {
|
|||
|
||||
Map<Integer, Set<Annotation>> indexToParamExtractor = methodToIndexOfParamToParamParserAnnotations
|
||||
.get(method);
|
||||
for (Entry<Integer, Set<Annotation>> entry : indexToMatrixParam.entrySet()) {
|
||||
for (Entry<Integer, Set<Annotation>> entry : indexToMatrixParam
|
||||
.entrySet()) {
|
||||
for (Annotation key : entry.getValue()) {
|
||||
Set<Annotation> extractors = indexToParamExtractor.get(entry.getKey());
|
||||
Set<Annotation> extractors = indexToParamExtractor.get(entry
|
||||
.getKey());
|
||||
String paramKey = ((MatrixParam) key).value();
|
||||
String paramValue;
|
||||
if (extractors != null && extractors.size() > 0) {
|
||||
ParamParser extractor = (ParamParser) extractors.iterator().next();
|
||||
paramValue = injector.getInstance(extractor.value()).apply(args[entry.getKey()]);
|
||||
ParamParser extractor = (ParamParser) extractors.iterator()
|
||||
.next();
|
||||
paramValue = injector.getInstance(extractor.value()).apply(
|
||||
args[entry.getKey()]);
|
||||
} else {
|
||||
paramValue = args[entry.getKey()].toString();
|
||||
}
|
||||
|
@ -1014,15 +1126,16 @@ public class RestAnnotationProcessor<T> {
|
|||
if (method.isAnnotationPresent(MatrixParam.class)
|
||||
&& method.isAnnotationPresent(ParamParser.class)) {
|
||||
String paramKey = method.getAnnotation(MatrixParam.class).value();
|
||||
String paramValue = injector.getInstance(method.getAnnotation(ParamParser.class).value())
|
||||
.apply(args);
|
||||
String paramValue = injector.getInstance(
|
||||
method.getAnnotation(ParamParser.class).value()).apply(args);
|
||||
matrixParamValues.put(paramKey, paramValue);
|
||||
|
||||
}
|
||||
return matrixParamValues;
|
||||
}
|
||||
|
||||
private Multimap<String, String> getFormParamKeyValues(Method method, Object... args) {
|
||||
private Multimap<String, String> getFormParamKeyValues(Method method,
|
||||
Object... args) {
|
||||
Multimap<String, String> formParamValues = LinkedHashMultimap.create();
|
||||
formParamValues.putAll(constants);
|
||||
Map<Integer, Set<Annotation>> indexToFormParam = methodToIndexOfParamToFormParamAnnotations
|
||||
|
@ -1032,12 +1145,15 @@ public class RestAnnotationProcessor<T> {
|
|||
.get(method);
|
||||
for (Entry<Integer, Set<Annotation>> entry : indexToFormParam.entrySet()) {
|
||||
for (Annotation key : entry.getValue()) {
|
||||
Set<Annotation> extractors = indexToParamExtractor.get(entry.getKey());
|
||||
Set<Annotation> extractors = indexToParamExtractor.get(entry
|
||||
.getKey());
|
||||
String paramKey = ((FormParam) key).value();
|
||||
String paramValue;
|
||||
if (extractors != null && extractors.size() > 0) {
|
||||
ParamParser extractor = (ParamParser) extractors.iterator().next();
|
||||
paramValue = injector.getInstance(extractor.value()).apply(args[entry.getKey()]);
|
||||
ParamParser extractor = (ParamParser) extractors.iterator()
|
||||
.next();
|
||||
paramValue = injector.getInstance(extractor.value()).apply(
|
||||
args[entry.getKey()]);
|
||||
} else {
|
||||
paramValue = args[entry.getKey()].toString();
|
||||
}
|
||||
|
@ -1048,15 +1164,16 @@ public class RestAnnotationProcessor<T> {
|
|||
if (method.isAnnotationPresent(FormParam.class)
|
||||
&& method.isAnnotationPresent(ParamParser.class)) {
|
||||
String paramKey = method.getAnnotation(FormParam.class).value();
|
||||
String paramValue = injector.getInstance(method.getAnnotation(ParamParser.class).value())
|
||||
.apply(args);
|
||||
String paramValue = injector.getInstance(
|
||||
method.getAnnotation(ParamParser.class).value()).apply(args);
|
||||
formParamValues.put(paramKey, paramValue);
|
||||
|
||||
}
|
||||
return formParamValues;
|
||||
}
|
||||
|
||||
private Multimap<String, String> getQueryParamKeyValues(Method method, Object... args) {
|
||||
private Multimap<String, String> getQueryParamKeyValues(Method method,
|
||||
Object... args) {
|
||||
Multimap<String, String> queryParamValues = LinkedHashMultimap.create();
|
||||
queryParamValues.putAll(constants);
|
||||
Map<Integer, Set<Annotation>> indexToQueryParam = methodToIndexOfParamToQueryParamAnnotations
|
||||
|
@ -1066,12 +1183,15 @@ public class RestAnnotationProcessor<T> {
|
|||
.get(method);
|
||||
for (Entry<Integer, Set<Annotation>> entry : indexToQueryParam.entrySet()) {
|
||||
for (Annotation key : entry.getValue()) {
|
||||
Set<Annotation> extractors = indexToParamExtractor.get(entry.getKey());
|
||||
Set<Annotation> extractors = indexToParamExtractor.get(entry
|
||||
.getKey());
|
||||
String paramKey = ((QueryParam) key).value();
|
||||
String paramValue;
|
||||
if (extractors != null && extractors.size() > 0) {
|
||||
ParamParser extractor = (ParamParser) extractors.iterator().next();
|
||||
paramValue = injector.getInstance(extractor.value()).apply(args[entry.getKey()]);
|
||||
ParamParser extractor = (ParamParser) extractors.iterator()
|
||||
.next();
|
||||
paramValue = injector.getInstance(extractor.value()).apply(
|
||||
args[entry.getKey()]);
|
||||
} else {
|
||||
paramValue = args[entry.getKey()].toString();
|
||||
}
|
||||
|
@ -1082,8 +1202,8 @@ public class RestAnnotationProcessor<T> {
|
|||
if (method.isAnnotationPresent(QueryParam.class)
|
||||
&& method.isAnnotationPresent(ParamParser.class)) {
|
||||
String paramKey = method.getAnnotation(QueryParam.class).value();
|
||||
String paramValue = injector.getInstance(method.getAnnotation(ParamParser.class).value())
|
||||
.apply(args);
|
||||
String paramValue = injector.getInstance(
|
||||
method.getAnnotation(ParamParser.class).value()).apply(args);
|
||||
queryParamValues.put(paramKey, paramValue);
|
||||
|
||||
}
|
||||
|
@ -1098,12 +1218,15 @@ public class RestAnnotationProcessor<T> {
|
|||
.get(method);
|
||||
for (Entry<Integer, Set<Annotation>> entry : indexToPathParam.entrySet()) {
|
||||
for (Annotation key : entry.getValue()) {
|
||||
Set<Annotation> extractors = indexToParamExtractor.get(entry.getKey());
|
||||
Set<Annotation> extractors = indexToParamExtractor.get(entry
|
||||
.getKey());
|
||||
String paramKey = ((MapPayloadParam) key).value();
|
||||
String paramValue;
|
||||
if (extractors != null && extractors.size() > 0) {
|
||||
ParamParser extractor = (ParamParser) extractors.iterator().next();
|
||||
paramValue = injector.getInstance(extractor.value()).apply(args[entry.getKey()]);
|
||||
ParamParser extractor = (ParamParser) extractors.iterator()
|
||||
.next();
|
||||
paramValue = injector.getInstance(extractor.value()).apply(
|
||||
args[entry.getKey()]);
|
||||
|
||||
} else {
|
||||
paramValue = args[entry.getKey()].toString();
|
||||
|
@ -1115,19 +1238,4 @@ public class RestAnnotationProcessor<T> {
|
|||
return postParams;
|
||||
}
|
||||
|
||||
public URI getEndpointFor(Method method, Object... args) {
|
||||
URI endpoint = getEndpointInParametersOrNull(method, args);
|
||||
if (endpoint == null) {
|
||||
Endpoint annotation;
|
||||
if (method.isAnnotationPresent(Endpoint.class)) {
|
||||
annotation = method.getAnnotation(Endpoint.class);
|
||||
} else if (method.getDeclaringClass().isAnnotationPresent(Endpoint.class)) {
|
||||
annotation = method.getDeclaringClass().getAnnotation(Endpoint.class);
|
||||
} else {
|
||||
throw new IllegalStateException("no annotations on class or method: " + method);
|
||||
}
|
||||
return injector.getInstance(Key.get(URI.class, annotation.value()));
|
||||
}
|
||||
return endpoint;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue