JCLOUDS-597: HashCode methods for Content-MD5

This works more naturally with Guava Hashing methods and immutability
provides better safety guarantees.  Also deprecate existing byte[]
methods.
This commit is contained in:
Andrew Gaul 2014-05-27 23:02:42 -07:00
parent 446671a2a7
commit e799a7409c
13 changed files with 98 additions and 48 deletions

View File

@ -23,6 +23,8 @@ import org.jclouds.atmos.domain.MutableContentMetadata;
import org.jclouds.io.ContentMetadataBuilder;
import org.jclouds.io.payloads.BaseMutableContentMetadata;
import com.google.common.hash.HashCode;
public class DelegatingMutableContentMetadata implements MutableContentMetadata {
private URI uri;
private String name;
@ -46,11 +48,18 @@ public class DelegatingMutableContentMetadata implements MutableContentMetadata
return delegate.getContentLength();
}
/** @deprecated use {@link #getContentMD5AsHashCode()} instead. */
@Deprecated
@Override
public byte[] getContentMD5() {
return delegate.getContentMD5();
}
@Override
public HashCode getContentMD5AsHashCode() {
return delegate.getContentMD5AsHashCode();
}
@Override
public String getContentType() {
return delegate.getContentType();
@ -66,11 +75,18 @@ public class DelegatingMutableContentMetadata implements MutableContentMetadata
delegate.setContentLength(contentLength);
}
/** @deprecated use {@link #setContentMD5(HashCode)} instead. */
@Deprecated
@Override
public void setContentMD5(byte[] contentMD5) {
delegate.setContentMD5(contentMD5);
}
@Override
public void setContentMD5(HashCode contentMD5) {
delegate.setContentMD5(contentMD5);
}
@Override
public void setContentType(String contentType) {
delegate.setContentType(contentType);

View File

@ -201,7 +201,7 @@ public class FilesystemStorageStrategyImpl implements LocalStorageStrategy {
Files.createParentDirs(outputFile);
his = new HashingInputStream(Hashing.md5(), payload.openStream());
Files.asByteSink(outputFile).writeFrom(his);
payload.getContentMetadata().setContentMD5(his.hash().asBytes());
payload.getContentMetadata().setContentMD5(his.hash());
String eTag = base16().lowerCase().encode(payload.getContentMetadata().getContentMD5());
return eTag;
} catch (IOException ex) {

View File

@ -160,11 +160,11 @@ public class TransientStorageStrategy implements LocalStorageStrategy {
MutableContentMetadata oldMd = in.getPayload().getContentMetadata();
byte[] out = ByteStreams.toByteArray(in.getPayload());
payload = Payloads.newByteArrayPayload(out);
payload.getContentMetadata().setContentMD5(Hashing.md5().hashBytes(out).asBytes());
HttpUtils.copy(oldMd, payload.getContentMetadata());
payload.getContentMetadata().setContentMD5(Hashing.md5().hashBytes(out));
} else {
if (payload.getContentMetadata().getContentMD5() == null) {
payload.getContentMetadata().setContentMD5(ByteStreams.hash(payload, Hashing.md5()).asBytes());
payload.getContentMetadata().setContentMD5(ByteStreams.hash(payload, Hashing.md5()));
}
}
} catch (IOException e) {

View File

@ -24,6 +24,7 @@ import java.util.Map;
import org.jclouds.blobstore.domain.internal.BlobBuilderImpl;
import org.jclouds.io.Payload;
import com.google.common.hash.HashCode;
import com.google.common.io.ByteSource;
import com.google.common.net.MediaType;
import com.google.inject.ImplementedBy;
@ -115,8 +116,12 @@ public interface BlobBuilder {
PayloadBlobBuilder contentLength(long contentLength);
/** @deprecated use {@link #contentMD5(HashCode)} instead. */
@Deprecated
PayloadBlobBuilder contentMD5(byte[] md5);
PayloadBlobBuilder contentMD5(HashCode md5);
PayloadBlobBuilder contentType(MediaType contentType);
PayloadBlobBuilder contentType(String contentType);

View File

@ -33,6 +33,7 @@ import org.jclouds.io.Payload;
import org.jclouds.io.payloads.PhantomPayload;
import com.google.common.collect.Maps;
import com.google.common.hash.HashCode;
import com.google.common.io.ByteSource;
import com.google.common.net.MediaType;
@ -185,8 +186,15 @@ public class BlobBuilderImpl implements BlobBuilder {
return this;
}
/** @deprecated use {@link #contentMD5(HashCode)} instead. */
@Deprecated
@Override
public PayloadBlobBuilder contentMD5(byte[] md5) {
return contentMD5(md5 == null ? null : HashCode.fromBytes(md5));
}
@Override
public PayloadBlobBuilder contentMD5(HashCode md5) {
payload.getContentMetadata().setContentMD5(md5);
return this;
}

View File

@ -221,7 +221,7 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
blobStore.putBlob(container, blobStore.blobBuilder(name)
.payload(new InputStreamSupplierPayload(supplier))
.contentType("text/plain")
.contentMD5(supplier.hash(md5()).asBytes())
.contentMD5(supplier.hash(md5()))
.contentLength(supplier.size())
.contentDisposition(contentDisposition)
.build());
@ -280,7 +280,7 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
Blob blob = blobStore
.blobBuilder(blobName)
.payload(payload)
.contentMD5(contentMD5.asBytes())
.contentMD5(contentMD5)
.build();
blobStore.putBlob(container, blob);
} finally {

View File

@ -28,6 +28,7 @@ import java.util.Set;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.hash.HashCode;
import com.google.common.collect.ImmutableSet;
public interface ContentMetadata {
@ -79,9 +80,14 @@ public interface ContentMetadata {
@Nullable
String getContentType();
/** @deprecated use {@link #getContentMD5AsHashCode()} instead. */
@Deprecated
@Nullable
byte[] getContentMD5();
@Nullable
HashCode getContentMD5AsHashCode();
/**
* Get Content Language of the payload
* <p/>

View File

@ -16,13 +16,13 @@
*/
package org.jclouds.io;
import java.util.Arrays;
import java.util.Date;
import org.jclouds.io.payloads.BaseImmutableContentMetadata;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.base.Objects;
import com.google.common.hash.HashCode;
public class ContentMetadataBuilder {
@ -32,7 +32,7 @@ public class ContentMetadataBuilder {
protected String contentType = "application/unknown";
protected Long contentLength;
protected byte[] contentMD5;
protected HashCode contentMD5;
protected String contentDisposition;
protected String contentLanguage;
protected String contentEncoding;
@ -43,14 +43,17 @@ public class ContentMetadataBuilder {
return this;
}
public ContentMetadataBuilder contentMD5(byte[] md5) {
if (md5 != null) {
byte[] retval = new byte[md5.length];
System.arraycopy(md5, 0, retval, 0, md5.length);
this.contentMD5 = md5;
/** @deprecated use {@link #contentMD5(HashCode)} instead. */
@Deprecated
public ContentMetadataBuilder contentMD5(@Nullable byte[] contentMD5) {
return contentMD5(contentMD5 == null ? null : HashCode.fromBytes(contentMD5));
}
public ContentMetadataBuilder contentMD5(@Nullable HashCode contentMD5) {
if (contentMD5 != null) {
this.contentMD5 = contentMD5;
}
return this;
}
public ContentMetadataBuilder contentType(@Nullable String contentType) {
@ -80,7 +83,8 @@ public class ContentMetadataBuilder {
}
public ContentMetadata build() {
return new BaseImmutableContentMetadata(contentType, contentLength, contentMD5, contentDisposition,
return new BaseImmutableContentMetadata(contentType, contentLength,
contentMD5 == null ? null : contentMD5.asBytes(), contentDisposition,
contentLanguage, contentEncoding, expires);
}
@ -109,7 +113,7 @@ public class ContentMetadataBuilder {
Objects.equal(contentEncoding, other.contentEncoding) &&
Objects.equal(contentLanguage, other.contentLanguage) &&
Objects.equal(contentLength, other.contentLength) &&
Arrays.equals(contentMD5, other.contentMD5) &&
Objects.equal(contentMD5, other.contentMD5) &&
Objects.equal(contentType, other.contentType) &&
Objects.equal(expires, other.expires);
}
@ -118,6 +122,6 @@ public class ContentMetadataBuilder {
public String toString() {
return "[contentDisposition=" + contentDisposition + ", contentEncoding=" + contentEncoding
+ ", contentLanguage=" + contentLanguage + ", contentLength=" + contentLength + ", contentMD5="
+ Arrays.toString(contentMD5) + ", contentType=" + contentType + ", expires=" + expires + "]";
+ contentMD5 + ", contentType=" + contentType + ", expires=" + expires + "]";
}
}

View File

@ -20,12 +20,18 @@ import java.util.Date;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.hash.HashCode;
public interface MutableContentMetadata extends ContentMetadata {
void setContentLength(@Nullable Long contentLength);
/** @deprecated use {@link #setContentMD5(HashCode)} instead. */
@Deprecated
void setContentMD5(@Nullable byte[] md5);
void setContentMD5(@Nullable HashCode md5);
void setContentType(@Nullable String contentType);
/**

View File

@ -42,6 +42,7 @@ import org.jclouds.io.payloads.InputStreamPayload;
import org.jclouds.io.payloads.InputStreamSupplierPayload;
import com.google.common.base.Throwables;
import com.google.common.hash.HashCode;
import com.google.common.io.ByteSource;
import com.google.common.io.ByteStreams;
import com.google.common.io.Files;
@ -113,7 +114,7 @@ public class BasePayloadSlicer implements PayloadSlicer {
if (content.length > 0) {
payload = new ByteArrayPayload(content);
ContentMetadata cm = metaData.toBuilder().contentLength((long)content.length).contentMD5(null).build();
ContentMetadata cm = metaData.toBuilder().contentLength((long)content.length).contentMD5((HashCode) null).build();
payload.setContentMetadata(BaseMutableContentMetadata.fromContentMetadata(cm));
}
@ -187,7 +188,7 @@ public class BasePayloadSlicer implements PayloadSlicer {
protected Payload copyMetadataAndSetLength(Payload input, Payload returnVal, long length) {
returnVal.setContentMetadata(BaseMutableContentMetadata.fromContentMetadata(input.getContentMetadata()
.toBuilder().contentLength(length).contentMD5(null).build()));
.toBuilder().contentLength(length).contentMD5((HashCode) null).build()));
return returnVal;
}
@ -199,7 +200,7 @@ public class BasePayloadSlicer implements PayloadSlicer {
ContentMetadata meta = BaseMutableContentMetadata.fromContentMetadata(input.getContentMetadata())
.toBuilder()
.contentLength(size)
.contentMD5(null)
.contentMD5((HashCode) null)
.build();
Object rawContent = input.getRawContent();
if (rawContent instanceof File) {

View File

@ -16,19 +16,19 @@
*/
package org.jclouds.io.payloads;
import java.util.Arrays;
import java.util.Date;
import org.jclouds.io.ContentMetadata;
import org.jclouds.io.ContentMetadataBuilder;
import com.google.common.base.Objects;
import com.google.common.hash.HashCode;
public class BaseImmutableContentMetadata implements ContentMetadata {
protected String contentType;
protected Long contentLength;
protected byte[] contentMD5;
protected HashCode contentMD5;
protected String contentDisposition;
protected String contentLanguage;
protected String contentEncoding;
@ -38,7 +38,7 @@ public class BaseImmutableContentMetadata implements ContentMetadata {
String contentDisposition, String contentLanguage, String contentEncoding, Date expires) {
this.contentType = contentType;
this.contentLength = contentLength;
this.contentMD5 = contentMD5;
this.contentMD5 = contentMD5 == null ? null : HashCode.fromBytes(contentMD5);
this.contentDisposition = contentDisposition;
this.contentLanguage = contentLanguage;
this.contentEncoding = contentEncoding;
@ -53,18 +53,17 @@ public class BaseImmutableContentMetadata implements ContentMetadata {
return contentLength;
}
/**
* {@inheritDoc}
*/
/** @deprecated use {@link #getContentMD5AsHashCode()} instead. */
@Deprecated
@Override
public byte[] getContentMD5() {
if (contentMD5 != null) {
byte[] retval = new byte[contentMD5.length];
System.arraycopy(this.contentMD5, 0, retval, 0, contentMD5.length);
return retval;
} else {
return null;
}
HashCode hashCode = getContentMD5AsHashCode();
return hashCode == null ? null : hashCode.asBytes();
}
@Override
public HashCode getContentMD5AsHashCode() {
return contentMD5;
}
/**
@ -111,7 +110,7 @@ public class BaseImmutableContentMetadata implements ContentMetadata {
public String toString() {
return "[contentType=" + contentType + ", contentLength=" + contentLength + ", contentDisposition="
+ contentDisposition + ", contentEncoding=" + contentEncoding + ", contentLanguage=" + contentLanguage
+ ", contentMD5=" + Arrays.toString(contentMD5) + ", expires = " + expires + "]";
+ ", contentMD5=" + contentMD5 + ", expires = " + expires + "]";
}
@Override
@ -149,7 +148,7 @@ public class BaseImmutableContentMetadata implements ContentMetadata {
return false;
} else if (!contentLength.equals(other.contentLength))
return false;
if (!Arrays.equals(contentMD5, other.contentMD5))
if (!Objects.equal(contentMD5, other.contentMD5))
return false;
if (contentType == null) {
if (other.contentType != null)

View File

@ -23,6 +23,8 @@ import org.jclouds.io.ContentMetadataBuilder;
import org.jclouds.io.MutableContentMetadata;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.hash.HashCode;
public class BaseMutableContentMetadata extends ContentMetadataBuilder implements MutableContentMetadata {
/**
@ -41,25 +43,28 @@ public class BaseMutableContentMetadata extends ContentMetadataBuilder implement
contentLength(contentLength);
}
/**
* {@inheritDoc}
*/
/** @deprecated use {@link #getContentMD5AsHashCode()} instead. */
@Deprecated
@Override
public byte[] getContentMD5() {
if (contentMD5 != null) {
byte[] retval = new byte[contentMD5.length];
System.arraycopy(this.contentMD5, 0, retval, 0, contentMD5.length);
return retval;
} else {
return null;
}
HashCode hashCode = getContentMD5AsHashCode();
return hashCode == null ? null : hashCode.asBytes();
}
/**
* {@inheritDoc}
*/
@Override
public HashCode getContentMD5AsHashCode() {
return contentMD5;
}
/** @deprecated use {@link #setContentMD5(HashCode)} instead. */
@Deprecated
@Override
public void setContentMD5(byte[] md5) {
setContentMD5(md5 == null ? null : HashCode.fromBytes(md5));
}
@Override
public void setContentMD5(HashCode md5) {
contentMD5(md5);
}

View File

@ -97,7 +97,7 @@ public class AWSS3ClientExpectTest extends BaseAWSS3ClientExpectTest {
final Payload requestPayload = Payloads.newStringPayload(request);
requestPayload.getContentMetadata().setContentType("text/xml");
requestPayload.getContentMetadata().setContentMD5(md5().hashString(request, UTF_8).asBytes());
requestPayload.getContentMetadata().setContentMD5(md5().hashString(request, UTF_8));
final String response = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<DeleteResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">\n" +