mirror of https://github.com/apache/jclouds.git
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:
parent
04f70ce8f7
commit
33d11fe07f
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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("\"", "")));
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
|
|
@ -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")) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
||||
|
|
|
@ -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/");
|
||||
|
||||
|
|
|
@ -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/");
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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()"));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,15 +116,13 @@ 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);
|
||||
Future<String> putBlob(String containerName, @BinderParam(BindDataToEntity.class) PCSFile object);
|
||||
|
||||
// @POST
|
||||
// @Path("/containers/{containerResourceId}/contents")
|
||||
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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());
|
|
@ -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) {
|
|
@ -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) {
|
||||
|
|
|
@ -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))));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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()));
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue