Issue 73: changed eTag to String, as at least two clouds don't have parsable etags; changed user metadata to Map from Multimap as there are no dupes

git-svn-id: http://jclouds.googlecode.com/svn/trunk@1973 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
adrian.f.cole 2009-10-12 06:10:15 +00:00
parent 04f70ce8f7
commit 33d11fe07f
63 changed files with 379 additions and 392 deletions

View File

@ -179,7 +179,7 @@ public interface S3BlobStore extends BlobStore<BucketMetadata, ObjectMetadata, S
@PUT
@Path("{key}")
@ResponseParser(ParseETagHeader.class)
Future<byte[]> putBlob(
Future<String> putBlob(
@HostPrefixParam String bucketName,
@PathParam("key") @ParamParser(BlobKey.class) @BinderParam(BindS3ObjectToEntity.class) S3Object object);

View File

@ -204,7 +204,7 @@ public interface S3Connection {
@PUT
@Path("{key}")
@ResponseParser(ParseETagHeader.class)
Future<byte[]> putObject(
Future<String> putObject(
@HostPrefixParam String bucketName,
@PathParam("key") @ParamParser(BlobKey.class) @BinderParam(BindS3ObjectToEntity.class) S3Object object,
PutObjectOptions... options);

View File

@ -24,7 +24,6 @@
package org.jclouds.aws.s3.domain;
import java.io.Serializable;
import java.util.Arrays;
import org.jclouds.blobstore.domain.BlobMetadata;
@ -52,9 +51,9 @@ public class ObjectMetadata extends BlobMetadata implements Serializable {
dataDisposition).append(", owner=").append(owner).append(", storageClass=").append(
storageClass).append(", allHeaders=").append(allHeaders).append(", dataEncoding=")
.append(dataEncoding).append(", dataType=").append(dataType).append(", eTag=")
.append(Arrays.toString(eTag)).append(", key=").append(key)
.append(", lastModified=").append(lastModified).append(", size=").append(size)
.append(", userMetadata=").append(userMetadata).append("]");
.append(eTag).append(", key=").append(key).append(", lastModified=").append(
lastModified).append(", size=").append(size).append(", userMetadata=")
.append(userMetadata).append("]");
return builder.toString();
}

View File

@ -77,10 +77,10 @@ public class ParseObjectMetadataFromHeaders extends
if (metadata.getETag() == null) {
String eTagHeader = from.getFirstHeaderOrNull(S3Headers.AMZ_MD5);
if (eTagHeader != null) {
metadata.setETag(HttpUtils.fromHexString(eTagHeader));
metadata.setETag(eTagHeader);
}
}
metadata.setContentMD5(metadata.getETag());
metadata.setContentMD5(HttpUtils.fromHexString(metadata.getETag().replaceAll("\"", "")));
}
}

View File

@ -28,10 +28,13 @@ import static com.google.common.base.Preconditions.checkState;
import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Named;
import org.jclouds.aws.s3.domain.CannedAccessPolicy;
import org.jclouds.aws.s3.reference.S3Headers;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.options.BaseHttpRequestOptions;
import org.jclouds.util.DateService;
import org.joda.time.DateTime;
@ -39,8 +42,6 @@ import org.joda.time.DateTime;
import com.google.common.base.Preconditions;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import javax.inject.Inject;
import javax.inject.Named;
/**
* Contains options supported in the REST API for the COPY object operation.
@ -76,7 +77,7 @@ public class CopyObjectOptions extends BaseHttpRequestOptions {
public static final CopyObjectOptions NONE = new CopyObjectOptions();
private Multimap<String, String> metadata;
private Map<String, String> metadata;
private CannedAccessPolicy acl = CannedAccessPolicy.PRIVATE;
@ -149,7 +150,7 @@ public class CopyObjectOptions extends BaseHttpRequestOptions {
* This header can be used with x-amz-copy-source-if-unmodified-since, but cannot be used with
* other conditional copy headers.
*
* @see CopyObjectOptions#ifSourceETagMatches(byte[])
* @see CopyObjectOptions#ifSourceETagMatches(String)
*/
public String getIfMatch() {
return getFirstHeaderOrNull("x-amz-copy-source-if-match");
@ -164,7 +165,7 @@ public class CopyObjectOptions extends BaseHttpRequestOptions {
* This header can be used with x-amz-copy-source-if-modified-since, but cannot be used with
* other conditional copy headers.
*
* @see CopyObjectOptions#ifSourceETagDoesntMatch(byte[])
* @see CopyObjectOptions#ifSourceETagDoesntMatch(String)
*/
public String getIfNoneMatch() {
return getFirstHeaderOrNull("x-amz-copy-source-if-none-match");
@ -176,14 +177,14 @@ public class CopyObjectOptions extends BaseHttpRequestOptions {
*
* @see #overrideMetadataWith(Multimap)
*/
public Multimap<String, String> getMetadata() {
public Map<String, String> getMetadata() {
return metadata;
}
/**
* Only return the object if it has changed since this time.
* <p/>
* Not compatible with {@link #ifSourceETagMatches(byte[])} or
* Not compatible with {@link #ifSourceETagMatches(String)} or
* {@link #ifSourceUnmodifiedSince(DateTime)}
*/
public CopyObjectOptions ifSourceModifiedSince(DateTime ifModifiedSince) {
@ -198,7 +199,7 @@ public class CopyObjectOptions extends BaseHttpRequestOptions {
/**
* Only return the object if it hasn't changed since this time.
* <p/>
* Not compatible with {@link #ifSourceETagDoesntMatch(byte[])} or
* Not compatible with {@link #ifSourceETagDoesntMatch(String)} or
* {@link #ifSourceModifiedSince(DateTime)}
*/
public CopyObjectOptions ifSourceUnmodifiedSince(DateTime ifUnmodifiedSince) {
@ -215,26 +216,26 @@ public class CopyObjectOptions extends BaseHttpRequestOptions {
* The object's eTag hash should match the parameter <code>eTag</code>.
* <p/>
* <p/>
* Not compatible with {@link #ifSourceETagDoesntMatch(byte[])} or
* Not compatible with {@link #ifSourceETagDoesntMatch(String)} or
* {@link #ifSourceModifiedSince(DateTime)}
*
* @param eTag
* hash representing the entity
*/
public CopyObjectOptions ifSourceETagMatches(byte[] eTag) throws UnsupportedEncodingException {
public CopyObjectOptions ifSourceETagMatches(String eTag) throws UnsupportedEncodingException {
checkState(getIfNoneMatch() == null,
"ifETagDoesntMatch() is not compatible with ifETagMatches()");
checkState(getIfModifiedSince() == null,
"ifModifiedSince() is not compatible with ifETagMatches()");
replaceHeader("x-amz-copy-source-if-match", String.format("\"%1$s\"", HttpUtils
.toHexString(checkNotNull(eTag, "eTag"))));
replaceHeader("x-amz-copy-source-if-match", String.format("\"%1$s\"", checkNotNull(eTag,
"eTag")));
return this;
}
/**
* The object should not have a eTag hash corresponding with the parameter <code>eTag</code>.
* <p/>
* Not compatible with {@link #ifSourceETagMatches(byte[])} or
* Not compatible with {@link #ifSourceETagMatches(String)} or
* {@link #ifSourceUnmodifiedSince(DateTime)}
*
* @param eTag
@ -242,13 +243,13 @@ public class CopyObjectOptions extends BaseHttpRequestOptions {
* @throws UnsupportedEncodingException
* if there was a problem converting this into an S3 eTag string
*/
public CopyObjectOptions ifSourceETagDoesntMatch(byte[] eTag)
public CopyObjectOptions ifSourceETagDoesntMatch(String eTag)
throws UnsupportedEncodingException {
checkState(getIfMatch() == null, "ifETagMatches() is not compatible with ifETagDoesntMatch()");
Preconditions.checkState(getIfUnmodifiedSince() == null,
"ifUnmodifiedSince() is not compatible with ifETagDoesntMatch()");
replaceHeader("x-amz-copy-source-if-none-match", String.format("\"%1$s\"", HttpUtils
.toHexString(checkNotNull(eTag, "ifETagDoesntMatch"))));
replaceHeader("x-amz-copy-source-if-none-match", String.format("\"%1$s\"", checkNotNull(eTag,
"ifETagDoesntMatch")));
return this;
}
@ -259,7 +260,7 @@ public class CopyObjectOptions extends BaseHttpRequestOptions {
returnVal.putAll(headers);
if (metadata != null) {
for (String key : metadata.keySet()) {
returnVal.putAll(key.startsWith(metadataPrefix) ? key : metadataPrefix + key, metadata
returnVal.put(key.startsWith(metadataPrefix) ? key : metadataPrefix + key, metadata
.get(key));
}
returnVal.put("x-amz-metadata-directive", "REPLACE");
@ -270,7 +271,7 @@ public class CopyObjectOptions extends BaseHttpRequestOptions {
/**
* Use the provided metadata instead of what is on the source object.
*/
public CopyObjectOptions overrideMetadataWith(Multimap<String, String> metadata) {
public CopyObjectOptions overrideMetadataWith(Map<String, String> metadata) {
checkNotNull(metadata, "metadata");
this.metadata = metadata;
return this;
@ -302,18 +303,18 @@ public class CopyObjectOptions extends BaseHttpRequestOptions {
}
/**
* @see CopyObjectOptions#ifSourceETagMatches(byte[])
* @see CopyObjectOptions#ifSourceETagMatches(String)
*/
public static CopyObjectOptions ifSourceETagMatches(byte[] eTag)
public static CopyObjectOptions ifSourceETagMatches(String eTag)
throws UnsupportedEncodingException {
CopyObjectOptions options = new CopyObjectOptions();
return options.ifSourceETagMatches(eTag);
}
/**
* @see CopyObjectOptions#ifSourceETagDoesntMatch(byte[])
* @see CopyObjectOptions#ifSourceETagDoesntMatch(String)
*/
public static CopyObjectOptions ifSourceETagDoesntMatch(byte[] eTag)
public static CopyObjectOptions ifSourceETagDoesntMatch(String eTag)
throws UnsupportedEncodingException {
CopyObjectOptions options = new CopyObjectOptions();
return options.ifSourceETagDoesntMatch(eTag);
@ -322,7 +323,7 @@ public class CopyObjectOptions extends BaseHttpRequestOptions {
/**
* @see #overrideMetadataWith(Multimap)
*/
public static CopyObjectOptions overrideMetadataWith(Multimap<String, String> metadata) {
public static CopyObjectOptions overrideMetadataWith(Map<String, String> metadata) {
CopyObjectOptions options = new CopyObjectOptions();
return options.overrideMetadataWith(metadata);
}

View File

@ -23,13 +23,12 @@
*/
package org.jclouds.aws.s3.xml;
import javax.inject.Inject;
import org.jclouds.aws.s3.domain.ObjectMetadata;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.util.DateService;
import javax.inject.Inject;
/**
* Parses the response from Amazon S3 COPY Object command.
* <p/>
@ -51,7 +50,7 @@ public class CopyObjectHandler extends ParseSax.HandlerWithResult<ObjectMetadata
public void endElement(String uri, String name, String qName) {
if (qName.equals("ETag")) {
metadata.setETag(HttpUtils.fromHexString(currentText.toString().replaceAll("\"", "")));
metadata.setETag(currentText.toString());
} else if (qName.equals("LastModified")) {
metadata.setLastModified(dateParser.iso8601DateParse(currentText.toString()));
}

View File

@ -93,9 +93,9 @@ public class ListBucketHandler extends ParseSax.HandlerWithResult<ListBucketResp
} else if (qName.equals("LastModified")) {
currentObjectMetadata.setLastModified(dateParser.iso8601DateParse(currentText.toString()));
} else if (qName.equals("ETag")) {
currentObjectMetadata.setETag(HttpUtils.fromHexString(currentText.toString().replaceAll(
"\"", "")));
currentObjectMetadata.setContentMD5(currentObjectMetadata.getETag());
currentObjectMetadata.setETag(currentText.toString());
currentObjectMetadata.setContentMD5(HttpUtils.fromHexString(currentObjectMetadata
.getETag().replaceAll("\"", "")));
} else if (qName.equals("Size")) {
currentObjectMetadata.setSize(Long.parseLong(currentText.toString()));
} else if (qName.equals("Owner")) {

View File

@ -45,6 +45,7 @@ import static org.testng.Assert.assertTrue;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.Map;
import java.util.SortedSet;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
@ -68,8 +69,7 @@ import org.jclouds.util.Utils;
import org.joda.time.DateTime;
import org.testng.annotations.Test;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Maps;
/**
*
@ -337,10 +337,11 @@ public class S3ConnectionLiveTest extends
}
}
private void addToContainerAndValidate(String containerName, String sourceKey)
protected String addToContainerAndValidate(String containerName, String sourceKey)
throws InterruptedException, ExecutionException, TimeoutException, IOException {
addBlobToContainer(containerName, sourceKey);
String etag = addBlobToContainer(containerName, sourceKey);
validateContent(containerName, sourceKey);
return etag;
}
// TODO: fails on linux and windows
@ -407,7 +408,7 @@ public class S3ConnectionLiveTest extends
String containerName = getContainerName();
String destinationContainer = getContainerName();
try {
addToContainerAndValidate(containerName, sourceKey);
String goodETag = addToContainerAndValidate(containerName, sourceKey);
context.getApi().copyObject(containerName, sourceKey, destinationContainer,
destinationKey, ifSourceETagMatches(goodETag)).get(10, TimeUnit.SECONDS);
@ -415,7 +416,7 @@ public class S3ConnectionLiveTest extends
try {
context.getApi().copyObject(containerName, sourceKey, destinationContainer,
destinationKey, ifSourceETagMatches(badETag)).get(10, TimeUnit.SECONDS);
destinationKey, ifSourceETagMatches("setsds")).get(10, TimeUnit.SECONDS);
} catch (ExecutionException e) {
HttpResponseException ex = (HttpResponseException) e.getCause();
assertEquals(ex.getResponse().getStatusCode(), 412);
@ -431,10 +432,10 @@ public class S3ConnectionLiveTest extends
String containerName = getContainerName();
String destinationContainer = getContainerName();
try {
addToContainerAndValidate(containerName, sourceKey);
String goodETag = addToContainerAndValidate(containerName, sourceKey);
context.getApi().copyObject(containerName, sourceKey, destinationContainer,
destinationKey, ifSourceETagDoesntMatch(badETag)).get(10, TimeUnit.SECONDS);
destinationKey, ifSourceETagDoesntMatch("asfasdf")).get(10, TimeUnit.SECONDS);
validateContent(destinationContainer, destinationKey);
try {
@ -458,7 +459,7 @@ public class S3ConnectionLiveTest extends
try {
addToContainerAndValidate(containerName, sourceKey);
Multimap<String, String> metadata = HashMultimap.create();
Map<String, String> metadata = Maps.newHashMap();
metadata.put("adrian", "cole");
context.getApi().copyObject(containerName, sourceKey, destinationContainer,

View File

@ -23,7 +23,6 @@
*/
package org.jclouds.aws.s3.internal;
import java.util.Arrays;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
@ -54,7 +53,6 @@ import org.jclouds.aws.s3.reference.S3Constants;
import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.blobstore.KeyNotFoundException;
import org.jclouds.blobstore.integration.internal.StubBlobStore;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.options.GetOptions;
import org.jclouds.util.DateService;
import org.joda.time.DateTime;
@ -187,14 +185,14 @@ public class StubS3Connection extends StubBlobStore<BucketMetadata, ObjectMetada
if (source.containsKey(sourceObject)) {
S3Object object = source.get(sourceObject);
if (options.getIfMatch() != null) {
if (!Arrays.equals(object.getMetadata().getETag(), HttpUtils
.fromHexString(options.getIfMatch().replaceAll("\"", ""))))
if (!object.getMetadata().getETag().equals(
options.getIfMatch()))
throwResponseException(412);
}
if (options.getIfNoneMatch() != null) {
if (Arrays.equals(object.getMetadata().getETag(), HttpUtils.fromHexString(options
.getIfNoneMatch().replaceAll("\"", ""))))
if (object.getMetadata().getETag().equals(
options.getIfNoneMatch()))
throwResponseException(412);
}
if (options.getIfModifiedSince() != null) {
@ -226,7 +224,7 @@ public class StubS3Connection extends StubBlobStore<BucketMetadata, ObjectMetada
};
}
public Future<byte[]> putObject(final String bucketName, final S3Object object,
public Future<String> putObject(final String bucketName, final S3Object object,
@Nullable PutObjectOptions nullableOptions) {
final PutObjectOptions options = (nullableOptions == null) ? new PutObjectOptions()
: nullableOptions;
@ -313,7 +311,7 @@ public class StubS3Connection extends StubBlobStore<BucketMetadata, ObjectMetada
return super.getBlob(bucketName, key, optionsList.length != 0 ? optionsList[0] : null);
}
public Future<byte[]> putObject(String bucketName, S3Object object,
public Future<String> putObject(String bucketName, S3Object object,
PutObjectOptions... optionsList) {
return putObject(bucketName, object, optionsList.length != 0 ? optionsList[0] : null);
}

View File

@ -34,16 +34,16 @@ import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import org.jclouds.aws.s3.domain.CannedAccessPolicy;
import org.jclouds.aws.s3.reference.S3Headers;
import org.jclouds.http.HttpUtils;
import org.jclouds.util.DateService;
import org.joda.time.DateTime;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
/**
@ -54,22 +54,22 @@ import com.google.common.collect.Multimap;
@Test(groups = "unit", testName = "s3.CopyObjectOptionsTest")
public class CopyObjectOptionsTest {
private byte[] testBytes;
private String etag;
private DateTime now;
private String nowExpected;
private Multimap<String, String> goodMeta;
private Multimap<String, String> badMeta;
private Map<String, String> goodMeta;
private Map<String, String> badMeta;
@BeforeMethod
void setUp() {
goodMeta = HashMultimap.create();
goodMeta = Maps.newHashMap();
goodMeta.put("x-amz-meta-adrian", "foo");
badMeta = HashMultimap.create();
badMeta = Maps.newHashMap();
badMeta.put("x-google-meta-adrian", "foo");
now = new DateTime();
nowExpected = new DateService().rfc822DateFormat(now);
testBytes = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 };
etag = "mama";
}
@Test
@ -93,7 +93,7 @@ public class CopyObjectOptionsTest {
assertEquals(headers.get("x-amz-metadata-directive").iterator().next(), "REPLACE");
assertEquals(options.getMetadata().size(), 1);
assertEquals(headers.get("x-amz-meta-adrian").iterator().next(), "foo");
assertEquals(options.getMetadata().get("x-amz-meta-adrian").iterator().next(), "foo");
assertEquals(options.getMetadata().get("x-amz-meta-adrian"), "foo");
}
@Test
@ -159,7 +159,7 @@ public class CopyObjectOptionsTest {
@Test
public void testIfETagMatches() throws UnsupportedEncodingException {
CopyObjectOptions options = new CopyObjectOptions();
options.ifSourceETagMatches(testBytes);
options.ifSourceETagMatches(etag);
matchesHex(options.getIfMatch());
}
@ -171,7 +171,7 @@ public class CopyObjectOptionsTest {
@Test
public void testIfETagMatchesStatic() throws UnsupportedEncodingException {
CopyObjectOptions options = ifSourceETagMatches(testBytes);
CopyObjectOptions options = ifSourceETagMatches(etag);
matchesHex(options.getIfMatch());
}
@ -183,7 +183,7 @@ public class CopyObjectOptionsTest {
@Test
public void testIfETagDoesntMatch() throws UnsupportedEncodingException {
CopyObjectOptions options = new CopyObjectOptions();
options.ifSourceETagDoesntMatch(testBytes);
options.ifSourceETagDoesntMatch(etag);
matchesHex(options.getIfNoneMatch());
}
@ -195,7 +195,7 @@ public class CopyObjectOptionsTest {
@Test
public void testIfETagDoesntMatchStatic() throws UnsupportedEncodingException {
CopyObjectOptions options = ifSourceETagDoesntMatch(testBytes);
CopyObjectOptions options = ifSourceETagDoesntMatch(etag);
matchesHex(options.getIfNoneMatch());
}
@ -205,7 +205,7 @@ public class CopyObjectOptionsTest {
}
private void matchesHex(String match) throws UnsupportedEncodingException {
String expected = "\"" + HttpUtils.toHexString(testBytes) + "\"";
String expected = "\"" + etag + "\"";
assertEquals(match, expected);
}
@ -216,13 +216,13 @@ public class CopyObjectOptionsTest {
}
public void testIfUnmodifiedAfterETagMatches() throws UnsupportedEncodingException {
ifSourceETagMatches(testBytes).ifSourceUnmodifiedSince(now);
ifSourceETagMatches(etag).ifSourceUnmodifiedSince(now);
}
@Test(expectedExceptions = IllegalStateException.class)
public void testIfUnmodifiedAfterETagDoesntMatch() throws UnsupportedEncodingException {
ifSourceETagDoesntMatch(testBytes).ifSourceUnmodifiedSince(now);
ifSourceETagDoesntMatch(etag).ifSourceUnmodifiedSince(now);
}
@Test(expectedExceptions = IllegalStateException.class)
@ -233,44 +233,44 @@ public class CopyObjectOptionsTest {
@Test(expectedExceptions = IllegalStateException.class)
public void testIfModifiedAfterETagMatches() throws UnsupportedEncodingException {
ifSourceETagMatches(testBytes).ifSourceModifiedSince(now);
ifSourceETagMatches(etag).ifSourceModifiedSince(now);
}
public void testIfModifiedAfterETagDoesntMatch() throws UnsupportedEncodingException {
ifSourceETagDoesntMatch(testBytes).ifSourceModifiedSince(now);
ifSourceETagDoesntMatch(etag).ifSourceModifiedSince(now);
}
@Test(expectedExceptions = IllegalStateException.class)
public void testETagMatchesAfterIfModified() throws UnsupportedEncodingException {
ifSourceModifiedSince(now).ifSourceETagMatches(testBytes);
ifSourceModifiedSince(now).ifSourceETagMatches(etag);
}
public void testETagMatchesAfterIfUnmodified() throws UnsupportedEncodingException {
ifSourceUnmodifiedSince(now).ifSourceETagMatches(testBytes);
ifSourceUnmodifiedSince(now).ifSourceETagMatches(etag);
}
@Test(expectedExceptions = IllegalStateException.class)
public void testETagMatchesAfterETagDoesntMatch() throws UnsupportedEncodingException {
ifSourceETagDoesntMatch(testBytes).ifSourceETagMatches(testBytes);
ifSourceETagDoesntMatch(etag).ifSourceETagMatches(etag);
}
public void testETagDoesntMatchAfterIfModified() throws UnsupportedEncodingException {
ifSourceModifiedSince(now).ifSourceETagDoesntMatch(testBytes);
ifSourceModifiedSince(now).ifSourceETagDoesntMatch(etag);
}
@Test(expectedExceptions = IllegalStateException.class)
public void testETagDoesntMatchAfterIfUnmodified() throws UnsupportedEncodingException {
ifSourceUnmodifiedSince(now).ifSourceETagDoesntMatch(testBytes);
ifSourceUnmodifiedSince(now).ifSourceETagDoesntMatch(etag);
}
@Test(expectedExceptions = IllegalStateException.class)
public void testETagDoesntMatchAfterETagMatches() throws UnsupportedEncodingException {
ifSourceETagMatches(testBytes).ifSourceETagDoesntMatch(testBytes);
ifSourceETagMatches(etag).ifSourceETagDoesntMatch(etag);
}
@Test
@ -282,15 +282,15 @@ public class CopyObjectOptionsTest {
@Test
void testBuildRequestHeaders() throws UnsupportedEncodingException {
CopyObjectOptions options = ifSourceModifiedSince(now).ifSourceETagDoesntMatch(testBytes)
CopyObjectOptions options = ifSourceModifiedSince(now).ifSourceETagDoesntMatch(etag)
.overrideMetadataWith(goodMeta);
options.setMetadataPrefix("x-amz-meta-");
Multimap<String, String> headers = options.buildRequestHeaders();
assertEquals(headers.get("x-amz-copy-source-if-modified-since").iterator().next(),
new DateService().rfc822DateFormat(now));
assertEquals(headers.get("x-amz-copy-source-if-none-match").iterator().next(), "\""
+ HttpUtils.toHexString(testBytes) + "\"");
assertEquals(headers.get("x-amz-copy-source-if-none-match").iterator().next(), "\"" + etag
+ "\"");
for (String value : goodMeta.values())
assertTrue(headers.containsValue(value));

View File

@ -40,7 +40,6 @@ import org.jclouds.aws.s3.domain.CanonicalUser;
import org.jclouds.aws.s3.domain.ListBucketResponse;
import org.jclouds.aws.s3.domain.ObjectMetadata;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.config.ParserModule;
import org.joda.time.DateTime;
@ -137,7 +136,7 @@ public class S3ParserTest extends PerformanceTest {
DateTime expected = new DateTime("2009-03-12T02:00:13.000Z");
assert object.getLastModified().equals(expected) : String.format(
"expected %1$s, but got %1$s", expected, object.getLastModified());
assertEquals(HttpUtils.toHexString(object.getETag()), "9d7bb64e8e18ee34eec06dd2cf37b766");
assertEquals(object.getETag(), "\"9d7bb64e8e18ee34eec06dd2cf37b766\"");
assert object.getSize() == 136;
CanonicalUser owner = new CanonicalUser(
"e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0");
@ -162,7 +161,7 @@ public class S3ParserTest extends PerformanceTest {
ObjectMetadata metadata = runParseCopyObjectResult();
DateTime expected = new DateTime("2009-03-19T13:23:27.000Z");
assertEquals(metadata.getLastModified(), expected);
assertEquals(HttpUtils.toHexString(metadata.getETag()), "92836a3ea45a6984d1b4d23a747d46bb");
assertEquals(metadata.getETag(), "\"92836a3ea45a6984d1b4d23a747d46bb\"");
}
@Test

View File

@ -42,7 +42,6 @@ import org.jclouds.aws.s3.options.CopyObjectOptions;
import org.jclouds.aws.s3.options.ListBucketOptions;
import org.jclouds.aws.s3.options.PutObjectOptions;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.options.GetOptions;
import org.jclouds.util.Utils;
import org.jets3t.service.S3ObjectsChunk;
@ -114,7 +113,7 @@ public class JCloudsS3Service extends S3Service {
Map map = new HashMap();
// Result fields returned when copy is successful.
map.put("Last-Modified", jcObjectMetadata.getLastModified().toDate());
map.put("ETag", HttpUtils.toHexString(jcObjectMetadata.getETag()));
map.put("ETag", jcObjectMetadata.getETag());
return map;
} catch (Exception e) {
Utils.<S3ServiceException> rethrowIfRuntimeOrSameType(e);
@ -353,9 +352,9 @@ public class JCloudsS3Service extends S3Service {
try {
PutObjectOptions options = Util.convertPutObjectOptions(jsObject.getAcl());
org.jclouds.aws.s3.domain.S3Object jcObject = Util.convertObject(jsObject);
byte eTag[] = connection.putObject(bucketName, jcObject, options).get(
String eTag = connection.putObject(bucketName, jcObject, options).get(
requestTimeoutMilliseconds, TimeUnit.MILLISECONDS);
jsObject.setMd5Hash(eTag);
jsObject.setETag(eTag);
return jsObject;
} catch (Exception e) {
Utils.<S3ServiceException> rethrowIfRuntimeOrSameType(e);

View File

@ -43,10 +43,8 @@ import org.jclouds.aws.s3.domain.ListBucketResponse;
import org.jclouds.aws.s3.options.CopyObjectOptions;
import org.jclouds.aws.s3.options.ListBucketOptions;
import org.jclouds.aws.s3.options.PutObjectOptions;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.options.GetOptions;
import org.jclouds.util.DateService;
import org.jclouds.util.Utils;
import org.jets3t.service.S3ServiceException;
import org.jets3t.service.acl.AccessControlList;
import org.jets3t.service.acl.CanonicalGrantee;
@ -61,9 +59,8 @@ import org.jets3t.service.model.S3Owner;
import org.jets3t.service.utils.RestUtils;
import org.joda.time.DateTime;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
import com.google.common.collect.Maps;
/**
* Convert between jCloud and JetS3t objects.
@ -158,7 +155,7 @@ public class Util {
jcObject.getMetadata().setStorageClass(jsObject.getStorageClass());
if (jsObject.getMd5HashAsHex() != null) {
jcObject.getMetadata().setETag(HttpUtils.fromHexString(jsObject.getMd5HashAsHex()));
jcObject.getMetadata().setETag(jsObject.getMd5HashAsHex());
}
if (jsObject.getOwner() != null) {
@ -207,11 +204,11 @@ public class Util {
}
// TODO: options.ifETagMatches should accept multiple match tags
if (ifMatchTags != null && ifMatchTags.length > 0) {
options.ifETagMatches(Utils.encodeString(ifMatchTags[0]));
options.ifETagMatches(ifMatchTags[0]);
}
// TODO: options.ifETagDoesntMatch should accept multiple match tags
if (ifNoneMatchTags != null && ifNoneMatchTags.length > 0) {
options.ifETagDoesntMatch(Utils.encodeString(ifNoneMatchTags[0]));
options.ifETagDoesntMatch(ifNoneMatchTags[0]);
}
return options;
}
@ -355,14 +352,14 @@ public class Util {
}
// TODO: options.ifETagMatches should accept multiple match tags
if (ifMatchTags != null && ifMatchTags.length > 0) {
options.ifSourceETagMatches(Utils.encodeString(ifMatchTags[0]));
options.ifSourceETagMatches(ifMatchTags[0]);
}
// TODO: options.ifETagDoesntMatch should accept multiple match tags
if (ifNoneMatchTags != null && ifNoneMatchTags.length > 0) {
options.ifSourceETagDoesntMatch(Utils.encodeString(ifNoneMatchTags[0]));
options.ifSourceETagDoesntMatch(ifNoneMatchTags[0]);
}
if (destinationMetadata != null) {
Multimap<String, String> newMetadata = HashMultimap.create();
Map<String, String> newMetadata = Maps.newHashMap();
for (Object maybeUserMetadataObj : destinationMetadata.entrySet()) {
String name = ((Entry<String, String>) maybeUserMetadataObj).getKey();
String value = ((Entry<String, String>) maybeUserMetadataObj).getValue();

View File

@ -51,7 +51,6 @@ import org.jclouds.aws.s3.domain.ObjectMetadata;
import org.jclouds.aws.s3.domain.AccessControlList.GroupGranteeURI;
import org.jclouds.aws.s3.domain.AccessControlList.Permission;
import org.jclouds.blobstore.integration.internal.BaseBlobStoreIntegrationTest;
import org.jclouds.http.HttpUtils;
import org.jets3t.service.S3ObjectsChunk;
import org.jets3t.service.S3Service;
import org.jets3t.service.S3ServiceException;
@ -71,7 +70,6 @@ import org.testng.annotations.Test;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
/**
* Tests to cover JCloudsS3Service
@ -398,8 +396,7 @@ public class JCloudsS3ServiceLiveTest
requestObject.addMetadata("x-amz-meta-" + "my-metadata-1", "value-1");
jsResultObject = service.putObject(new S3Bucket(bucketName), requestObject);
jcObject = context.getApi().getObject(bucketName, objectKey).get(10, TimeUnit.SECONDS);
assertEquals(Iterables.getLast(jcObject.getMetadata().getUserMetadata().get(
"my-metadata-1")), "value-1");
assertEquals(jcObject.getMetadata().getUserMetadata().get("my-metadata-1"), "value-1");
assertEquals(jsResultObject.getMetadata("x-amz-meta-" + "my-metadata-1"), "value-1");
// Upload object with canned public-read ACL
@ -424,8 +421,8 @@ public class JCloudsS3ServiceLiveTest
jsResultObject = service.putObject(new S3Bucket(bucketName), requestObject);
jcObject = context.getApi().getObject(bucketName, objectKey).get(10, TimeUnit.SECONDS);
assertTrue(jsResultObject.verifyData(data.getBytes("UTF-8")));
assertEquals(jsResultObject.getMd5HashAsHex(), HttpUtils.toHexString(jcObject
.getMetadata().getETag()));
assertEquals(jsResultObject.getETag(), jcObject.getMetadata().getETag().replaceAll("\"",
""));
} finally {
returnContainer(bucketName);
}
@ -462,10 +459,9 @@ public class JCloudsS3ServiceLiveTest
.get(10, TimeUnit.SECONDS);
// TODO null keys from s3object! assertEquals(jcDestinationObject.getKey(),
// destinationObjectKey);
assertEquals(Iterators.getLast(jcDestinationObject.getMetadata().getUserMetadata().get(
metadataName).iterator()), sourceMetadataValue);
assertEquals(copyResult.get("ETag"), HttpUtils.toHexString(jcDestinationObject
.getMetadata().getETag()));
assertEquals(jcDestinationObject.getMetadata().getUserMetadata().get(metadataName),
sourceMetadataValue);
assertEquals(copyResult.get("ETag"), jcDestinationObject.getMetadata().getETag());
// Test destination ACL is unchanged (ie private)
org.jclouds.aws.s3.domain.AccessControlList jcACL = context.getApi().getObjectACL(
bucketName, destinationObject.getKey()).get(10, TimeUnit.SECONDS);
@ -479,8 +475,8 @@ public class JCloudsS3ServiceLiveTest
destinationObject, true);
jcDestinationObject = context.getApi().getObject(bucketName, destinationObject.getKey())
.get(10, TimeUnit.SECONDS);
assertEquals(Iterators.getLast(jcDestinationObject.getMetadata().getUserMetadata().get(
metadataName).iterator()), destinationMetadataValue);
assertEquals(jcDestinationObject.getMetadata().getUserMetadata().get(metadataName),
destinationMetadataValue);
// Test destination ACL is unchanged (ie private)
jcACL = context.getApi().getObjectACL(bucketName, destinationObject.getKey()).get(10,
TimeUnit.SECONDS);

View File

@ -271,7 +271,7 @@ public interface AzureBlobConnection {
@PUT
@Path("{container}/{key}")
@ResponseParser(ParseETagHeader.class)
Future<byte[]> putBlob(@PathParam("container") String container,
Future<String> putBlob(@PathParam("container") String container,
@PathParam("key") @ParamParser(BlobKey.class) @BinderParam(BindBlobToEntity.class) Blob object);
/**

View File

@ -147,7 +147,7 @@ public interface AzureBlobStore extends BlobStore<ContainerMetadata, BlobMetadat
@PUT
@Path("{container}/{key}")
@ResponseParser(ParseETagHeader.class)
Future<byte[]> putBlob(
Future<String> putBlob(
@PathParam("container") String container,
@PathParam("key") @ParamParser(BlobKey.class) @BinderParam(GenerateMD5AndBindBlobToEntity.class) Blob object);

View File

@ -53,7 +53,7 @@ public class BlobMetadata extends org.jclouds.blobstore.domain.BlobMetadata {
}
public BlobMetadata(String currentName, URI currentUrl, DateTime currentLastModified,
byte[] currentETag, long currentSize, String currentContentType,
String currentETag, long currentSize, String currentContentType,
@Nullable byte[] contentMD5, @Nullable String currentContentEncoding,
@Nullable String currentContentLanguage) {
this(currentName);

View File

@ -99,7 +99,7 @@ public class ParseContainerMetadataFromHeaders implements
protected void addETagTo(HttpResponse from, ContainerMetadata metadata) {
String eTag = from.getFirstHeaderOrNull(HttpHeaders.ETAG);
if (metadata.getETag() == null && eTag != null) {
metadata.setETag(HttpUtils.fromHexString(eTag.replaceAll("\"", "")));
metadata.setETag(HttpUtils.fromHexString(eTag));
}
}

View File

@ -31,7 +31,6 @@ import javax.inject.Inject;
import org.jclouds.azure.storage.blob.domain.BlobMetadata;
import org.jclouds.azure.storage.blob.domain.ListBlobsResponse;
import org.jclouds.azure.storage.blob.domain.TreeSetListBlobsResponse;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.util.DateService;
import org.joda.time.DateTime;
@ -59,7 +58,7 @@ public class ContainerNameEnumerationResultsHandler extends
private URI currentUrl;
private URI containerUrl;
private DateTime currentLastModified;
private byte[] currentETag;
private String currentETag;
private StringBuilder currentText = new StringBuilder();
@ -131,7 +130,7 @@ public class ContainerNameEnumerationResultsHandler extends
} else if (qName.equals("LastModified")) {
currentLastModified = dateParser.rfc822DateParse(currentText.toString().trim());
} else if (qName.equals("Etag")) {
currentETag = HttpUtils.fromHexString(currentText.toString().trim());
currentETag = currentText.toString().trim();
} else if (qName.equals("Name")) {
if (inBlob)
currentName = currentText.toString().trim();

View File

@ -54,7 +54,6 @@ import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Iterables;
/**
* Tests behavior of {@code AzureBlobConnection}
@ -239,7 +238,7 @@ public class AzureBlobConnectionLiveTest {
object.getMetadata().setContentType("text/plain");
object.getMetadata().getUserMetadata().put("Metadata", "metadata-value");
byte[] md5 = object.getMetadata().getContentMD5();
byte[] newEtag = connection.putBlob(privateContainer, object).get(10, TimeUnit.SECONDS);
String newEtag = connection.putBlob(privateContainer, object).get(10, TimeUnit.SECONDS);
assertEquals(HttpUtils.toHexString(md5), HttpUtils.toHexString(object.getMetadata()
.getContentMD5()));
@ -265,8 +264,8 @@ public class AzureBlobConnectionLiveTest {
assertEquals(HttpUtils.toHexString(md5), HttpUtils.toHexString(object.getMetadata()
.getContentMD5()));
assertEquals(metadata.getETag(), newEtag);
assertEquals(metadata.getUserMetadata().entries().size(), 1);
assertEquals(Iterables.getLast(metadata.getUserMetadata().get("metadata")), "metadata-value");
assertEquals(metadata.getUserMetadata().entrySet().size(), 1);
assertEquals(metadata.getUserMetadata().get("metadata"), "metadata-value");
// // Test POST to update object's metadata
// Multimap<String, String> userMetadata = HashMultimap.create();
@ -299,13 +298,13 @@ public class AzureBlobConnectionLiveTest {
// assertEquals(
// Iterables.getLast(getBlob.getMetadata().getUserMetadata().get("New-Metadata-2")),
// "value-2");
assertEquals(metadata.getUserMetadata().entries().size(), 1);
assertEquals(Iterables.getLast(metadata.getUserMetadata().get("metadata")), "metadata-value");
assertEquals(metadata.getUserMetadata().entrySet().size(), 1);
assertEquals(metadata.getUserMetadata().get("metadata"), "metadata-value");
// Test PUT with invalid ETag (as if object's data was corrupted in transit)
String correctEtag = HttpUtils.toHexString(newEtag);
String correctEtag = newEtag;
String incorrectEtag = "0" + correctEtag.substring(1);
object.getMetadata().setETag(HttpUtils.fromHexString(incorrectEtag));
object.getMetadata().setETag(incorrectEtag);
try {
connection.putBlob(privateContainer, object).get(10, TimeUnit.SECONDS);
} catch (Throwable e) {
@ -347,5 +346,4 @@ public class AzureBlobConnectionLiveTest {
connection.deleteBlob(privateContainer, "object").get(10, TimeUnit.SECONDS);
connection.deleteBlob(privateContainer, "chunked-object").get(10, TimeUnit.SECONDS);
}
}

View File

@ -26,7 +26,6 @@ package org.jclouds.azure.storage.blob.integration;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.util.Collections;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
@ -74,8 +73,7 @@ public class AzureBlobIntegrationTest extends
// inexpensive fashion
// http://code.google.com/p/jclouds/issues/detail?id=92
// assertEquals(metadata.getSize(), TEST_STRING.length());
assertEquals(metadata.getUserMetadata().get("adrian"), Collections
.singletonList("powderpuff"));
assertEquals(metadata.getUserMetadata().get("adrian"), "powderpuff");
assertEquals(metadata.getContentMD5(), HttpUtils.md5(TEST_STRING.getBytes()));
}

View File

@ -100,27 +100,24 @@ public class AddMD5ToListBlobsResponseTest extends BaseHandlerTest {
.create("http://myaccount.blob.core.windows.net/mycontainer/blob1.txt"),
dateService
.rfc822DateParse("Thu, 18 Sep 2008 18:41:57 GMT"),
HttpUtils.fromHexString("0x8CAE7D55D050B8B"), 8,
"text/plain; charset=UTF-8", HttpUtils
.fromHexString("01"), null, null),
"0x8CAE7D55D050B8B", 8, "text/plain; charset=UTF-8",
HttpUtils.fromHexString("01"), null, null),
new BlobMetadata(
"blob2.txt",
URI
.create("http://myaccount.blob.core.windows.net/mycontainer/blob2.txt"),
dateService
.rfc822DateParse("Thu, 18 Sep 2008 18:41:57 GMT"),
HttpUtils.fromHexString("0x8CAE7D55CF6C339"), 14,
"text/plain; charset=UTF-8", HttpUtils
.fromHexString("02"), null, null),
"0x8CAE7D55CF6C339", 14, "text/plain; charset=UTF-8",
HttpUtils.fromHexString("02"), null, null),
new BlobMetadata(
"newblob1.txt",
URI
.create("http://myaccount.blob.core.windows.net/mycontainer/newblob1.txt"),
dateService
.rfc822DateParse("Thu, 18 Sep 2008 18:41:57 GMT"),
HttpUtils.fromHexString("0x8CAE7D55CF6C339"), 25,
"text/plain; charset=UTF-8", HttpUtils
.fromHexString("03"), null, null)
"0x8CAE7D55CF6C339", 25, "text/plain; charset=UTF-8",
HttpUtils.fromHexString("03"), null, null)
), null, null, 4, "newblob2.txt", null, "myfolder/");

View File

@ -32,7 +32,6 @@ import org.jclouds.azure.storage.blob.domain.BlobMetadata;
import org.jclouds.azure.storage.blob.domain.ListBlobsResponse;
import org.jclouds.azure.storage.blob.domain.TreeSetListBlobsResponse;
import org.jclouds.azure.storage.domain.BoundedSortedSet;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.functions.BaseHandlerTest;
import org.jclouds.util.DateService;
import org.testng.annotations.BeforeTest;
@ -70,24 +69,24 @@ public class ContainerNameEnumerationResultsHandlerTest extends BaseHandlerTest
.create("http://myaccount.blob.core.windows.net/mycontainer/blob1.txt"),
dateService
.rfc822DateParse("Thu, 18 Sep 2008 18:41:57 GMT"),
HttpUtils.fromHexString("0x8CAE7D55D050B8B"), 8,
"text/plain; charset=UTF-8", null, null, null),
"0x8CAE7D55D050B8B", 8, "text/plain; charset=UTF-8",
null, null, null),
new BlobMetadata(
"blob2.txt",
URI
.create("http://myaccount.blob.core.windows.net/mycontainer/blob2.txt"),
dateService
.rfc822DateParse("Thu, 18 Sep 2008 18:41:57 GMT"),
HttpUtils.fromHexString("0x8CAE7D55CF6C339"), 14,
"text/plain; charset=UTF-8", null, null, null),
"0x8CAE7D55CF6C339", 14, "text/plain; charset=UTF-8",
null, null, null),
new BlobMetadata(
"newblob1.txt",
URI
.create("http://myaccount.blob.core.windows.net/mycontainer/newblob1.txt"),
dateService
.rfc822DateParse("Thu, 18 Sep 2008 18:41:57 GMT"),
HttpUtils.fromHexString("0x8CAE7D55CF6C339"), 25,
"text/plain; charset=UTF-8", null, null, null)
"0x8CAE7D55CF6C339", 25, "text/plain; charset=UTF-8",
null, null, null)
), null, null, 4, "newblob2.txt", null, "myfolder/");

View File

@ -50,7 +50,7 @@ public interface BlobStore<C extends ContainerMetadata, M extends BlobMetadata,
Future<? extends SortedSet<M>> listBlobs(String container);
Future<byte[]> putBlob(String container, B blob);
Future<String> putBlob(String container, B blob);
Future<B> getBlob(String container, String key);

View File

@ -47,7 +47,7 @@ public class BindBlobToEntity implements Binder {
Blob<?> object = (Blob<?>) entity;
for (String key : object.getMetadata().getUserMetadata().keySet()) {
request.getHeaders().putAll(key.startsWith(metadataPrefix) ? key : metadataPrefix + key,
request.getHeaders().put(key.startsWith(metadataPrefix) ? key : metadataPrefix + key,
object.getMetadata().getUserMetadata().get(key));
}
request.setEntity(checkNotNull(object.getData(), "object.getContent()"));

View File

@ -27,7 +27,7 @@ import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Map;
import javax.inject.Inject;
import javax.ws.rs.core.MediaType;
@ -35,6 +35,7 @@ import javax.ws.rs.core.MediaType;
import org.joda.time.DateTime;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
/**
@ -47,22 +48,22 @@ public class BlobMetadata implements Comparable<BlobMetadata>, Serializable {
private static final long serialVersionUID = -5932618957134612231L;
protected String key;
protected byte[] eTag;
protected String eTag;
protected volatile long size = -1;
private byte[] contentMD5;
protected Multimap<String, String> allHeaders = HashMultimap.create();
protected Multimap<String, String> userMetadata = HashMultimap.create();
protected Map<String, String> userMetadata = Maps.newHashMap();
protected DateTime lastModified;
protected String dataType = MediaType.APPLICATION_OCTET_STREAM;
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("BlobMetadata [key=").append(key).append(", eTag=").append(
Arrays.toString(eTag)).append(", lastModified=").append(lastModified).append(
", size=").append(size).append(", dataType=").append(dataType).append(
", userMetadata=").append(userMetadata).append("]");
builder.append("BlobMetadata [key=").append(key).append(", eTag=").append(eTag).append(
", lastModified=").append(lastModified).append(", size=").append(size).append(
", dataType=").append(dataType).append(", userMetadata=").append(userMetadata)
.append("]");
return builder.toString();
}
@ -71,7 +72,7 @@ public class BlobMetadata implements Comparable<BlobMetadata>, Serializable {
final int prime = 31;
int result = 1;
result = prime * result + ((dataType == null) ? 0 : dataType.hashCode());
result = prime * result + Arrays.hashCode(eTag);
result = prime * result + ((eTag == null) ? 0 : eTag.hashCode());
result = prime * result + ((key == null) ? 0 : key.hashCode());
result = prime * result + ((lastModified == null) ? 0 : lastModified.hashCode());
result = prime * result + (int) (size ^ (size >>> 32));
@ -93,7 +94,10 @@ public class BlobMetadata implements Comparable<BlobMetadata>, Serializable {
return false;
} else if (!dataType.equals(other.dataType))
return false;
if (!Arrays.equals(eTag, other.eTag))
if (eTag == null) {
if (other.eTag != null)
return false;
} else if (!eTag.equals(other.eTag))
return false;
if (key == null) {
if (other.key != null)
@ -197,34 +201,25 @@ public class BlobMetadata implements Comparable<BlobMetadata>, Serializable {
}
}
public void setETag(byte[] eTag) {
if (eTag != null) {
this.eTag = new byte[eTag.length];
System.arraycopy(eTag, 0, this.eTag, 0, eTag.length);
}
public void setETag(String eTag) {
this.eTag = eTag;
}
/**
* @return the eTag value stored in the Etag header returned by HTTP.
*/
public byte[] getETag() {
if (eTag != null) {
byte[] retval = new byte[eTag.length];
System.arraycopy(this.eTag, 0, retval, 0, eTag.length);
return retval;
} else {
return null;
}
public String getETag() {
return eTag;
}
public void setUserMetadata(Multimap<String, String> userMetadata) {
public void setUserMetadata(Map<String, String> userMetadata) {
this.userMetadata = userMetadata;
}
/**
* Any key-value pairs associated with the object.
*/
public Multimap<String, String> getUserMetadata() {
public Map<String, String> getUserMetadata() {
return userMetadata;
}

View File

@ -50,8 +50,7 @@ public class ParseSystemAndUserMetadataFromHeaders<M extends BlobMetadata> exten
@Inject
public ParseSystemAndUserMetadataFromHeaders(DateService dateParser,
@Named(PROPERTY_USER_METADATA_PREFIX) String metadataPrefix,
Provider<M> metadataFactory) {
@Named(PROPERTY_USER_METADATA_PREFIX) String metadataPrefix, Provider<M> metadataFactory) {
super(metadataFactory);
this.dateParser = dateParser;
this.metadataPrefix = metadataPrefix;
@ -102,7 +101,7 @@ public class ParseSystemAndUserMetadataFromHeaders<M extends BlobMetadata> exten
protected void addETagTo(HttpResponse from, M metadata) {
String eTag = from.getFirstHeaderOrNull(HttpHeaders.ETAG);
if (metadata.getETag() == null && eTag != null) {
metadata.setETag(HttpUtils.fromHexString(eTag.replaceAll("\"", "")));
metadata.setETag(eTag);
}
}

View File

@ -157,11 +157,11 @@ public class BlobMapImpl<C extends ContainerMetadata, M extends BlobMetadata, B
*/
public void putAll(Map<? extends String, ? extends B> map) {
try {
Set<Future<byte[]>> puts = Sets.newHashSet();
Set<Future<String>> puts = Sets.newHashSet();
for (B object : map.values()) {
puts.add(connection.putBlob(containerName, object));
}
for (Future<byte[]> put : puts)
for (Future<String> put : puts)
// this will throw an exception if there was a problem
put.get(requestTimeoutMilliseconds, TimeUnit.MILLISECONDS);
} catch (Exception e) {

View File

@ -223,7 +223,7 @@ public class InputStreamMapImpl<C extends ContainerMetadata, M extends BlobMetad
@VisibleForTesting
void putAllInternal(Map<? extends String, ? extends Object> map) {
try {
Set<Future<byte[]>> puts = Sets.newHashSet();
Set<Future<String>> puts = Sets.newHashSet();
for (Map.Entry<? extends String, ? extends Object> entry : map.entrySet()) {
B object = blobFactory.get();
object.getMetadata().setKey(entry.getKey());
@ -234,7 +234,7 @@ public class InputStreamMapImpl<C extends ContainerMetadata, M extends BlobMetad
// / response transformer set key on the way out.
// / ExceptionHandler convert 404 to NOT_FOUND
}
for (Future<byte[]> put : puts)
for (Future<String> put : puts)
// this will throw an exception if there was a problem
put.get(requestTimeoutMilliseconds, TimeUnit.MILLISECONDS);
} catch (Exception e) {

View File

@ -24,7 +24,6 @@
package org.jclouds.blobstore.domain;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotSame;
import java.io.File;
@ -43,13 +42,4 @@ public class BlobTest {
assertEquals(object.getMetadata().getContentType(), MediaType.APPLICATION_OCTET_STREAM);
}
@Test
void testETagCopyingNotReference() {
byte[] eTag = new byte[12];
Blob<BlobMetadata> object = new Blob<BlobMetadata>("test");
object.getMetadata().setETag(eTag);
byte[] returnedETag = object.getMetadata().getETag();
assertNotSame(eTag, returnedETag);
}
}

View File

@ -145,7 +145,7 @@ public class ParseBlobMetadataFromHeadersTest {
from.getHeaders().put(HttpHeaders.ETAG, "0xfeb");
BlobMetadata metadata = new BlobMetadata("test");
parser.addETagTo(from, metadata);
assertEquals(metadata.getETag(), HttpUtils.fromHexString("0xfeb"));
assertEquals(metadata.getETag(), "0xfeb");
}
@Test
@ -155,6 +155,6 @@ public class ParseBlobMetadataFromHeadersTest {
from.setHeaders(allHeaders);
BlobMetadata metadata = new BlobMetadata("test");
parser.addUserMetadataTo(from, metadata);
assertEquals(metadata.getUserMetadata().get("key"), Collections.singletonList("value"));
assertEquals(metadata.getUserMetadata().get("key"), "value");
}
}

View File

@ -37,7 +37,6 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.SortedSet;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
@ -142,15 +141,15 @@ public class BaseBlobIntegrationTest<S, C extends ContainerMetadata, M extends B
String key = "apples";
addObjectAndValidateContent(containerName, key);
String goodETag = addObjectAndValidateContent(containerName, key);
context.getBlobStore().getBlob(containerName, key, ifETagMatches(goodETag)).get(30,
TimeUnit.SECONDS);
validateContent(containerName, key);
try {
context.getBlobStore().getBlob(containerName, key, ifETagMatches(badETag)).get(30,
TimeUnit.SECONDS);
context.getBlobStore().getBlob(containerName, key, ifETagMatches("powerfrisbee")).get(
30, TimeUnit.SECONDS);
validateContent(containerName, key);
} catch (ExecutionException e) {
if (e.getCause() instanceof HttpResponseException) {
@ -175,10 +174,10 @@ public class BaseBlobIntegrationTest<S, C extends ContainerMetadata, M extends B
String key = "apples";
addObjectAndValidateContent(containerName, key);
String goodETag = addObjectAndValidateContent(containerName, key);
context.getBlobStore().getBlob(containerName, key, ifETagDoesntMatch(badETag)).get(30,
TimeUnit.SECONDS);
context.getBlobStore().getBlob(containerName, key, ifETagDoesntMatch("powerfrisbee")).get(
30, TimeUnit.SECONDS);
validateContent(containerName, key);
try {
@ -278,10 +277,11 @@ public class BaseBlobIntegrationTest<S, C extends ContainerMetadata, M extends B
}
}
private void addObjectAndValidateContent(String sourcecontainerName, String sourceKey)
private String addObjectAndValidateContent(String sourcecontainerName, String sourceKey)
throws InterruptedException, ExecutionException, TimeoutException, IOException {
addBlobToContainer(sourcecontainerName, sourceKey);
String eTag = addBlobToContainer(sourcecontainerName, sourceKey);
validateContent(sourcecontainerName, sourceKey);
return eTag;
}
@Test(groups = { "integration", "live" })
@ -397,8 +397,7 @@ public class BaseBlobIntegrationTest<S, C extends ContainerMetadata, M extends B
protected void validateMetadata(M metadata) {
assertEquals(metadata.getContentType(), "text/plain");
assertEquals(metadata.getSize(), TEST_STRING.length());
assertEquals(metadata.getUserMetadata().get("adrian"), Collections
.singletonList("powderpuff"));
assertEquals(metadata.getUserMetadata().get("adrian"), "powderpuff");
assertEquals(metadata.getContentMD5(), HttpUtils.md5(TEST_STRING.getBytes()));
}

View File

@ -44,13 +44,11 @@ import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.domain.ContainerMetadata;
import org.jclouds.blobstore.util.BlobStoreUtils;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.util.Utils;
import org.testng.ITestContext;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.BeforeSuite;
import com.google.common.base.Predicate;
@ -65,9 +63,6 @@ public class BaseBlobStoreIntegrationTest<S, C extends ContainerMetadata, M exte
public static long INCONSISTENCY_WINDOW = 5000;
protected static volatile AtomicInteger containerIndex = new AtomicInteger(0);
protected byte[] goodETag;
protected byte[] badETag;
protected volatile BlobStoreContext<S, C, M, B> context;
protected static volatile int containerCount = 20;
public static final String CONTAINER_PREFIX = System.getProperty("user.name") + "-blobstore";
@ -77,12 +72,6 @@ public class BaseBlobStoreIntegrationTest<S, C extends ContainerMetadata, M exte
private volatile static BlockingQueue<String> containerJsr330 = new ArrayBlockingQueue<String>(
containerCount);
@BeforeGroups(groups = { "integration", "live" })
public void setupTags() throws IOException {
goodETag = HttpUtils.md5(TEST_STRING);
badETag = HttpUtils.md5("alf");
}
/**
* There are a lot of retries here mainly from experience running inside amazon EC2.
*/
@ -239,17 +228,17 @@ public class BaseBlobStoreIntegrationTest<S, C extends ContainerMetadata, M exte
createContainerAndEnsureEmpty(context, containerName);
}
protected void addBlobToContainer(String sourceContainer, String key)
protected String addBlobToContainer(String sourceContainer, String key)
throws InterruptedException, ExecutionException, TimeoutException, IOException {
B sourceObject = context.newBlob(key);
sourceObject.getMetadata().setContentType("text/xml");
sourceObject.setData(TEST_STRING);
addBlobToContainer(sourceContainer, sourceObject);
return addBlobToContainer(sourceContainer, sourceObject);
}
protected void addBlobToContainer(String sourceContainer, B object) throws InterruptedException,
ExecutionException, TimeoutException, IOException {
context.getBlobStore().putBlob(sourceContainer, object).get(30, TimeUnit.SECONDS);
protected String addBlobToContainer(String sourceContainer, B object)
throws InterruptedException, ExecutionException, TimeoutException, IOException {
return context.getBlobStore().putBlob(sourceContainer, object).get(30, TimeUnit.SECONDS);
}
protected B validateContent(String sourceContainer, String key) throws InterruptedException,

View File

@ -34,7 +34,6 @@ import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@ -71,10 +70,9 @@ import org.joda.time.DateTime;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.inject.internal.Nullable;
@ -177,8 +175,8 @@ public class StubBlobStore<C extends ContainerMetadata, M extends BlobMetadata,
}
private void convertUserMetadataKeysToLowercase(M metadata) {
Multimap<String, String> lowerCaseUserMetadata = HashMultimap.create();
for (Entry<String, String> entry : metadata.getUserMetadata().entries()) {
Map<String, String> lowerCaseUserMetadata = Maps.newHashMap();
for (Entry<String, String> entry : metadata.getUserMetadata().entrySet()) {
lowerCaseUserMetadata.put(entry.getKey().toLowerCase(), entry.getValue());
}
metadata.setUserMetadata(lowerCaseUserMetadata);
@ -385,7 +383,7 @@ public class StubBlobStore<C extends ContainerMetadata, M extends BlobMetadata,
}, response));
}
public Future<byte[]> putBlob(final String bucketName, final B object) {
public Future<String> putBlob(final String bucketName, final B object) {
Map<String, B> container = getContainerToBlobs().get(bucketName);
if (container == null) {
new RuntimeException("bucketName not found: " + bucketName);
@ -394,9 +392,10 @@ public class StubBlobStore<C extends ContainerMetadata, M extends BlobMetadata,
M newMd = copy(object.getMetadata());
newMd.setLastModified(new DateTime());
byte[] data = toByteArray(object.getData());
final byte[] eTag = HttpUtils.md5(data);
final byte[] md5 = HttpUtils.md5(data);
final String eTag = HttpUtils.toHexString(md5);
newMd.setETag(eTag);
newMd.setContentMD5(eTag);
newMd.setContentMD5(md5);
newMd.setContentType(object.getMetadata().getContentType());
B blob = blobProvider.get();
@ -407,15 +406,15 @@ public class StubBlobStore<C extends ContainerMetadata, M extends BlobMetadata,
// Set HTTP headers to match metadata
newMd.getAllHeaders().put(HttpHeaders.LAST_MODIFIED,
dateService.rfc822DateFormat(newMd.getLastModified()));
newMd.getAllHeaders().put(HttpHeaders.ETAG, HttpUtils.toHexString(eTag));
newMd.getAllHeaders().put(HttpHeaders.ETAG, eTag);
newMd.getAllHeaders().put(HttpHeaders.CONTENT_TYPE, newMd.getContentType());
newMd.getAllHeaders().put(HttpHeaders.CONTENT_LENGTH, newMd.getSize() + "");
for (Entry<String, String> userMD : newMd.getUserMetadata().entries()) {
for (Entry<String, String> userMD : newMd.getUserMetadata().entrySet()) {
newMd.getAllHeaders().put(userMD.getKey(), userMD.getValue());
}
return new FutureBase<byte[]>() {
public byte[] get() throws InterruptedException, ExecutionException {
return new FutureBase<String>() {
public String get() throws InterruptedException, ExecutionException {
return eTag;
}
};
@ -439,13 +438,11 @@ public class StubBlobStore<C extends ContainerMetadata, M extends BlobMetadata,
B object = realContents.get(key);
if (options.getIfMatch() != null) {
if (!Arrays.equals(object.getMetadata().getETag(), HttpUtils.fromHexString(options
.getIfMatch().replaceAll("\"", ""))))
if (object.getMetadata().getETag().equals(options.getIfMatch()))
throwResponseException(412);
}
if (options.getIfNoneMatch() != null) {
if (Arrays.equals(object.getMetadata().getETag(), HttpUtils.fromHexString(options
.getIfNoneMatch().replaceAll("\"", ""))))
if (object.getMetadata().getETag().equals(options.getIfNoneMatch()))
throwResponseException(304);
}
if (options.getIfModifiedSince() != null) {

View File

@ -28,7 +28,6 @@ import javax.ws.rs.core.HttpHeaders;
import org.apache.commons.io.IOUtils;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpUtils;
import com.google.common.base.Function;
@ -37,9 +36,9 @@ import com.google.common.base.Function;
*
* @author Adrian Cole
*/
public class ParseETagHeader implements Function<HttpResponse, byte[]> {
public class ParseETagHeader implements Function<HttpResponse, String> {
public byte[] apply(HttpResponse from) {
public String apply(HttpResponse from) {
IOUtils.closeQuietly(from.getContent());
String eTag = from.getFirstHeaderOrNull(HttpHeaders.ETAG);
@ -48,7 +47,7 @@ public class ParseETagHeader implements Function<HttpResponse, byte[]> {
eTag = from.getFirstHeaderOrNull("Etag");
}
if (eTag != null) {
return HttpUtils.fromHexString(eTag.replaceAll("\"", ""));
return eTag;
}
throw new HttpException("did not receive ETag");
}

View File

@ -32,7 +32,6 @@ import java.util.List;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.http.HttpUtils;
import org.jclouds.util.DateService;
import org.joda.time.DateTime;
@ -173,13 +172,12 @@ public class GetOptions extends BaseHttpRequestOptions {
* @throws UnsupportedEncodingException
* if there was a problem converting this into an S3 eTag string
*/
public GetOptions ifETagMatches(byte[] eTag) throws UnsupportedEncodingException {
public GetOptions ifETagMatches(String eTag) throws UnsupportedEncodingException {
checkArgument(getIfNoneMatch() == null,
"ifETagDoesntMatch() is not compatible with ifETagMatches()");
checkArgument(getIfModifiedSince() == null,
"ifModifiedSince() is not compatible with ifETagMatches()");
this.headers.put(HttpHeaders.IF_MATCH, String.format("\"%1$s\"", HttpUtils
.toHexString(checkNotNull(eTag, "eTag"))));
this.headers.put(HttpHeaders.IF_MATCH, String.format("\"%1$s\"", checkNotNull(eTag, "eTag")));
return this;
}
@ -198,20 +196,20 @@ public class GetOptions extends BaseHttpRequestOptions {
/**
* The object should not have a eTag hash corresponding with the parameter <code>eTag</code>.
* <p />
* Not compatible with {@link #ifETagMatches(byte[])} or {@link #ifUnmodifiedSince(DateTime)}
* Not compatible with {@link #ifETagMatches(String)} or {@link #ifUnmodifiedSince(DateTime)}
*
* @param eTag
* hash representing the entity
* @throws UnsupportedEncodingException
* if there was a problem converting this into an S3 eTag string
*/
public GetOptions ifETagDoesntMatch(byte[] eTag) throws UnsupportedEncodingException {
public GetOptions ifETagDoesntMatch(String eTag) throws UnsupportedEncodingException {
checkArgument(getIfMatch() == null,
"ifETagMatches() is not compatible with ifETagDoesntMatch()");
checkArgument(getIfUnmodifiedSince() == null,
"ifUnmodifiedSince() is not compatible with ifETagDoesntMatch()");
this.headers.put(HttpHeaders.IF_NONE_MATCH, String.format("\"%1$s\"", HttpUtils
.toHexString(checkNotNull(eTag, "ifETagDoesntMatch"))));
this.headers.put(HttpHeaders.IF_NONE_MATCH, String.format("\"%1$s\"", checkNotNull(eTag,
"ifETagDoesntMatch")));
return this;
}
@ -270,18 +268,17 @@ public class GetOptions extends BaseHttpRequestOptions {
}
/**
* @see GetOptions#ifETagMatches(byte[])
* @see GetOptions#ifETagMatches(String)
*/
public static GetOptions ifETagMatches(byte[] eTag) throws UnsupportedEncodingException {
public static GetOptions ifETagMatches(String eTag) throws UnsupportedEncodingException {
GetOptions options = new GetOptions();
return options.ifETagMatches(eTag);
}
/**
* @see GetOptions#ifETagDoesntMatch(byte[])
* @see GetOptions#ifETagDoesntMatch(String)
*/
public static GetOptions ifETagDoesntMatch(byte[] eTag)
throws UnsupportedEncodingException {
public static GetOptions ifETagDoesntMatch(String eTag) throws UnsupportedEncodingException {
GetOptions options = new GetOptions();
return options.ifETagDoesntMatch(eTag);
}

View File

@ -0,0 +1,40 @@
/**
*
* 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.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/**
* Do not accept filters that were passed from the type.
*
* @author Adrian Cole
*/
@Target( { METHOD })
@Retention(RUNTIME)
public @interface OverrideRequestFilters {
}

View File

@ -49,4 +49,10 @@ public class GeneratedHttpRequest<T> extends HttpRequest {
URI newEndpoint = processor.replaceQuery(getEndpoint(), builder.build().getQuery());
setEndpoint(newEndpoint);
}
public void replacePath(String path) {
UriBuilder builder = UriBuilder.fromUri(getEndpoint());
builder.replacePath(path);
setEndpoint(builder.build());
}
}

View File

@ -80,6 +80,7 @@ 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.OverrideRequestFilters;
import org.jclouds.rest.annotations.ParamParser;
import org.jclouds.rest.annotations.QueryParams;
import org.jclouds.rest.annotations.RequestFilters;
@ -446,6 +447,8 @@ public class RestAnnotationProcessor<T> {
}
}
if (method.isAnnotationPresent(RequestFilters.class)) {
if (method.isAnnotationPresent(OverrideRequestFilters.class))
request.getFilters().clear();
for (Class<? extends HttpRequestFilter> clazz : method.getAnnotation(RequestFilters.class)
.value()) {
HttpRequestFilter instance = injector.getInstance(clazz);

View File

@ -35,7 +35,6 @@ import static org.testng.Assert.assertNull;
import java.io.UnsupportedEncodingException;
import org.jclouds.http.HttpUtils;
import org.jclouds.util.DateService;
import org.joda.time.DateTime;
import org.testng.annotations.BeforeTest;
@ -49,7 +48,7 @@ import org.testng.annotations.Test;
@Test(groups = "unit", testName = "s3.GetOptionsTest")
public class GetOptionsTest {
private byte[] testBytes;
private String etag;
private DateTime now;
private String nowExpected;
@ -57,7 +56,7 @@ public class GetOptionsTest {
void setUp() {
now = new DateTime();
nowExpected = new DateService().rfc822DateFormat(now);
testBytes = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 };
etag = "yrdy";
}
@Test
@ -213,7 +212,7 @@ public class GetOptionsTest {
@Test
public void testIfETagMatches() throws UnsupportedEncodingException {
GetOptions options = new GetOptions();
options.ifETagMatches(testBytes);
options.ifETagMatches(etag);
matchesHex(options.getIfMatch());
}
@ -225,7 +224,7 @@ public class GetOptionsTest {
@Test
public void testIfETagMatchesStatic() throws UnsupportedEncodingException {
GetOptions options = ifETagMatches(testBytes);
GetOptions options = ifETagMatches(etag);
matchesHex(options.getIfMatch());
}
@ -237,7 +236,7 @@ public class GetOptionsTest {
@Test
public void testIfETagDoesntMatch() throws UnsupportedEncodingException {
GetOptions options = new GetOptions();
options.ifETagDoesntMatch(testBytes);
options.ifETagDoesntMatch(etag);
matchesHex(options.getIfNoneMatch());
}
@ -249,7 +248,7 @@ public class GetOptionsTest {
@Test
public void testIfETagDoesntMatchStatic() throws UnsupportedEncodingException {
GetOptions options = ifETagDoesntMatch(testBytes);
GetOptions options = ifETagDoesntMatch(etag);
matchesHex(options.getIfNoneMatch());
}
@ -259,7 +258,7 @@ public class GetOptionsTest {
}
private void matchesHex(String match) throws UnsupportedEncodingException {
String expected = "\"" + HttpUtils.toHexString(testBytes) + "\"";
String expected = "\"" + etag + "\"";
assertEquals(match, expected);
}
@ -270,13 +269,13 @@ public class GetOptionsTest {
}
public void testIfUnmodifiedAfterETagMatches() throws UnsupportedEncodingException {
ifETagMatches(testBytes).ifUnmodifiedSince(now);
ifETagMatches(etag).ifUnmodifiedSince(now);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testIfUnmodifiedAfterETagDoesntMatch() throws UnsupportedEncodingException {
ifETagDoesntMatch(testBytes).ifUnmodifiedSince(now);
ifETagDoesntMatch(etag).ifUnmodifiedSince(now);
}
@Test(expectedExceptions = IllegalArgumentException.class)
@ -287,44 +286,44 @@ public class GetOptionsTest {
@Test(expectedExceptions = IllegalArgumentException.class)
public void testIfModifiedAfterETagMatches() throws UnsupportedEncodingException {
ifETagMatches(testBytes).ifModifiedSince(now);
ifETagMatches(etag).ifModifiedSince(now);
}
public void testIfModifiedAfterETagDoesntMatch() throws UnsupportedEncodingException {
ifETagDoesntMatch(testBytes).ifModifiedSince(now);
ifETagDoesntMatch(etag).ifModifiedSince(now);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testETagMatchesAfterIfModified() throws UnsupportedEncodingException {
ifModifiedSince(now).ifETagMatches(testBytes);
ifModifiedSince(now).ifETagMatches(etag);
}
public void testETagMatchesAfterIfUnmodified() throws UnsupportedEncodingException {
ifUnmodifiedSince(now).ifETagMatches(testBytes);
ifUnmodifiedSince(now).ifETagMatches(etag);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testETagMatchesAfterETagDoesntMatch() throws UnsupportedEncodingException {
ifETagDoesntMatch(testBytes).ifETagMatches(testBytes);
ifETagDoesntMatch(etag).ifETagMatches(etag);
}
public void testETagDoesntMatchAfterIfModified() throws UnsupportedEncodingException {
ifModifiedSince(now).ifETagDoesntMatch(testBytes);
ifModifiedSince(now).ifETagDoesntMatch(etag);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testETagDoesntMatchAfterIfUnmodified() throws UnsupportedEncodingException {
ifUnmodifiedSince(now).ifETagDoesntMatch(testBytes);
ifUnmodifiedSince(now).ifETagDoesntMatch(etag);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testETagDoesntMatchAfterETagMatches() throws UnsupportedEncodingException {
ifETagMatches(testBytes).ifETagDoesntMatch(testBytes);
ifETagMatches(etag).ifETagDoesntMatch(etag);
}
}

View File

@ -80,6 +80,7 @@ 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.OverrideRequestFilters;
import org.jclouds.rest.annotations.ParamParser;
import org.jclouds.rest.annotations.QueryParams;
import org.jclouds.rest.annotations.RequestFilters;
@ -496,6 +497,12 @@ public class RestAnnotationProcessorTest {
@RequestFilters(TestRequestFilter2.class)
public void get() {
}
@GET
@OverrideRequestFilters
@RequestFilters(TestRequestFilter2.class)
public void getOverride() {
}
}
@Test
@ -508,6 +515,14 @@ public class RestAnnotationProcessorTest {
assertEquals(httpMethod.getFilters().get(1).getClass(), TestRequestFilter2.class);
}
public void testRequestFilterOverride() throws SecurityException, NoSuchMethodException {
Method method = TestRequestFilter.class.getMethod("getOverride");
HttpRequest httpMethod = factory(TestRequestFilter.class).createRequest(method,
new Object[] {});
assertEquals(httpMethod.getFilters().size(), 1);
assertEquals(httpMethod.getFilters().get(0).getClass(), TestRequestFilter2.class);
}
@SkipEncoding('/')
@Endpoint(Localhost.class)
public class TestEncoding {

View File

@ -45,7 +45,7 @@ import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.jclouds.mezeo.pcs2.endpoints.RootContainer;
import org.jclouds.mezeo.pcs2.endpoints.WebDAV;
import org.jclouds.mezeo.pcs2.functions.AddMetadataAndParseResourceIdIntoBytes;
import org.jclouds.mezeo.pcs2.functions.AddMetadataAndReturnId;
import org.jclouds.mezeo.pcs2.functions.AssembleBlobFromContentAndMetadataCache;
import org.jclouds.mezeo.pcs2.functions.ContainerAndFileNameToResourceId;
import org.jclouds.mezeo.pcs2.functions.ContainerNameToResourceId;
@ -116,24 +116,22 @@ public interface PCSBlobStore extends BlobStore<ContainerMetadata, FileMetadata,
Future<? extends SortedSet<FileMetadata>> listBlobs(
@PathParam("containerResourceId") @ParamParser(ContainerNameToResourceId.class) String containerName);
@PUT
@Path("/files/{fileResourceId}/content")
@Endpoint(PCS.class)
@ResponseParser(AddMetadataAndParseResourceIdIntoBytes.class)
@ResponseParser(AddMetadataAndReturnId.class)
@PathParam("fileResourceId")
@ParamParser(CreateSubFolderIfNotExistsAndNewFileResource.class)
Future<byte[]> putBlob(String containerName,
@BinderParam(BindDataToEntity.class) PCSFile object);
// @POST
// @Path("/containers/{containerResourceId}/contents")
// @Endpoint(PCS.class)
// @ResponseParser(AddMetadataAndParseResourceIdIntoBytes.class)
// @PathParam("containerResourceId")
// @ParamParser(CreateSubFolderIfNotExistsAndGetResourceId.class)
// Future<byte[]> putBlob(String containerName,
// @EntityParam(BlobAsMultipartFormBinder.class) PCSFile object);
Future<String> putBlob(String containerName, @BinderParam(BindDataToEntity.class) PCSFile object);
// @POST
// @Path("/containers/{containerResourceId}/contents")
// @Endpoint(PCS.class)
// @ResponseParser(AddMetadataAndParseResourceIdIntoBytes.class)
// @PathParam("containerResourceId")
// @ParamParser(CreateSubFolderIfNotExistsAndGetResourceId.class)
// Future<byte[]> putBlob(String containerName,
// @EntityParam(BlobAsMultipartFormBinder.class) PCSFile object);
@DELETE
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
@ -156,7 +154,8 @@ public interface PCSBlobStore extends BlobStore<ContainerMetadata, FileMetadata,
@Path("{container}/{key}")
@Endpoint(WebDAV.class)
@ResponseParser(AssembleBlobFromContentAndMetadataCache.class)
Future<PCSFile> getBlob(@PathParam("container") String container, @PathParam("key") String key, GetOptions options);
Future<PCSFile> getBlob(@PathParam("container") String container, @PathParam("key") String key,
GetOptions options);
@GET
@ExceptionParser(ThrowKeyNotFoundOn404.class)

View File

@ -24,6 +24,7 @@
package org.jclouds.mezeo.pcs2;
import java.net.URI;
import java.util.Map;
import java.util.concurrent.Future;
import javax.ws.rs.GET;
@ -32,7 +33,7 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.mezeo.pcs2.functions.AddEntryIntoMultiMap;
import org.jclouds.mezeo.pcs2.functions.AddEntryIntoMap;
import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.RequestFilters;
@ -40,8 +41,6 @@ import org.jclouds.rest.annotations.ResponseParser;
import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.binders.BindToStringEntity;
import com.google.common.collect.Multimap;
/**
* Provides access to Mezeo PCS v2 via their REST API.
* <p/>
@ -62,6 +61,6 @@ public interface PCSUtil {
@PathParam("key") String key, @BinderParam(BindToStringEntity.class) String value);
@GET
@ResponseParser(AddEntryIntoMultiMap.class)
Future<Void> addEntryToMultiMap(Multimap<String, String> map, String key, @Endpoint URI value);
@ResponseParser(AddEntryIntoMap.class)
Future<Void> addEntryToMap(Map<String, String> map, String key, @Endpoint URI value);
}

View File

@ -24,7 +24,6 @@
package org.jclouds.mezeo.pcs2.domain;
import java.net.URI;
import java.util.Arrays;
import org.jclouds.mezeo.pcs2.util.PCSUtils;
import org.joda.time.DateTime;
@ -51,7 +50,7 @@ public class FileMetadata extends org.jclouds.blobstore.domain.BlobMetadata {
return "FileMetadata [key=" + key + ", created=" + created + ", isInProject=" + isInProject
+ ", isPublic=" + isPublic + ", isShared=" + isShared + ", owner=" + owner
+ ", url=" + url + ", version=" + version + ", allHeaders=" + allHeaders
+ ", dataType=" + dataType + ", eTag=" + Arrays.toString(eTag) + ", accessed="
+ ", dataType=" + dataType + ", eTag=" + eTag + ", accessed="
+ accessed + ", lastModified=" + lastModified + ", size=" + size + ", userMetadata="
+ userMetadata + "]";
}
@ -138,8 +137,7 @@ public class FileMetadata extends org.jclouds.blobstore.domain.BlobMetadata {
this.isInProject = isInProject;
this.version = version;
this.isPublic = isPublic;
byte[] eTag = PCSUtils.getETag(url);
setETag(eTag);
setETag(PCSUtils.getId(url));
}
public FileMetadata(String key) {

View File

@ -3,6 +3,7 @@ package org.jclouds.mezeo.pcs2.functions;
import static com.google.common.base.Preconditions.checkState;
import java.lang.reflect.Constructor;
import java.util.Map;
import javax.inject.Inject;
@ -12,18 +13,17 @@ import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import com.google.common.base.Function;
import com.google.common.collect.Multimap;
/**
*
* @author Adrian Cole
*/
public class AddEntryIntoMultiMap implements Function<HttpResponse, Void>, InvocationContext {
public class AddEntryIntoMap implements Function<HttpResponse, Void>, InvocationContext {
ReturnStringIf200 returnIf200;
private GeneratedHttpRequest<?> request;
@Inject
private AddEntryIntoMultiMap(ReturnStringIf200 returnIf200) {
private AddEntryIntoMap(ReturnStringIf200 returnIf200) {
this.returnIf200 = returnIf200;
}
@ -44,15 +44,15 @@ public class AddEntryIntoMultiMap implements Function<HttpResponse, Void>, Invoc
{
checkState(request.getArgs() != null, "args should be initialized at this point");
Multimap<String, String> map = null;
Map<String, String> map = null;
String key = null;
for (Object arg : request.getArgs()) {
if (arg instanceof Multimap)
map = (Multimap<String, String>) arg;
if (arg instanceof Map)
map = (Map<String, String>) arg;
else if (arg instanceof String)
key = arg.toString();
}
checkState(map != null, "No Multimap found in args, improper method declarations");
checkState(map != null, "No Map found in args, improper method declarations");
checkState(key != null, "No String found in args, improper method declarations");
map.put(key, returnIf200.apply(from).trim());

View File

@ -45,7 +45,6 @@ import org.jclouds.http.HttpResponse;
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.InvocationContext;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.util.Utils;
@ -58,7 +57,7 @@ import com.google.common.collect.Sets;
*
* @author Adrian Cole
*/
public class AddMetadataAndParseResourceIdIntoBytes implements Function<HttpResponse, byte[]>,
public class AddMetadataAndReturnId implements Function<HttpResponse, String>,
InvocationContext {
private final PCSUtil util;
private final ConcurrentMap<Key, String> fileCache;
@ -75,12 +74,12 @@ public class AddMetadataAndParseResourceIdIntoBytes implements Function<HttpResp
private GeneratedHttpRequest<?> request;
@Inject
public AddMetadataAndParseResourceIdIntoBytes(ConcurrentMap<Key, String> fileCache, PCSUtil util) {
public AddMetadataAndReturnId(ConcurrentMap<Key, String> fileCache, PCSUtil util) {
this.fileCache = fileCache;
this.util = util;
}
public byte[] apply(HttpResponse from) {
public String apply(HttpResponse from) {
if (from.getStatusCode() > 204)
throw new BlobRuntimeException("Incorrect code for: " + from);
checkState(request != null, "request should be initialized at this point");
@ -97,7 +96,7 @@ public class AddMetadataAndParseResourceIdIntoBytes implements Function<HttpResp
IOUtils.closeQuietly(from.getContent());
Set<Future<Void>> puts = Sets.newHashSet();
for (Entry<String, String> entry : file.getMetadata().getUserMetadata().entries()) {
for (Entry<String, String> entry : file.getMetadata().getUserMetadata().entrySet()) {
puts.add(util.putMetadata(id, entry.getKey(), entry.getValue()));
}
for (Future<Void> put : puts) {
@ -108,8 +107,7 @@ public class AddMetadataAndParseResourceIdIntoBytes implements Function<HttpResp
throw new BlobRuntimeException("Error putting metadata for file: " + file, e);
}
}
return PCSUtils.getETag(id);
return id;
}
public void setContext(GeneratedHttpRequest<?> request) {

View File

@ -25,8 +25,6 @@ package org.jclouds.mezeo.pcs2.util;
import java.net.URI;
import org.jclouds.http.HttpUtils;
/**
* Utilities for PCS connections.
*
@ -36,16 +34,8 @@ public class PCSUtils {
/**
* converts the object id into something we can use as an etag
*/
public static byte[] getETag(URI url) {
String id = url.getPath().substring(url.getPath().lastIndexOf('/') + 1);
return getETag(id);
}
public static byte[] getETag(String id) {
id = id.replaceAll("-", "");
// parse url to create an "etag"
byte[] eTag = HttpUtils.fromHexString(id);
return eTag;
public static String getId(URI url) {
return url.getPath().substring(url.getPath().lastIndexOf('/') + 1);
}
public static String getContainerId(URI url) {

View File

@ -24,6 +24,7 @@
package org.jclouds.mezeo.pcs2.xml;
import java.net.URI;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
@ -40,8 +41,7 @@ import org.jclouds.util.Utils;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
/**
@ -50,7 +50,7 @@ import com.google.common.collect.Sets;
public class FileMetadataHandler extends BaseFileMetadataHandler<FileMetadata> {
private final PCSUtil util;
private FileMetadata fileMetadata = null;
protected Multimap<String, String> userMetadata = HashMultimap.create();
protected Map<String, String> userMetadata = Maps.newHashMap();
Set<Future<Void>> puts = Sets.newHashSet();
/**
* maximum duration of an blob Request
@ -89,7 +89,7 @@ public class FileMetadataHandler extends BaseFileMetadataHandler<FileMetadata> {
int index = attributes.getIndex("xlink:href");
if (index != -1) {
String key = attributes.getValue(index).replaceAll(".*/metadata/", "");
puts.add(util.addEntryToMultiMap(userMetadata, key.toLowerCase(), URI.create(attributes
puts.add(util.addEntryToMap(userMetadata, key.toLowerCase(), URI.create(attributes
.getValue(index))));
}
}

View File

@ -31,6 +31,7 @@ import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.Collections;
import java.util.Map;
import java.util.SortedSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@ -60,8 +61,8 @@ import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.jclouds.mezeo.pcs2.endpoints.RootContainer;
import org.jclouds.mezeo.pcs2.endpoints.WebDAV;
import org.jclouds.mezeo.pcs2.functions.AddEntryIntoMultiMap;
import org.jclouds.mezeo.pcs2.functions.AddMetadataAndParseResourceIdIntoBytes;
import org.jclouds.mezeo.pcs2.functions.AddEntryIntoMap;
import org.jclouds.mezeo.pcs2.functions.AddMetadataAndReturnId;
import org.jclouds.mezeo.pcs2.functions.AssembleBlobFromContentAndMetadataCache;
import org.jclouds.mezeo.pcs2.functions.InvalidateContainerNameCacheAndReturnTrueIf2xx;
import org.jclouds.mezeo.pcs2.functions.InvalidatePCSKeyCacheAndReturnVoidIf2xx;
@ -74,9 +75,8 @@ import org.jclouds.util.DateService;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Multimap;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
@ -315,7 +315,7 @@ public class PCSBlobStoreTest {
.singletonList(file.getData().toString().getBytes().length + ""));
assertEquals(httpMethod.getEntity(), file.getData());
assertEquals(processor.createResponseParser(method, httpMethod).getClass(),
AddMetadataAndParseResourceIdIntoBytes.class);
AddMetadataAndReturnId.class);
}
public void testRemoveBlob() throws SecurityException, NoSuchMethodException, IOException {
@ -405,12 +405,12 @@ public class PCSBlobStoreTest {
ReturnVoidIf2xx.class);
}
public void testAddEntryToMultiMap() throws SecurityException, NoSuchMethodException {
Method method = PCSUtil.class.getMethod("addEntryToMultiMap", Multimap.class, String.class,
public void testAddEntryToMap() throws SecurityException, NoSuchMethodException {
Method method = PCSUtil.class.getMethod("addEntryToMap", Map.class, String.class,
URI.class);
GeneratedHttpRequest<PCSUtil> httpMethod = utilProcessor
.createRequest(method, new Object[] { ImmutableMultimap.of("key", "value"),
.createRequest(method, new Object[] { ImmutableMap.of("key", "value"),
"newkey", URI.create("http://localhost/pow") });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/pow");
@ -418,7 +418,7 @@ public class PCSBlobStoreTest {
assertEquals(httpMethod.getHeaders().size(), 0);
assertEquals(utilProcessor.createExceptionParserOrNullIfNotFound(method), null);
assertEquals(utilProcessor.createResponseParser(method, httpMethod).getClass(),
AddEntryIntoMultiMap.class);
AddEntryIntoMap.class);
}
RestAnnotationProcessor<PCSBlobStore> processor;
@ -451,7 +451,7 @@ public class PCSBlobStoreTest {
public PCSUtil getPCSUtil() {
return new PCSUtil() {
public Future<Void> addEntryToMultiMap(Multimap<String, String> map,
public Future<Void> addEntryToMap(Map<String, String> map,
String key, URI value) {
return null;
}

View File

@ -35,6 +35,8 @@ import org.jclouds.concurrent.WithinThreadExecutorService;
import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.logging.Logger;
import org.jclouds.logging.Logger.LoggerFactory;
import org.jclouds.mezeo.pcs2.PCSCloud.Response;
import org.jclouds.rest.RestClientFactory;
import org.jclouds.rest.config.RestModule;
@ -81,6 +83,11 @@ public class PCSCloudLiveTest {
@Override
protected void configure() {
bind(URI.class).annotatedWith(PCS.class).toInstance(endpoint);
bind(Logger.LoggerFactory.class).toInstance(new LoggerFactory() {
public Logger getLogger(String category) {
return Logger.NULL;
}
});
}
@SuppressWarnings("unused")

View File

@ -31,6 +31,7 @@ import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Future;
@ -61,7 +62,6 @@ import org.jclouds.util.Utils;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.collect.Multimap;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
@ -240,7 +240,7 @@ public class PCSConnectionTest {
public PCSUtil getPCSUtil() {
return new PCSUtil() {
public Future<Void> addEntryToMultiMap(Multimap<String, String> map,
public Future<Void> addEntryToMap(Map<String, String> map,
String key, URI value) {
return null;
}

View File

@ -44,7 +44,6 @@ import org.jclouds.blobstore.domain.Key;
import org.jclouds.concurrent.WithinThreadExecutorService;
import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.logging.Logger;
import org.jclouds.logging.Logger.LoggerFactory;
@ -67,14 +66,14 @@ import com.google.inject.TypeLiteral;
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "pcs2.AddMetadataAndParseResourceIdIntoBytesTest")
public class AddMetadataAndParseResourceIdIntoBytesTest {
@Test(groups = "unit", testName = "pcs2.AddMetadataAndReturnIdTest")
public class AddMetadataAndReturnIdTest {
static {
RuntimeDelegate.setInstance(new RuntimeDelegateImpl());
}
HttpResponse response = new HttpResponse();
ConcurrentMap<Key, String> fileCache;
private RestAnnotationProcessor<org.jclouds.mezeo.pcs2.functions.AddMetadataAndParseResourceIdIntoBytesTest.TestService> factory;
private RestAnnotationProcessor<TestService> factory;
private Method method;
private static interface TestService {
@ -104,37 +103,31 @@ public class AddMetadataAndParseResourceIdIntoBytesTest {
@Test(expectedExceptions = IllegalStateException.class)
public void testNoArgs() {
AddMetadataAndParseResourceIdIntoBytes function = new AddMetadataAndParseResourceIdIntoBytes(
fileCache, createPCSUtil());
AddMetadataAndReturnId function = new AddMetadataAndReturnId(fileCache, createPCSUtil());
function.apply(response);
}
@Test(expectedExceptions = IllegalStateException.class)
public void testNoRequest() {
AddMetadataAndParseResourceIdIntoBytes function = new AddMetadataAndParseResourceIdIntoBytes(
fileCache, createPCSUtil());
AddMetadataAndReturnId function = new AddMetadataAndReturnId(fileCache, createPCSUtil());
function.apply(response);
}
public void testGetEtag() {
PCSUtil connection = createPCSUtil();
AddMetadataAndParseResourceIdIntoBytes function = new AddMetadataAndParseResourceIdIntoBytes(
fileCache, connection);
AddMetadataAndReturnId function = new AddMetadataAndReturnId(fileCache, connection);
function.setContext(factory.createRequest(method, "container", new PCSFile("key"), URI
.create("http://localhost:8080")));
response.setContent(IOUtils
.toInputStream("http://localhost/contents/7F143552-AAF5-11DE-BBB0-0BC388ED913B"));
byte[] eTag = function.apply(response);
byte[] expected = HttpUtils.fromHexString("7F143552AAF511DEBBB00BC388ED913B");
assertEquals(eTag, expected);
String eTag = function.apply(response);
assertEquals(eTag, "7F143552-AAF5-11DE-BBB0-0BC388ED913B");
}
public void testMetadataGetEtag() {
PCSUtil connection = createPCSUtil();
AddMetadataAndParseResourceIdIntoBytes function = new AddMetadataAndParseResourceIdIntoBytes(
fileCache, connection);
AddMetadataAndReturnId function = new AddMetadataAndReturnId(fileCache, connection);
PCSFile pcsFile = new PCSFile("key");
pcsFile.getMetadata().getUserMetadata().put("foo", "bar");
pcsFile.getMetadata().getUserMetadata().put("biz", "baz");
@ -143,10 +136,8 @@ public class AddMetadataAndParseResourceIdIntoBytesTest {
.create("http://localhost:8080")));
response.setContent(IOUtils
.toInputStream("http://localhost/contents/7F143552-AAF5-11DE-BBB0-0BC388ED913B"));
byte[] eTag = function.apply(response);
byte[] expected = HttpUtils.fromHexString("7F143552AAF511DEBBB00BC388ED913B");
assertEquals(eTag, expected);
String eTag = function.apply(response);
assertEquals(eTag, "7F143552-AAF5-11DE-BBB0-0BC388ED913B");
verify(connection);
}

View File

@ -26,7 +26,6 @@ package org.jclouds.mezeo.pcs2.integration;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.util.Collections;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
@ -48,8 +47,7 @@ public class PCSBlobStoreIntegrationTest extends
protected void validateMetadata(FileMetadata metadata) {
assertEquals(metadata.getContentType(), "text/plain");
assertEquals(metadata.getSize(), TEST_STRING.length());
assertEquals(metadata.getUserMetadata().get("adrian"), Collections
.singletonList("powderpuff"));
assertEquals(metadata.getUserMetadata().get("adrian"), "powderpuff");
// Issue 105
// assertEquals(metadata.getContentMD5(), HttpUtils.md5(TEST_STRING.getBytes()));
}

View File

@ -27,7 +27,6 @@ import static org.testng.Assert.assertEquals;
import java.net.URI;
import org.jclouds.http.HttpUtils;
import org.testng.annotations.Test;
/**
@ -38,10 +37,8 @@ import org.testng.annotations.Test;
@Test(groups = "unit", testName = "pcs2.PCSUtilsTest")
public class PCSUtilsTest {
public void testGetEtag() {
byte[] expected = HttpUtils.fromHexString("7F143552AAF511DEBBB00BC388ED913B");
byte[] eTag = PCSUtils.getETag(URI
String eTag = PCSUtils.getId(URI
.create("http://localhost/contents/7F143552-AAF5-11DE-BBB0-0BC388ED913B"));
assertEquals(eTag, expected);
assertEquals(eTag, "7F143552-AAF5-11DE-BBB0-0BC388ED913B");
}
}

View File

@ -28,6 +28,7 @@ import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.net.URI;
import java.util.Map;
import java.util.concurrent.Future;
import javax.inject.Singleton;
@ -40,7 +41,6 @@ import org.jclouds.util.DateService;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.google.common.collect.Multimap;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
@ -70,7 +70,7 @@ public class FileMetadataHandlerTest extends BaseHandlerTest {
PCSUtil provideUtil() {
final Future<Void> voidF = createMock(Future.class);
return new PCSUtil() {
public Future<Void> addEntryToMultiMap(Multimap<String, String> map, String key,
public Future<Void> addEntryToMap(Map<String, String> map, String key,
URI value) {
map.put(key.toLowerCase(), "bar");
return voidF;

View File

@ -421,8 +421,12 @@ pageTracker._trackPageview();
<value>${jclouds.test.endpoint}</value>
</property>
<property>
<name>jclouds.test.app</name>
<value>${jclouds.test.app}</value>
<name>jclouds.test.appname</name>
<value>${jclouds.test.appname}</value>
</property>
<property>
<name>jclouds.test.appid</name>
<value>${jclouds.test.appid}</value>
</property>
<property>
<name>jclouds.blobstore.httpstream.url</name>

View File

@ -111,7 +111,7 @@ public interface CloudFilesBlobStore extends
@PUT
@Path("{container}/{key}")
@ResponseParser(ParseETagHeader.class)
Future<byte[]> putBlob(
Future<String> putBlob(
@PathParam("container") String container,
@PathParam("key") @ParamParser(BlobKey.class) @BinderParam(BindBlobToEntity.class) Blob<BlobMetadata> object);

View File

@ -139,7 +139,8 @@ public interface CloudFilesConnection {
@POST
@Path("{container}/{key}")
boolean setObjectMetadata(@PathParam("container") String container,
boolean setObjectMetadata(
@PathParam("container") String container,
@PathParam("key") String key,
@BinderParam(BindMultimapToHeadersWithPrefix.class) Multimap<String, String> userMetadata);
@ -203,7 +204,7 @@ public interface CloudFilesConnection {
@PUT
@Path("{container}/{key}")
@ResponseParser(ParseETagHeader.class)
Future<byte[]> putObject(
Future<String> putObject(
@PathParam("container") String container,
@PathParam("key") @ParamParser(BlobKey.class) @BinderParam(BindBlobToEntity.class) Blob<BlobMetadata> object);
@ -218,11 +219,13 @@ public interface CloudFilesConnection {
@ResponseParser(ParseObjectMetadataFromHeaders.class)
@ExceptionParser(ThrowKeyNotFoundOn404.class)
@Path("{container}/{key}")
BlobMetadata getObjectMetadata(@PathParam("container") String container, @PathParam("key") String key);
BlobMetadata getObjectMetadata(@PathParam("container") String container,
@PathParam("key") String key);
@DELETE
@ExceptionParser(ReturnTrueOn404.class)
@Path("{container}/{key}")
Future<Boolean> removeObject(@PathParam("container") String container, @PathParam("key") String key);
Future<Boolean> removeObject(@PathParam("container") String container,
@PathParam("key") String key);
}

View File

@ -83,7 +83,7 @@ public class ParseBlobMetadataListFromJsonResponse extends ParseJson<SortedSet<B
metadata.setSize(from.bytes);
metadata.setLastModified(from.last_modified);
metadata.setContentType(from.content_type);
metadata.setETag(HttpUtils.fromHexString(from.hash));
metadata.setETag(from.hash);
metadata.setContentMD5(HttpUtils.fromHexString(from.hash));
return metadata;
}

View File

@ -60,9 +60,9 @@ public class ParseObjectMetadataFromHeaders extends
// etag comes back incorrect case
String eTagHeader = from.getFirstHeaderOrNull("Etag");
if (eTagHeader != null) {
metadata.setETag(HttpUtils.fromHexString(eTagHeader));
metadata.setETag(eTagHeader);
}
}
metadata.setContentMD5(metadata.getETag());
metadata.setContentMD5(HttpUtils.fromHexString(metadata.getETag()));
}
}

View File

@ -284,7 +284,7 @@ public class CloudFilesConnectionLiveTest {
object.getMetadata().setContentType("text/plain");
object.getMetadata().getUserMetadata().put("Metadata", "metadata-value");
byte[] md5 = object.getMetadata().getContentMD5();
byte[] newEtag = connection.putObject(containerName, object).get(10, TimeUnit.SECONDS);
String newEtag = connection.putObject(containerName, object).get(10, TimeUnit.SECONDS);
assertEquals(HttpUtils.toHexString(md5), HttpUtils.toHexString(object.getMetadata()
.getContentMD5()));
@ -303,8 +303,8 @@ public class CloudFilesConnectionLiveTest {
assertEquals(HttpUtils.toHexString(md5), HttpUtils.toHexString(object.getMetadata()
.getContentMD5()));
assertEquals(metadata.getETag(), newEtag);
assertEquals(metadata.getUserMetadata().entries().size(), 1);
assertEquals(Iterables.getLast(metadata.getUserMetadata().get("metadata")), "metadata-value");
assertEquals(metadata.getUserMetadata().entrySet().size(), 1);
assertEquals(metadata.getUserMetadata().get("metadata"), "metadata-value");
// // Test POST to update object's metadata
Multimap<String, String> userMetadata = HashMultimap.create();
@ -328,18 +328,14 @@ public class CloudFilesConnectionLiveTest {
assertEquals(HttpUtils.toHexString(md5), HttpUtils.toHexString(getBlob.getMetadata()
.getContentMD5()));
assertEquals(newEtag, getBlob.getMetadata().getETag());
assertEquals(getBlob.getMetadata().getUserMetadata().entries().size(), 2);
assertEquals(
Iterables.getLast(getBlob.getMetadata().getUserMetadata().get("new-metadata-1")),
"value-1");
assertEquals(
Iterables.getLast(getBlob.getMetadata().getUserMetadata().get("new-metadata-2")),
"value-2");
assertEquals(getBlob.getMetadata().getUserMetadata().entrySet().size(), 2);
assertEquals(getBlob.getMetadata().getUserMetadata().get("new-metadata-1"), "value-1");
assertEquals(getBlob.getMetadata().getUserMetadata().get("new-metadata-2"), "value-2");
// Test PUT with invalid ETag (as if object's data was corrupted in transit)
String correctEtag = HttpUtils.toHexString(newEtag);
String correctEtag = newEtag;
String incorrectEtag = "0" + correctEtag.substring(1);
object.getMetadata().setETag(HttpUtils.fromHexString(incorrectEtag));
object.getMetadata().setETag(incorrectEtag);
try {
connection.putObject(containerName, object).get(10, TimeUnit.SECONDS);
} catch (Throwable e) {

View File

@ -29,7 +29,6 @@ import java.io.InputStream;
import java.util.List;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.functions.config.ParserModule;
import org.joda.time.DateTime;
import org.testng.annotations.Test;
@ -53,13 +52,13 @@ public class ParseBlobMetadataListFromJsonResponseTest {
InputStream is = getClass().getResourceAsStream("/test_list_container.json");
List<BlobMetadata> expects = Lists.newArrayList();
BlobMetadata one = new BlobMetadata("test_obj_1");
one.setETag(HttpUtils.fromHexString("4281c348eaf83e70ddce0e07221c3d28"));
one.setETag("4281c348eaf83e70ddce0e07221c3d28");
one.setSize(14);
one.setContentType("application/octet-stream");
one.setLastModified(new DateTime("2009-02-03T05:26:32.612278"));
expects.add(one);
BlobMetadata two = new BlobMetadata("test_obj_2");
two.setETag(HttpUtils.fromHexString("b039efe731ad111bc1b0ef221c3849d0"));
two.setETag("b039efe731ad111bc1b0ef221c3849d0");
two.setSize(64);
two.setContentType("application/octet-stream");
two.setLastModified(new DateTime("2009-02-03T05:26:32.612278"));

View File

@ -122,7 +122,7 @@ public class StubCloudFilesConnection extends
throw new UnsupportedOperationException();
}
public Future<byte[]> putObject(String container, Blob<BlobMetadata> object) {
public Future<String> putObject(String container, Blob<BlobMetadata> object) {
throw new UnsupportedOperationException();
}