From 427ccfa9637a4cbb821c82dabdbdd96219b6551c Mon Sep 17 00:00:00 2001 From: jamurty Date: Sun, 19 Jul 2009 23:08:08 +0000 Subject: [PATCH] Issue 75: Added GET with options for object git-svn-id: http://jclouds.googlecode.com/svn/trunk@1820 3d8758e0-26b5-11de-8745-db77d3ebf521 --- .../org/jclouds/http/options/GetOptions.java | 2 +- .../cloudfiles/CloudFilesConnection.java | 13 +---- .../ParseObjectMetadataFromHeaders.java | 5 +- .../CloudFilesConnectionLiveTest.java | 57 +++++++++++++++---- 4 files changed, 53 insertions(+), 24 deletions(-) diff --git a/core/src/main/java/org/jclouds/http/options/GetOptions.java b/core/src/main/java/org/jclouds/http/options/GetOptions.java index bb6819233d..bafeb98607 100644 --- a/core/src/main/java/org/jclouds/http/options/GetOptions.java +++ b/core/src/main/java/org/jclouds/http/options/GetOptions.java @@ -66,7 +66,7 @@ public class GetOptions extends BaseHttpRequestOptions { Multimap headers = super.buildRequestHeaders(); String range = getRange(); if (range != null) - headers.put("Content-Range", this.getRange()); + headers.put("Range", this.getRange()); return headers; } diff --git a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/CloudFilesConnection.java b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/CloudFilesConnection.java index 39a8690e10..617102395a 100644 --- a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/CloudFilesConnection.java +++ b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/CloudFilesConnection.java @@ -36,6 +36,7 @@ import javax.ws.rs.Path; import javax.ws.rs.PathParam; import org.jclouds.http.functions.ParseETagHeader; +import org.jclouds.http.options.GetOptions; import org.jclouds.rackspace.cloudfiles.binders.CFObjectBinder; import org.jclouds.rackspace.cloudfiles.binders.UserMetadataBinder; import org.jclouds.rackspace.cloudfiles.domain.AccountMetadata; @@ -86,13 +87,7 @@ public interface CloudFilesConnection { @ResponseParser(ParseContainerListFromGsonResponse.class) @Query(key = "format", value = "json") @Path("/") - List listOwnedContainers(); - - @GET - @ResponseParser(ParseContainerListFromGsonResponse.class) - @Query(key = "format", value = "json") - @Path("/") - List listOwnedContainers(ListContainerOptions options); + List listOwnedContainers(ListContainerOptions ... options); @PUT @Path("{container}") @@ -124,9 +119,7 @@ public interface CloudFilesConnection { @ExceptionParser(ReturnS3ObjectNotFoundOn404.class) @Path("{container}/{key}") Future getObject(@PathParam("container") String container, - @PathParam("key") String key); - - // TODO: GET object with options + @PathParam("key") String key, GetOptions ... options); @POST @ResponseParser(ReturnTrueOn202FalseOtherwise.class) diff --git a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/functions/ParseObjectMetadataFromHeaders.java b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/functions/ParseObjectMetadataFromHeaders.java index 3b47c46f86..24199b1dbb 100644 --- a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/functions/ParseObjectMetadataFromHeaders.java +++ b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/functions/ParseObjectMetadataFromHeaders.java @@ -118,9 +118,10 @@ public class ParseObjectMetadataFromHeaders implements Function header : from.getHeaders().entries()) { if (header.getKey() != null - && header.getKey().startsWith(CloudFilesHeaders.USER_METADATA_PREFIX)) + && header.getKey().toLowerCase().startsWith( + CloudFilesHeaders.USER_METADATA_PREFIX.toLowerCase())) { - metadata.getUserMetadata().put(header.getKey(), header.getValue()); + metadata.getUserMetadata().put(header.getKey().toLowerCase(), header.getValue()); } } } diff --git a/rackspace/cloudfiles/core/src/test/java/org/jclouds/rackspace/cloudfiles/CloudFilesConnectionLiveTest.java b/rackspace/cloudfiles/core/src/test/java/org/jclouds/rackspace/cloudfiles/CloudFilesConnectionLiveTest.java index 682c2df06f..68bae74bb7 100644 --- a/rackspace/cloudfiles/core/src/test/java/org/jclouds/rackspace/cloudfiles/CloudFilesConnectionLiveTest.java +++ b/rackspace/cloudfiles/core/src/test/java/org/jclouds/rackspace/cloudfiles/CloudFilesConnectionLiveTest.java @@ -38,6 +38,7 @@ import java.util.concurrent.TimeUnit; import org.apache.commons.io.IOUtils; import org.jclouds.http.HttpResponseException; import org.jclouds.http.HttpUtils; +import org.jclouds.http.options.GetOptions; import org.jclouds.logging.log4j.config.Log4JLoggingModule; import org.jclouds.rackspace.cloudfiles.domain.AccountMetadata; import org.jclouds.rackspace.cloudfiles.domain.CFObject; @@ -78,13 +79,30 @@ public class CloudFilesConnectionLiveTest { long initialContainerCount = response.size(); assertTrue(initialContainerCount >= 0); - String[] containerNames = new String[] { bucketPrefix + ".testListOwnedContainers1", - bucketPrefix + ".testListOwnedContainers2" }; + // Create test containers + String[] containerNames = new String[] { + bucketPrefix + ".testListOwnedContainers1", + bucketPrefix + ".testListOwnedContainers2" }; assertTrue(connection.putContainer(containerNames[0])); assertTrue(connection.putContainer(containerNames[1])); + + // Test default listing response = connection.listOwnedContainers(); assertEquals(response.size(), initialContainerCount + 2); + + // Test listing with options + response = connection.listOwnedContainers(ListContainerOptions.Builder + .afterMarker(containerNames[0].substring(0, containerNames[0].length() - 1)) + .maxResults(1)); + assertEquals(response.size(), 1); + assertEquals(response.get(0).getName(), containerNames[0]); + response = connection.listOwnedContainers(ListContainerOptions.Builder + .afterMarker(containerNames[0]).maxResults(1)); + assertEquals(response.size(), 1); + assertEquals(response.get(0).getName(), containerNames[1]); + + // Cleanup and test containers have been removed assertTrue(connection.deleteContainerIfEmpty(containerNames[0])); assertTrue(connection.deleteContainerIfEmpty(containerNames[1])); response = connection.listOwnedContainers(); @@ -160,7 +178,7 @@ public class CloudFilesConnectionLiveTest { object.generateETag(); object.getMetadata().setContentType("text/plain"); object.getMetadata().getUserMetadata().put( - CloudFilesHeaders.USER_METADATA_PREFIX + "metadata", "metadata-value"); + CloudFilesHeaders.USER_METADATA_PREFIX + "Metadata", "metadata-value"); byte[] md5 = connection.putObject(containerName, object).get(10, TimeUnit.SECONDS); assertEquals(HttpUtils.toHexString(md5), HttpUtils.toHexString(object.getMetadata().getETag())); @@ -178,13 +196,13 @@ public class CloudFilesConnectionLiveTest { assertEquals(metadata.getUserMetadata().entries().size(), 1); // Notice the quirk where CF changes the case of returned metadata names assertEquals(Iterables.getLast(metadata.getUserMetadata().get( - CloudFilesHeaders.USER_METADATA_PREFIX + "Metadata")), + (CloudFilesHeaders.USER_METADATA_PREFIX + "Metadata").toLowerCase())), "metadata-value"); // Test POST to update object's metadata Multimap userMetadata = HashMultimap.create(); - userMetadata.put(CloudFilesHeaders.USER_METADATA_PREFIX + "new-metadata-1", "value-1"); - userMetadata.put(CloudFilesHeaders.USER_METADATA_PREFIX + "new-metadata-2", "value-2"); + userMetadata.put(CloudFilesHeaders.USER_METADATA_PREFIX + "New-Metadata-1", "value-1"); + userMetadata.put(CloudFilesHeaders.USER_METADATA_PREFIX + "New-Metadata-2", "value-2"); assertTrue(connection.setObjectMetadata(containerName, object.getKey(), userMetadata)); // Test GET of missing object @@ -193,18 +211,18 @@ public class CloudFilesConnectionLiveTest { assertEquals(getObject, CFObject.NOT_FOUND); // Test GET of object (including updated metadata) - getObject = connection.getObject(containerName, object.getKey()).get(10, TimeUnit.SECONDS); + getObject = connection.getObject(containerName, object.getKey()).get(120, TimeUnit.SECONDS); assertEquals(IOUtils.toString((InputStream)getObject.getData()), data); assertEquals(getObject.getKey(), object.getKey()); assertEquals(getObject.getContentLength(), data.length()); assertEquals(getObject.getMetadata().getContentType(), "text/plain"); assertEquals(getObject.getMetadata().getETag(), object.getMetadata().getETag()); assertEquals(getObject.getMetadata().getUserMetadata().entries().size(), 2); - // Notice the quirk where CF changes the case of sreturned metadata names + // Notice the quirk where CF changes the case of returned metadata names assertEquals(Iterables.getLast(getObject.getMetadata().getUserMetadata().get( - CloudFilesHeaders.USER_METADATA_PREFIX + "New-Metadata-1")), "value-1"); + (CloudFilesHeaders.USER_METADATA_PREFIX + "New-Metadata-1").toLowerCase())), "value-1"); assertEquals(Iterables.getLast(getObject.getMetadata().getUserMetadata().get( - CloudFilesHeaders.USER_METADATA_PREFIX + "New-Metadata-2")), "value-2"); + (CloudFilesHeaders.USER_METADATA_PREFIX + "New-Metadata-2").toLowerCase())), "value-2"); // Test PUT with invalid ETag (as if object's data was corrupted in transit) String correctEtag = HttpUtils.toHexString(object.getMetadata().getETag()); @@ -222,7 +240,24 @@ public class CloudFilesConnectionLiveTest { object = new CFObject("chunked-object", bais); md5 = connection.putObject(containerName, object).get(10, TimeUnit.SECONDS); assertEquals(HttpUtils.toHexString(md5), correctEtag); - // TODO: Get and confirm data + + // Test GET with options + // Non-matching ETag + try { + connection.getObject(containerName, object.getKey(), + GetOptions.Builder.ifETagDoesntMatch(md5)).get(120, TimeUnit.SECONDS); + } catch (Exception e) { + assertEquals(e.getCause().getClass(), HttpResponseException.class); + assertEquals(((HttpResponseException) e.getCause()).getResponse().getStatusCode(), 304); + } + // Matching ETag + getObject = connection.getObject(containerName, object.getKey(), + GetOptions.Builder.ifETagMatches(md5)).get(120, TimeUnit.SECONDS); + assertEquals(getObject.getMetadata().getETag(), md5); + // Range + getObject = connection.getObject(containerName, object.getKey(), + GetOptions.Builder.startAt(8)).get(120, TimeUnit.SECONDS); + assertEquals(IOUtils.toString((InputStream)getObject.getData()), data.substring(8)); assertTrue(connection.deleteObject(containerName, "object")); assertTrue(connection.deleteObject(containerName, "chunked-object"));