mirror of https://github.com/apache/jclouds.git
Issue 76: added ability to specify multiple default headers and queries, as well addedd a common collection type
git-svn-id: http://jclouds.googlecode.com/svn/trunk@1901 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
parent
0ad0fc6a83
commit
6de55b5fd6
|
@ -0,0 +1,56 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ArrayBoundedList<T> extends ArrayList<T> implements BoundedList<T> {
|
||||||
|
|
||||||
|
/** The serialVersionUID */
|
||||||
|
private static final long serialVersionUID = -7133632087734650835L;
|
||||||
|
protected final String prefix;
|
||||||
|
protected final String marker;
|
||||||
|
protected final int maxResults;
|
||||||
|
|
||||||
|
public ArrayBoundedList(List<T> contents, String prefix, String marker, int maxResults) {
|
||||||
|
this.addAll(contents);
|
||||||
|
this.prefix = prefix;
|
||||||
|
this.marker = marker;
|
||||||
|
this.maxResults = maxResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPrefix() {
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMarker() {
|
||||||
|
return marker;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxResults() {
|
||||||
|
return maxResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface BoundedList<T> extends List<T> {
|
||||||
|
|
||||||
|
String getPrefix();
|
||||||
|
|
||||||
|
String getMarker();
|
||||||
|
|
||||||
|
int getMaxResults();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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;
|
||||||
|
|
||||||
|
import static java.lang.annotation.ElementType.METHOD;
|
||||||
|
import static java.lang.annotation.ElementType.TYPE;
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import javax.ws.rs.PathParam;
|
||||||
|
import javax.ws.rs.core.HttpHeaders;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Designates that a header will be added to the request. This header will contain the specified
|
||||||
|
* {@code value}, expanding any variables annotated with {@code PathParam}.
|
||||||
|
*
|
||||||
|
* @see PathParam
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Target( { TYPE, METHOD })
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
public @interface Headers {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see HttpHeaders
|
||||||
|
*/
|
||||||
|
String [] keys();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* can be defined literally, or with enclosed variables (ex. <code>{variable}</code>)
|
||||||
|
* <p/>
|
||||||
|
* The inputs to these variables are taken from method parameters annotated with {@code
|
||||||
|
* @PathParam}.
|
||||||
|
*
|
||||||
|
* @see PathParam
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String [] values();
|
||||||
|
}
|
|
@ -23,6 +23,9 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.rest;
|
package org.jclouds.rest;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
@ -90,6 +93,7 @@ public class JaxrsAnnotationProcessor {
|
||||||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToindexOfParamToPathParamAnnotations = createMethodToIndexOfParamToAnnotation(PathParam.class);
|
private final Map<Method, Map<Integer, Set<Annotation>>> methodToindexOfParamToPathParamAnnotations = createMethodToIndexOfParamToAnnotation(PathParam.class);
|
||||||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToindexOfParamToPostParamAnnotations = createMethodToIndexOfParamToAnnotation(MapEntityParam.class);
|
private final Map<Method, Map<Integer, Set<Annotation>>> methodToindexOfParamToPostParamAnnotations = createMethodToIndexOfParamToAnnotation(MapEntityParam.class);
|
||||||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToindexOfParamToParamParserAnnotations = createMethodToIndexOfParamToAnnotation(ParamParser.class);
|
private final Map<Method, Map<Integer, Set<Annotation>>> methodToindexOfParamToParamParserAnnotations = createMethodToIndexOfParamToAnnotation(ParamParser.class);
|
||||||
|
private final Map<MethodKey, Method> delegationMap = Maps.newHashMap();
|
||||||
|
|
||||||
static Map<Method, Map<Integer, Set<Annotation>>> createMethodToIndexOfParamToAnnotation(
|
static Map<Method, Map<Integer, Set<Annotation>>> createMethodToIndexOfParamToAnnotation(
|
||||||
final Class<? extends Annotation> annotation) {
|
final Class<? extends Annotation> annotation) {
|
||||||
|
@ -182,9 +186,14 @@ public class JaxrsAnnotationProcessor {
|
||||||
seedCache(declaring);
|
seedCache(declaring);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Method getDelegateOrNull(Method in) {
|
||||||
|
return delegationMap.get(new MethodKey(in));
|
||||||
|
}
|
||||||
|
|
||||||
private void seedCache(Class<?> declaring) {
|
private void seedCache(Class<?> declaring) {
|
||||||
Set<Method> methods = Sets.newHashSet(declaring.getMethods());
|
Set<Method> methods = Sets.newHashSet(declaring.getMethods());
|
||||||
for (Method method : Sets.difference(methods, Sets.newHashSet(Object.class.getMethods()))) {
|
methods = Sets.difference(methods, Sets.newHashSet(Object.class.getMethods()));
|
||||||
|
for (Method method : methods) {
|
||||||
if (isHttpMethod(method)) {
|
if (isHttpMethod(method)) {
|
||||||
for (int index = 0; index < method.getParameterTypes().length; index++) {
|
for (int index = 0; index < method.getParameterTypes().length; index++) {
|
||||||
methodToIndexOfParamToEntityAnnotation.get(method).get(index);
|
methodToIndexOfParamToEntityAnnotation.get(method).get(index);
|
||||||
|
@ -195,14 +204,58 @@ public class JaxrsAnnotationProcessor {
|
||||||
methodToindexOfParamToParamParserAnnotations.get(method).get(index);
|
methodToindexOfParamToParamParserAnnotations.get(method).get(index);
|
||||||
methodToIndexesOfOptions.get(method);
|
methodToIndexesOfOptions.get(method);
|
||||||
}
|
}
|
||||||
|
delegationMap.put(new MethodKey(method), method);
|
||||||
} else if (isConstantDeclaration(method)) {
|
} else if (isConstantDeclaration(method)) {
|
||||||
bindConstant(method);
|
bindConstant(method);
|
||||||
|
} else if (!method.getDeclaringClass().equals(declaring)) {
|
||||||
|
logger.debug("skipping potentially overridden method", method);
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("Method is not annotated as either http or constant");
|
throw new RuntimeException("Method is not annotated as either http or constant: "
|
||||||
|
+ method);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class MethodKey {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||||
|
result = prime * result + parameterCount;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
MethodKey other = (MethodKey) obj;
|
||||||
|
if (name == null) {
|
||||||
|
if (other.name != null)
|
||||||
|
return false;
|
||||||
|
} else if (!name.equals(other.name))
|
||||||
|
return false;
|
||||||
|
if (parameterCount != other.parameterCount)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
private final int parameterCount;
|
||||||
|
|
||||||
|
public MethodKey(Method method) {
|
||||||
|
this.name = method.getName();
|
||||||
|
this.parameterCount = method.getParameterTypes().length;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
final Injector injector;
|
final Injector injector;
|
||||||
|
|
||||||
private HttpRequestOptionsBinder optionsBinder;
|
private HttpRequestOptionsBinder optionsBinder;
|
||||||
|
@ -214,13 +267,13 @@ public class JaxrsAnnotationProcessor {
|
||||||
builder.path(declaring);
|
builder.path(declaring);
|
||||||
builder.path(method);
|
builder.path(method);
|
||||||
|
|
||||||
if (declaring.isAnnotationPresent(Query.class)) {
|
if (declaring.isAnnotationPresent(QueryParams.class)) {
|
||||||
Query query = declaring.getAnnotation(Query.class);
|
QueryParams query = declaring.getAnnotation(QueryParams.class);
|
||||||
addQuery(builder, query);
|
addQuery(builder, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (method.isAnnotationPresent(Query.class)) {
|
if (method.isAnnotationPresent(QueryParams.class)) {
|
||||||
Query query = method.getAnnotation(Query.class);
|
QueryParams query = method.getAnnotation(QueryParams.class);
|
||||||
addQuery(builder, query);
|
addQuery(builder, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,6 +281,7 @@ public class JaxrsAnnotationProcessor {
|
||||||
|
|
||||||
HttpRequestOptions options = findOptionsIn(method, args);
|
HttpRequestOptions options = findOptionsIn(method, args);
|
||||||
if (options != null) {
|
if (options != null) {
|
||||||
|
injector.injectMembers(options);// TODO test case
|
||||||
headers.putAll(options.buildRequestHeaders());
|
headers.putAll(options.buildRequestHeaders());
|
||||||
for (Entry<String, String> query : options.buildQueryParameters().entries()) {
|
for (Entry<String, String> query : options.buildQueryParameters().entries()) {
|
||||||
builder.queryParam(query.getKey(), query.getValue());
|
builder.queryParam(query.getKey(), query.getValue());
|
||||||
|
@ -261,24 +315,33 @@ public class JaxrsAnnotationProcessor {
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addQuery(UriBuilder builder, Query query) {
|
private void addQuery(UriBuilder builder, QueryParams query) {
|
||||||
if (query.value().equals(Query.NULL))
|
for (int i = 0; i < query.keys().length; i++) {
|
||||||
builder.replaceQuery(query.key());
|
if (query.values()[i].equals(QueryParams.NULL)) {
|
||||||
else
|
builder.replaceQuery(query.keys()[i]);
|
||||||
builder.queryParam(query.key(), query.value());
|
} else {
|
||||||
|
builder.queryParam(query.keys()[i], query.values()[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addFiltersIfAnnotated(Method method, HttpRequest request) {
|
private void addFiltersIfAnnotated(Method method, HttpRequest request) {
|
||||||
if (declaring.isAnnotationPresent(RequestFilters.class)) {
|
if (declaring.isAnnotationPresent(RequestFilters.class)) {
|
||||||
for (Class<? extends HttpRequestFilter> clazz : declaring.getAnnotation(
|
for (Class<? extends HttpRequestFilter> clazz : declaring.getAnnotation(
|
||||||
RequestFilters.class).value()) {
|
RequestFilters.class).value()) {
|
||||||
request.getFilters().add(injector.getInstance(clazz));
|
HttpRequestFilter instance = injector.getInstance(clazz);
|
||||||
|
request.getFilters().add(instance);
|
||||||
|
logger.debug("%s - adding filter %s from annotation on %s", request, instance,
|
||||||
|
declaring.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (method.isAnnotationPresent(RequestFilters.class)) {
|
if (method.isAnnotationPresent(RequestFilters.class)) {
|
||||||
for (Class<? extends HttpRequestFilter> clazz : method.getAnnotation(RequestFilters.class)
|
for (Class<? extends HttpRequestFilter> clazz : method.getAnnotation(RequestFilters.class)
|
||||||
.value()) {
|
.value()) {
|
||||||
request.getFilters().add(injector.getInstance(clazz));
|
HttpRequestFilter instance = injector.getInstance(clazz);
|
||||||
|
request.getFilters().add(instance);
|
||||||
|
logger.debug("%s - adding filter %s from annotation on %s", request, instance, method
|
||||||
|
.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -290,7 +353,10 @@ public class JaxrsAnnotationProcessor {
|
||||||
HostPrefixParam param = (HostPrefixParam) map.values().iterator().next().iterator().next();
|
HostPrefixParam param = (HostPrefixParam) map.values().iterator().next().iterator().next();
|
||||||
int index = map.keySet().iterator().next();
|
int index = map.keySet().iterator().next();
|
||||||
|
|
||||||
String prefix = args[index].toString();
|
String prefix = checkNotNull(args[index],
|
||||||
|
String.format("argument at index %d on method %s", index, method)).toString();
|
||||||
|
checkArgument(!prefix.equals(""), String.format(
|
||||||
|
"argument at index %d must be a valid hostname for method %s", index, method));
|
||||||
String joinOn = param.value();
|
String joinOn = param.value();
|
||||||
String host = endpoint.getHost();
|
String host = endpoint.getHost();
|
||||||
|
|
||||||
|
@ -332,27 +398,29 @@ public class JaxrsAnnotationProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
public MapEntityBinder getMapEntityBinderOrNull(Method method, Object[] args) {
|
public MapEntityBinder getMapEntityBinderOrNull(Method method, Object[] args) {
|
||||||
for (Object arg : args) {
|
if (args != null) {
|
||||||
if (arg instanceof Object[]) {
|
for (Object arg : args) {
|
||||||
Object[] postBinders = (Object[]) arg;
|
if (arg instanceof Object[]) {
|
||||||
if (postBinders.length == 0) {
|
Object[] postBinders = (Object[]) arg;
|
||||||
} else if (postBinders.length == 1) {
|
if (postBinders.length == 0) {
|
||||||
if (postBinders[0] instanceof MapEntityBinder) {
|
} else if (postBinders.length == 1) {
|
||||||
MapEntityBinder binder = (MapEntityBinder) postBinders[0];
|
if (postBinders[0] instanceof MapEntityBinder) {
|
||||||
injector.injectMembers(binder);
|
MapEntityBinder binder = (MapEntityBinder) postBinders[0];
|
||||||
return binder;
|
injector.injectMembers(binder);
|
||||||
}
|
return binder;
|
||||||
} else {
|
}
|
||||||
if (postBinders[0] instanceof MapEntityBinder) {
|
} else {
|
||||||
throw new IllegalArgumentException(
|
if (postBinders[0] instanceof MapEntityBinder) {
|
||||||
"we currently do not support multiple varargs postBinders in: "
|
throw new IllegalArgumentException(
|
||||||
+ method.getName());
|
"we currently do not support multiple varargs postBinders in: "
|
||||||
|
+ method.getName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else if (arg instanceof MapEntityBinder) {
|
||||||
|
MapEntityBinder binder = (MapEntityBinder) arg;
|
||||||
|
injector.injectMembers(binder);
|
||||||
|
return binder;
|
||||||
}
|
}
|
||||||
} else if (arg instanceof MapEntityBinder) {
|
|
||||||
MapEntityBinder binder = (MapEntityBinder) arg;
|
|
||||||
injector.injectMembers(binder);
|
|
||||||
return binder;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MapBinder annotation = method.getAnnotation(MapBinder.class);
|
MapBinder annotation = method.getAnnotation(MapBinder.class);
|
||||||
|
@ -515,24 +583,28 @@ public class JaxrsAnnotationProcessor {
|
||||||
|
|
||||||
public void addHeaderIfAnnotationPresentOnMethod(Multimap<String, String> headers,
|
public void addHeaderIfAnnotationPresentOnMethod(Multimap<String, String> headers,
|
||||||
Method method, Object[] args, char... skipEncode) throws UnsupportedEncodingException {
|
Method method, Object[] args, char... skipEncode) throws UnsupportedEncodingException {
|
||||||
if (declaring.isAnnotationPresent(Header.class)) {
|
if (declaring.isAnnotationPresent(Headers.class)) {
|
||||||
Header header = declaring.getAnnotation(Header.class);
|
Headers header = declaring.getAnnotation(Headers.class);
|
||||||
addHeader(headers, method, args, header);
|
addHeader(headers, method, args, header);
|
||||||
}
|
}
|
||||||
if (method.isAnnotationPresent(Header.class)) {
|
if (method.isAnnotationPresent(Headers.class)) {
|
||||||
Header header = method.getAnnotation(Header.class);
|
Headers header = method.getAnnotation(Headers.class);
|
||||||
addHeader(headers, method, args, header);
|
addHeader(headers, method, args, header);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addHeader(Multimap<String, String> headers, Method method, Object[] args,
|
private void addHeader(Multimap<String, String> headers, Method method, Object[] args,
|
||||||
Header header) throws UnsupportedEncodingException {
|
Headers header) throws UnsupportedEncodingException {
|
||||||
String value = header.value();
|
for (int i = 0; i < header.keys().length; i++) {
|
||||||
for (Entry<String, Object> tokenValue : getEncodedPathParamKeyValues(method, args).entrySet()) {
|
String value = header.values()[i];
|
||||||
value = value.replaceAll("\\{" + tokenValue.getKey() + "\\}", tokenValue.getValue()
|
for (Entry<String, Object> tokenValue : getEncodedPathParamKeyValues(method, args)
|
||||||
.toString());
|
.entrySet()) {
|
||||||
|
value = value.replaceAll("\\{" + tokenValue.getKey() + "\\}", tokenValue.getValue()
|
||||||
|
.toString());
|
||||||
|
}
|
||||||
|
headers.put(header.keys()[i], value);
|
||||||
}
|
}
|
||||||
headers.put(header.key(), value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, Object> getEncodedPathParamKeyValues(Method method, Object[] args,
|
private Map<String, Object> getEncodedPathParamKeyValues(Method method, Object[] args,
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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;
|
||||||
|
|
||||||
|
import static java.lang.annotation.ElementType.*;
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import javax.ws.rs.QueryParam;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Designates that a query will be added to the request.
|
||||||
|
*
|
||||||
|
* @see QueryParam
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Target( { TYPE, METHOD })
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
public @interface QueryParams {
|
||||||
|
|
||||||
|
public static final String NULL = "QUERY_NULL";
|
||||||
|
|
||||||
|
String [] keys();
|
||||||
|
|
||||||
|
String [] values() default NULL;
|
||||||
|
}
|
|
@ -84,7 +84,8 @@ public class RestClientProxy implements InvocationHandler {
|
||||||
return this.equals(o);
|
return this.equals(o);
|
||||||
} else if (method.getName().equals("hashCode")) {
|
} else if (method.getName().equals("hashCode")) {
|
||||||
return this.hashCode();
|
return this.hashCode();
|
||||||
} else if (util.isHttpMethod(method)) {
|
} else if (util.getDelegateOrNull(method) != null) {
|
||||||
|
method = util.getDelegateOrNull(method);
|
||||||
logger.trace("%s - converting method to request", method);
|
logger.trace("%s - converting method to request", method);
|
||||||
HttpRequest request = util.createRequest(endPoint, method, args);
|
HttpRequest request = util.createRequest(endPoint, method, args);
|
||||||
logger.trace("%s - converted method to request %s", method, request);
|
logger.trace("%s - converted method to request %s", method, request);
|
||||||
|
|
|
@ -90,12 +90,17 @@ public class JaxrsAnnotationProcessorTest {
|
||||||
public @interface FOO {
|
public @interface FOO {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Query(key = "x-ms-version", value = "2009-07-17")
|
@QueryParams(keys = "x-ms-version", values = "2009-07-17")
|
||||||
public class TestQuery {
|
public class TestQuery {
|
||||||
@FOO
|
@FOO
|
||||||
@Query(key = "x-ms-rubbish", value = "bin")
|
@QueryParams(keys = "x-ms-rubbish", values = "bin")
|
||||||
public void foo() {
|
public void foo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@FOO
|
||||||
|
@QueryParams(keys = { "foo", "fooble" }, values = { "bar", "baz" })
|
||||||
|
public void foo2() {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testQuery() throws SecurityException, NoSuchMethodException {
|
public void testQuery() throws SecurityException, NoSuchMethodException {
|
||||||
|
@ -109,6 +114,18 @@ public class JaxrsAnnotationProcessorTest {
|
||||||
assertEquals(httpMethod.getMethod(), "FOO");
|
assertEquals(httpMethod.getMethod(), "FOO");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testQuery2() throws SecurityException, NoSuchMethodException {
|
||||||
|
Method method = TestQuery.class.getMethod("foo2");
|
||||||
|
URI endpoint = URI.create("http://localhost");
|
||||||
|
HttpRequest httpMethod = factory.create(TestQuery.class).createRequest(endpoint, method,
|
||||||
|
new Object[] {});
|
||||||
|
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
|
||||||
|
assertEquals(httpMethod.getEndpoint().getPath(), "");
|
||||||
|
assertEquals(httpMethod.getEndpoint().getQuery(),
|
||||||
|
"x-ms-version=2009-07-17&foo=bar&fooble=baz");
|
||||||
|
assertEquals(httpMethod.getMethod(), "FOO");
|
||||||
|
}
|
||||||
|
|
||||||
public class TestCustomMethod {
|
public class TestCustomMethod {
|
||||||
@FOO
|
@FOO
|
||||||
public void foo() {
|
public void foo() {
|
||||||
|
@ -125,6 +142,27 @@ public class JaxrsAnnotationProcessorTest {
|
||||||
assertEquals(httpMethod.getMethod(), "FOO");
|
assertEquals(httpMethod.getMethod(), "FOO");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface Parent {
|
||||||
|
public void foo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TestOverridden implements Parent {
|
||||||
|
@POST
|
||||||
|
public void foo() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testOverriddenMethod() throws SecurityException, NoSuchMethodException {
|
||||||
|
Method method = TestOverridden.class.getMethod("foo");
|
||||||
|
URI endpoint = URI.create("http://localhost");
|
||||||
|
HttpRequest httpMethod = factory.create(TestOverridden.class).createRequest(endpoint, method,
|
||||||
|
new Object[] {});
|
||||||
|
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
|
||||||
|
assertEquals(httpMethod.getEndpoint().getPath(), "");
|
||||||
|
assertEquals(httpMethod.getMethod(), "POST");
|
||||||
|
}
|
||||||
|
|
||||||
public class TestPost {
|
public class TestPost {
|
||||||
@POST
|
@POST
|
||||||
public void post(@EntityParam String content) {
|
public void post(@EntityParam String content) {
|
||||||
|
@ -376,23 +414,40 @@ public class JaxrsAnnotationProcessorTest {
|
||||||
public class TestHeader {
|
public class TestHeader {
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Header(key = "x-amz-copy-source", value = "/{bucket}")
|
@Headers(keys = "x-amz-copy-source", values = "/{bucket}")
|
||||||
public void oneHeader(@PathParam("bucket") String path) {
|
public void oneHeader(@PathParam("bucket") String path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Header(key = "x-amz-copy-source", value = "/{bucket}/{key}")
|
@Headers(keys = { "slash", "hyphen" }, values = { "/{bucket}", "-{bucket}" })
|
||||||
|
public void twoHeader(@PathParam("bucket") String path) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Headers(keys = "x-amz-copy-source", values = "/{bucket}/{key}")
|
||||||
public void twoHeaders(@PathParam("bucket") String path, @PathParam("key") String path2) {
|
public void twoHeaders(@PathParam("bucket") String path, @PathParam("key") String path2) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Header(key = "x-amz-copy-source", value = "/{bucket}/{key}")
|
@Headers(keys = "x-amz-copy-source", values = "/{bucket}/{key}")
|
||||||
public void twoHeadersOutOfOrder(@PathParam("key") String path,
|
public void twoHeadersOutOfOrder(@PathParam("key") String path,
|
||||||
@PathParam("bucket") String path2) {
|
@PathParam("bucket") String path2) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Header(key = "x-amz-copy-source", value = "/{bucket}")
|
@Test
|
||||||
|
public void testBuildTwoHeader() throws SecurityException, NoSuchMethodException,
|
||||||
|
UnsupportedEncodingException {
|
||||||
|
Method oneHeader = TestHeader.class.getMethod("twoHeader", String.class);
|
||||||
|
Multimap<String, String> headers = HashMultimap.create();
|
||||||
|
factory.create(TestHeader.class).addHeaderIfAnnotationPresentOnMethod(headers, oneHeader,
|
||||||
|
new Object[] { "robot" });
|
||||||
|
assertEquals(headers.size(), 2);
|
||||||
|
assertEquals(headers.get("slash"), Collections.singletonList("/robot"));
|
||||||
|
assertEquals(headers.get("hyphen"), Collections.singletonList("-robot"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Headers(keys = "x-amz-copy-source", values = "/{bucket}")
|
||||||
public class TestClassHeader {
|
public class TestClassHeader {
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
|
@ -501,14 +556,14 @@ public class JaxrsAnnotationProcessorTest {
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("/{id}")
|
@Path("/{id}")
|
||||||
@Query(key = "max-keys", value = "0")
|
@QueryParams(keys = "max-keys", values = "0")
|
||||||
public Future<String> getQuery(@PathParam("id") String id) {
|
public Future<String> getQuery(@PathParam("id") String id) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("/{id}")
|
@Path("/{id}")
|
||||||
@Query(key = "acl")
|
@QueryParams(keys = "acl")
|
||||||
public Future<String> getQueryNull(@PathParam("id") String id) {
|
public Future<String> getQueryNull(@PathParam("id") String id) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -529,7 +584,7 @@ public class JaxrsAnnotationProcessorTest {
|
||||||
|
|
||||||
@PUT
|
@PUT
|
||||||
@Path("/{id}")
|
@Path("/{id}")
|
||||||
@Header(key = "foo", value = "--{id}--")
|
@Headers(keys = "foo", values = "--{id}--")
|
||||||
@ResponseParser(ReturnTrueIf2xx.class)
|
@ResponseParser(ReturnTrueIf2xx.class)
|
||||||
public Future<String> putHeader(@PathParam("id") String id, @EntityParam String payload) {
|
public Future<String> putHeader(@PathParam("id") String id, @EntityParam String payload) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -798,6 +853,23 @@ public class JaxrsAnnotationProcessorTest {
|
||||||
assertEquals(httpMethod.getHeaders().size(), 0);
|
assertEquals(httpMethod.getHeaders().size(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||||
|
public void testHostPrefixDotEmpty() throws SecurityException, NoSuchMethodException {
|
||||||
|
Method method = TestVirtualHost.class.getMethod("getPrefixDot", String.class, String.class);
|
||||||
|
URI endpoint = URI.create("http://localhost");
|
||||||
|
factory.create(TestVirtualHost.class).createRequest(endpoint, method,
|
||||||
|
new Object[] { "1", "" });
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expectedExceptions = NullPointerException.class)
|
||||||
|
public void testHostPrefixDotNull() throws SecurityException, NoSuchMethodException {
|
||||||
|
Method method = TestVirtualHost.class.getMethod("getPrefixDot", String.class, String.class);
|
||||||
|
URI endpoint = URI.create("http://localhost");
|
||||||
|
factory.create(TestVirtualHost.class).createRequest(endpoint, method,
|
||||||
|
new Object[] { "1", null });
|
||||||
|
}
|
||||||
|
|
||||||
public class TestHeaders {
|
public class TestHeaders {
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
|
|
Loading…
Reference in New Issue