Issue 76: added support for @Produces and @Consumes, replaced @EntityBinder with @DecoratorParam so that we can manipulate more things then just entities; organized rest module

git-svn-id: http://jclouds.googlecode.com/svn/trunk@1952 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
adrian.f.cole 2009-10-10 00:18:34 +00:00
parent b3a9e76d21
commit 5b7878b0ea
117 changed files with 1248 additions and 829 deletions

View File

@ -34,7 +34,7 @@ import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import org.jclouds.aws.s3.binders.S3ObjectBinder;
import org.jclouds.aws.s3.decorators.AddS3ObjectEntity;
import org.jclouds.aws.s3.domain.BucketMetadata;
import org.jclouds.aws.s3.domain.ListBucketResponse;
import org.jclouds.aws.s3.domain.ObjectMetadata;
@ -55,17 +55,17 @@ import org.jclouds.blobstore.functions.ThrowKeyNotFoundOn404;
import org.jclouds.http.functions.ParseETagHeader;
import org.jclouds.http.functions.ReturnFalseOn404;
import org.jclouds.http.options.GetOptions;
import org.jclouds.rest.Endpoint;
import org.jclouds.rest.EntityParam;
import org.jclouds.rest.ExceptionParser;
import org.jclouds.rest.HostPrefixParam;
import org.jclouds.rest.ParamParser;
import org.jclouds.rest.QueryParams;
import org.jclouds.rest.RequestFilters;
import org.jclouds.rest.ResponseParser;
import org.jclouds.rest.SkipEncoding;
import org.jclouds.rest.VirtualHost;
import org.jclouds.rest.XMLResponseParser;
import org.jclouds.rest.annotations.DecoratorParam;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.HostPrefixParam;
import org.jclouds.rest.annotations.ParamParser;
import org.jclouds.rest.annotations.QueryParams;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.ResponseParser;
import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.annotations.VirtualHost;
import org.jclouds.rest.annotations.XMLResponseParser;
/**
* Provides access to S3 via their REST API.
@ -181,7 +181,7 @@ public interface S3BlobStore extends BlobStore<BucketMetadata, ObjectMetadata, S
@ResponseParser(ParseETagHeader.class)
Future<byte[]> putBlob(
@HostPrefixParam String bucketName,
@PathParam("key") @ParamParser(BlobKey.class) @EntityParam(S3ObjectBinder.class) S3Object object);
@PathParam("key") @ParamParser(BlobKey.class) @DecoratorParam(AddS3ObjectEntity.class) S3Object object);
@PUT
@Path("/")

View File

@ -34,8 +34,8 @@ import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import org.jclouds.aws.s3.binders.AccessControlListBinder;
import org.jclouds.aws.s3.binders.S3ObjectBinder;
import org.jclouds.aws.s3.decorators.AddACLAsXMLEntity;
import org.jclouds.aws.s3.decorators.AddS3ObjectEntity;
import org.jclouds.aws.s3.domain.AccessControlList;
import org.jclouds.aws.s3.domain.BucketMetadata;
import org.jclouds.aws.s3.domain.ListBucketResponse;
@ -62,21 +62,18 @@ import org.jclouds.blobstore.functions.ThrowKeyNotFoundOn404;
import org.jclouds.http.functions.ParseETagHeader;
import org.jclouds.http.functions.ReturnFalseOn404;
import org.jclouds.http.options.GetOptions;
import org.jclouds.rest.Endpoint;
import org.jclouds.rest.EntityParam;
import org.jclouds.rest.ExceptionParser;
import org.jclouds.rest.Headers;
import org.jclouds.rest.HostPrefixParam;
import org.jclouds.rest.ParamParser;
import org.jclouds.rest.QueryParams;
import org.jclouds.rest.RequestFilters;
import org.jclouds.rest.ResponseParser;
import org.jclouds.rest.SkipEncoding;
import org.jclouds.rest.VirtualHost;
import org.jclouds.rest.XMLResponseParser;
import org.jclouds.rest.binders.HttpRequestOptionsBinder;
import com.google.inject.internal.Nullable;
import org.jclouds.rest.annotations.DecoratorParam;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.Headers;
import org.jclouds.rest.annotations.HostPrefixParam;
import org.jclouds.rest.annotations.ParamParser;
import org.jclouds.rest.annotations.QueryParams;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.ResponseParser;
import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.annotations.VirtualHost;
import org.jclouds.rest.annotations.XMLResponseParser;
/**
* Provides access to S3 via their REST API.
@ -209,7 +206,7 @@ public interface S3Connection {
@ResponseParser(ParseETagHeader.class)
Future<byte[]> putObject(
@HostPrefixParam String bucketName,
@PathParam("key") @ParamParser(BlobKey.class) @EntityParam(S3ObjectBinder.class) S3Object object,
@PathParam("key") @ParamParser(BlobKey.class) @DecoratorParam(AddS3ObjectEntity.class) S3Object object,
PutObjectOptions... options);
/**
@ -237,7 +234,7 @@ public interface S3Connection {
@Path("/")
@ExceptionParser(ReturnTrueIfBucketAlreadyOwnedByYou.class)
Future<Boolean> putBucketIfNotExists(@HostPrefixParam String bucketName,
@Nullable @EntityParam(HttpRequestOptionsBinder.class) PutBucketOptions... options);
PutBucketOptions... options);
/**
* Deletes the bucket, if it is empty.
@ -378,7 +375,7 @@ public interface S3Connection {
@Path("/")
@QueryParams(keys = "acl")
Future<Boolean> putBucketACL(@HostPrefixParam String bucketName,
@EntityParam(AccessControlListBinder.class) AccessControlList acl);
@DecoratorParam(AddACLAsXMLEntity.class) AccessControlList acl);
/**
* A GET request operation directed at an object or bucket URI with the "acl" parameter retrieves
@ -421,6 +418,6 @@ public interface S3Connection {
@QueryParams(keys = "acl")
@Path("{key}")
Future<Boolean> putObjectACL(@HostPrefixParam String bucketName, @PathParam("key") String key,
@EntityParam(AccessControlListBinder.class) AccessControlList acl);
@DecoratorParam(AddACLAsXMLEntity.class) AccessControlList acl);
}

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.aws.s3.binders;
package org.jclouds.aws.s3.decorators;
import java.util.Properties;
@ -37,14 +37,14 @@ import org.jclouds.aws.s3.domain.AccessControlList.Grant;
import org.jclouds.aws.s3.domain.AccessControlList.GroupGrantee;
import org.jclouds.aws.s3.reference.S3Constants;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.binders.EntityBinder;
import org.jclouds.rest.decorators.RequestDecorator;
import org.jclouds.util.Utils;
import com.jamesmurty.utils.XMLBuilder;
public class AccessControlListBinder implements EntityBinder {
public class AddACLAsXMLEntity implements RequestDecorator {
public void addEntityToRequest(Object entity, HttpRequest request) {
public HttpRequest decorateRequest(HttpRequest request, Object entity) {
AccessControlList from = (AccessControlList) entity;
Properties outputProperties = new Properties();
outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
@ -57,6 +57,7 @@ public class AccessControlListBinder implements EntityBinder {
Utils.rethrowIfRuntime(e);
throw new RuntimeException("error transforming acl: " + from, e);
}
return request;
}
protected XMLBuilder generateBuilder(AccessControlList acl) throws ParserConfigurationException,

View File

@ -21,28 +21,27 @@
* under the License.
* ====================================================================
*/
package org.jclouds.aws.s3.binders;
package org.jclouds.aws.s3.decorators;
import static com.google.common.base.Preconditions.checkArgument;
import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX;
import javax.inject.Inject;
import javax.inject.Named;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.blobstore.binders.BlobBinder;
import org.jclouds.blobstore.decorators.AddBlobEntity;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.http.HttpRequest;
import javax.inject.Inject;
import javax.inject.Named;
public class S3ObjectBinder extends BlobBinder {
public class AddS3ObjectEntity extends AddBlobEntity {
@Inject
public S3ObjectBinder(@Named(PROPERTY_USER_METADATA_PREFIX) String metadataPrefix) {
public AddS3ObjectEntity(@Named(PROPERTY_USER_METADATA_PREFIX) String metadataPrefix) {
super(metadataPrefix);
}
public void addEntityToRequest(Object entity, HttpRequest request) {
public HttpRequest decorateRequest(HttpRequest request, Object entity) {
Blob<?> object = (Blob<?>) entity;
checkArgument(object.getMetadata().getSize() >= 0, "size must be set");
checkArgument(object.getContentLength() <= 5 * 1024 * 1024 * 1024,
@ -64,6 +63,6 @@ public class S3ObjectBinder extends BlobBinder {
s3Object.getMetadata().getContentEncoding());
}
}
super.addEntityToRequest(entity, request);
return super.decorateRequest(request, entity);
}
}

View File

@ -48,7 +48,7 @@ import java.util.SortedSet;
* @author Adrian Cole
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html" />
*/
public interface ListBucketResponse extends org.jclouds.rest.BoundedSortedSet<ObjectMetadata> {
public interface ListBucketResponse extends org.jclouds.rest.internal.BoundedSortedSet<ObjectMetadata> {
/**
* Example:

View File

@ -30,7 +30,7 @@ import java.util.SortedSet;
* @author Adrian Cole
*
*/
public class TreeSetListBucketResponse extends org.jclouds.rest.BoundedTreeSet<ObjectMetadata>
public class TreeSetListBucketResponse extends org.jclouds.rest.internal.BoundedTreeSet<ObjectMetadata>
implements ListBucketResponse {
/** The serialVersionUID */
private static final long serialVersionUID = -4475709781001190244L;

View File

@ -50,24 +50,24 @@ import org.jclouds.azure.storage.domain.BoundedSortedSet;
import org.jclouds.azure.storage.filters.SharedKeyAuthentication;
import org.jclouds.azure.storage.options.ListOptions;
import org.jclouds.azure.storage.reference.AzureStorageHeaders;
import org.jclouds.blobstore.binders.BlobBinder;
import org.jclouds.blobstore.binders.UserMetadataBinder;
import org.jclouds.blobstore.decorators.AddBlobEntity;
import org.jclouds.blobstore.decorators.AddHeadersWithPrefix;
import org.jclouds.blobstore.functions.BlobKey;
import org.jclouds.blobstore.functions.ReturnVoidOnNotFoundOr404;
import org.jclouds.blobstore.functions.ThrowKeyNotFoundOn404;
import org.jclouds.http.functions.ParseETagHeader;
import org.jclouds.http.functions.ReturnTrueOn404;
import org.jclouds.http.options.GetOptions;
import org.jclouds.rest.Endpoint;
import org.jclouds.rest.EntityParam;
import org.jclouds.rest.ExceptionParser;
import org.jclouds.rest.Headers;
import org.jclouds.rest.ParamParser;
import org.jclouds.rest.QueryParams;
import org.jclouds.rest.RequestFilters;
import org.jclouds.rest.ResponseParser;
import org.jclouds.rest.SkipEncoding;
import org.jclouds.rest.XMLResponseParser;
import org.jclouds.rest.annotations.DecoratorParam;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.Headers;
import org.jclouds.rest.annotations.ParamParser;
import org.jclouds.rest.annotations.QueryParams;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.ResponseParser;
import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.annotations.XMLResponseParser;
import com.google.common.collect.Multimap;
@ -144,7 +144,7 @@ public interface AzureBlobConnection {
@Path("{container}")
@QueryParams(keys = { "restype", "comp" }, values = { "container", "metadata" })
void setContainerMetadata(@PathParam("container") String container,
@EntityParam(UserMetadataBinder.class) Multimap<String, String> metadata);
@DecoratorParam(AddHeadersWithPrefix.class) Multimap<String, String> metadata);
/**
* The Delete Container operation marks the specified container for deletion. The container and
@ -272,7 +272,7 @@ public interface AzureBlobConnection {
@Path("{container}/{key}")
@ResponseParser(ParseETagHeader.class)
Future<byte[]> putBlob(@PathParam("container") String container,
@PathParam("key") @ParamParser(BlobKey.class) @EntityParam(BlobBinder.class) Blob object);
@PathParam("key") @ParamParser(BlobKey.class) @DecoratorParam(AddBlobEntity.class) Blob object);
/**
* The Get Blob operation reads or downloads a blob from the system, including its metadata and
@ -302,7 +302,7 @@ public interface AzureBlobConnection {
@Path("{container}/{key}")
@QueryParams(keys = { "comp" }, values = { "metadata" })
void setBlobMetadata(@PathParam("container") String container, @PathParam("key") String key,
@EntityParam(UserMetadataBinder.class) Multimap<String, String> metadata);
@DecoratorParam(AddHeadersWithPrefix.class) Multimap<String, String> metadata);
/**
* The Delete Blob operation marks the specified blob for deletion. The blob is later deleted

View File

@ -35,11 +35,11 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import org.jclouds.azure.storage.AzureBlob;
import org.jclouds.azure.storage.blob.decorators.GenerateMD5AndAddBlobEntity;
import org.jclouds.azure.storage.blob.domain.Blob;
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
import org.jclouds.azure.storage.blob.domain.ListBlobsResponse;
import org.jclouds.azure.storage.blob.functions.MD5EnforcingBlobBinder;
import org.jclouds.azure.storage.blob.functions.ParseBlobFromHeadersAndHttpContent;
import org.jclouds.azure.storage.blob.functions.ParseBlobMetadataFromHeaders;
import org.jclouds.azure.storage.blob.functions.ReturnTrueIfContainerAlreadyExists;
@ -56,16 +56,16 @@ import org.jclouds.blobstore.functions.ThrowKeyNotFoundOn404;
import org.jclouds.http.functions.ParseETagHeader;
import org.jclouds.http.functions.ReturnFalseOn404;
import org.jclouds.http.options.GetOptions;
import org.jclouds.rest.Endpoint;
import org.jclouds.rest.EntityParam;
import org.jclouds.rest.ExceptionParser;
import org.jclouds.rest.Headers;
import org.jclouds.rest.ParamParser;
import org.jclouds.rest.QueryParams;
import org.jclouds.rest.RequestFilters;
import org.jclouds.rest.ResponseParser;
import org.jclouds.rest.SkipEncoding;
import org.jclouds.rest.XMLResponseParser;
import org.jclouds.rest.annotations.DecoratorParam;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.Headers;
import org.jclouds.rest.annotations.ParamParser;
import org.jclouds.rest.annotations.QueryParams;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.ResponseParser;
import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.annotations.XMLResponseParser;
/**
* Provides access to Azure Blob via their REST API.
@ -149,7 +149,7 @@ public interface AzureBlobStore extends BlobStore<ContainerMetadata, BlobMetadat
@ResponseParser(ParseETagHeader.class)
Future<byte[]> putBlob(
@PathParam("container") String container,
@PathParam("key") @ParamParser(BlobKey.class) @EntityParam(MD5EnforcingBlobBinder.class) Blob object);
@PathParam("key") @ParamParser(BlobKey.class) @DecoratorParam(GenerateMD5AndAddBlobEntity.class) Blob object);
@GET
@ResponseParser(ParseBlobFromHeadersAndHttpContent.class)

View File

@ -33,12 +33,12 @@ import org.jclouds.azure.storage.filters.SharedKeyAuthentication;
import org.jclouds.azure.storage.reference.AzureStorageHeaders;
import org.jclouds.blobstore.functions.ThrowKeyNotFoundOn404;
import org.jclouds.http.functions.ParseContentMD5FromHeaders;
import org.jclouds.rest.Endpoint;
import org.jclouds.rest.ExceptionParser;
import org.jclouds.rest.Headers;
import org.jclouds.rest.RequestFilters;
import org.jclouds.rest.ResponseParser;
import org.jclouds.rest.SkipEncoding;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.Headers;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.ResponseParser;
import org.jclouds.rest.annotations.SkipEncoding;
/**
* Helper functions needed to to derive BlobStore values

View File

@ -21,27 +21,27 @@
* under the License.
* ====================================================================
*/
package org.jclouds.azure.storage.blob.binders;
package org.jclouds.azure.storage.blob.decorators;
import static com.google.common.base.Preconditions.checkArgument;
import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX;
import javax.inject.Inject;
import javax.inject.Named;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.http.HttpRequest;
import javax.inject.Inject;
import javax.inject.Named;
public class BlobBinder extends org.jclouds.blobstore.binders.BlobBinder {
public class AddBlobEntity extends org.jclouds.blobstore.decorators.AddBlobEntity {
@Inject
public BlobBinder(@Named(PROPERTY_USER_METADATA_PREFIX) String metadataPrefix) {
public AddBlobEntity(@Named(PROPERTY_USER_METADATA_PREFIX) String metadataPrefix) {
super(metadataPrefix);
}
public void addEntityToRequest(Object entity, HttpRequest request) {
@Override
public HttpRequest decorateRequest(HttpRequest request, Object entity) {
Blob<?> object = (Blob<?>) entity;
checkArgument(object.getMetadata().getSize() >= 0, "size must be set");
checkArgument(object.getContentLength() <= 64 * 1024 * 1024,
@ -57,6 +57,6 @@ public class BlobBinder extends org.jclouds.blobstore.binders.BlobBinder {
request.getHeaders().put(HttpHeaders.CONTENT_ENCODING, md.getContentEncoding());
}
}
super.addEntityToRequest(entity, request);
return super.decorateRequest(request, entity);
}
}

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.azure.storage.blob.functions;
package org.jclouds.azure.storage.blob.decorators;
import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX;
@ -30,18 +30,18 @@ import java.io.IOException;
import javax.inject.Inject;
import javax.inject.Named;
import org.jclouds.azure.storage.blob.binders.BlobBinder;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.http.HttpRequest;
public class MD5EnforcingBlobBinder extends BlobBinder {
public class GenerateMD5AndAddBlobEntity extends AddBlobEntity {
@Inject
public MD5EnforcingBlobBinder(@Named(PROPERTY_USER_METADATA_PREFIX) String metadataPrefix) {
public GenerateMD5AndAddBlobEntity(@Named(PROPERTY_USER_METADATA_PREFIX) String metadataPrefix) {
super(metadataPrefix);
}
public void addEntityToRequest(Object entity, HttpRequest request) {
@Override
public HttpRequest decorateRequest(HttpRequest request, Object entity) {
Blob<?> object = (Blob<?>) entity;
if (object.getMetadata().getContentMD5() == null) {
try {
@ -50,6 +50,6 @@ public class MD5EnforcingBlobBinder extends BlobBinder {
throw new RuntimeException("Could not generate MD5 for " + object.getKey(), e);
}
}
super.addEntityToRequest(entity, request);
return super.decorateRequest(request, entity);
}
}

View File

@ -36,7 +36,7 @@ import org.jclouds.http.HttpException;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpUtils;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.InvocationContext;
import org.jclouds.util.DateService;
import com.google.common.annotations.VisibleForTesting;
@ -50,7 +50,7 @@ import com.google.common.base.Function;
* @author Adrian Cole
*/
public class ParseContainerMetadataFromHeaders implements
Function<HttpResponse, ContainerMetadata>, RestContext {
Function<HttpResponse, ContainerMetadata>, InvocationContext {
private final DateService dateParser;
private final String metadataPrefix;

View File

@ -33,6 +33,7 @@ import java.net.URI;
import java.util.Collections;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.azure.storage.AzureBlob;
import org.jclouds.azure.storage.blob.functions.ParseContainerMetadataFromHeaders;
@ -52,8 +53,8 @@ import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.ReturnTrueIf2xx;
import org.jclouds.http.functions.ReturnTrueOn404;
import org.jclouds.http.functions.ReturnVoidIf2xx;
import org.jclouds.rest.JaxrsAnnotationProcessor;
import org.jclouds.rest.config.JaxrsModule;
import org.jclouds.rest.config.RestModule;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.jclouds.util.Jsr330;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@ -300,7 +301,9 @@ public class AzureBlobConnectionTest {
assertEquals(httpMethod.getEndpoint().getPath(), "/container");
assertEquals(httpMethod.getEndpoint().getQuery(), "restype=container&comp=metadata");
assertEquals(httpMethod.getMethod(), HttpMethod.PUT);
assertEquals(httpMethod.getHeaders().size(), 2);
assertEquals(httpMethod.getHeaders().size(), 3);
assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_LENGTH), Collections
.singletonList("0"));
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
.singletonList("2009-07-17"));
assertEquals(httpMethod.getHeaders().get("x-ms-meta-key"), Collections.singletonList("value"));
@ -319,9 +322,11 @@ public class AzureBlobConnectionTest {
assertEquals(httpMethod.getEndpoint().getPath(), "/container/blob");
assertEquals(httpMethod.getEndpoint().getQuery(), "comp=metadata");
assertEquals(httpMethod.getMethod(), HttpMethod.PUT);
assertEquals(httpMethod.getHeaders().size(), 2);
assertEquals(httpMethod.getHeaders().size(), 3);
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
.singletonList("2009-07-17"));
assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_LENGTH), Collections
.singletonList("0"));
assertEquals(httpMethod.getHeaders().get("x-ms-meta-key"), Collections.singletonList("value"));
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
@ -346,12 +351,12 @@ public class AzureBlobConnectionTest {
Jsr330.named(BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX)).to(
"x-ms-meta-");
}
}, new JaxrsModule(), new ExecutorServiceModule(new WithinThreadExecutorService()),
}, new RestModule(), new ExecutorServiceModule(new WithinThreadExecutorService()),
new JavaUrlHttpCommandExecutorServiceModule());
processor = injector.getInstance(Key
.get(new TypeLiteral<JaxrsAnnotationProcessor<AzureBlobConnection>>() {
.get(new TypeLiteral<RestAnnotationProcessor<AzureBlobConnection>>() {
}));
}
JaxrsAnnotationProcessor<AzureBlobConnection> processor;
RestAnnotationProcessor<AzureBlobConnection> processor;
}

View File

@ -49,8 +49,8 @@ import org.jclouds.http.functions.ParseETagHeader;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.ReturnTrueIf2xx;
import org.jclouds.http.functions.ReturnVoidIf2xx;
import org.jclouds.rest.JaxrsAnnotationProcessor;
import org.jclouds.rest.config.JaxrsModule;
import org.jclouds.rest.config.RestModule;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.jclouds.util.Jsr330;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@ -195,12 +195,12 @@ public class AzureBlobStoreTest {
};
}
}, new JaxrsModule(), new ExecutorServiceModule(new WithinThreadExecutorService()),
}, new RestModule(), new ExecutorServiceModule(new WithinThreadExecutorService()),
new JavaUrlHttpCommandExecutorServiceModule());
processor = injector.getInstance(Key
.get(new TypeLiteral<JaxrsAnnotationProcessor<AzureBlobStore>>() {
.get(new TypeLiteral<RestAnnotationProcessor<AzureBlobStore>>() {
}));
}
JaxrsAnnotationProcessor<AzureBlobStore> processor;
RestAnnotationProcessor<AzureBlobStore> processor;
}

View File

@ -28,7 +28,7 @@ package org.jclouds.azure.storage.domain;
* @author Adrian Cole
*
*/
public interface BoundedSortedSet<T> extends org.jclouds.rest.BoundedSortedSet<T> {
public interface BoundedSortedSet<T> extends org.jclouds.rest.internal.BoundedSortedSet<T> {
String getNextMarker();

View File

@ -30,7 +30,7 @@ import java.util.SortedSet;
* @author Adrian Cole
*
*/
public class BoundedTreeSet<T> extends org.jclouds.rest.BoundedTreeSet<T> implements
public class BoundedTreeSet<T> extends org.jclouds.rest.internal.BoundedTreeSet<T> implements
BoundedSortedSet<T> {
/** The serialVersionUID */
private static final long serialVersionUID = -4475709781001190244L;

View File

@ -37,11 +37,11 @@ import org.jclouds.concurrent.WithinThreadExecutorService;
import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.rest.Endpoint;
import org.jclouds.rest.QueryParams;
import org.jclouds.rest.RequestFilters;
import org.jclouds.rest.RestClientFactory;
import org.jclouds.rest.config.JaxrsModule;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.QueryParams;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.config.RestModule;
import org.jclouds.util.Jsr330;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@ -96,7 +96,7 @@ public class SharedKeyAuthenticationLiveTest {
Jsr330.named(AzureStorageConstants.PROPERTY_AZURESTORAGE_KEY)).to(key);
}
}, new JaxrsModule(), new Log4JLoggingModule(), new ExecutorServiceModule(
}, new RestModule(), new Log4JLoggingModule(), new ExecutorServiceModule(
new WithinThreadExecutorService()), new JavaUrlHttpCommandExecutorServiceModule());
RestClientFactory factory = injector.getInstance(RestClientFactory.class);
client = factory.create(IntegrationTestClient.class);

View File

@ -40,12 +40,12 @@ import org.jclouds.azure.storage.options.ListOptions;
import org.jclouds.azure.storage.queue.domain.QueueMetadata;
import org.jclouds.azure.storage.queue.xml.AccountNameEnumerationResultsHandler;
import org.jclouds.azure.storage.reference.AzureStorageHeaders;
import org.jclouds.rest.Endpoint;
import org.jclouds.rest.Headers;
import org.jclouds.rest.QueryParams;
import org.jclouds.rest.RequestFilters;
import org.jclouds.rest.SkipEncoding;
import org.jclouds.rest.XMLResponseParser;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.Headers;
import org.jclouds.rest.annotations.QueryParams;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.annotations.XMLResponseParser;
/**
* Provides access to Azure Queue via their REST API.

View File

@ -44,8 +44,8 @@ import org.jclouds.http.HttpUtils;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.ReturnTrueIf2xx;
import org.jclouds.rest.JaxrsAnnotationProcessor;
import org.jclouds.rest.config.JaxrsModule;
import org.jclouds.rest.config.RestModule;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.jclouds.util.Jsr330;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@ -177,12 +177,12 @@ public class AzureQueueConnectionTest {
Jsr330.named(AzureStorageConstants.PROPERTY_AZURESTORAGE_KEY)).to(
HttpUtils.toBase64String("key".getBytes()));
}
}, new JaxrsModule(), new ExecutorServiceModule(new WithinThreadExecutorService()),
}, new RestModule(), new ExecutorServiceModule(new WithinThreadExecutorService()),
new JavaUrlHttpCommandExecutorServiceModule());
processor = injector.getInstance(Key
.get(new TypeLiteral<JaxrsAnnotationProcessor<AzureQueueConnection>>() {
.get(new TypeLiteral<RestAnnotationProcessor<AzureQueueConnection>>() {
}));
}
JaxrsAnnotationProcessor<AzureQueueConnection> processor;
RestAnnotationProcessor<AzureQueueConnection> processor;
}

View File

@ -21,9 +21,9 @@
* under the License.
* ====================================================================
*/
package org.jclouds.blobstore.binders;
package org.jclouds.blobstore.decorators;
import static com.google.common.base.Preconditions.*;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX;
import javax.inject.Inject;
@ -33,17 +33,17 @@ import javax.ws.rs.core.HttpHeaders;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpUtils;
import org.jclouds.rest.binders.EntityBinder;
import org.jclouds.rest.decorators.RequestDecorator;
public class BlobBinder implements EntityBinder {
public class AddBlobEntity implements RequestDecorator {
private final String metadataPrefix;
@Inject
public BlobBinder(@Named(PROPERTY_USER_METADATA_PREFIX) String metadataPrefix) {
public AddBlobEntity(@Named(PROPERTY_USER_METADATA_PREFIX) String metadataPrefix) {
this.metadataPrefix = metadataPrefix;
}
public void addEntityToRequest(Object entity, HttpRequest request) {
public HttpRequest decorateRequest(HttpRequest request, Object entity) {
Blob<?> object = (Blob<?>) entity;
for (String key : object.getMetadata().getUserMetadata().keySet()) {
@ -63,6 +63,6 @@ public class BlobBinder implements EntityBinder {
request.getHeaders().put("Content-MD5",
HttpUtils.toBase64String(object.getMetadata().getContentMD5()));
}
return request;
}
}

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.binders;
package org.jclouds.blobstore.decorators;
import static com.google.common.base.Preconditions.checkNotNull;
@ -32,12 +32,12 @@ import java.io.InputStream;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.Key;
import org.jclouds.blobstore.util.BlobStoreUtils;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.MultipartForm;
import org.jclouds.http.MultipartForm.Part;
import org.jclouds.mezeo.pcs2.functions.Key;
import org.jclouds.mezeo.pcs2.util.PCSUtils;
import org.jclouds.rest.binders.EntityBinder;
import org.jclouds.rest.decorators.RequestDecorator;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
@ -46,13 +46,13 @@ import com.google.common.collect.Multimap;
*
* @author Adrian Cole
*/
public class PCSFileAsMultipartFormBinder implements EntityBinder {
public class AddBlobEntityAsMultipartForm implements RequestDecorator {
public static final String BOUNDARY = "--PCS--";
public static final String BOUNDARY = "--JCLOUDS--";
public void addEntityToRequest(Object entity, HttpRequest request) {
public HttpRequest decorateRequest(HttpRequest request, Object entity) {
Blob<?> object = (Blob<?>) entity;
Key key = PCSUtils.parseKey(new Key("junk", object.getKey()));
Key key = BlobStoreUtils.parseKey(new Key("junk", object.getKey()));
Multimap<String, String> partHeaders = ImmutableMultimap.of("Content-Disposition", String
.format("form-data; name=\"%s\"; filename=\"%s\"", key.getKey(), key.getKey()),
HttpHeaders.CONTENT_TYPE, checkNotNull(object.getMetadata().getContentType(),
@ -84,6 +84,6 @@ public class PCSFileAsMultipartFormBinder implements EntityBinder {
"multipart/form-data; boundary=" + BOUNDARY);
request.getHeaders().put(HttpHeaders.CONTENT_LENGTH, form.getSize() + "");
return request;
}
}

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.blobstore.binders;
package org.jclouds.blobstore.decorators;
import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX;
@ -31,20 +31,20 @@ import javax.inject.Inject;
import javax.inject.Named;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.binders.EntityBinder;
import org.jclouds.rest.decorators.RequestDecorator;
import com.google.common.collect.Multimap;
public class UserMetadataBinder implements EntityBinder {
public class AddHeadersWithPrefix implements RequestDecorator {
private final String metadataPrefix;
@Inject
public UserMetadataBinder(@Named(PROPERTY_USER_METADATA_PREFIX) String metadataPrefix) {
public AddHeadersWithPrefix(@Named(PROPERTY_USER_METADATA_PREFIX) String metadataPrefix) {
this.metadataPrefix = metadataPrefix;
}
@SuppressWarnings("unchecked")
public void addEntityToRequest(Object entity, HttpRequest request) {
public HttpRequest decorateRequest( HttpRequest request, Object entity) {
Multimap<String, String> userMetadata = (Multimap<String, String>) entity;
for (Entry<String, String> entry : userMetadata.entries()) {
if (entry.getKey().startsWith(metadataPrefix)) {
@ -54,6 +54,7 @@ public class UserMetadataBinder implements EntityBinder {
entry.getValue());
}
}
return request;
}
}

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.functions;
package org.jclouds.blobstore.domain;
public class Key {
private final String container;

View File

@ -38,13 +38,13 @@ import org.jclouds.blobstore.reference.BlobStoreConstants;
import org.jclouds.blobstore.strategy.ClearContainerStrategy;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponseException;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.InvocationContext;
import org.jclouds.util.Utils;
import com.google.common.base.Function;
public class ClearAndDeleteIfNotEmpty<C extends ContainerMetadata, M extends BlobMetadata, B extends Blob<M>>
implements Function<Exception, Void>, RestContext {
implements Function<Exception, Void>, InvocationContext {
static final Void v;
static {
Constructor<Void> cv;

View File

@ -32,7 +32,7 @@ import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.InvocationContext;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
@ -44,7 +44,7 @@ import com.google.common.base.Function;
* @author Adrian Cole
*/
public class ParseBlobFromHeadersAndHttpContent<M extends BlobMetadata, B extends Blob<M>>
implements Function<HttpResponse, B>, RestContext {
implements Function<HttpResponse, B>, InvocationContext {
private final ParseContentTypeFromHeaders<M> metadataParser;
private final Provider<B> blobFactory;

View File

@ -31,7 +31,7 @@ import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.InvocationContext;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
@ -40,7 +40,7 @@ import com.google.common.base.Function;
* @author Adrian Cole
*/
public class ParseContentTypeFromHeaders<M extends BlobMetadata> implements
Function<HttpResponse, M>, RestContext {
Function<HttpResponse, M>, InvocationContext {
private final Provider<M> metadataFactory;
private HttpRequest request;
private Object[] args;

View File

@ -44,7 +44,7 @@ import org.jclouds.blobstore.strategy.ContainerCountStrategy;
import org.jclouds.blobstore.strategy.ContainsValueStrategy;
import org.jclouds.blobstore.strategy.GetAllBlobMetadataStrategy;
import org.jclouds.blobstore.strategy.GetAllBlobsStrategy;
import org.jclouds.rest.BoundedSortedSet;
import org.jclouds.rest.internal.BoundedSortedSet;
import org.jclouds.util.Utils;
import com.google.common.collect.Sets;

View File

@ -30,6 +30,7 @@ import java.io.InputStream;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.domain.Key;
import org.jclouds.util.Utils;
/**
@ -39,6 +40,17 @@ import org.jclouds.util.Utils;
*/
public class BlobStoreUtils {
public static Key parseKey(Key key) {
if (key.getKey().indexOf('/') != -1) {
String container = key.getContainer() + '/'
+ key.getKey().substring(0, key.getKey().lastIndexOf('/'));
String newKey = key.getKey().substring(key.getKey().lastIndexOf('/') + 1);
key = new Key(container.replaceAll("//", "/"), newKey);
}
return key;
}
public static String getContentAsStringAndClose(Blob<? extends BlobMetadata> object)
throws IOException {
checkNotNull(object, "s3Object");

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.binders;
package org.jclouds.blobstore.decorators;
import static org.testng.Assert.assertEquals;
@ -32,8 +32,10 @@ import java.net.URI;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import org.jclouds.blobstore.decorators.AddBlobEntityAsMultipartForm;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.http.HttpRequest;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.jclouds.util.Utils;
import org.testng.annotations.Test;
@ -42,34 +44,34 @@ import org.testng.annotations.Test;
*
* @author Adrian Cole
*/
@Test(testName = "pcs2.PCSFileAsMultipartFormBinderTest")
public class PCSFileAsMultipartFormBinderTest {
@Test(testName = "blobstore.AddBlobEntityAsMultipartFormTest")
public class AddBlobEntityAsMultipartFormTest {
public static String BOUNDRY = PCSFileAsMultipartFormBinder.BOUNDARY;
public static String BOUNDRY = AddBlobEntityAsMultipartForm.BOUNDARY;
public static final String EXPECTS;
public static final PCSFile TEST_BLOB;
public static final Blob<BlobMetadata> TEST_BLOB;
static {
StringBuilder builder = new StringBuilder("--");
addData(BOUNDRY, "hello", builder);
builder.append("--").append(BOUNDRY).append("--").append("\r\n");
EXPECTS = builder.toString();
TEST_BLOB = new PCSFile("hello");
TEST_BLOB = new Blob<BlobMetadata>("hello");
TEST_BLOB.setData("hello");
TEST_BLOB.getMetadata().setContentType(MediaType.TEXT_PLAIN);
}
public void testSinglePart() throws IOException {
assertEquals(EXPECTS.length(), 123);
assertEquals(EXPECTS.length(), 131);
PCSFileAsMultipartFormBinder binder = new PCSFileAsMultipartFormBinder();
AddBlobEntityAsMultipartForm binder = new AddBlobEntityAsMultipartForm();
HttpRequest request = new HttpRequest("GET", URI.create("http://localhost:8001"));
binder.addEntityToRequest(TEST_BLOB, request);
binder.decorateRequest(request, TEST_BLOB);
assertEquals(Utils.toStringAndClose((InputStream) request.getEntity()), EXPECTS);
assertEquals(request.getFirstHeaderOrNull(HttpHeaders.CONTENT_LENGTH), 123 + "");
assertEquals(request.getFirstHeaderOrNull(HttpHeaders.CONTENT_LENGTH), 131 + "");
assertEquals(request.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE),
"multipart/form-data; boundary=" + BOUNDRY);

View File

@ -0,0 +1,28 @@
package org.jclouds.blobstore.util;
import static org.testng.Assert.assertEquals;
import org.jclouds.blobstore.domain.Key;
import org.testng.annotations.Test;
/**
* Tests behavior of {@code BlobStoreUtils}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "blobstore.BlobStoreUtilsTest")
public class BlobStoreUtilsTest {
public void testParseKey() {
Key key = BlobStoreUtils.parseKey(new Key("container", "key"));
assertEquals(key.getContainer(), "container");
assertEquals(key.getKey(), "key");
key = BlobStoreUtils.parseKey(new Key("container", "container/key"));
assertEquals(key.getContainer(), "container/container");
assertEquals(key.getKey(), "key");
key = BlobStoreUtils.parseKey(new Key("container", "/container/key"));
assertEquals(key.getContainer(), "container/container");
assertEquals(key.getKey(), "key");
}
}

View File

@ -52,7 +52,7 @@ import org.jclouds.http.config.ConfiguresHttpCommandExecutorService;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.logging.config.LoggingModule;
import org.jclouds.logging.jdk.config.JDKLoggingModule;
import org.jclouds.rest.config.JaxrsModule;
import org.jclouds.rest.config.RestModule;
import org.jclouds.util.Jsr330;
import com.google.common.annotations.VisibleForTesting;
@ -218,7 +218,7 @@ public abstract class CloudContextBuilder<C> {
}
})) {
modules.add(new JaxrsModule());
modules.add(new RestModule());
}
}

View File

@ -30,14 +30,14 @@ import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpUtils;
import org.jclouds.logging.Logger;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.InvocationContext;
import com.google.common.base.Function;
/**
* @author Adrian Cole
*/
public class ParseContentMD5FromHeaders implements Function<HttpResponse, byte[]>, RestContext {
public class ParseContentMD5FromHeaders implements Function<HttpResponse, byte[]>, InvocationContext {
public static class NoContentMD5Exception extends RuntimeException {

View File

@ -75,7 +75,7 @@ public abstract class BaseHttpCommandExecutorService<Q> implements HttpCommandEx
try {
logger.trace("%s - filtering request %s", request.getEndpoint(), request);
for (HttpRequestFilter filter : request.getFilters()) {
filter.filter(request);
request = filter.filter(request);
}
logger.trace("%s - request now %s", request.getEndpoint(), request);
nativeRequest = convert(request);

View File

@ -34,7 +34,7 @@ import org.jclouds.http.HttpRequest;
* @see PathParam
* @author Adrian Cole
*/
public interface RestContext {
public interface InvocationContext {
void setContext(HttpRequest request, Object[] args);
Object[] getArgs();

View File

@ -28,6 +28,8 @@ import java.lang.reflect.Proxy;
import javax.inject.Inject;
import org.jclouds.rest.internal.RestClientProxy;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rest;
package org.jclouds.rest.annotations;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@ -29,20 +29,20 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.jclouds.rest.binders.EntityBinder;
import org.jclouds.rest.binders.ToStringEntityBinder;
import org.jclouds.rest.decorators.RequestDecorator;
/**
* Designates that this parameter will hold the entity for a PUT or POST command.
* Designates that this parameter will modify the request, possibly including adding an entity to
* it.
*
* @author Adrian Cole
*/
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface EntityParam {
public @interface DecoratorParam {
/**
* how to persist this entity.
*/
Class<? extends EntityBinder> value() default ToStringEntityBinder.class;
Class<? extends RequestDecorator> value();
}

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rest;
package org.jclouds.rest.annotations;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rest;
package org.jclouds.rest.annotations;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rest;
package org.jclouds.rest.annotations;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rest;
package org.jclouds.rest.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rest;
package org.jclouds.rest.annotations;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@ -29,7 +29,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.jclouds.rest.binders.MapEntityBinder;
import org.jclouds.rest.decorators.MapRequestDecorator;
/**
* Designates that this parameter will hold the entity for a PUT or POST command.
@ -41,8 +41,8 @@ import org.jclouds.rest.binders.MapEntityBinder;
public @interface MapBinder {
/**
* How to bind {@link MapEntityParam} values, if there is no {@link MapEntityBinder} in the method
* How to bind {@link MapEntityParam} values, if there is no {@link MapRequestDecorator} in the method
* definition
*/
Class<? extends MapEntityBinder> value();
Class<? extends MapRequestDecorator> value();
}

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rest;
package org.jclouds.rest.annotations;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@ -39,7 +39,7 @@ import java.lang.annotation.Target;
public @interface MapEntityParam {
/**
* The key used in a map passed to the {@link MapEntityBinder} associated with the request.
* The key used in a map passed to the {@link MapRequestDecorator} associated with the request.
*/
String value();
}

View File

@ -0,0 +1,50 @@
/**
*
* 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.annotations;
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.MatrixParam;
/**
* Designates that a matrix param will be added to the request.
*
* @see MatrixParam
* @author Adrian Cole
*/
@Target( { TYPE, METHOD })
@Retention(RUNTIME)
public @interface MatrixParams {
public static final String NULL = "MATRIX_NULL";
String[] keys();
String[] values() default NULL;
}

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rest;
package org.jclouds.rest.annotations;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rest;
package org.jclouds.rest.annotations;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rest;
package org.jclouds.rest.annotations;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rest;
package org.jclouds.rest.annotations;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rest;
package org.jclouds.rest.annotations;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rest;
package org.jclouds.rest.annotations;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.ElementType.METHOD;

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rest;
package org.jclouds.rest.annotations;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

View File

@ -1,49 +0,0 @@
/**
*
* 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.binders;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.options.HttpRequestOptions;
import javax.inject.Singleton;
/**
* Adds an entity to a request.
*
* @author Adrian Cole
*/
@Singleton
public class HttpRequestOptionsBinder implements EntityBinder {
public void addEntityToRequest(Object entity, HttpRequest request) {
HttpRequestOptions options = (HttpRequestOptions) entity;
String stringEntity = options.buildStringEntity();
if (stringEntity != null) {
request.getHeaders().put(HttpHeaders.CONTENT_TYPE, "application/unknown");
request.getHeaders().put(HttpHeaders.CONTENT_LENGTH, stringEntity.getBytes().length + "");
request.setEntity(stringEntity);
}
}
}

View File

@ -28,7 +28,7 @@ import javax.ws.rs.ext.RuntimeDelegate;
import org.jclouds.http.TransformingHttpCommand;
import org.jclouds.http.TransformingHttpCommandImpl;
import org.jclouds.http.functions.config.ParserModule;
import org.jclouds.rest.RuntimeDelegateImpl;
import org.jclouds.rest.internal.RuntimeDelegateImpl;
import com.google.inject.AbstractModule;
import com.google.inject.TypeLiteral;
@ -38,7 +38,7 @@ import com.google.inject.assistedinject.FactoryProvider;
*
* @author Adrian Cole
*/
public class JaxrsModule extends AbstractModule {
public class RestModule extends AbstractModule {
private final static TypeLiteral<TransformingHttpCommand.Factory> httpCommandFactoryLiteral = new TypeLiteral<TransformingHttpCommand.Factory>() {
};

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rest.binders;
package org.jclouds.rest.decorators;
import static com.google.common.base.Preconditions.checkState;
@ -42,16 +42,16 @@ import com.google.gson.Gson;
* @author Adrian Cole
* @since 4.0
*/
public class JsonBinder implements MapEntityBinder {
public class AddAsJsonEntity implements MapRequestDecorator {
@Inject
protected Gson gson;
public void addEntityToRequest(Map<String, String> postParams, HttpRequest request) {
addEntityToRequest((Object) postParams, request);
public HttpRequest decorateRequest(HttpRequest request, Map<String, String> postParams) {
return decorateRequest(request, (Object) postParams);
}
public void addEntityToRequest(Object toBind, HttpRequest request) {
public HttpRequest decorateRequest(HttpRequest request, Object toBind) {
checkState(gson != null, "Program error: gson should have been injected at this point");
String json = gson.toJson(toBind);
request.setEntity(json);
@ -59,6 +59,7 @@ public class JsonBinder implements MapEntityBinder {
Collections.singletonList(json.getBytes().length + ""));
request.getHeaders().replaceValues(HttpHeaders.CONTENT_TYPE,
Collections.singletonList(MediaType.APPLICATION_JSON));
return request;
}
}

View File

@ -21,25 +21,26 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rest.binders;
package org.jclouds.rest.decorators;
import javax.inject.Singleton;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.http.HttpRequest;
import javax.inject.Singleton;
/**
* Adds an entity to a request.
*
* @author Adrian Cole
*/
@Singleton
public class ToStringEntityBinder implements EntityBinder {
public void addEntityToRequest(Object entity, HttpRequest request) {
public class AddAsStringEntity implements RequestDecorator {
public HttpRequest decorateRequest(HttpRequest request, Object entity) {
String stringEntity = entity.toString();
request.getHeaders().put(HttpHeaders.CONTENT_TYPE, "application/unknown");
if (request.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE) == null)
request.getHeaders().put(HttpHeaders.CONTENT_TYPE, "application/unknown");
request.getHeaders().put(HttpHeaders.CONTENT_LENGTH, stringEntity.getBytes().length + "");
request.setEntity(stringEntity);
return request;
}
}

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rest.binders;
package org.jclouds.rest.decorators;
import java.util.Map;
@ -33,13 +33,13 @@ import org.jclouds.http.HttpRequest;
* @author Adrian Cole
*
*/
public interface MapEntityBinder extends EntityBinder {
public interface MapRequestDecorator extends RequestDecorator {
/**
* creates and binds the POST entity to the request using parameters specified.
*
* @see MapEntityParam
*/
public void addEntityToRequest(Map<String,String> postParams, HttpRequest request);
public HttpRequest decorateRequest(HttpRequest request, Map<String, String> postParams);
}

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rest.binders;
package org.jclouds.rest.decorators;
import org.jclouds.http.HttpRequest;
@ -30,6 +30,6 @@ import org.jclouds.http.HttpRequest;
*
* @author Adrian Cole
*/
public interface EntityBinder {
public void addEntityToRequest(Object toBind, HttpRequest request);
public interface RequestDecorator {
public HttpRequest decorateRequest(HttpRequest request, Object input);
}

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rest;
package org.jclouds.rest.internal;
import java.util.SortedSet;

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rest;
package org.jclouds.rest.internal;
import java.util.SortedSet;
import java.util.TreeSet;

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rest;
package org.jclouds.rest.internal;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
@ -33,7 +33,9 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@ -45,8 +47,11 @@ import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.ws.rs.Consumes;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.MatrixParam;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.UriBuilder;
@ -65,9 +70,24 @@ import org.jclouds.http.functions.ReturnVoidIf2xx;
import org.jclouds.http.functions.ParseSax.HandlerWithResult;
import org.jclouds.http.options.HttpRequestOptions;
import org.jclouds.logging.Logger;
import org.jclouds.rest.binders.EntityBinder;
import org.jclouds.rest.binders.HttpRequestOptionsBinder;
import org.jclouds.rest.binders.MapEntityBinder;
import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.annotations.DecoratorParam;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.Headers;
import org.jclouds.rest.annotations.HostPrefixParam;
import org.jclouds.rest.annotations.MapBinder;
import org.jclouds.rest.annotations.MapEntityParam;
import org.jclouds.rest.annotations.MatrixParams;
import org.jclouds.rest.annotations.ParamParser;
import org.jclouds.rest.annotations.QueryParams;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.ResponseParser;
import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.annotations.VirtualHost;
import org.jclouds.rest.annotations.XMLResponseParser;
import org.jclouds.rest.decorators.MapRequestDecorator;
import org.jclouds.rest.decorators.RequestDecorator;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
@ -89,17 +109,18 @@ import com.google.inject.internal.Lists;
* @author Adrian Cole
*/
@Singleton
public class JaxrsAnnotationProcessor<T> {
public class RestAnnotationProcessor<T> {
@Resource
protected Logger logger = Logger.NULL;
private final Class<T> declaring;
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToEntityAnnotation = createMethodToIndexOfParamToAnnotation(EntityParam.class);
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToDecoratorParamAnnotation = createMethodToIndexOfParamToAnnotation(DecoratorParam.class);
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToHeaderParamAnnotations = createMethodToIndexOfParamToAnnotation(HeaderParam.class);
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToHostPrefixParamAnnotations = createMethodToIndexOfParamToAnnotation(HostPrefixParam.class);
private final Map<Method, Map<Integer, Set<Annotation>>> methodToindexOfParamToEndpointAnnotations = createMethodToIndexOfParamToAnnotation(Endpoint.class);
private final Map<Method, Map<Integer, Set<Annotation>>> methodToindexOfParamToMatrixParamAnnotations = createMethodToIndexOfParamToAnnotation(MatrixParam.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(MapEntityParam.class);
@ -172,8 +193,8 @@ public class JaxrsAnnotationProcessor<T> {
} else {
transformer = injector.getInstance(getParserOrThrowException(method));
}
if (transformer instanceof RestContext) {
((RestContext) transformer).setContext(request, args);
if (transformer instanceof InvocationContext) {
((InvocationContext) transformer).setContext(request, args);
}
return transformer;
}
@ -189,16 +210,15 @@ public class JaxrsAnnotationProcessor<T> {
@SuppressWarnings("unchecked")
@Inject
public JaxrsAnnotationProcessor(Injector injector, ParseSax.Factory parserFactory,
public RestAnnotationProcessor(Injector injector, ParseSax.Factory parserFactory,
TypeLiteral<T> typeLiteral) {
this.declaring = (Class<T>) typeLiteral.getRawType();
this.injector = injector;
this.parserFactory = parserFactory;
this.optionsBinder = injector.getInstance(HttpRequestOptionsBinder.class);
seedCache(declaring);
}
protected Method getDelegateOrNull(Method in) {
public Method getDelegateOrNull(Method in) {
return delegationMap.get(new MethodKey(in));
}
@ -208,9 +228,10 @@ public class JaxrsAnnotationProcessor<T> {
for (Method method : methods) {
if (isHttpMethod(method)) {
for (int index = 0; index < method.getParameterTypes().length; index++) {
methodToIndexOfParamToEntityAnnotation.get(method).get(index);
methodToIndexOfParamToDecoratorParamAnnotation.get(method).get(index);
methodToIndexOfParamToHeaderParamAnnotations.get(method).get(index);
methodToIndexOfParamToHostPrefixParamAnnotations.get(method).get(index);
methodToindexOfParamToMatrixParamAnnotations.get(method).get(index);
methodToindexOfParamToQueryParamAnnotations.get(method).get(index);
methodToindexOfParamToEndpointAnnotations.get(method).get(index);
methodToindexOfParamToPathParamAnnotations.get(method).get(index);
@ -272,8 +293,6 @@ public class JaxrsAnnotationProcessor<T> {
final Injector injector;
private HttpRequestOptionsBinder optionsBinder;
public HttpRequest createRequest(Method method, Object[] args) {
URI endpoint = getEndpointFor(method, args);
@ -283,68 +302,116 @@ public class JaxrsAnnotationProcessor<T> {
builder.path(declaring);
builder.path(method);
if (declaring.isAnnotationPresent(QueryParams.class)) {
QueryParams query = declaring.getAnnotation(QueryParams.class);
addQuery(builder, query);
Multimap<String, String> tokenValues;
if (declaring.isAnnotationPresent(SkipEncoding.class)) {
tokenValues = encodeValues(getPathParamKeyValues(method, args), declaring.getAnnotation(
SkipEncoding.class).value());
} else {
tokenValues = encodeValues(getPathParamKeyValues(method, args));
}
if (method.isAnnotationPresent(QueryParams.class)) {
QueryParams query = method.getAnnotation(QueryParams.class);
addQuery(builder, query);
}
addQueryParams(method, args, builder, tokenValues.entries());
addMatrixParams(method, args, builder, tokenValues.entries());
for (Entry<String, String> query : getQueryParamKeyValues(method, args).entrySet()) {
builder.queryParam(query.getKey(), query.getValue());
}
Multimap<String, String> headers = buildHeaders(method, args);
Multimap<String, String> headers = buildHeaders(method, args, tokenValues.entries());
String stringEntity = null;
HttpRequestOptions options = findOptionsIn(method, args);
if (options != null) {
injector.injectMembers(options);// TODO test case
headers.putAll(options.buildRequestHeaders());
for (Entry<String, String> header : options.buildRequestHeaders().entries()) {
headers.put(header.getKey(), replaceTokens(header.getValue(), tokenValues.entries()));
}
for (Entry<String, String> query : options.buildQueryParameters().entries()) {
builder.queryParam(query.getKey(), query.getValue());
builder.queryParam(query.getKey(), replaceTokens(query.getValue(), tokenValues
.entries()));
}
for (Entry<String, String> matrix : options.buildMatrixParameters().entries()) {
builder.matrixParam(matrix.getKey(), matrix.getValue());
builder.matrixParam(matrix.getKey(), replaceTokens(matrix.getValue(), tokenValues
.entries()));
}
String pathSuffix = options.buildPathSuffix();
if (pathSuffix != null) {
builder.path(pathSuffix);
}
stringEntity = options.buildStringEntity();
if (stringEntity != null) {
headers.put(HttpHeaders.CONTENT_LENGTH, stringEntity.getBytes().length + "");
}
}
URI endPoint;
try {
addHeaderIfAnnotationPresentOnMethod(headers, method, args);
if (declaring.isAnnotationPresent(SkipEncoding.class)) {
endPoint = builder.buildFromEncodedMap(getEncodedPathParamKeyValues(method, args,
declaring.getAnnotation(SkipEncoding.class).value()));
} else {
endPoint = builder.buildFromEncodedMap(getEncodedPathParamKeyValues(method, args));
}
endPoint = builder.buildFromEncodedMap(convertUnsafe(tokenValues));
} catch (IllegalArgumentException e) {
throw new IllegalStateException(e);
} catch (UriBuilderException e) {
throw new IllegalStateException(e);
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException(e);
}
HttpRequest request = new HttpRequest(httpMethod, endPoint, headers);
addHostHeaderIfAnnotatedWithVirtualHost(headers, request.getEndpoint().getHost(), method);
addFiltersIfAnnotated(method, request);
buildEntityIfPostOrPutRequest(method, args, request);
return request;
if (stringEntity != null) {
request.setEntity(stringEntity);
if (headers.get(HttpHeaders.CONTENT_TYPE) != null)
headers.put(HttpHeaders.CONTENT_TYPE, "application/unknown");
}
return decorateRequest(method, args, request);
}
private void addQuery(UriBuilder builder, QueryParams query) {
private void addMatrixParams(Method method, Object[] args, UriBuilder builder,
Collection<Entry<String, String>> tokenValues) {
if (declaring.isAnnotationPresent(MatrixParams.class)) {
MatrixParams query = declaring.getAnnotation(MatrixParams.class);
addMatrix(builder, query, tokenValues);
}
if (method.isAnnotationPresent(MatrixParams.class)) {
MatrixParams query = method.getAnnotation(MatrixParams.class);
addMatrix(builder, query, tokenValues);
}
for (Entry<String, String> query : getMatrixParamKeyValues(method, args).entries()) {
builder.queryParam(query.getKey(), replaceTokens(query.getValue(), tokenValues));
}
}
private void addQueryParams(Method method, Object[] args, UriBuilder builder,
Collection<Entry<String, String>> tokenValues) {
if (declaring.isAnnotationPresent(QueryParams.class)) {
QueryParams query = declaring.getAnnotation(QueryParams.class);
addQuery(builder, query, tokenValues);
}
if (method.isAnnotationPresent(QueryParams.class)) {
QueryParams query = method.getAnnotation(QueryParams.class);
addQuery(builder, query, tokenValues);
}
for (Entry<String, String> query : getQueryParamKeyValues(method, args).entries()) {
builder.queryParam(query.getKey(), replaceTokens(query.getValue(), tokenValues));
}
}
private void addQuery(UriBuilder builder, QueryParams query,
Collection<Entry<String, String>> tokenValues) {
for (int i = 0; i < query.keys().length; i++) {
if (query.values()[i].equals(QueryParams.NULL)) {
builder.replaceQuery(query.keys()[i]);
} else {
builder.queryParam(query.keys()[i], query.values()[i]);
builder.queryParam(query.keys()[i], replaceTokens(query.values()[i], tokenValues));
}
}
}
private void addMatrix(UriBuilder builder, MatrixParams matrix,
Collection<Entry<String, String>> tokenValues) {
for (int i = 0; i < matrix.keys().length; i++) {
if (matrix.values()[i].equals(MatrixParams.NULL)) {
builder.replaceMatrix(matrix.keys()[i]);
} else {
builder.matrixParam(matrix.keys()[i], replaceTokens(matrix.values()[i], tokenValues));
}
}
}
@ -461,27 +528,27 @@ public class JaxrsAnnotationProcessor<T> {
return null;
}
public MapEntityBinder getMapEntityBinderOrNull(Method method, Object[] args) {
public MapRequestDecorator getMapEntityBinderOrNull(Method method, Object[] args) {
if (args != null) {
for (Object arg : args) {
if (arg instanceof Object[]) {
Object[] postBinders = (Object[]) arg;
if (postBinders.length == 0) {
} else if (postBinders.length == 1) {
if (postBinders[0] instanceof MapEntityBinder) {
MapEntityBinder binder = (MapEntityBinder) postBinders[0];
if (postBinders[0] instanceof MapRequestDecorator) {
MapRequestDecorator binder = (MapRequestDecorator) postBinders[0];
injector.injectMembers(binder);
return binder;
}
} else {
if (postBinders[0] instanceof MapEntityBinder) {
if (postBinders[0] instanceof MapRequestDecorator) {
throw new IllegalArgumentException(
"we currently do not support multiple varargs postBinders in: "
+ method.getName());
}
}
} else if (arg instanceof MapEntityBinder) {
MapEntityBinder binder = (MapEntityBinder) arg;
} else if (arg instanceof MapRequestDecorator) {
MapRequestDecorator binder = (MapRequestDecorator) arg;
injector.injectMembers(binder);
return binder;
}
@ -494,7 +561,7 @@ public class JaxrsAnnotationProcessor<T> {
return null;
}
private Map<String, String> constants = Maps.newHashMap();
private Multimap<String, String> constants = HashMultimap.create();
public boolean isHttpMethod(Method method) {
return IsHttpMethod.getHttpMethods(method) != null;
@ -528,49 +595,41 @@ public class JaxrsAnnotationProcessor<T> {
}
}
public HttpRequest buildEntityIfPostOrPutRequest(Method method, Object[] args,
HttpRequest request) {
OUTER: if (request.getMethod().toUpperCase().equals("POST")
|| request.getMethod().toUpperCase().equals("PUT")) {
MapEntityBinder mapBinder = getMapEntityBinderOrNull(method, args);
Map<String, String> mapParams = buildPostParams(method, args);
// MapEntityBinder is only useful if there are parameters. We guard here in case the
// MapEntityBinder is also an EntityBinder. If so, it can be used with or without
// parameters.
if (mapBinder != null) {
mapBinder.addEntityToRequest(mapParams, request);
break OUTER;
}
HttpRequestOptions options = findOptionsIn(method, args);
if (options != null) {
optionsBinder.addEntityToRequest(options, request);
}
if (request.getEntity() == null) {
public HttpRequest decorateRequest(Method method, Object[] args, HttpRequest request) {
MapRequestDecorator mapBinder = getMapEntityBinderOrNull(method, args);
Map<String, String> mapParams = buildPostParams(method, args);
// MapEntityBinder is only useful if there are parameters. We guard here in case the
// MapEntityBinder is also an EntityBinder. If so, it can be used with or without
// parameters.
if (mapBinder != null) {
mapBinder.decorateRequest(request, mapParams);
return request;
}
Map<Integer, Set<Annotation>> indexToEntityAnnotation = indexWithOnlyOneAnnotation(
method, "@Entity", methodToIndexOfParamToEntityAnnotation);
if (indexToEntityAnnotation.size() == 1) {
Entry<Integer, Set<Annotation>> entry = indexToEntityAnnotation.entrySet()
.iterator().next();
EntityParam entityAnnotation = (EntityParam) entry.getValue().iterator().next();
EntityBinder binder = injector.getInstance(entityAnnotation.value());
Object entity = args[entry.getKey()];
if (entity.getClass().isArray()) {
Object[] entityArray = (Object[]) entity;
entity = entityArray.length > 0 ? entityArray[0] : null;
}
if (entity != null)
binder.addEntityToRequest(entity, request);
} else if (indexToEntityAnnotation.size() > 1) {
throw new IllegalStateException("cannot have multiple @Entity annotations on "
+ method);
} else {
request.getHeaders().replaceValues(HttpHeaders.CONTENT_LENGTH,
Lists.newArrayList("0"));
}
for (Entry<Integer, Set<Annotation>> entry : Maps.filterValues(
methodToIndexOfParamToDecoratorParamAnnotation.get(method),
new Predicate<Set<Annotation>>() {
public boolean apply(Set<Annotation> input) {
return input.size() >= 1;
}
}).entrySet()) {
DecoratorParam entityAnnotation = (DecoratorParam) entry.getValue().iterator().next();
RequestDecorator binder = injector.getInstance(entityAnnotation.value());
Object input = args[entry.getKey()];
if (input.getClass().isArray()) {
Object[] entityArray = (Object[]) input;
input = entityArray.length > 0 ? entityArray[0] : null;
}
Object oldEntity = request.getEntity();
request = binder.decorateRequest(request, input);
if (oldEntity != null && !oldEntity.equals(request.getEntity())) {
throw new IllegalStateException(String.format(
"binder %s replaced the previous entity on request: %s", binder, request));
}
}
if (request.getMethod().equals("PUT") && request.getEntity() == null) {
request.getHeaders().replaceValues(HttpHeaders.CONTENT_LENGTH,
Collections.singletonList(0 + ""));
}
return request;
}
@ -619,46 +678,85 @@ public class JaxrsAnnotationProcessor<T> {
return null;
}
public Multimap<String, String> buildHeaders(Method method, final Object[] args) {
public Multimap<String, String> buildHeaders(Method method, final Object[] args,
Collection<Entry<String, String>> tokenValues) {
Multimap<String, String> headers = HashMultimap.create();
addHeaderIfAnnotationPresentOnMethod(headers, method, tokenValues);
Map<Integer, Set<Annotation>> indexToHeaderParam = methodToIndexOfParamToHeaderParamAnnotations
.get(method);
for (Entry<Integer, Set<Annotation>> entry : indexToHeaderParam.entrySet()) {
for (Annotation key : entry.getValue()) {
headers.put(((HeaderParam) key).value(), args[entry.getKey()].toString());
String value = args[entry.getKey()].toString();
value = replaceTokens(value, tokenValues);
headers.put(((HeaderParam) key).value(), value);
}
}
addProducesIfPresentOnTypeOrMethod(headers, method);
addConsumesIfPresentOnTypeOrMethod(headers, method);
return headers;
}
public void addHeaderIfAnnotationPresentOnMethod(Multimap<String, String> headers,
Method method, Object[] args, char... skipEncode) throws UnsupportedEncodingException {
if (declaring.isAnnotationPresent(Headers.class)) {
Headers header = declaring.getAnnotation(Headers.class);
addHeader(headers, method, args, header);
void addConsumesIfPresentOnTypeOrMethod(Multimap<String, String> headers, Method method) {
if (declaring.isAnnotationPresent(Consumes.class)) {
Consumes header = declaring.getAnnotation(Consumes.class);
headers.replaceValues(HttpHeaders.ACCEPT, Arrays.asList(header.value()));
}
if (method.isAnnotationPresent(Headers.class)) {
Headers header = method.getAnnotation(Headers.class);
addHeader(headers, method, args, header);
if (method.isAnnotationPresent(Consumes.class)) {
Consumes header = method.getAnnotation(Consumes.class);
headers.replaceValues(HttpHeaders.ACCEPT, Arrays.asList(header.value()));
}
}
private void addHeader(Multimap<String, String> headers, Method method, Object[] args,
Headers header) throws UnsupportedEncodingException {
void addProducesIfPresentOnTypeOrMethod(Multimap<String, String> headers, Method method) {
if (declaring.isAnnotationPresent(Produces.class)) {
Produces header = declaring.getAnnotation(Produces.class);
headers.replaceValues(HttpHeaders.CONTENT_TYPE, Arrays.asList(header.value()));
}
if (method.isAnnotationPresent(Produces.class)) {
Produces header = method.getAnnotation(Produces.class);
headers.replaceValues(HttpHeaders.CONTENT_TYPE, Arrays.asList(header.value()));
}
}
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);
}
if (method.isAnnotationPresent(Headers.class)) {
Headers header = method.getAnnotation(Headers.class);
addHeader(headers, header, tokenValues);
}
}
private void addHeader(Multimap<String, String> headers, Headers header,
Collection<Entry<String, String>> tokenValues) {
for (int i = 0; i < header.keys().length; i++) {
String value = header.values()[i];
for (Entry<String, String> tokenValue : getEncodedPathParamKeyValues(method, args)
.entrySet()) {
value = value.replaceAll("\\{" + tokenValue.getKey() + "\\}", tokenValue.getValue());
}
value = replaceTokens(value, tokenValues);
headers.put(header.keys()[i], value);
}
}
private Map<String, String> getEncodedPathParamKeyValues(Method method, Object[] args,
final char... skipEncode) throws UnsupportedEncodingException {
Map<String, String> pathParamValues = Maps.newHashMap();
private String replaceTokens(String value, Collection<Entry<String, String>> tokenValues) {
for (Entry<String, String> tokenValue : tokenValues) {
value = value.replaceAll("\\{" + tokenValue.getKey() + "\\}", tokenValue.getValue());
}
return value;
}
private Map<String, String> convertUnsafe(Multimap<String, String> in) {
Map<String, String> out = Maps.newHashMap();
for (Entry<String, String> entry : in.entries()) {
out.put(entry.getKey(), entry.getValue());
}
return out;
}
private Multimap<String, String> getPathParamKeyValues(Method method, Object[] args) {
Multimap<String, String> pathParamValues = HashMultimap.create();
pathParamValues.putAll(constants);
Map<Integer, Set<Annotation>> indexToPathParam = methodToindexOfParamToPathParamAnnotations
.get(method);
@ -686,30 +784,50 @@ public class JaxrsAnnotationProcessor<T> {
String paramValue = injector.getInstance(method.getAnnotation(ParamParser.class).value())
.apply(args);
pathParamValues.put(paramKey, paramValue);
}
return Maps.transformValues(pathParamValues, new Function<String, String>() {
public String apply(String paramValue) {
try {
paramValue = URLEncoder.encode(paramValue, "UTF-8");
// Web browsers do not always handle '+' characters well, use the well-supported
// '%20' instead.
paramValue = paramValue.replaceAll("\\+", "%20");
for (char c : skipEncode) {
String value = Character.toString(c);
String encoded = URLEncoder.encode(value, "UTF-8");
paramValue = paramValue.replaceAll(encoded, value);
}
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("jclouds only supports UTF-8", e);
}
return paramValue;
}
});
}
return pathParamValues;
}
private Map<String, String> getQueryParamKeyValues(Method method, Object[] args) {
Map<String, String> queryParamValues = Maps.newHashMap();
private Multimap<String, String> encodeValues(Multimap<String, String> unencoded,
final char... skipEncode) {
Multimap<String, String> encoded = HashMultimap.create();
for (Entry<String, String> entry : unencoded.entries()) {
try {
String value = URLEncoder.encode(entry.getValue(), "UTF-8");
// Web browsers do not always handle '+' characters well, use the well-supported
// '%20' instead.
value = value.replaceAll("\\+", "%20");
for (char c : skipEncode) {
String toSkip = Character.toString(c);
String encodedValueToSkip = URLEncoder.encode(toSkip, "UTF-8");
value = value.replaceAll(encodedValueToSkip, toSkip);
}
encoded.put(entry.getKey(), value);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("jclouds only supports UTF-8", e);
}
}
return encoded;
}
private Multimap<String, String> getMatrixParamKeyValues(Method method, Object[] args) {
Multimap<String, String> queryParamValues = HashMultimap.create();
queryParamValues.putAll(constants);
Map<Integer, Set<Annotation>> indexToMatrixParam = methodToindexOfParamToMatrixParamAnnotations
.get(method);
for (Entry<Integer, Set<Annotation>> entry : indexToMatrixParam.entrySet()) {
for (Annotation key : entry.getValue()) {
String paramKey = ((MatrixParam) key).value();
String paramValue = args[entry.getKey()].toString();
queryParamValues.put(paramKey, paramValue);
}
}
return queryParamValues;
}
private Multimap<String, String> getQueryParamKeyValues(Method method, Object[] args) {
Multimap<String, String> queryParamValues = HashMultimap.create();
queryParamValues.putAll(constants);
Map<Integer, Set<Annotation>> indexToQueryParam = methodToindexOfParamToQueryParamAnnotations
.get(method);

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rest;
package org.jclouds.rest.internal;
/**
* Generates RESTful clients from appropriately annotated interfaces.
@ -46,13 +46,14 @@ import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.TransformingHttpCommand;
import org.jclouds.logging.Logger;
import org.jclouds.rest.InvocationContext;
import com.google.common.base.Function;
import com.google.inject.TypeLiteral;
@Singleton
public class RestClientProxy<T> implements InvocationHandler {
private final JaxrsAnnotationProcessor<T> util;
private final RestAnnotationProcessor<T> util;
private final Class<T> declaring;
private final TransformingHttpCommand.Factory commandFactory;
@ -69,7 +70,7 @@ public class RestClientProxy<T> implements InvocationHandler {
@SuppressWarnings("unchecked")
@Inject
public RestClientProxy(TransformingHttpCommand.Factory factory,
JaxrsAnnotationProcessor<T> util, TypeLiteral<T> typeLiteral) {
RestAnnotationProcessor<T> util, TypeLiteral<T> typeLiteral) {
this.util = util;
this.declaring = (Class<T>) typeLiteral.getRawType();
this.commandFactory = factory;
@ -87,14 +88,14 @@ public class RestClientProxy<T> implements InvocationHandler {
Function<Exception, ?> exceptionParser = util
.createExceptionParserOrNullIfNotFound(method);
// in case there is an exception creating the request, we should at least pass in args
if (exceptionParser instanceof RestContext) {
((RestContext) exceptionParser).setContext(null, args);
if (exceptionParser instanceof InvocationContext) {
((InvocationContext) exceptionParser).setContext(null, args);
}
HttpRequest request;
try {
request = util.createRequest(method, args);
if (exceptionParser instanceof RestContext) {
((RestContext) exceptionParser).setContext(request, args);
if (exceptionParser instanceof InvocationContext) {
((InvocationContext) exceptionParser).setContext(request, args);
}
} catch (RuntimeException e) {
if (exceptionParser != null) {

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rest;
package org.jclouds.rest.internal;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.UriBuilder;

View File

@ -41,7 +41,7 @@ import org.jclouds.cloud.ConfiguresCloudConnection;
import org.jclouds.cloud.internal.CloudContextImpl;
import org.jclouds.lifecycle.Closer;
import org.jclouds.rest.RestClientFactory;
import org.jclouds.rest.JaxrsAnnotationProcessorTest.Localhost;
import org.jclouds.rest.RestAnnotationProcessorTest.Localhost;
import org.jclouds.util.Jsr330;
import org.jclouds.util.Utils;
import org.mortbay.jetty.Handler;

View File

@ -33,17 +33,18 @@ import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import org.jclouds.rest.binders.JsonBinder;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.options.HttpRequestOptions;
import org.jclouds.rest.Endpoint;
import org.jclouds.rest.EntityParam;
import org.jclouds.rest.ExceptionParser;
import org.jclouds.rest.MapBinder;
import org.jclouds.rest.MapEntityParam;
import org.jclouds.rest.RequestFilters;
import org.jclouds.rest.XMLResponseParser;
import org.jclouds.rest.JaxrsAnnotationProcessorTest.Localhost;
import org.jclouds.rest.RestAnnotationProcessorTest.Localhost;
import org.jclouds.rest.annotations.DecoratorParam;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.MapBinder;
import org.jclouds.rest.annotations.MapEntityParam;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.XMLResponseParser;
import org.jclouds.rest.decorators.AddAsJsonEntity;
import org.jclouds.rest.decorators.AddAsStringEntity;
import com.google.common.base.Function;
@ -87,15 +88,15 @@ public interface IntegrationTestClient {
@PUT
@Path("objects/{id}")
Future<String> upload(@PathParam("id") String id, @EntityParam String toPut);
Future<String> upload(@PathParam("id") String id, @DecoratorParam(AddAsStringEntity.class) String toPut);
@POST
@Path("objects/{id}")
Future<String> post(@PathParam("id") String id, @EntityParam String toPut);
Future<String> post(@PathParam("id") String id, @DecoratorParam(AddAsStringEntity.class) String toPut);
@POST
@Path("objects/{id}")
@MapBinder(JsonBinder.class)
@MapBinder(AddAsJsonEntity.class)
Future<String> postJson(@PathParam("id") String id, @MapEntityParam("key") String toPut);
@GET

View File

@ -43,6 +43,7 @@ import java.util.concurrent.Future;
import javax.inject.Named;
import javax.inject.Qualifier;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.HttpMethod;
@ -50,7 +51,9 @@ import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import org.jclouds.concurrent.WithinThreadExecutorService;
import org.jclouds.concurrent.config.ExecutorServiceModule;
@ -67,10 +70,25 @@ import org.jclouds.http.functions.ReturnVoidIf2xx;
import org.jclouds.http.options.BaseHttpRequestOptions;
import org.jclouds.http.options.GetOptions;
import org.jclouds.http.options.HttpRequestOptions;
import org.jclouds.rest.binders.HttpRequestOptionsBinder;
import org.jclouds.rest.binders.JsonBinder;
import org.jclouds.rest.binders.MapEntityBinder;
import org.jclouds.rest.config.JaxrsModule;
import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.annotations.DecoratorParam;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.Headers;
import org.jclouds.rest.annotations.HostPrefixParam;
import org.jclouds.rest.annotations.MapBinder;
import org.jclouds.rest.annotations.MapEntityParam;
import org.jclouds.rest.annotations.MatrixParams;
import org.jclouds.rest.annotations.ParamParser;
import org.jclouds.rest.annotations.QueryParams;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.ResponseParser;
import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.annotations.VirtualHost;
import org.jclouds.rest.config.RestModule;
import org.jclouds.rest.decorators.AddAsJsonEntity;
import org.jclouds.rest.decorators.AddAsStringEntity;
import org.jclouds.rest.decorators.MapRequestDecorator;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.jclouds.util.DateService;
import org.jclouds.util.Jsr330;
import org.joda.time.DateTime;
@ -81,6 +99,7 @@ import org.testng.annotations.Test;
import com.google.common.base.Function;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
@ -95,7 +114,7 @@ import com.google.inject.util.Types;
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "jaxrs.JaxrsUtilTest")
public class JaxrsAnnotationProcessorTest {
public class RestAnnotationProcessorTest {
@Target( { ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@javax.ws.rs.HttpMethod("FOO")
@ -166,12 +185,11 @@ public class JaxrsAnnotationProcessorTest {
@Endpoint(Localhost.class)
public class TestEntityParamVarargs {
@POST
public void varargs(
@EntityParam(HttpRequestOptionsBinder.class) HttpRequestOptions... options) {
public void varargs(HttpRequestOptions... options) {
}
@POST
public void post(@EntityParam(HttpRequestOptionsBinder.class) HttpRequestOptions options) {
public void post(HttpRequestOptions options) {
}
}
@ -293,22 +311,22 @@ public class JaxrsAnnotationProcessorTest {
@Endpoint(Localhost.class)
public class TestPost {
@POST
public void post(@EntityParam String content) {
public void post(@DecoratorParam(AddAsStringEntity.class) String content) {
}
@POST
public void postAsJson(@EntityParam(JsonBinder.class) String content) {
public void postAsJson(@DecoratorParam(AddAsJsonEntity.class) String content) {
}
@POST
@Path("{foo}")
public void postWithPath(@PathParam("foo") @MapEntityParam("fooble") String path,
MapEntityBinder content) {
MapRequestDecorator content) {
}
@POST
@Path("{foo}")
@MapBinder(JsonBinder.class)
@MapBinder(AddAsJsonEntity.class)
public void postWithMethodBinder(@PathParam("foo") @MapEntityParam("fooble") String path) {
}
}
@ -344,14 +362,17 @@ public class JaxrsAnnotationProcessorTest {
}
public void testCreatePostWithPathRequest() throws SecurityException, NoSuchMethodException {
Method method = TestPost.class.getMethod("postWithPath", String.class, MapEntityBinder.class);
Method method = TestPost.class.getMethod("postWithPath", String.class,
MapRequestDecorator.class);
HttpRequest httpMethod = factory(TestPost.class).createRequest(method,
new Object[] { "data", new MapEntityBinder() {
public void addEntityToRequest(Map<String, String> postParams, HttpRequest request) {
new Object[] { "data", new MapRequestDecorator() {
public HttpRequest decorateRequest(HttpRequest request,
Map<String, String> postParams) {
request.setEntity(postParams.get("fooble"));
return request;
}
public void addEntityToRequest(Object toBind, HttpRequest request) {
public HttpRequest decorateRequest(HttpRequest request, Object toBind) {
throw new RuntimeException("this shouldn't be used in POST");
}
} });
@ -382,9 +403,24 @@ public class JaxrsAnnotationProcessorTest {
public class TestPut {
@PUT
@Path("{foo}")
@MapBinder(JsonBinder.class)
@MapBinder(AddAsJsonEntity.class)
public void putWithMethodBinder(@PathParam("foo") @MapEntityParam("fooble") String path) {
}
@PUT
@Path("{foo}")
@Produces(MediaType.TEXT_PLAIN)
public void putWithMethodBinderProduces(
@PathParam("foo") @DecoratorParam(AddAsStringEntity.class) String path) {
}
@PUT
@Path("{foo}")
@MapBinder(AddAsJsonEntity.class)
@Consumes(MediaType.APPLICATION_JSON)
public void putWithMethodBinderConsumes(
@PathParam("foo") @MapEntityParam("fooble") String path) {
}
}
public void testCreatePutWithMethodBinder() throws SecurityException, NoSuchMethodException {
@ -403,6 +439,40 @@ public class JaxrsAnnotationProcessorTest {
assertEquals(httpMethod.getEntity(), expected);
}
public void testCreatePutWithMethodProduces() throws SecurityException, NoSuchMethodException {
Method method = TestPut.class.getMethod("putWithMethodBinderProduces", String.class);
HttpRequest httpMethod = factory(TestPut.class).createRequest(method,
new Object[] { "data", });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/data");
assertEquals(httpMethod.getMethod(), HttpMethod.PUT);
assertEquals(httpMethod.getHeaders().size(), 2);
assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_TYPE), Collections
.singletonList("text/plain"));
assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_LENGTH), Collections
.singletonList("data".getBytes().length + ""));
assertEquals(httpMethod.getEntity(), "data");
}
public void testCreatePutWithMethodConsumes() throws SecurityException, NoSuchMethodException {
Method method = TestPut.class.getMethod("putWithMethodBinderConsumes", String.class);
HttpRequest httpMethod = factory(TestPut.class).createRequest(method,
new Object[] { "data", });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/data");
assertEquals(httpMethod.getMethod(), HttpMethod.PUT);
assertEquals(httpMethod.getHeaders().size(), 3);
assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_TYPE), Collections
.singletonList("application/json"));
assertEquals(httpMethod.getHeaders().get(HttpHeaders.ACCEPT), Collections
.singletonList("application/json"));
String expected = "{\"fooble\":\"data\"}";
assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_LENGTH), Collections
.singletonList(expected.getBytes().length + ""));
assertEquals(httpMethod.getEntity(), expected);
}
static class TestRequestFilter1 implements HttpRequestFilter {
public HttpRequest filter(HttpRequest request) throws HttpException {
return null;
@ -578,9 +648,8 @@ public class JaxrsAnnotationProcessorTest {
public void testBuildTwoHeader() throws SecurityException, NoSuchMethodException,
UnsupportedEncodingException {
Method oneHeader = TestHeader.class.getMethod("twoHeader", String.class);
Multimap<String, String> headers = HashMultimap.create();
factory(TestHeader.class).addHeaderIfAnnotationPresentOnMethod(headers, oneHeader,
new Object[] { "robot" });
Multimap<String, String> headers = factory(TestHeader.class).createRequest(oneHeader,
new Object[] { "robot" }).getHeaders();
assertEquals(headers.size(), 2);
assertEquals(headers.get("slash"), Collections.singletonList("/robot"));
assertEquals(headers.get("hyphen"), Collections.singletonList("-robot"));
@ -598,9 +667,8 @@ public class JaxrsAnnotationProcessorTest {
public void testBuildOneClassHeader() throws SecurityException, NoSuchMethodException,
UnsupportedEncodingException {
Method oneHeader = TestClassHeader.class.getMethod("oneHeader", String.class);
Multimap<String, String> headers = HashMultimap.create();
factory(TestClassHeader.class).addHeaderIfAnnotationPresentOnMethod(headers, oneHeader,
new Object[] { "robot" });
Multimap<String, String> headers = factory(TestClassHeader.class).createRequest(oneHeader,
new Object[] { "robot" }).getHeaders();
assertEquals(headers.size(), 1);
assertEquals(headers.get("x-amz-copy-source"), Collections.singletonList("/robot"));
}
@ -609,9 +677,8 @@ public class JaxrsAnnotationProcessorTest {
public void testBuildOneHeader() throws SecurityException, NoSuchMethodException,
UnsupportedEncodingException {
Method oneHeader = TestHeader.class.getMethod("oneHeader", String.class);
Multimap<String, String> headers = HashMultimap.create();
factory(TestHeader.class).addHeaderIfAnnotationPresentOnMethod(headers, oneHeader,
new Object[] { "robot" });
Multimap<String, String> headers = factory(TestHeader.class).createRequest(oneHeader,
new Object[] { "robot" }).getHeaders();
assertEquals(headers.size(), 1);
assertEquals(headers.get("x-amz-copy-source"), Collections.singletonList("/robot"));
}
@ -620,9 +687,8 @@ public class JaxrsAnnotationProcessorTest {
public void testBuildTwoHeaders() throws SecurityException, NoSuchMethodException,
UnsupportedEncodingException {
Method twoHeaders = TestHeader.class.getMethod("twoHeaders", String.class, String.class);
Multimap<String, String> headers = HashMultimap.create();
factory(TestHeader.class).addHeaderIfAnnotationPresentOnMethod(headers, twoHeaders,
new Object[] { "robot", "eggs" });
Multimap<String, String> headers = factory(TestHeader.class).createRequest(twoHeaders,
new Object[] { "robot", "eggs" }).getHeaders();
assertEquals(headers.size(), 1);
assertEquals(headers.get("x-amz-copy-source"), Collections.singletonList("/robot/eggs"));
}
@ -632,13 +698,213 @@ public class JaxrsAnnotationProcessorTest {
UnsupportedEncodingException {
Method twoHeadersOutOfOrder = TestHeader.class.getMethod("twoHeadersOutOfOrder",
String.class, String.class);
Multimap<String, String> headers = HashMultimap.create();
factory(TestHeader.class).addHeaderIfAnnotationPresentOnMethod(headers, twoHeadersOutOfOrder,
new Object[] { "robot", "eggs" });
Multimap<String, String> headers = factory(TestHeader.class).createRequest(
twoHeadersOutOfOrder, new Object[] { "robot", "eggs" }).getHeaders();
assertEquals(headers.size(), 1);
assertEquals(headers.get("x-amz-copy-source"), Collections.singletonList("/eggs/robot"));
}
public class TestReplaceQueryOptions extends BaseHttpRequestOptions {
public TestReplaceQueryOptions() {
this.queryParameters.put("x-amz-copy-source", "/{bucket}");
}
}
@Test
public void testQueryInOptions() throws SecurityException, NoSuchMethodException,
UnsupportedEncodingException {
Method oneQuery = TestQueryReplace.class.getMethod("queryInOptions", String.class,
TestReplaceQueryOptions.class);
String query = factory(TestQueryReplace.class).createRequest(oneQuery,
new Object[] { "robot", new TestReplaceQueryOptions() }).getEndpoint().getQuery();
assertEquals(query, "x-amz-copy-source=/robot");
}
@Endpoint(Localhost.class)
public class TestQueryReplace {
@GET
public void queryInOptions(@PathParam("bucket") String path, TestReplaceQueryOptions options) {
}
@GET
@QueryParams(keys = "x-amz-copy-source", values = "/{bucket}")
public void oneQuery(@PathParam("bucket") String path) {
}
@GET
@QueryParams(keys = { "slash", "hyphen" }, values = { "/{bucket}", "-{bucket}" })
public void twoQuery(@PathParam("bucket") String path) {
}
@GET
@QueryParams(keys = "x-amz-copy-source", values = "/{bucket}/{key}")
public void twoQuerys(@PathParam("bucket") String path, @PathParam("key") String path2) {
}
@GET
@QueryParams(keys = "x-amz-copy-source", values = "/{bucket}/{key}")
public void twoQuerysOutOfOrder(@PathParam("key") String path,
@PathParam("bucket") String path2) {
}
}
@Test
public void testBuildTwoQuery() throws SecurityException, NoSuchMethodException,
UnsupportedEncodingException {
Method oneQuery = TestQueryReplace.class.getMethod("twoQuery", String.class);
String query = factory(TestQueryReplace.class).createRequest(oneQuery,
new Object[] { "robot" }).getEndpoint().getQuery();
assertEquals(query, "slash=/robot&hyphen=-robot");
}
@QueryParams(keys = "x-amz-copy-source", values = "/{bucket}")
@Endpoint(Localhost.class)
public class TestClassQuery {
@GET
public void oneQuery(@PathParam("bucket") String path) {
}
}
@Test
public void testBuildOneClassQuery() throws SecurityException, NoSuchMethodException,
UnsupportedEncodingException {
Method oneQuery = TestClassQuery.class.getMethod("oneQuery", String.class);
String query = factory(TestClassQuery.class)
.createRequest(oneQuery, new Object[] { "robot" }).getEndpoint().getQuery();
assertEquals(query, "x-amz-copy-source=/robot");
}
@Test
public void testBuildOneQuery() throws SecurityException, NoSuchMethodException,
UnsupportedEncodingException {
Method oneQuery = TestQueryReplace.class.getMethod("oneQuery", String.class);
String query = factory(TestQueryReplace.class).createRequest(oneQuery,
new Object[] { "robot" }).getEndpoint().getQuery();
assertEquals(query, "x-amz-copy-source=/robot");
}
@Test
public void testBuildTwoQuerys() throws SecurityException, NoSuchMethodException,
UnsupportedEncodingException {
Method twoQuerys = TestQueryReplace.class.getMethod("twoQuerys", String.class, String.class);
String query = factory(TestQueryReplace.class).createRequest(twoQuerys,
new Object[] { "robot", "eggs" }).getEndpoint().getQuery();
assertEquals(query, "x-amz-copy-source=/robot/eggs");
}
@Test
public void testBuildTwoQuerysOutOfOrder() throws SecurityException, NoSuchMethodException,
UnsupportedEncodingException {
Method twoQuerysOutOfOrder = TestQueryReplace.class.getMethod("twoQuerysOutOfOrder",
String.class, String.class);
String query = factory(TestQueryReplace.class).createRequest(twoQuerysOutOfOrder,
new Object[] { "robot", "eggs" }).getEndpoint().getQuery();
assertEquals(query, "x-amz-copy-source=/eggs/robot");
}
public class TestReplaceMatrixOptions extends BaseHttpRequestOptions {
public TestReplaceMatrixOptions() {
this.matrixParameters.put("x-amz-copy-source", "/{bucket}");
}
}
@Test
public void testMatrixInOptions() throws SecurityException, NoSuchMethodException,
UnsupportedEncodingException {
Method oneMatrix = TestMatrixReplace.class.getMethod("matrixInOptions", String.class,
TestReplaceMatrixOptions.class);
String path = factory(TestMatrixReplace.class).createRequest(oneMatrix,
new Object[] { "robot", new TestReplaceMatrixOptions() }).getEndpoint().getPath();
assertEquals(path, "/;x-amz-copy-source=/robot");
}
@Endpoint(Localhost.class)
@Path("/")
public class TestMatrixReplace {
@GET
public void matrixInOptions(@PathParam("bucket") String path, TestReplaceMatrixOptions options) {
}
@GET
@MatrixParams(keys = "x-amz-copy-source", values = "/{bucket}")
public void oneMatrix(@PathParam("bucket") String path) {
}
@GET
@MatrixParams(keys = { "slash", "hyphen" }, values = { "/{bucket}", "-{bucket}" })
public void twoMatrix(@PathParam("bucket") String path) {
}
@GET
@MatrixParams(keys = "x-amz-copy-source", values = "/{bucket}/{key}")
public void twoMatrixs(@PathParam("bucket") String path, @PathParam("key") String path2) {
}
@GET
@MatrixParams(keys = "x-amz-copy-source", values = "/{bucket}/{key}")
public void twoMatrixsOutOfOrder(@PathParam("key") String path,
@PathParam("bucket") String path2) {
}
}
@Test
public void testBuildTwoMatrix() throws SecurityException, NoSuchMethodException,
UnsupportedEncodingException {
Method oneMatrix = TestMatrixReplace.class.getMethod("twoMatrix", String.class);
String path = factory(TestMatrixReplace.class).createRequest(oneMatrix,
new Object[] { "robot" }).getEndpoint().getPath();
assertEquals(path, "/;slash=/robot;hyphen=-robot");
}
@MatrixParams(keys = "x-amz-copy-source", values = "/{bucket}")
@Endpoint(Localhost.class)
@Path("/")
public class TestClassMatrix {
@GET
public void oneMatrix(@PathParam("bucket") String path) {
}
}
@Test
public void testBuildOneClassMatrix() throws SecurityException, NoSuchMethodException,
UnsupportedEncodingException {
Method oneMatrix = TestClassMatrix.class.getMethod("oneMatrix", String.class);
String path = factory(TestClassMatrix.class).createRequest(oneMatrix,
new Object[] { "robot" }).getEndpoint().getPath();
assertEquals(path, "/;x-amz-copy-source=/robot");
}
@Test
public void testBuildOneMatrix() throws SecurityException, NoSuchMethodException,
UnsupportedEncodingException {
Method oneMatrix = TestMatrixReplace.class.getMethod("oneMatrix", String.class);
String path = factory(TestMatrixReplace.class).createRequest(oneMatrix,
new Object[] { "robot" }).getEndpoint().getPath();
assertEquals(path, "/;x-amz-copy-source=/robot");
}
@Test
public void testBuildTwoMatrixs() throws SecurityException, NoSuchMethodException,
UnsupportedEncodingException {
Method twoMatrixs = TestMatrixReplace.class.getMethod("twoMatrixs", String.class,
String.class);
String path = factory(TestMatrixReplace.class).createRequest(twoMatrixs,
new Object[] { "robot", "eggs" }).getEndpoint().getPath();
assertEquals(path, "/;x-amz-copy-source=/robot/eggs");
}
@Test
public void testBuildTwoMatrixsOutOfOrder() throws SecurityException, NoSuchMethodException,
UnsupportedEncodingException {
Method twoMatrixsOutOfOrder = TestMatrixReplace.class.getMethod("twoMatrixsOutOfOrder",
String.class, String.class);
String path = factory(TestMatrixReplace.class).createRequest(twoMatrixsOutOfOrder,
new Object[] { "robot", "eggs" }).getEndpoint().getPath();
assertEquals(path, "/;x-amz-copy-source=/eggs/robot");
}
@Endpoint(Localhost.class)
public interface TestTransformers {
@GET
@ -697,7 +963,7 @@ public class JaxrsAnnotationProcessorTest {
assertEquals(transformer, ParseURIList.class);
}
public static class ReturnStringIf200Context extends ReturnStringIf200 implements RestContext {
public static class ReturnStringIf200Context extends ReturnStringIf200 implements InvocationContext {
private Object[] args;
private HttpRequest request;
@ -783,7 +1049,7 @@ public class JaxrsAnnotationProcessorTest {
@PUT
@Path("/{id}")
public Future<String> put(@PathParam("id") @ParamParser(FirstCharacter.class) String id,
@EntityParam String payload) {
@DecoratorParam(AddAsStringEntity.class) String payload) {
return null;
}
@ -798,7 +1064,8 @@ public class JaxrsAnnotationProcessorTest {
@Path("/{id}")
@Headers(keys = "foo", values = "--{id}--")
@ResponseParser(ReturnTrueIf2xx.class)
public Future<String> putHeader(@PathParam("id") String id, @EntityParam String payload) {
public Future<String> putHeader(@PathParam("id") String id,
@DecoratorParam(AddAsStringEntity.class) String payload) {
return null;
}
}
@ -1080,7 +1347,7 @@ public class JaxrsAnnotationProcessorTest {
public void testOneHeader() throws SecurityException, NoSuchMethodException {
Method method = TestHeaders.class.getMethod("oneHeader", String.class);
Multimap<String, String> headers = factory(TestHeaders.class).buildHeaders(method,
new Object[] { "robot" });
new Object[] { "robot" }, ImmutableMultimap.<String, String> of().entries());
assertEquals(headers.size(), 1);
assertEquals(headers.get("header"), Collections.singletonList("robot"));
}
@ -1089,7 +1356,7 @@ public class JaxrsAnnotationProcessorTest {
public void testOneIntHeader() throws SecurityException, NoSuchMethodException {
Method method = TestHeaders.class.getMethod("oneIntHeader", int.class);
Multimap<String, String> headers = factory(TestHeaders.class).buildHeaders(method,
new Object[] { 1 });
new Object[] { 1 }, ImmutableMultimap.<String, String> of().entries());
assertEquals(headers.size(), 1);
assertEquals(headers.get("header"), Collections.singletonList("1"));
}
@ -1099,7 +1366,7 @@ public class JaxrsAnnotationProcessorTest {
Method method = TestHeaders.class
.getMethod("twoDifferentHeaders", String.class, String.class);
Multimap<String, String> headers = factory(TestHeaders.class).buildHeaders(method,
new Object[] { "robot", "egg" });
new Object[] { "robot", "egg" }, ImmutableMultimap.<String, String> of().entries());
assertEquals(headers.size(), 2);
assertEquals(headers.get("header1"), Collections.singletonList("robot"));
assertEquals(headers.get("header2"), Collections.singletonList("egg"));
@ -1109,7 +1376,7 @@ public class JaxrsAnnotationProcessorTest {
public void testTwoSameHeaders() throws SecurityException, NoSuchMethodException {
Method method = TestHeaders.class.getMethod("twoSameHeaders", String.class, String.class);
Multimap<String, String> headers = factory(TestHeaders.class).buildHeaders(method,
new Object[] { "robot", "egg" });
new Object[] { "robot", "egg" }, ImmutableMultimap.<String, String> of().entries());
assertEquals(headers.size(), 2);
Collection<String> values = headers.get("header");
assert values.contains("robot");
@ -1119,22 +1386,23 @@ public class JaxrsAnnotationProcessorTest {
@Endpoint(Localhost.class)
public interface TestEntity {
@PUT
public void put(@EntityParam String content);
public void put(@DecoratorParam(AddAsStringEntity.class) String content);
@PUT
@Path("{foo}")
public Future<Void> putWithPath(@PathParam("foo") String path, @EntityParam String content);
public Future<Void> putWithPath(@PathParam("foo") String path,
@DecoratorParam(AddAsStringEntity.class) String content);
@PUT
public void twoEntities(@EntityParam String entity1, @EntityParam String entity2);
public void twoEntities(@DecoratorParam(AddAsStringEntity.class) String entity1,
@DecoratorParam(AddAsStringEntity.class) String entity2);
}
@Test
public void testPut() throws SecurityException, NoSuchMethodException {
Method method = TestEntity.class.getMethod("put", String.class);
HttpRequest request = new HttpRequest(HttpMethod.PUT, URI.create("http://localhost:8080"));
factory(TestEntity.class).buildEntityIfPostOrPutRequest(method, new Object[] { "test" },
request);
factory(TestEntity.class).decorateRequest(method, new Object[] { "test" }, request);
assertEquals(request.getEntity(), "test");
assertEquals(request.getHeaders().get(HttpHeaders.CONTENT_TYPE), Collections
.singletonList("application/unknown"));
@ -1149,8 +1417,7 @@ public class JaxrsAnnotationProcessorTest {
public void putWithPath() throws SecurityException, NoSuchMethodException {
Method method = TestEntity.class.getMethod("putWithPath", String.class, String.class);
HttpRequest request = new HttpRequest(HttpMethod.PUT, URI.create("http://localhost:8080"));
factory(TestEntity.class).buildEntityIfPostOrPutRequest(method,
new Object[] { "rabble", "test" }, request);
factory(TestEntity.class).decorateRequest(method, new Object[] { "rabble", "test" }, request);
assertEquals(request.getEntity(), "test");
assertEquals(request.getHeaders().get(HttpHeaders.CONTENT_TYPE), Collections
.singletonList("application/unknown"));
@ -1162,14 +1429,14 @@ public class JaxrsAnnotationProcessorTest {
public void testPutTwoEntities() throws SecurityException, NoSuchMethodException {
Method method = TestEntity.class.getMethod("twoEntities", String.class, String.class);
HttpRequest request = new HttpRequest(HttpMethod.PUT, URI.create("http://localhost:8080"));
factory(TestEntity.class).buildEntityIfPostOrPutRequest(method,
new Object[] { "test", "ralphie" }, request);
factory(TestEntity.class)
.decorateRequest(method, new Object[] { "test", "ralphie" }, request);
}
@SuppressWarnings("unchecked")
private <T> JaxrsAnnotationProcessor<T> factory(Class<T> clazz) {
return ((JaxrsAnnotationProcessor<T>) injector.getInstance(Key.get(TypeLiteral.get(Types
.newParameterizedType(JaxrsAnnotationProcessor.class, clazz)))));
private <T> RestAnnotationProcessor<T> factory(Class<T> clazz) {
return ((RestAnnotationProcessor<T>) injector.getInstance(Key.get(TypeLiteral.get(Types
.newParameterizedType(RestAnnotationProcessor.class, clazz)))));
}
Injector injector;
@ -1186,7 +1453,7 @@ public class JaxrsAnnotationProcessorTest {
bind(URI.class).annotatedWith(Localhost2.class).toInstance(
URI.create("http://localhost:8081"));
}
}, new JaxrsModule(), new ExecutorServiceModule(new WithinThreadExecutorService()),
}, new RestModule(), new ExecutorServiceModule(new WithinThreadExecutorService()),
new JavaUrlHttpCommandExecutorServiceModule());
}

View File

@ -85,7 +85,7 @@ public class NioHttpCommandExecutionHandler implements NHttpRequestExecutionHand
if (rendezvous != null) {
HttpRequest request = rendezvous.getCommand().getRequest();
for (HttpRequestFilter filter : request.getFilters()) {
filter.filter(request);
request = filter.filter(request);
}
return NioHttpUtils.convertToApacheRequest(request);
}

View File

@ -38,8 +38,8 @@ import org.jclouds.blobstore.functions.ReturnVoidOnNotFoundOr404;
import org.jclouds.blobstore.functions.ThrowKeyNotFoundOn404;
import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.http.options.GetOptions;
import org.jclouds.mezeo.pcs2.binders.BlockBinder;
import org.jclouds.mezeo.pcs2.binders.CreateContainerBinder;
import org.jclouds.mezeo.pcs2.decorators.AddDataAndLength;
import org.jclouds.mezeo.pcs2.decorators.AddContainerNameAsXmlEntity;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
@ -57,15 +57,15 @@ import org.jclouds.mezeo.pcs2.functions.ReturnTrueIfContainerAlreadyExists;
import org.jclouds.mezeo.pcs2.xml.CachingFileListToContainerMetadataListHandler;
import org.jclouds.mezeo.pcs2.xml.FileListToFileMetadataListHandler;
import org.jclouds.mezeo.pcs2.xml.FileMetadataHandler;
import org.jclouds.rest.Endpoint;
import org.jclouds.rest.EntityParam;
import org.jclouds.rest.ExceptionParser;
import org.jclouds.rest.Headers;
import org.jclouds.rest.ParamParser;
import org.jclouds.rest.RequestFilters;
import org.jclouds.rest.ResponseParser;
import org.jclouds.rest.SkipEncoding;
import org.jclouds.rest.XMLResponseParser;
import org.jclouds.rest.annotations.DecoratorParam;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.Headers;
import org.jclouds.rest.annotations.ParamParser;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.ResponseParser;
import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.annotations.XMLResponseParser;
/**
* Provides access to Mezeo PCS v2 via their REST API.
@ -98,7 +98,7 @@ public interface PCSBlobStore extends BlobStore<ContainerMetadata, FileMetadata,
@Path("/contents")
@Endpoint(RootContainer.class)
@ExceptionParser(ReturnTrueIfContainerAlreadyExists.class)
Future<Boolean> createContainer(@EntityParam(CreateContainerBinder.class) String container);
Future<Boolean> createContainer(@DecoratorParam(AddContainerNameAsXmlEntity.class) String container);
@DELETE
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
@ -124,7 +124,7 @@ public interface PCSBlobStore extends BlobStore<ContainerMetadata, FileMetadata,
@PathParam("fileResourceId")
@ParamParser(CreateSubFolderIfNotExistsAndNewFileResource.class)
Future<byte[]> putBlob(String containerName,
@EntityParam(BlockBinder.class) PCSFile object);
@DecoratorParam(AddDataAndLength.class) PCSFile object);
// @POST
// @Path("/containers/{containerResourceId}/contents")
@ -133,7 +133,7 @@ public interface PCSBlobStore extends BlobStore<ContainerMetadata, FileMetadata,
// @PathParam("containerResourceId")
// @ParamParser(CreateSubFolderIfNotExistsAndGetResourceId.class)
// Future<byte[]> putBlob(String containerName,
// @EntityParam(PCSFileAsMultipartFormBinder.class) PCSFile object);
// @EntityParam(BlobAsMultipartFormBinder.class) PCSFile object);
@DELETE
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)

View File

@ -37,9 +37,9 @@ import org.jclouds.mezeo.pcs2.endpoints.RootContainer;
import org.jclouds.mezeo.pcs2.endpoints.Shares;
import org.jclouds.mezeo.pcs2.endpoints.Tags;
import org.jclouds.mezeo.pcs2.xml.CloudXlinkHandler;
import org.jclouds.rest.Endpoint;
import org.jclouds.rest.RequestFilters;
import org.jclouds.rest.XMLResponseParser;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.XMLResponseParser;
/**
* Provides URIs to PCS services via their REST API.

View File

@ -34,13 +34,13 @@ import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import org.jclouds.blobstore.decorators.AddBlobEntityAsMultipartForm;
import org.jclouds.blobstore.functions.ReturnVoidOnNotFoundOr404;
import org.jclouds.blobstore.functions.ThrowKeyNotFoundOn404;
import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.mezeo.pcs2.binders.BlockBinder;
import org.jclouds.mezeo.pcs2.binders.CreateContainerBinder;
import org.jclouds.mezeo.pcs2.binders.CreateFileBinder;
import org.jclouds.mezeo.pcs2.binders.PCSFileAsMultipartFormBinder;
import org.jclouds.mezeo.pcs2.decorators.AddDataAndLength;
import org.jclouds.mezeo.pcs2.decorators.AddContainerNameAsXmlEntity;
import org.jclouds.mezeo.pcs2.decorators.AddFileInfoAsXmlEntity;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
@ -48,13 +48,13 @@ import org.jclouds.mezeo.pcs2.endpoints.RootContainer;
import org.jclouds.mezeo.pcs2.options.PutBlockOptions;
import org.jclouds.mezeo.pcs2.xml.FileListToContainerMetadataListHandler;
import org.jclouds.mezeo.pcs2.xml.FileListToFileMetadataListHandler;
import org.jclouds.rest.Endpoint;
import org.jclouds.rest.EntityParam;
import org.jclouds.rest.ExceptionParser;
import org.jclouds.rest.Headers;
import org.jclouds.rest.RequestFilters;
import org.jclouds.rest.SkipEncoding;
import org.jclouds.rest.XMLResponseParser;
import org.jclouds.rest.annotations.DecoratorParam;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.Headers;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.annotations.XMLResponseParser;
/**
* Provides access to Mezeo PCS v2 via their REST API.
@ -79,12 +79,12 @@ public interface PCSConnection {
@POST
@Path("/contents")
@Endpoint(RootContainer.class)
Future<URI> createContainer(@EntityParam(CreateContainerBinder.class) String container);
Future<URI> createContainer(@DecoratorParam(AddContainerNameAsXmlEntity.class) String container);
@POST
@Path("/contents")
Future<URI> createContainer(@Endpoint URI parent,
@EntityParam(CreateContainerBinder.class) String container);
@DecoratorParam(AddContainerNameAsXmlEntity.class) String container);
@DELETE
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
@ -105,17 +105,17 @@ public interface PCSConnection {
@POST
@Path("/contents")
Future<URI> uploadFile(@Endpoint URI container,
@EntityParam(PCSFileAsMultipartFormBinder.class) PCSFile object);
@DecoratorParam(AddBlobEntityAsMultipartForm.class) PCSFile object);
@POST
@Path("/contents")
Future<URI> createFile(@Endpoint URI container,
@EntityParam(CreateFileBinder.class) PCSFile object);
@DecoratorParam(AddFileInfoAsXmlEntity.class) PCSFile object);
@PUT
@Path("/content")
Future<Void> uploadBlock(@Endpoint URI file,
@EntityParam(BlockBinder.class) PCSFile object, PutBlockOptions ... options);
@DecoratorParam(AddDataAndLength.class) PCSFile object, PutBlockOptions ... options);
@DELETE
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)

View File

@ -33,11 +33,12 @@ import javax.ws.rs.PathParam;
import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.mezeo.pcs2.functions.AddEntryIntoMultiMap;
import org.jclouds.rest.Endpoint;
import org.jclouds.rest.EntityParam;
import org.jclouds.rest.RequestFilters;
import org.jclouds.rest.ResponseParser;
import org.jclouds.rest.SkipEncoding;
import org.jclouds.rest.annotations.DecoratorParam;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.ResponseParser;
import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.decorators.AddAsStringEntity;
import com.google.common.collect.Multimap;
@ -58,7 +59,7 @@ public interface PCSUtil {
@Endpoint(PCS.class)
@Path("/files/{fileResourceId}/metadata/{key}")
Future<Void> putMetadata(@PathParam("fileResourceId") String resourceId,
@PathParam("key") String key, @EntityParam String value);
@PathParam("key") String key, @DecoratorParam(AddAsStringEntity.class) String value);
@GET
@ResponseParser(AddEntryIntoMultiMap.class)

View File

@ -35,6 +35,7 @@ import javax.inject.Singleton;
import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.BlobStoreContextImpl;
import org.jclouds.blobstore.BlobMap.Factory;
import org.jclouds.blobstore.domain.Key;
import org.jclouds.lifecycle.Closer;
import org.jclouds.mezeo.pcs2.PCS;
import org.jclouds.mezeo.pcs2.PCSConnection;
@ -44,7 +45,6 @@ import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.jclouds.mezeo.pcs2.functions.FindIdInContainerList;
import org.jclouds.mezeo.pcs2.functions.FindIdInFileList;
import org.jclouds.mezeo.pcs2.functions.Key;
import org.jclouds.mezeo.pcs2.reference.PCSConstants;
import com.google.common.base.Function;

View File

@ -21,28 +21,29 @@
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.binders;
package org.jclouds.mezeo.pcs2.decorators;
import java.util.Collections;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.binders.EntityBinder;
import org.jclouds.rest.decorators.RequestDecorator;
/**
*
* @author Adrian Cole
*
*/
public class CreateContainerBinder implements EntityBinder {
public class AddContainerNameAsXmlEntity implements RequestDecorator {
public void addEntityToRequest(Object toBind, HttpRequest request) {
public HttpRequest decorateRequest(HttpRequest request, Object toBind) {
String container = String.format("<container><name>%s</name></container>", toBind);
request.setEntity(container);
request.getHeaders().replaceValues(HttpHeaders.CONTENT_LENGTH,
Collections.singletonList(container.getBytes().length + ""));
request.getHeaders().replaceValues(HttpHeaders.CONTENT_TYPE,
Collections.singletonList("application/vnd.csp.container-info+xml"));
return request;
}
}

View File

@ -1,4 +1,4 @@
package org.jclouds.mezeo.pcs2.binders;
package org.jclouds.mezeo.pcs2.decorators;
import static com.google.common.base.Preconditions.checkNotNull;
@ -6,13 +6,14 @@ import javax.ws.rs.core.HttpHeaders;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.binders.EntityBinder;
import org.jclouds.rest.decorators.RequestDecorator;
public class BlockBinder implements EntityBinder {
public class AddDataAndLength implements RequestDecorator {
public void addEntityToRequest(Object entity, HttpRequest request) {
public HttpRequest decorateRequest(HttpRequest request, Object entity) {
Blob<?> object = (Blob<?>) entity;
request.setEntity(checkNotNull(object.getData(), "object.getContent()"));
request.getHeaders().put(HttpHeaders.CONTENT_LENGTH, object.getMetadata().getSize() + "");
return request;
}
}

View File

@ -21,28 +21,28 @@
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.binders;
package org.jclouds.mezeo.pcs2.decorators;
import java.util.Collections;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.Key;
import org.jclouds.blobstore.util.BlobStoreUtils;
import org.jclouds.http.HttpRequest;
import org.jclouds.mezeo.pcs2.functions.Key;
import org.jclouds.mezeo.pcs2.util.PCSUtils;
import org.jclouds.rest.binders.EntityBinder;
import org.jclouds.rest.decorators.RequestDecorator;
/**
*
* @author Adrian Cole
*
*/
public class CreateFileBinder implements EntityBinder {
public class AddFileInfoAsXmlEntity implements RequestDecorator {
public void addEntityToRequest(Object toBind, HttpRequest request) {
public HttpRequest decorateRequest(HttpRequest request, Object toBind) {
Blob<?> blob = (Blob<?>) toBind;
String bareKey = PCSUtils.parseKey(new Key("trash", blob.getKey())).getKey();
String bareKey = BlobStoreUtils.parseKey(new Key("trash", blob.getKey())).getKey();
String file = String.format(
"<file><name>%s</name><mime_type>%s</mime_type><public>false</public></file>",
bareKey, blob.getMetadata().getContentType());
@ -51,5 +51,6 @@ public class CreateFileBinder implements EntityBinder {
Collections.singletonList(file.getBytes().length + ""));
request.getHeaders().replaceValues(HttpHeaders.CONTENT_TYPE,
Collections.singletonList("application/vnd.csp.file-info+xml"));
return request;
}
}

View File

@ -9,7 +9,7 @@ import javax.inject.Inject;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.functions.ReturnStringIf200;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.InvocationContext;
import com.google.common.base.Function;
import com.google.common.collect.Multimap;
@ -18,7 +18,7 @@ import com.google.common.collect.Multimap;
*
* @author Adrian Cole
*/
public class AddEntryIntoMultiMap implements Function<HttpResponse, Void>, RestContext {
public class AddEntryIntoMultiMap implements Function<HttpResponse, Void>, InvocationContext {
ReturnStringIf200 returnIf200;
@Inject

View File

@ -38,6 +38,7 @@ import javax.inject.Inject;
import javax.inject.Named;
import org.apache.commons.io.IOUtils;
import org.jclouds.blobstore.domain.Key;
import org.jclouds.blobstore.internal.BlobRuntimeException;
import org.jclouds.blobstore.reference.BlobStoreConstants;
import org.jclouds.http.HttpRequest;
@ -46,7 +47,7 @@ import org.jclouds.logging.Logger;
import org.jclouds.mezeo.pcs2.PCSUtil;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.jclouds.mezeo.pcs2.util.PCSUtils;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.InvocationContext;
import org.jclouds.util.Utils;
import com.google.common.base.Function;
@ -58,7 +59,7 @@ import com.google.common.collect.Sets;
* @author Adrian Cole
*/
public class AddMetadataAndParseResourceIdIntoBytes implements Function<HttpResponse, byte[]>,
RestContext {
InvocationContext {
private final PCSUtil util;
private final ConcurrentMap<Key, String> fileCache;

View File

@ -27,12 +27,13 @@ import java.util.concurrent.ConcurrentMap;
import javax.inject.Inject;
import org.jclouds.blobstore.domain.Key;
import org.jclouds.blobstore.functions.ParseContentTypeFromHeaders;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.InvocationContext;
import com.google.common.base.Function;
@ -43,7 +44,7 @@ import com.google.common.base.Function;
* @author Adrian Cole
*/
public class AssembleBlobFromContentAndMetadataCache implements Function<HttpResponse, PCSFile>,
RestContext {
InvocationContext {
private final ConcurrentMap<Key, FileMetadata> cache;
private HttpRequest request;

View File

@ -34,6 +34,7 @@ import javax.inject.Singleton;
import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.blobstore.KeyNotFoundException;
import org.jclouds.blobstore.domain.Key;
import org.jclouds.util.Utils;
import com.google.common.base.Function;

View File

@ -40,8 +40,10 @@ import javax.inject.Singleton;
import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.Key;
import org.jclouds.blobstore.internal.BlobRuntimeException;
import org.jclouds.blobstore.reference.BlobStoreConstants;
import org.jclouds.blobstore.util.BlobStoreUtils;
import org.jclouds.mezeo.pcs2.PCSConnection;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.endpoints.RootContainer;
@ -85,7 +87,7 @@ public class CreateSubFolderIfNotExistsAndGetResourceId implements Function<Obje
Object[] args = (Object[]) from;
checkArgument(args[0] instanceof String, "arg[0] must be a container name");
checkArgument(args[1] instanceof Blob, "arg[1] must be a pcsfile");
Key key = PCSUtils.parseKey(new Key(args[0].toString(), ((Blob) args[1]).getKey()));
Key key = BlobStoreUtils.parseKey(new Key(args[0].toString(), ((Blob) args[1]).getKey()));
try {
return finder.get(key.getContainer());
} catch (ComputationException e) {
@ -95,12 +97,12 @@ public class CreateSubFolderIfNotExistsAndGetResourceId implements Function<Obje
SortedSet<ContainerMetadata> response = blobStore.listContainers();
URI containerUri;
try {
containerUri = urlForNameInListOrCreate(rootContainer, containerTree[0],
response);
containerUri = urlForNameInListOrCreate(rootContainer, containerTree[0], response);
} catch (Exception e1) {
Utils.<ContainerNotFoundException> rethrowIfRuntimeOrSameType(e1);
throw new BlobRuntimeException("error creating container at: " + containerTree[0], e1);
throw new BlobRuntimeException("error creating container at: " + containerTree[0],
e1);
}
if (containerTree.length != 1) {
for (int i = 1; i < containerTree.length; i++) {

View File

@ -38,6 +38,7 @@ import javax.ws.rs.core.UriBuilder;
import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.blobstore.KeyNotFoundException;
import org.jclouds.blobstore.domain.Key;
import org.jclouds.blobstore.internal.BlobRuntimeException;
import org.jclouds.blobstore.reference.BlobStoreConstants;
import org.jclouds.mezeo.pcs2.PCS;

View File

@ -32,11 +32,12 @@ import javax.inject.Inject;
import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.blobstore.KeyNotFoundException;
import org.jclouds.blobstore.domain.Key;
import org.jclouds.blobstore.util.BlobStoreUtils;
import org.jclouds.http.HttpException;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.jclouds.mezeo.pcs2.util.PCSUtils;
import org.jclouds.util.Utils;
import com.google.common.annotations.VisibleForTesting;
@ -51,7 +52,7 @@ public class FindIdInFileList implements Function<Key, String> {
}
public String apply(Key key) {
key = PCSUtils.parseKey(key);
key = BlobStoreUtils.parseKey(key);
SortedSet<FileMetadata> response;
try {
response = connection.listBlobs(key.getContainer()).get(10, TimeUnit.SECONDS);

View File

@ -30,7 +30,7 @@ import javax.inject.Inject;
import org.apache.commons.io.IOUtils;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.InvocationContext;
import com.google.common.base.Function;
@ -40,7 +40,7 @@ import com.google.common.base.Function;
* @author Adrian Cole
*/
public class InvalidateContainerNameCacheAndReturnTrueIf2xx implements Function<HttpResponse, Boolean>,
RestContext {
InvocationContext {
private final ConcurrentMap<String, String> cache;
private HttpRequest request;
private Object[] args;

View File

@ -28,10 +28,11 @@ import java.util.concurrent.ConcurrentMap;
import javax.inject.Inject;
import org.apache.commons.io.IOUtils;
import org.jclouds.blobstore.domain.Key;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.InvocationContext;
import com.google.common.base.Function;
@ -41,7 +42,7 @@ import com.google.common.base.Function;
* @author Adrian Cole
*/
public class InvalidatePCSKeyCacheAndReturnVoidIf2xx implements Function<HttpResponse, Void>,
RestContext {
InvocationContext {
private final ConcurrentMap<Key, String> cache;
private final ConcurrentMap<Key, FileMetadata> mdCache;
private HttpRequest request;

View File

@ -26,7 +26,6 @@ package org.jclouds.mezeo.pcs2.util;
import java.net.URI;
import org.jclouds.http.HttpUtils;
import org.jclouds.mezeo.pcs2.functions.Key;
/**
* Utilities for PCS connections.
@ -49,17 +48,6 @@ public class PCSUtils {
return eTag;
}
public static Key parseKey(Key key) {
if (key.getKey().indexOf('/') != -1) {
String container = key.getContainer() + '/'
+ key.getKey().substring(0, key.getKey().lastIndexOf('/'));
String newKey = key.getKey().substring(key.getKey().lastIndexOf('/') + 1);
key = new Key(container.replaceAll("//", "/"), newKey);
}
return key;
}
public static String getContainerId(URI url) {
String path = url.getPath();
int indexAfterContainersSlash = path.indexOf("containers/") + "containers/".length();

View File

@ -54,7 +54,6 @@ import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.ReturnTrueIf2xx;
import org.jclouds.http.functions.ReturnVoidIf2xx;
import org.jclouds.http.options.GetOptions;
import org.jclouds.mezeo.pcs2.binders.PCSFileAsMultipartFormBinderTest;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
@ -67,8 +66,8 @@ import org.jclouds.mezeo.pcs2.functions.InvalidateContainerNameCacheAndReturnTru
import org.jclouds.mezeo.pcs2.functions.InvalidatePCSKeyCacheAndReturnVoidIf2xx;
import org.jclouds.mezeo.pcs2.functions.ReturnFalseIfContainerNotFound;
import org.jclouds.mezeo.pcs2.options.PutBlockOptions;
import org.jclouds.rest.JaxrsAnnotationProcessor;
import org.jclouds.rest.config.JaxrsModule;
import org.jclouds.rest.config.RestModule;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.jclouds.util.DateService;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@ -298,19 +297,18 @@ public class PCSBlobStoreTest {
public void testPutBlob() throws SecurityException, NoSuchMethodException, IOException {
Method method = PCSBlobStore.class.getMethod("putBlob", String.class, PCSFile.class);
HttpRequest httpMethod = processor.createRequest(method, new Object[] { "mycontainer",
PCSFileAsMultipartFormBinderTest.TEST_BLOB });
PCSFile file = new PCSFile("hello");
file.setData("wonkers");
HttpRequest httpMethod = processor
.createRequest(method, new Object[] { "mycontainer", file });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/files/o/content");
assertEquals(httpMethod.getEndpoint().getQuery(), null);
assertEquals(httpMethod.getMethod(), HttpMethod.PUT);
assertEquals(httpMethod.getHeaders().size(), 1);
assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_LENGTH), Collections
.singletonList(PCSFileAsMultipartFormBinderTest.TEST_BLOB.getData().toString()
.getBytes().length
+ ""));
assertEquals(httpMethod.getEntity(), PCSFileAsMultipartFormBinderTest.TEST_BLOB.getData());
.singletonList(file.getData().toString().getBytes().length + ""));
assertEquals(httpMethod.getEntity(), file.getData());
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
AddMetadataAndParseResourceIdIntoBytes.class);
}
@ -419,8 +417,8 @@ public class PCSBlobStoreTest {
AddEntryIntoMultiMap.class);
}
JaxrsAnnotationProcessor<PCSBlobStore> processor;
private JaxrsAnnotationProcessor<PCSUtil> utilProcessor;
RestAnnotationProcessor<PCSBlobStore> processor;
private RestAnnotationProcessor<PCSUtil> utilProcessor;
@BeforeClass
void setupFactory() {
@ -459,22 +457,20 @@ public class PCSBlobStoreTest {
@SuppressWarnings("unused")
@Provides
@Singleton
ConcurrentMap<org.jclouds.mezeo.pcs2.functions.Key, String> giveMap() {
ConcurrentHashMap<org.jclouds.mezeo.pcs2.functions.Key, String> map = new ConcurrentHashMap<org.jclouds.mezeo.pcs2.functions.Key, String>();
map.put(
new org.jclouds.mezeo.pcs2.functions.Key("mycontainer",
"testfile.txt"), "9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3");
ConcurrentMap<org.jclouds.blobstore.domain.Key, String> giveMap() {
ConcurrentHashMap<org.jclouds.blobstore.domain.Key, String> map = new ConcurrentHashMap<org.jclouds.blobstore.domain.Key, String>();
map.put(new org.jclouds.blobstore.domain.Key("mycontainer", "testfile.txt"),
"9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3");
return map;
}
@SuppressWarnings("unused")
@Provides
@Singleton
ConcurrentMap<org.jclouds.mezeo.pcs2.functions.Key, FileMetadata> giveMap2() {
ConcurrentHashMap<org.jclouds.mezeo.pcs2.functions.Key, FileMetadata> map = new ConcurrentHashMap<org.jclouds.mezeo.pcs2.functions.Key, FileMetadata>();
map.put(
new org.jclouds.mezeo.pcs2.functions.Key("mycontainer",
"testfile.txt"), new FileMetadata("testfile.txt"));
ConcurrentMap<org.jclouds.blobstore.domain.Key, FileMetadata> giveMap2() {
ConcurrentHashMap<org.jclouds.blobstore.domain.Key, FileMetadata> map = new ConcurrentHashMap<org.jclouds.blobstore.domain.Key, FileMetadata>();
map.put(new org.jclouds.blobstore.domain.Key("mycontainer", "testfile.txt"),
new FileMetadata("testfile.txt"));
return map;
}
@ -494,14 +490,14 @@ public class PCSBlobStoreTest {
throws UnsupportedEncodingException {
return new BasicAuthentication("foo", "bar");
}
}, new JaxrsModule(), new ExecutorServiceModule(new WithinThreadExecutorService()),
}, new RestModule(), new ExecutorServiceModule(new WithinThreadExecutorService()),
new JavaUrlHttpCommandExecutorServiceModule());
processor = injector.getInstance(Key
.get(new TypeLiteral<JaxrsAnnotationProcessor<PCSBlobStore>>() {
.get(new TypeLiteral<RestAnnotationProcessor<PCSBlobStore>>() {
}));
utilProcessor = injector.getInstance(Key
.get(new TypeLiteral<JaxrsAnnotationProcessor<PCSUtil>>() {
.get(new TypeLiteral<RestAnnotationProcessor<PCSUtil>>() {
}));
}
}

View File

@ -37,7 +37,7 @@ import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.mezeo.pcs2.PCSCloud.Response;
import org.jclouds.rest.RestClientFactory;
import org.jclouds.rest.config.JaxrsModule;
import org.jclouds.rest.config.RestModule;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@ -97,7 +97,7 @@ public class PCSCloudLiveTest {
protected PCSCloud provideCloud(RestClientFactory factory) {
return factory.create(PCSCloud.class);
}
}, new JaxrsModule(), new ExecutorServiceModule(new WithinThreadExecutorService()),
}, new RestModule(), new ExecutorServiceModule(new WithinThreadExecutorService()),
new JavaUrlHttpCommandExecutorServiceModule());
}
}

View File

@ -39,6 +39,7 @@ import javax.inject.Singleton;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.blobstore.decorators.AddBlobEntityAsMultipartFormTest;
import org.jclouds.blobstore.functions.ReturnVoidOnNotFoundOr404;
import org.jclouds.concurrent.WithinThreadExecutorService;
import org.jclouds.concurrent.config.ExecutorServiceModule;
@ -49,12 +50,11 @@ import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.ParseURIList;
import org.jclouds.http.functions.ReturnInputStream;
import org.jclouds.http.functions.ReturnVoidIf2xx;
import org.jclouds.mezeo.pcs2.binders.PCSFileAsMultipartFormBinderTest;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.jclouds.mezeo.pcs2.endpoints.RootContainer;
import org.jclouds.rest.JaxrsAnnotationProcessor;
import org.jclouds.rest.config.JaxrsModule;
import org.jclouds.rest.config.RestModule;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.jclouds.util.Utils;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@ -165,19 +165,19 @@ public class PCSConnectionTest {
HttpRequest httpMethod = processor.createRequest(method, new Object[] {
URI.create("http://localhost/mycontainer"),
PCSFileAsMultipartFormBinderTest.TEST_BLOB });
AddBlobEntityAsMultipartFormTest.TEST_BLOB });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/mycontainer/contents");
assertEquals(httpMethod.getEndpoint().getQuery(), null);
assertEquals(httpMethod.getMethod(), HttpMethod.POST);
assertEquals(httpMethod.getHeaders().size(), 2);
assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_LENGTH), Collections
.singletonList(PCSFileAsMultipartFormBinderTest.EXPECTS.length() + ""));
.singletonList(AddBlobEntityAsMultipartFormTest.EXPECTS.length() + ""));
assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_TYPE), Collections
.singletonList("multipart/form-data; boundary="
+ PCSFileAsMultipartFormBinderTest.BOUNDRY));
+ AddBlobEntityAsMultipartFormTest.BOUNDRY));
assertEquals(Utils.toStringAndClose((InputStream) httpMethod.getEntity()),
PCSFileAsMultipartFormBinderTest.EXPECTS);
AddBlobEntityAsMultipartFormTest.EXPECTS);
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
ParseURIList.class);
}
@ -212,7 +212,7 @@ public class PCSConnectionTest {
ReturnVoidOnNotFoundOr404.class);
}
JaxrsAnnotationProcessor<PCSConnection> processor;
RestAnnotationProcessor<PCSConnection> processor;
@BeforeClass
void setupFactory() {
@ -248,22 +248,20 @@ public class PCSConnectionTest {
@SuppressWarnings("unused")
@Provides
@Singleton
ConcurrentMap<org.jclouds.mezeo.pcs2.functions.Key, String> giveMap() {
ConcurrentHashMap<org.jclouds.mezeo.pcs2.functions.Key, String> map = new ConcurrentHashMap<org.jclouds.mezeo.pcs2.functions.Key, String>();
map.put(
new org.jclouds.mezeo.pcs2.functions.Key("mycontainer",
"testfile.txt"), "9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3");
ConcurrentMap<org.jclouds.blobstore.domain.Key, String> giveMap() {
ConcurrentHashMap<org.jclouds.blobstore.domain.Key, String> map = new ConcurrentHashMap<org.jclouds.blobstore.domain.Key, String>();
map.put(new org.jclouds.blobstore.domain.Key("mycontainer", "testfile.txt"),
"9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3");
return map;
}
@SuppressWarnings("unused")
@Provides
@Singleton
ConcurrentMap<org.jclouds.mezeo.pcs2.functions.Key, FileMetadata> giveMap2() {
ConcurrentHashMap<org.jclouds.mezeo.pcs2.functions.Key, FileMetadata> map = new ConcurrentHashMap<org.jclouds.mezeo.pcs2.functions.Key, FileMetadata>();
map.put(
new org.jclouds.mezeo.pcs2.functions.Key("mycontainer",
"testfile.txt"), new FileMetadata("testfile.txt"));
ConcurrentMap<org.jclouds.blobstore.domain.Key, FileMetadata> giveMap2() {
ConcurrentHashMap<org.jclouds.blobstore.domain.Key, FileMetadata> map = new ConcurrentHashMap<org.jclouds.blobstore.domain.Key, FileMetadata>();
map.put(new org.jclouds.blobstore.domain.Key("mycontainer", "testfile.txt"),
new FileMetadata("testfile.txt"));
return map;
}
@ -283,11 +281,11 @@ public class PCSConnectionTest {
throws UnsupportedEncodingException {
return new BasicAuthentication("foo", "bar");
}
}, new JaxrsModule(), new ExecutorServiceModule(new WithinThreadExecutorService()),
}, new RestModule(), new ExecutorServiceModule(new WithinThreadExecutorService()),
new JavaUrlHttpCommandExecutorServiceModule());
processor = injector.getInstance(Key
.get(new TypeLiteral<JaxrsAnnotationProcessor<PCSConnection>>() {
.get(new TypeLiteral<RestAnnotationProcessor<PCSConnection>>() {
}));
}
}

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.binders;
package org.jclouds.mezeo.pcs2.decorators;
import static org.testng.Assert.assertEquals;
@ -33,17 +33,17 @@ import org.jclouds.http.HttpRequest;
import org.testng.annotations.Test;
/**
* Tests behavior of {@code ParseFlavorListFromGsonResponseTest}
* Tests behavior of {@code AddContainerNameAsXmlEntity}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "pcs2.CreateContainerBinderTest")
public class CreateContainerBinderTest {
@Test(groups = "unit", testName = "pcs2.AddContainerNameAsXmlEntityTest")
public class AddContainerNameAsXmlEntityTest {
public void test() {
CreateContainerBinder binder = new CreateContainerBinder();
AddContainerNameAsXmlEntity binder = new AddContainerNameAsXmlEntity();
HttpRequest request = new HttpRequest("GET", URI.create("http://localhost"));
binder.addEntityToRequest("foo", request);
binder.decorateRequest(request, "foo");
assertEquals(request.getEntity(), "<container><name>foo</name></container>");
assertEquals(request.getFirstHeaderOrNull(HttpHeaders.CONTENT_LENGTH),
"<container><name>foo</name></container>".getBytes().length + "");

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.binders;
package org.jclouds.mezeo.pcs2.decorators;
import static org.testng.Assert.assertEquals;
@ -34,18 +34,18 @@ import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.testng.annotations.Test;
/**
* Tests behavior of {@code CreateFileBinder}
* Tests behavior of {@code AddFileInfoAsXmlEntity}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "pcs2.CreateFileBinderTest")
public class CreateFileBinderTest {
@Test(groups = "unit", testName = "pcs2.AddFileInfoAsXmlEntityTest")
public class AddFileInfoAsXmlEntityTest {
public void test() {
CreateFileBinder binder = new CreateFileBinder();
AddFileInfoAsXmlEntity binder = new AddFileInfoAsXmlEntity();
HttpRequest request = new HttpRequest("GET", URI.create("http://localhost"));
PCSFile file = new PCSFile("foo");
binder.addEntityToRequest(file, request);
binder.decorateRequest(request, file);
assertEquals(
request.getEntity(),
"<file><name>foo</name><mime_type>application/octet-stream</mime_type><public>false</public></file>");
@ -59,12 +59,11 @@ public class CreateFileBinderTest {
}
public void testCompound() {
CreateFileBinder binder = new CreateFileBinder();
AddFileInfoAsXmlEntity binder = new AddFileInfoAsXmlEntity();
HttpRequest request = new HttpRequest("GET", URI.create("http://localhost"));
PCSFile file = new PCSFile("subdir/foo");
binder.addEntityToRequest(file, request);
binder.decorateRequest(request, file);
assertEquals(
request.getEntity(),
"<file><name>foo</name><mime_type>application/octet-stream</mime_type><public>false</public></file>");

View File

@ -38,12 +38,13 @@ import java.util.concurrent.Future;
import javax.ws.rs.ext.RuntimeDelegate;
import org.apache.commons.io.IOUtils;
import org.jclouds.blobstore.domain.Key;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpUtils;
import org.jclouds.mezeo.pcs2.PCSUtil;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.jclouds.rest.RuntimeDelegateImpl;
import org.jclouds.rest.internal.RuntimeDelegateImpl;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

View File

@ -31,6 +31,7 @@ import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.util.concurrent.ConcurrentMap;
import org.jclouds.blobstore.domain.Key;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpResponse;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;

View File

@ -28,7 +28,6 @@ import static org.testng.Assert.assertEquals;
import java.net.URI;
import org.jclouds.http.HttpUtils;
import org.jclouds.mezeo.pcs2.functions.Key;
import org.testng.annotations.Test;
/**
@ -45,17 +44,4 @@ public class PCSUtilsTest {
.create("http://localhost/contents/7F143552-AAF5-11DE-BBB0-0BC388ED913B"));
assertEquals(eTag, expected);
}
public void testParseKey() {
Key key = PCSUtils.parseKey(new Key("container", "key"));
assertEquals(key.getContainer(), "container");
assertEquals(key.getKey(), "key");
key = PCSUtils.parseKey(new Key("container", "container/key"));
assertEquals(key.getContainer(), "container/container");
assertEquals(key.getKey(), "key");
key = PCSUtils.parseKey(new Key("container", "/container/key"));
assertEquals(key.getContainer(), "container/container");
assertEquals(key.getKey(), "key");
}
}

View File

@ -35,7 +35,7 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.binders.BlobBinder;
import org.jclouds.blobstore.decorators.AddBlobEntity;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.functions.BlobKey;
@ -53,14 +53,14 @@ import org.jclouds.rackspace.cloudfiles.functions.ParseObjectFromHeadersAndHttpC
import org.jclouds.rackspace.cloudfiles.functions.ParseObjectMetadataFromHeaders;
import org.jclouds.rackspace.cloudfiles.options.ListContainerOptions;
import org.jclouds.rackspace.filters.AuthenticateRequest;
import org.jclouds.rest.Endpoint;
import org.jclouds.rest.EntityParam;
import org.jclouds.rest.ExceptionParser;
import org.jclouds.rest.ParamParser;
import org.jclouds.rest.QueryParams;
import org.jclouds.rest.RequestFilters;
import org.jclouds.rest.ResponseParser;
import org.jclouds.rest.SkipEncoding;
import org.jclouds.rest.annotations.DecoratorParam;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.ParamParser;
import org.jclouds.rest.annotations.QueryParams;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.ResponseParser;
import org.jclouds.rest.annotations.SkipEncoding;
/**
* Provides access to Cloud Files via their REST API.
@ -113,7 +113,7 @@ public interface CloudFilesBlobStore extends
@ResponseParser(ParseETagHeader.class)
Future<byte[]> putBlob(
@PathParam("container") String container,
@PathParam("key") @ParamParser(BlobKey.class) @EntityParam(BlobBinder.class) Blob<BlobMetadata> object);
@PathParam("key") @ParamParser(BlobKey.class) @DecoratorParam(AddBlobEntity.class) Blob<BlobMetadata> object);
@GET
@ResponseParser(ParseObjectFromHeadersAndHttpContent.class)

View File

@ -36,8 +36,8 @@ import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import org.jclouds.blobstore.binders.BlobBinder;
import org.jclouds.blobstore.binders.UserMetadataBinder;
import org.jclouds.blobstore.decorators.AddBlobEntity;
import org.jclouds.blobstore.decorators.AddHeadersWithPrefix;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.functions.BlobKey;
@ -64,15 +64,15 @@ import org.jclouds.rackspace.cloudfiles.options.ListCdnContainerOptions;
import org.jclouds.rackspace.cloudfiles.options.ListContainerOptions;
import org.jclouds.rackspace.cloudfiles.reference.CloudFilesHeaders;
import org.jclouds.rackspace.filters.AuthenticateRequest;
import org.jclouds.rest.Endpoint;
import org.jclouds.rest.EntityParam;
import org.jclouds.rest.ExceptionParser;
import org.jclouds.rest.Headers;
import org.jclouds.rest.ParamParser;
import org.jclouds.rest.QueryParams;
import org.jclouds.rest.RequestFilters;
import org.jclouds.rest.ResponseParser;
import org.jclouds.rest.SkipEncoding;
import org.jclouds.rest.annotations.DecoratorParam;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.Headers;
import org.jclouds.rest.annotations.ParamParser;
import org.jclouds.rest.annotations.QueryParams;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.ResponseParser;
import org.jclouds.rest.annotations.SkipEncoding;
import com.google.common.collect.Multimap;
@ -141,7 +141,7 @@ public interface CloudFilesConnection {
@Path("{container}/{key}")
boolean setObjectMetadata(@PathParam("container") String container,
@PathParam("key") String key,
@EntityParam(UserMetadataBinder.class) Multimap<String, String> userMetadata);
@DecoratorParam(AddHeadersWithPrefix.class) Multimap<String, String> userMetadata);
@GET
@ResponseParser(ParseContainerCDNMetadataListFromGsonResponse.class)
@ -205,7 +205,7 @@ public interface CloudFilesConnection {
@ResponseParser(ParseETagHeader.class)
Future<byte[]> putObject(
@PathParam("container") String container,
@PathParam("key") @ParamParser(BlobKey.class) @EntityParam(BlobBinder.class) Blob<BlobMetadata> object);
@PathParam("key") @ParamParser(BlobKey.class) @DecoratorParam(AddBlobEntity.class) Blob<BlobMetadata> object);
@GET
@ResponseParser(ParseObjectFromHeadersAndHttpContent.class)

View File

@ -21,28 +21,27 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rackspace.cloudfiles.binders;
package org.jclouds.rackspace.cloudfiles.decorators;
import static com.google.common.base.Preconditions.checkArgument;
import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX;
import javax.inject.Inject;
import javax.inject.Named;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.blobstore.binders.BlobBinder;
import org.jclouds.blobstore.decorators.AddBlobEntity;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpUtils;
import javax.inject.Inject;
import javax.inject.Named;
public class CFObjectBinder extends BlobBinder {
public class AddCFObjectEntity extends AddBlobEntity {
@Inject
public CFObjectBinder(@Named(PROPERTY_USER_METADATA_PREFIX) String metadataPrefix) {
public AddCFObjectEntity(@Named(PROPERTY_USER_METADATA_PREFIX) String metadataPrefix) {
super(metadataPrefix);
}
public void addEntityToRequest(Object entity, HttpRequest request) {
public HttpRequest decorateRequest(HttpRequest request, Object entity) {
Blob<?> object = (Blob<?>) entity;
if (object.getMetadata().getSize() >= 0) {
checkArgument(object.getContentLength() <= 5 * 1024 * 1024 * 1024,
@ -59,6 +58,6 @@ public class CFObjectBinder extends BlobBinder {
request.getHeaders().put(HttpHeaders.ETAG,
HttpUtils.toBase64String(object.getMetadata().getContentMD5()));
}
super.addEntityToRequest(entity, request);
return super.decorateRequest(request, entity);
}
}

View File

@ -37,15 +37,15 @@ import javax.ws.rs.PathParam;
import org.jclouds.http.functions.ReturnFalseOn404;
import org.jclouds.rackspace.CloudServers;
import org.jclouds.rackspace.cloudservers.binders.BackupScheduleBinder;
import org.jclouds.rackspace.cloudservers.binders.ChangeAdminPassBinder;
import org.jclouds.rackspace.cloudservers.binders.ChangeServerNameBinder;
import org.jclouds.rackspace.cloudservers.binders.ConfirmResizeBinder;
import org.jclouds.rackspace.cloudservers.binders.CreateImageBinder;
import org.jclouds.rackspace.cloudservers.binders.RebootTypeBinder;
import org.jclouds.rackspace.cloudservers.binders.ResizeBinder;
import org.jclouds.rackspace.cloudservers.binders.RevertResizeBinder;
import org.jclouds.rackspace.cloudservers.binders.ShareIpBinder;
import org.jclouds.rackspace.cloudservers.decorators.AddBackupScheduleAsJsonEntity;
import org.jclouds.rackspace.cloudservers.decorators.AddAdminPassAsJsonEntity;
import org.jclouds.rackspace.cloudservers.decorators.AddServerNameAsJsonEntity;
import org.jclouds.rackspace.cloudservers.decorators.AddConfirmResizeAsJsonEntity;
import org.jclouds.rackspace.cloudservers.decorators.AddCreateImageAsJsonEntity;
import org.jclouds.rackspace.cloudservers.decorators.AddRebootTypeAsJsonEntity;
import org.jclouds.rackspace.cloudservers.decorators.AddResizeFlavorAsJsonEntity;
import org.jclouds.rackspace.cloudservers.decorators.AddRevertResizeAsJsonEntity;
import org.jclouds.rackspace.cloudservers.decorators.AddSharedIpGroupAsJsonEntity;
import org.jclouds.rackspace.cloudservers.domain.Addresses;
import org.jclouds.rackspace.cloudservers.domain.BackupSchedule;
import org.jclouds.rackspace.cloudservers.domain.Flavor;
@ -74,16 +74,16 @@ import org.jclouds.rackspace.cloudservers.options.CreateSharedIpGroupOptions;
import org.jclouds.rackspace.cloudservers.options.ListOptions;
import org.jclouds.rackspace.cloudservers.options.RebuildServerOptions;
import org.jclouds.rackspace.filters.AuthenticateRequest;
import org.jclouds.rest.Endpoint;
import org.jclouds.rest.EntityParam;
import org.jclouds.rest.ExceptionParser;
import org.jclouds.rest.MapBinder;
import org.jclouds.rest.MapEntityParam;
import org.jclouds.rest.ParamParser;
import org.jclouds.rest.QueryParams;
import org.jclouds.rest.RequestFilters;
import org.jclouds.rest.ResponseParser;
import org.jclouds.rest.SkipEncoding;
import org.jclouds.rest.annotations.DecoratorParam;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.MapBinder;
import org.jclouds.rest.annotations.MapEntityParam;
import org.jclouds.rest.annotations.ParamParser;
import org.jclouds.rest.annotations.QueryParams;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.ResponseParser;
import org.jclouds.rest.annotations.SkipEncoding;
/**
* Provides access to Cloud Servers via their REST API.
@ -170,7 +170,7 @@ public interface CloudServersConnection {
// TODO:cloudServersFault (400, 500), serviceUnavailable (503), unauthorized (401), badRequest
// (400), badMediaType(415),buildInProgress (409), overLimit (403)
boolean rebootServer(@PathParam("id") int id,
@EntityParam(RebootTypeBinder.class) RebootType rebootType);
@DecoratorParam(AddRebootTypeAsJsonEntity.class) RebootType rebootType);
/**
* The resize function converts an existing server to a different flavor, in essence, scaling the
@ -192,7 +192,7 @@ public interface CloudServersConnection {
// TODO:cloudServersFault (400, 500), serviceUnavailable (503), unauthorized (401), badRequest
// (400), badMediaType(415), itemNotFound (404), buildInProgress (409), serverCapacityUnavailable
// (503), overLimit (413), resizeNotAllowed (403)
boolean resizeServer(@PathParam("id") int id, @EntityParam(ResizeBinder.class) int flavorId);
boolean resizeServer(@PathParam("id") int id, @DecoratorParam(AddResizeFlavorAsJsonEntity.class) int flavorId);
/**
* The resize function converts an existing server to a different flavor, in essence, scaling the
@ -212,7 +212,7 @@ public interface CloudServersConnection {
// TODO:cloudServersFault (400, 500), serviceUnavailable (503), unauthorized (401), badRequest
// (400), badMediaType(415), itemNotFound (404), buildInProgress (409), serverCapacityUnavailable
// (503), overLimit (413), resizeNotAllowed (403)
boolean confirmResizeServer(@PathParam("id") @EntityParam(ConfirmResizeBinder.class) int id);
boolean confirmResizeServer(@PathParam("id") @DecoratorParam(AddConfirmResizeAsJsonEntity.class) int id);
/**
* The resize function converts an existing server to a different flavor, in essence, scaling the
@ -232,7 +232,7 @@ public interface CloudServersConnection {
// TODO:cloudServersFault (400, 500), serviceUnavailable (503), unauthorized (401), badRequest
// (400), badMediaType(415), itemNotFound (404), buildInProgress (409), serverCapacityUnavailable
// (503), overLimit (413), resizeNotAllowed (403)
boolean revertResizeServer(@PathParam("id") @EntityParam(RevertResizeBinder.class) int id);
boolean revertResizeServer(@PathParam("id") @DecoratorParam(AddRevertResizeAsJsonEntity.class) int id);
/**
* This operation asynchronously provisions a new server. The progress of this operation depends
@ -304,7 +304,7 @@ public interface CloudServersConnection {
@PUT
@ExceptionParser(ReturnFalseOn404.class)
@Path("/servers/{id}/ips/public/{address}")
@MapBinder(ShareIpBinder.class)
@MapBinder(AddSharedIpGroupAsJsonEntity.class)
// TODO: cloudServersFault (400, 500), serviceUnavailable (503), unauthorized (401), badRequest
// (400), badMediaType(415), buildInProgress (409), overLimit (413)
boolean shareIp(@PathParam("address") @ParamParser(IpAddress.class) InetAddress addressToShare,
@ -344,7 +344,7 @@ public interface CloudServersConnection {
// TODO: cloudServersFault (400, 500), serviceUnavailable (503), unauthorized (401), badRequest
// (400), badMediaType(415), buildInProgress (409), overLimit (413)
boolean changeAdminPass(@PathParam("id") int id,
@EntityParam(ChangeAdminPassBinder.class) String adminPass);
@DecoratorParam(AddAdminPassAsJsonEntity.class) String adminPass);
/**
* This operation allows you to update the name of the server. This operation changes the name of
@ -360,7 +360,7 @@ public interface CloudServersConnection {
// TODO: cloudServersFault (400, 500), serviceUnavailable (503), unauthorized (401), badRequest
// (400), badMediaType(415), buildInProgress (409), overLimit (413)
boolean renameServer(@PathParam("id") int id,
@EntityParam(ChangeServerNameBinder.class) String newName);
@DecoratorParam(AddServerNameAsJsonEntity.class) String newName);
/**
*
@ -447,7 +447,7 @@ public interface CloudServersConnection {
@ResponseParser(ParseImageFromJsonResponse.class)
@QueryParams(keys = "format", values = "json")
@ExceptionParser(ReturnImageNotFoundOn404.class)
@MapBinder(CreateImageBinder.class)
@MapBinder(AddCreateImageAsJsonEntity.class)
@Path("/images")
// TODO: cloudServersFault (400, 500), serviceUnavailable (503), unauthorized (401), badRequest
// (400), badMediaType(415), buildInProgress (409), serverCapacityUnavailable (503), overLimit
@ -554,7 +554,7 @@ public interface CloudServersConnection {
// (400), badMediaType(415), buildInProgress (409), serverCapacityUnavailable (503),
// backupOrResizeInProgress(409), resizeNotAllowed (403). overLimit (413)
boolean replaceBackupSchedule(@PathParam("id") int id,
@EntityParam(BackupScheduleBinder.class) BackupSchedule backupSchedule);
@DecoratorParam(AddBackupScheduleAsJsonEntity.class) BackupSchedule backupSchedule);
/**
* List all server addresses

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rackspace.cloudservers.binders;
package org.jclouds.rackspace.cloudservers.decorators;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
@ -29,7 +29,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.binders.JsonBinder;
import org.jclouds.rest.decorators.AddAsJsonEntity;
import com.google.common.collect.ImmutableMap;
@ -38,17 +38,17 @@ import com.google.common.collect.ImmutableMap;
* @author Adrian Cole
*
*/
public class ChangeAdminPassBinder extends JsonBinder {
public class AddAdminPassAsJsonEntity extends AddAsJsonEntity {
@Override
public void addEntityToRequest(Map<String, String> postParams, HttpRequest request) {
public HttpRequest decorateRequest(HttpRequest request, Map<String, String> postParams) {
throw new IllegalStateException("Change Admin Pass is a PUT operation");
}
@Override
public void addEntityToRequest(Object toBind, HttpRequest request) {
public HttpRequest decorateRequest(HttpRequest request, Object toBind) {
checkArgument(toBind instanceof String, "this binder is only valid for Strings!");
super.addEntityToRequest(ImmutableMap.of("server", ImmutableMap.of("adminPass", checkNotNull(
toBind, "adminPass"))), request);
return super.decorateRequest(request, ImmutableMap.of("server", ImmutableMap.of("adminPass",
checkNotNull(toBind, "adminPass"))));
}
}

View File

@ -21,15 +21,15 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rackspace.cloudservers.binders;
package org.jclouds.rackspace.cloudservers.decorators;
import static com.google.common.base.Preconditions.checkArgument;
import java.util.Map;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.binders.JsonBinder;
import org.jclouds.rackspace.cloudservers.domain.BackupSchedule;
import org.jclouds.rest.decorators.AddAsJsonEntity;
import com.google.common.collect.ImmutableMap;
@ -38,18 +38,18 @@ import com.google.common.collect.ImmutableMap;
* @author Adrian Cole
*
*/
public class BackupScheduleBinder extends JsonBinder {
public class AddBackupScheduleAsJsonEntity extends AddAsJsonEntity {
@Override
public void addEntityToRequest(Map<String, String> postParams, HttpRequest request) {
public HttpRequest decorateRequest(HttpRequest request, Map<String, String> postParams) {
throw new IllegalStateException(
"Replace Backup Schedule needs an BackupSchedule object, not a Map");
}
@Override
public void addEntityToRequest(Object toBind, HttpRequest request) {
public HttpRequest decorateRequest(HttpRequest request, Object toBind) {
checkArgument(toBind instanceof BackupSchedule,
"this binder is only valid for BackupSchedules!");
super.addEntityToRequest(ImmutableMap.of("backupSchedule", toBind), request);
return super.decorateRequest(request, ImmutableMap.of("backupSchedule", toBind));
}
}

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rackspace.cloudservers.binders;
package org.jclouds.rackspace.cloudservers.decorators;
import java.util.Collections;
@ -29,20 +29,21 @@ import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.binders.EntityBinder;
import org.jclouds.rest.decorators.RequestDecorator;
/**
*
* @author Adrian Cole
*
*/
public class ConfirmResizeBinder implements EntityBinder {
public class AddConfirmResizeAsJsonEntity implements RequestDecorator {
public void addEntityToRequest(Object toBind, HttpRequest request) {
public HttpRequest decorateRequest(HttpRequest request, Object toBind) {
request.setEntity("{\"confirmResize\":null}");
request.getHeaders().replaceValues(HttpHeaders.CONTENT_LENGTH,
Collections.singletonList("{\"confirmResize\":null}".getBytes().length + ""));
request.getHeaders().replaceValues(HttpHeaders.CONTENT_TYPE,
Collections.singletonList(MediaType.APPLICATION_JSON));
return request;
}
}

View File

@ -21,14 +21,14 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rackspace.cloudservers.binders;
package org.jclouds.rackspace.cloudservers.decorators;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.binders.JsonBinder;
import org.jclouds.rest.decorators.AddAsJsonEntity;
import com.google.common.collect.ImmutableMap;
@ -37,7 +37,7 @@ import com.google.common.collect.ImmutableMap;
* @author Adrian Cole
*
*/
public class CreateImageBinder extends JsonBinder {
public class AddCreateImageAsJsonEntity extends AddAsJsonEntity {
@SuppressWarnings("unused")
private class CreateImageRequest {
@ -52,15 +52,15 @@ public class CreateImageBinder extends JsonBinder {
}
@Override
public void addEntityToRequest(Map<String, String> postParams, HttpRequest request) {
public HttpRequest decorateRequest(HttpRequest request, Map<String, String> postParams) {
CreateImageRequest createRequest = new CreateImageRequest(Integer
.parseInt(checkNotNull(postParams.get("serverId"))), checkNotNull(postParams
.get("imageName")));
super.addEntityToRequest(ImmutableMap.of("image", createRequest), request);
return super.decorateRequest(request, ImmutableMap.of("image", createRequest));
}
@Override
public void addEntityToRequest(Object toBind, HttpRequest request) {
public HttpRequest decorateRequest(HttpRequest request, Object toBind) {
throw new IllegalArgumentException("image is needs parameters");
}
}

View File

@ -21,7 +21,7 @@
* under the License.
* ====================================================================
*/
package org.jclouds.rackspace.cloudservers.binders;
package org.jclouds.rackspace.cloudservers.decorators;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
@ -29,8 +29,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.binders.JsonBinder;
import org.jclouds.rackspace.cloudservers.domain.RebootType;
import org.jclouds.rest.decorators.AddAsJsonEntity;
import com.google.common.collect.ImmutableMap;
@ -39,17 +39,17 @@ import com.google.common.collect.ImmutableMap;
* @author Adrian Cole
*
*/
public class RebootTypeBinder extends JsonBinder {
public class AddRebootTypeAsJsonEntity extends AddAsJsonEntity {
@Override
public void addEntityToRequest(Map<String, String> postParams, HttpRequest request) {
public HttpRequest decorateRequest(HttpRequest request, Map<String, String> postParams) {
throw new IllegalStateException("Reboot doesn't take map parameters");
}
@Override
public void addEntityToRequest(Object toBind, HttpRequest request) {
public HttpRequest decorateRequest(HttpRequest request, Object toBind) {
checkArgument(toBind instanceof RebootType, "this binder is only valid for RebootTypes!");
super.addEntityToRequest(ImmutableMap.of("reboot", ImmutableMap.of("type", checkNotNull(
toBind, "type"))), request);
return super.decorateRequest(request, ImmutableMap.of("reboot", ImmutableMap.of("type",
checkNotNull(toBind, "type"))));
}
}

Some files were not shown because too many files have changed in this diff Show More