Issue 75: Added GET with options for object

git-svn-id: http://jclouds.googlecode.com/svn/trunk@1820 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
jamurty 2009-07-19 23:08:08 +00:00
parent 3c0547c7df
commit 427ccfa963
4 changed files with 53 additions and 24 deletions

View File

@ -66,7 +66,7 @@ public class GetOptions extends BaseHttpRequestOptions {
Multimap<String, String> headers = super.buildRequestHeaders(); Multimap<String, String> headers = super.buildRequestHeaders();
String range = getRange(); String range = getRange();
if (range != null) if (range != null)
headers.put("Content-Range", this.getRange()); headers.put("Range", this.getRange());
return headers; return headers;
} }

View File

@ -36,6 +36,7 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import org.jclouds.http.functions.ParseETagHeader; 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.CFObjectBinder;
import org.jclouds.rackspace.cloudfiles.binders.UserMetadataBinder; import org.jclouds.rackspace.cloudfiles.binders.UserMetadataBinder;
import org.jclouds.rackspace.cloudfiles.domain.AccountMetadata; import org.jclouds.rackspace.cloudfiles.domain.AccountMetadata;
@ -86,13 +87,7 @@ public interface CloudFilesConnection {
@ResponseParser(ParseContainerListFromGsonResponse.class) @ResponseParser(ParseContainerListFromGsonResponse.class)
@Query(key = "format", value = "json") @Query(key = "format", value = "json")
@Path("/") @Path("/")
List<ContainerMetadata> listOwnedContainers(); List<ContainerMetadata> listOwnedContainers(ListContainerOptions ... options);
@GET
@ResponseParser(ParseContainerListFromGsonResponse.class)
@Query(key = "format", value = "json")
@Path("/")
List<ContainerMetadata> listOwnedContainers(ListContainerOptions options);
@PUT @PUT
@Path("{container}") @Path("{container}")
@ -124,9 +119,7 @@ public interface CloudFilesConnection {
@ExceptionParser(ReturnS3ObjectNotFoundOn404.class) @ExceptionParser(ReturnS3ObjectNotFoundOn404.class)
@Path("{container}/{key}") @Path("{container}/{key}")
Future<CFObject> getObject(@PathParam("container") String container, Future<CFObject> getObject(@PathParam("container") String container,
@PathParam("key") String key); @PathParam("key") String key, GetOptions ... options);
// TODO: GET object with options
@POST @POST
@ResponseParser(ReturnTrueOn202FalseOtherwise.class) @ResponseParser(ReturnTrueOn202FalseOtherwise.class)

View File

@ -118,9 +118,10 @@ public class ParseObjectMetadataFromHeaders implements Function<HttpResponse, CF
private void addUserMetadataTo(HttpResponse from, Metadata metadata) { private void addUserMetadataTo(HttpResponse from, Metadata metadata) {
for (Entry<String, String> header : from.getHeaders().entries()) { for (Entry<String, String> header : from.getHeaders().entries()) {
if (header.getKey() != null 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());
} }
} }
} }

View File

@ -38,6 +38,7 @@ import java.util.concurrent.TimeUnit;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.jclouds.http.HttpResponseException; import org.jclouds.http.HttpResponseException;
import org.jclouds.http.HttpUtils; import org.jclouds.http.HttpUtils;
import org.jclouds.http.options.GetOptions;
import org.jclouds.logging.log4j.config.Log4JLoggingModule; import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.rackspace.cloudfiles.domain.AccountMetadata; import org.jclouds.rackspace.cloudfiles.domain.AccountMetadata;
import org.jclouds.rackspace.cloudfiles.domain.CFObject; import org.jclouds.rackspace.cloudfiles.domain.CFObject;
@ -78,13 +79,30 @@ public class CloudFilesConnectionLiveTest {
long initialContainerCount = response.size(); long initialContainerCount = response.size();
assertTrue(initialContainerCount >= 0); assertTrue(initialContainerCount >= 0);
String[] containerNames = new String[] { bucketPrefix + ".testListOwnedContainers1", // Create test containers
String[] containerNames = new String[] {
bucketPrefix + ".testListOwnedContainers1",
bucketPrefix + ".testListOwnedContainers2" }; bucketPrefix + ".testListOwnedContainers2" };
assertTrue(connection.putContainer(containerNames[0])); assertTrue(connection.putContainer(containerNames[0]));
assertTrue(connection.putContainer(containerNames[1])); assertTrue(connection.putContainer(containerNames[1]));
// Test default listing
response = connection.listOwnedContainers(); response = connection.listOwnedContainers();
assertEquals(response.size(), initialContainerCount + 2); 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[0]));
assertTrue(connection.deleteContainerIfEmpty(containerNames[1])); assertTrue(connection.deleteContainerIfEmpty(containerNames[1]));
response = connection.listOwnedContainers(); response = connection.listOwnedContainers();
@ -160,7 +178,7 @@ public class CloudFilesConnectionLiveTest {
object.generateETag(); object.generateETag();
object.getMetadata().setContentType("text/plain"); object.getMetadata().setContentType("text/plain");
object.getMetadata().getUserMetadata().put( 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); byte[] md5 = connection.putObject(containerName, object).get(10, TimeUnit.SECONDS);
assertEquals(HttpUtils.toHexString(md5), assertEquals(HttpUtils.toHexString(md5),
HttpUtils.toHexString(object.getMetadata().getETag())); HttpUtils.toHexString(object.getMetadata().getETag()));
@ -178,13 +196,13 @@ public class CloudFilesConnectionLiveTest {
assertEquals(metadata.getUserMetadata().entries().size(), 1); assertEquals(metadata.getUserMetadata().entries().size(), 1);
// Notice the quirk where CF changes the case of returned metadata names // Notice the quirk where CF changes the case of returned metadata names
assertEquals(Iterables.getLast(metadata.getUserMetadata().get( assertEquals(Iterables.getLast(metadata.getUserMetadata().get(
CloudFilesHeaders.USER_METADATA_PREFIX + "Metadata")), (CloudFilesHeaders.USER_METADATA_PREFIX + "Metadata").toLowerCase())),
"metadata-value"); "metadata-value");
// Test POST to update object's metadata // Test POST to update object's metadata
Multimap<String, String> userMetadata = HashMultimap.create(); Multimap<String, String> userMetadata = HashMultimap.create();
userMetadata.put(CloudFilesHeaders.USER_METADATA_PREFIX + "new-metadata-1", "value-1"); 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-2", "value-2");
assertTrue(connection.setObjectMetadata(containerName, object.getKey(), userMetadata)); assertTrue(connection.setObjectMetadata(containerName, object.getKey(), userMetadata));
// Test GET of missing object // Test GET of missing object
@ -193,18 +211,18 @@ public class CloudFilesConnectionLiveTest {
assertEquals(getObject, CFObject.NOT_FOUND); assertEquals(getObject, CFObject.NOT_FOUND);
// Test GET of object (including updated metadata) // 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(IOUtils.toString((InputStream)getObject.getData()), data);
assertEquals(getObject.getKey(), object.getKey()); assertEquals(getObject.getKey(), object.getKey());
assertEquals(getObject.getContentLength(), data.length()); assertEquals(getObject.getContentLength(), data.length());
assertEquals(getObject.getMetadata().getContentType(), "text/plain"); assertEquals(getObject.getMetadata().getContentType(), "text/plain");
assertEquals(getObject.getMetadata().getETag(), object.getMetadata().getETag()); assertEquals(getObject.getMetadata().getETag(), object.getMetadata().getETag());
assertEquals(getObject.getMetadata().getUserMetadata().entries().size(), 2); 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( 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( 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) // Test PUT with invalid ETag (as if object's data was corrupted in transit)
String correctEtag = HttpUtils.toHexString(object.getMetadata().getETag()); String correctEtag = HttpUtils.toHexString(object.getMetadata().getETag());
@ -222,7 +240,24 @@ public class CloudFilesConnectionLiveTest {
object = new CFObject("chunked-object", bais); object = new CFObject("chunked-object", bais);
md5 = connection.putObject(containerName, object).get(10, TimeUnit.SECONDS); md5 = connection.putObject(containerName, object).get(10, TimeUnit.SECONDS);
assertEquals(HttpUtils.toHexString(md5), correctEtag); 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, "object"));
assertTrue(connection.deleteObject(containerName, "chunked-object")); assertTrue(connection.deleteObject(containerName, "chunked-object"));