Issue 353: added disposition, encoding, language to blob and transient blobstore

This commit is contained in:
Adrian Cole 2010-09-18 19:38:14 -07:00
parent 50a44b91c4
commit ac9a642cd3
16 changed files with 377 additions and 137 deletions

View File

@ -63,7 +63,7 @@ public class DirectoryEntryListToResourceMetadataList implements
null, null, null, null, Maps.<String, String> newHashMap());
else
return new BlobMetadataImpl(from.getObjectID(), from.getObjectName(), defaultLocation.get(), null,
null, null, null, Maps.<String, String> newHashMap(), null, null);
null, null, null, Maps.<String, String> newHashMap(), null, null, null, null, null);
}
}), from.getToken());

View File

@ -94,7 +94,7 @@ public class AtmosBlobRequestSignerTest extends RestClientTest<AtmosStorageAsync
request,
"Accept: */*\nDate: Thu, 05 Jun 2008 16:38:19 GMT\nx-emc-signature: aLpB1oQaCA27AXT6Nzam7s0f0pI=\nx-emc-uid: identity\n");
assertContentHeadersEqual(request, "text/plain", (long) 2l, new byte[] { 0, 2, 4, 8 });
assertContentHeadersEqual(request, "text/plain", null, null, null, (long) 2l, new byte[] { 0, 2, 4, 8 });
assertEquals(request.getFilters().size(), 0);
}

View File

@ -91,7 +91,7 @@ public class S3BlobRequestSignerTest extends RestClientTest<S3AsyncClient> {
request,
"Authorization: AWS identity:j9Dy/lmmvlCKjA4lkqZenLxMkR4=\nDate: Thu, 05 Jun 2008 16:38:19 GMT\nHost: container.s3.amazonaws.com\n");
assertContentHeadersEqual(request, "text/plain", (long) 2l, new byte[] { 0, 2, 4, 8 });
assertContentHeadersEqual(request, "text/plain", null, null, null, (long) 2l, new byte[] { 0, 2, 4, 8 });
assertEquals(request.getFilters().size(), 0);
}

View File

@ -90,7 +90,7 @@ public class AzureBlobBlobRequestSignerTest extends RestClientTest<AzureBlobAsyn
assertNonPayloadHeadersEqual(
request,
"Authorization: SharedKeyLite identity:LT+HBNzhbRsZY07kC+/JxeuAURbxTmwJaIe464LO36c=\nDate: Thu, 05 Jun 2008 16:38:19 GMT\nx-ms-blob-type: BlockBlob\nx-ms-version: 2009-09-19\n");
assertContentHeadersEqual(request, "text/plain", (long) 2l, new byte[] { 0, 2, 4, 8 });
assertContentHeadersEqual(request, "text/plain", null, null, null, (long) 2l, new byte[] { 0, 2, 4, 8 });
assertEquals(request.getFilters().size(), 0);
}

View File

@ -87,6 +87,7 @@ import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpResponseException;
import org.jclouds.http.options.HttpRequestOptions;
import org.jclouds.io.Payload;
import org.jclouds.io.Payloads;
import org.jclouds.io.payloads.ByteArrayPayload;
import org.jclouds.io.payloads.DelegatingPayload;
@ -102,7 +103,8 @@ import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.internal.Nullable;
/**
* Implementation of {@link BaseAsyncBlobStore} which keeps all data in a local Map object.
* Implementation of {@link BaseAsyncBlobStore} which keeps all data in a local
* Map object.
*
* @author Adrian Cole
* @author James Murty
@ -119,12 +121,11 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
@Inject
protected TransientAsyncBlobStore(BlobStoreContext context, DateService dateService, Crypto crypto,
ConcurrentMap<String, ConcurrentMap<String, Blob>> containerToBlobs,
ConcurrentMap<String, Location> containerToLocation,
HttpGetOptionsListToGetOptions httpGetOptionsConverter,
IfDirectoryReturnNameStrategy ifDirectoryReturnName, Blob.Factory blobFactory, BlobUtils blobUtils,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation,
Supplier<Set<? extends Location>> locations) {
ConcurrentMap<String, ConcurrentMap<String, Blob>> containerToBlobs,
ConcurrentMap<String, Location> containerToLocation, HttpGetOptionsListToGetOptions httpGetOptionsConverter,
IfDirectoryReturnNameStrategy ifDirectoryReturnName, Blob.Factory blobFactory, BlobUtils blobUtils,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation,
Supplier<Set<? extends Location>> locations) {
super(context, blobUtils, service, defaultLocation, locations);
this.blobFactory = blobFactory;
this.dateService = dateService;
@ -148,21 +149,21 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
return immediateFailedFuture(cnfe(container));
SortedSet<StorageMetadata> contents = newTreeSet(transform(realContents.keySet(),
new Function<String, StorageMetadata>() {
public StorageMetadata apply(String key) {
Blob oldBlob = realContents.get(key);
checkState(oldBlob != null, "blob " + key + " is not present although it was in the list of "
+ container);
checkState(oldBlob.getMetadata() != null, "blob " + container + "/" + key + " has no metadata");
MutableBlobMetadata md = copy(oldBlob.getMetadata());
String directoryName = ifDirectoryReturnName.execute(md);
if (directoryName != null) {
md.setName(directoryName);
md.setType(StorageType.RELATIVE_PATH);
}
return md;
new Function<String, StorageMetadata>() {
public StorageMetadata apply(String key) {
Blob oldBlob = realContents.get(key);
checkState(oldBlob != null, "blob " + key + " is not present although it was in the list of "
+ container);
checkState(oldBlob.getMetadata() != null, "blob " + container + "/" + key + " has no metadata");
MutableBlobMetadata md = copy(oldBlob.getMetadata());
String directoryName = ifDirectoryReturnName.execute(md);
if (directoryName != null) {
md.setName(directoryName);
md.setType(StorageType.RELATIVE_PATH);
}
}));
return md;
}
}));
if (options.getMarker() != null) {
final String finalMarker = options.getMarker();
@ -207,14 +208,14 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
contents = newTreeSet(filter(contents, new DelimiterFilter(prefix != null ? prefix : null, delimiter)));
Iterables.<StorageMetadata> addAll(contents, transform(commonPrefixes,
new Function<String, StorageMetadata>() {
public StorageMetadata apply(String o) {
MutableStorageMetadata md = new MutableStorageMetadataImpl();
md.setType(StorageType.RELATIVE_PATH);
md.setName(o);
return md;
}
}));
new Function<String, StorageMetadata>() {
public StorageMetadata apply(String o) {
MutableStorageMetadata md = new MutableStorageMetadataImpl();
md.setType(StorageType.RELATIVE_PATH);
md.setName(o);
return md;
}
}));
}
// trim metadata, if the response isn't supposed to be detailed.
@ -225,13 +226,13 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
}
return Futures.<PageSet<? extends StorageMetadata>> immediateFuture(new PageSetImpl<StorageMetadata>(contents,
marker));
marker));
}
private ContainerNotFoundException cnfe(final String name) {
return new ContainerNotFoundException(name, String.format("container %s not in %s", name, getContainerToBlobs()
.keySet()));
.keySet()));
}
public static MutableBlobMetadata copy(MutableBlobMetadata in) {
@ -328,15 +329,15 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
@Override
public ListenableFuture<PageSet<? extends StorageMetadata>> list() {
return Futures.<PageSet<? extends StorageMetadata>> immediateFuture(new PageSetImpl<StorageMetadata>(transform(
getContainerToBlobs().keySet(), new Function<String, StorageMetadata>() {
public StorageMetadata apply(String name) {
MutableStorageMetadata cmd = create();
cmd.setName(name);
cmd.setType(StorageType.CONTAINER);
cmd.setLocation(getContainerToLocation().get(name));
return cmd;
}
}), null));
getContainerToBlobs().keySet(), new Function<String, StorageMetadata>() {
public StorageMetadata apply(String name) {
MutableStorageMetadata cmd = create();
cmd.setName(name);
cmd.setType(StorageType.CONTAINER);
cmd.setLocation(getContainerToLocation().get(name));
return cmd;
}
}), null));
}
protected MutableStorageMetadata create() {
@ -360,7 +361,7 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
*/
public ListenableFuture<Void> createContainerInLocationIfAbsent(final Location location, final String name) {
ConcurrentMap<String, Blob> container = getContainerToBlobs().putIfAbsent(name,
new ConcurrentHashMap<String, Blob>());
new ConcurrentHashMap<String, Blob>());
if (container == null) {
getContainerToLocation().put(name, location != null ? location : defaultLocation.get());
return immediateFuture((Void) null);
@ -505,11 +506,11 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
protected Blob createUpdatedCopyOfBlob(Blob in) {
ByteArrayPayload payload = (in.getPayload() instanceof ByteArrayPayload) ? ByteArrayPayload.class.cast(in
.getPayload()) : null;
.getPayload()) : null;
if (payload == null)
payload = (in.getPayload() instanceof DelegatingPayload) ? (DelegatingPayload.class.cast(in.getPayload())
.getDelegate() instanceof ByteArrayPayload) ? ByteArrayPayload.class.cast(DelegatingPayload.class
.cast(in.getPayload()).getDelegate()) : null : null;
.getDelegate() instanceof ByteArrayPayload) ? ByteArrayPayload.class.cast(DelegatingPayload.class.cast(
in.getPayload()).getDelegate()) : null : null;
try {
if (payload == null || !(payload instanceof ByteArrayPayload)) {
String oldContentType = in.getPayload().getContentType();
@ -531,23 +532,40 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
blob.getMetadata().setContentMD5(payload.getContentMD5());
blob.getMetadata().setContentType(payload.getContentType());
blob.getMetadata().setContentDisposition(payload.getContentDisposition());
blob.getMetadata().setContentEncoding(payload.getContentEncoding());
blob.getMetadata().setContentLanguage(payload.getContentLanguage());
String eTag = CryptoStreams.hex(payload.getContentMD5());
blob.getMetadata().setETag(eTag);
// Set HTTP headers to match metadata
blob.getAllHeaders().replaceValues(HttpHeaders.LAST_MODIFIED,
Collections.singleton(dateService.rfc822DateFormat(blob.getMetadata().getLastModified())));
Collections.singleton(dateService.rfc822DateFormat(blob.getMetadata().getLastModified())));
blob.getAllHeaders().replaceValues(HttpHeaders.ETAG, Collections.singleton(eTag));
blob.getAllHeaders().replaceValues(HttpHeaders.CONTENT_TYPE, Collections.singleton(payload.getContentType()));
blob.getAllHeaders().replaceValues(HttpHeaders.CONTENT_LENGTH,
Collections.singleton(payload.getContentLength() + ""));
blob.getAllHeaders().replaceValues("Content-MD5",
Collections.singleton(CryptoStreams.base64(payload.getContentMD5())));
//TODO maybe i should change here content-disposition
copyPayloadHeadersToBlob(payload, blob);
blob.getAllHeaders().putAll(Multimaps.forMap(blob.getMetadata().getUserMetadata()));
return blob;
}
private void copyPayloadHeadersToBlob(Payload payload, Blob blob) {
if (payload.getContentType() != null)
blob.getAllHeaders().replaceValues(HttpHeaders.CONTENT_TYPE, Collections.singleton(payload.getContentType()));
if (payload.getContentDisposition() != null)
blob.getAllHeaders().replaceValues("Content-Disposition",
Collections.singleton(payload.getContentDisposition()));
if (payload.getContentEncoding() != null)
blob.getAllHeaders().replaceValues(HttpHeaders.CONTENT_ENCODING,
Collections.singleton(payload.getContentEncoding()));
if (payload.getContentEncoding() != null)
blob.getAllHeaders().replaceValues(HttpHeaders.CONTENT_LANGUAGE,
Collections.singleton(payload.getContentLanguage()));
if (payload.getContentLength() != null)
blob.getAllHeaders().replaceValues(HttpHeaders.CONTENT_LENGTH,
Collections.singleton(payload.getContentLength() + ""));
if (payload.getContentMD5() != null)
blob.getAllHeaders().replaceValues("Content-MD5",
Collections.singleton(CryptoStreams.base64(payload.getContentMD5())));
}
/**
* {@inheritDoc}
*/
@ -585,7 +603,7 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
if (object.getMetadata().getLastModified().before(modifiedSince)) {
HttpResponse response = new HttpResponse(304, null, null);
return immediateFailedFuture(new HttpResponseException(String.format("%1$s is before %2$s", object
.getMetadata().getLastModified(), modifiedSince), null, response));
.getMetadata().getLastModified(), modifiedSince), null, response));
}
}
@ -594,7 +612,7 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
if (object.getMetadata().getLastModified().after(unmodifiedSince)) {
HttpResponse response = new HttpResponse(412, null, null);
return immediateFailedFuture(new HttpResponseException(String.format("%1$s is after %2$s", object
.getMetadata().getLastModified(), unmodifiedSince), null, response));
.getMetadata().getLastModified(), unmodifiedSince), null, response));
}
}
Blob returnVal = copyBlob(object);
@ -647,9 +665,10 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
}
}
private Blob copyBlob(Blob object) {
Blob returnVal = blobFactory.create(copy(object.getMetadata()));
returnVal.setPayload(object.getPayload());
private Blob copyBlob(Blob blob) {
Blob returnVal = blobFactory.create(copy(blob.getMetadata()));
returnVal.setPayload(blob.getPayload());
copyPayloadHeadersToBlob(blob.getPayload(), returnVal);
return returnVal;
}

View File

@ -19,6 +19,8 @@
package org.jclouds.blobstore.domain;
import javax.annotation.Nullable;
import org.jclouds.blobstore.domain.internal.BlobMetadataImpl;
import com.google.inject.ImplementedBy;
@ -32,10 +34,11 @@ import com.google.inject.ImplementedBy;
public interface BlobMetadata extends StorageMetadata {
/**
* A standard MIME type describing the format of the contents. If none is provided, the default
* is binary/octet-stream.
* A standard MIME type describing the format of the contents. If none is
* provided, the default is binary/octet-stream.
*
* @see <a href= "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html?sec14.17." />
* @see <a href=
* "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html?sec14.17." />
*/
String getContentType();
@ -45,8 +48,24 @@ public interface BlobMetadata extends StorageMetadata {
* Content-Disposition to set for the blob.
* <p/>
* <b>Attention</b>: Not all provider support it!
*
* @return
*/
String getContentDisposition();
/**
* Get Content Encoding of the blob
* <p/>
* Not all providers may support it
*/
@Nullable
String getContentEncoding();
/**
* Get Content Language of the blob
* <p/>
* Not all providers may support it
*/
@Nullable
String getContentLanguage();
}

View File

@ -34,15 +34,20 @@ import com.google.inject.ImplementedBy;
public interface MutableBlobMetadata extends BlobMetadata, MutableStorageMetadata {
/**
* A standard MIME type describing the format of the contents. If none is provided, the default
* is binary/octet-stream.
* A standard MIME type describing the format of the contents. If none is
* provided, the default is binary/octet-stream.
*
* @see <a href= "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html?sec14.17." />
* @see <a href=
* "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html?sec14.17." />
*/
void setContentType(@Nullable String type);
void setContentMD5(@Nullable byte[] md5);
String setContentDisposition(@Nullable String contentDisposition);
void setContentDisposition(@Nullable String contentDisposition);
void setContentEncoding(@Nullable String contentEncoding);
void setContentLanguage(@Nullable String contentLanguage);
}

View File

@ -125,13 +125,13 @@ public class BlobImpl extends PayloadEnclosingImpl implements Blob, Comparable<B
}
/**
* link the new payload to the metadata object so that when content-related metadata is updated
* on the payload, it is also copied the metadata object.
* link the new payload to the metadata object so that when content-related
* metadata is updated on the payload, it is also copied the metadata object.
*/
void linkPayloadToMetadata(Payload data) {
if (data instanceof DelegatingPayload)
super.setPayload(new SetMetadataPropertiesPayload(DelegatingPayload.class.cast(data)
.getDelegate(), _metadata));
super
.setPayload(new SetMetadataPropertiesPayload(DelegatingPayload.class.cast(data).getDelegate(), _metadata));
else
super.setPayload(new SetMetadataPropertiesPayload(data, _metadata));
}
@ -145,6 +145,8 @@ public class BlobImpl extends PayloadEnclosingImpl implements Blob, Comparable<B
this.metadata = metadata;
setContentType(metadata.getContentType());
setContentDisposition(metadata.getContentDisposition());
setContentEncoding(metadata.getContentEncoding());
setContentLanguage(metadata.getContentLanguage());
}
@Override
@ -158,16 +160,28 @@ public class BlobImpl extends PayloadEnclosingImpl implements Blob, Comparable<B
super.setContentDisposition(contentDisposition);
metadata.setContentDisposition(contentDisposition);
}
@Override
public void setContentEncoding(String contentEncoding) {
super.setContentEncoding(contentEncoding);
metadata.setContentEncoding(contentEncoding);
}
@Override
public void setContentLanguage(String contentLanguage) {
super.setContentLanguage(contentLanguage);
metadata.setContentLanguage(contentLanguage);
}
}
/**
* link the metadata object to this so that when content-related metadata is updated, it is also
* copied the currentpayload object.
* link the metadata object to this so that when content-related metadata is
* updated, it is also copied the currentpayload object.
*/
SetPayloadPropertiesMutableBlobMetadata linkMetadataToThis(MutableBlobMetadata metadata) {
return metadata instanceof DelegatingMutableBlobMetadata ? new SetPayloadPropertiesMutableBlobMetadata(
DelegatingMutableBlobMetadata.class.cast(metadata).getDelegate(), this)
: new SetPayloadPropertiesMutableBlobMetadata(metadata, this);
DelegatingMutableBlobMetadata.class.cast(metadata).getDelegate(), this)
: new SetPayloadPropertiesMutableBlobMetadata(metadata, this);
}
static class SetPayloadPropertiesMutableBlobMetadata extends DelegatingMutableBlobMetadata {
@ -175,8 +189,7 @@ public class BlobImpl extends PayloadEnclosingImpl implements Blob, Comparable<B
private static final long serialVersionUID = -5072270546219814521L;
private transient final PayloadEnclosing blob;
public SetPayloadPropertiesMutableBlobMetadata(MutableBlobMetadata delegate,
PayloadEnclosing blob) {
public SetPayloadPropertiesMutableBlobMetadata(MutableBlobMetadata delegate, PayloadEnclosing blob) {
super(delegate);
this.blob = blob;
}
@ -188,6 +201,27 @@ public class BlobImpl extends PayloadEnclosingImpl implements Blob, Comparable<B
blob.getPayload().setContentType(type);
}
@Override
public void setContentDisposition(String Disposition) {
super.setContentDisposition(Disposition);
if (canSetPayload())
blob.getPayload().setContentDisposition(Disposition);
}
@Override
public void setContentEncoding(String Encoding) {
super.setContentEncoding(Encoding);
if (canSetPayload())
blob.getPayload().setContentEncoding(Encoding);
}
@Override
public void setContentLanguage(String Language) {
super.setContentLanguage(Language);
if (canSetPayload())
blob.getPayload().setContentLanguage(Language);
}
private boolean canSetPayload() {
return blob != null && blob.getPayload() != null;
}

View File

@ -41,13 +41,19 @@ public class BlobMetadataImpl extends StorageMetadataImpl implements Serializabl
private static final long serialVersionUID = -5932618957134612231L;
private final String contentType;
private final String contentDisposition;
private final String contentEncoding;
private final String contentLanguage;
private final byte[] contentMD5;
public BlobMetadataImpl(String id, String name, @Nullable Location location, URI uri,
String eTag, Long size, Date lastModified, Map<String, String> userMetadata,
String contentType, byte[] contentMD5) {
public BlobMetadataImpl(String id, String name, @Nullable Location location, URI uri, String eTag, Long size,
Date lastModified, Map<String, String> userMetadata, String contentType, String contentDisposition,
String contentEncoding, String contentLanguage, byte[] contentMD5) {
super(StorageType.BLOB, id, name, location, uri, eTag, size, lastModified, userMetadata);
this.contentType = contentType;
this.contentDisposition = contentDisposition;
this.contentEncoding = contentEncoding;
this.contentLanguage = contentLanguage;
this.contentMD5 = contentMD5;
}
@ -59,6 +65,30 @@ public class BlobMetadataImpl extends StorageMetadataImpl implements Serializabl
return contentType;
}
/**
* {@inheritDoc}
*/
@Override
public String getContentDisposition() {
return contentDisposition;
}
/**
* {@inheritDoc}
*/
@Override
public String getContentEncoding() {
return contentEncoding;
}
/**
* {@inheritDoc}
*/
@Override
public String getContentLanguage() {
return contentLanguage;
}
/**
* {@inheritDoc}
*/

View File

@ -176,4 +176,34 @@ public class DelegatingMutableBlobMetadata implements MutableBlobMetadata, Seria
return delegate;
}
@Override
public void setContentDisposition(String contentDisposition) {
delegate.setContentDisposition(contentDisposition);
}
@Override
public String getContentDisposition() {
return delegate.getContentDisposition();
}
@Override
public String getContentEncoding() {
return delegate.getContentEncoding();
}
@Override
public String getContentLanguage() {
return delegate.getContentLanguage();
}
@Override
public void setContentEncoding(String contentEncoding) {
delegate.setContentEncoding(contentEncoding);
}
@Override
public void setContentLanguage(String contentLanguage) {
delegate.setContentLanguage(contentLanguage);
}
}

View File

@ -29,12 +29,14 @@ import org.jclouds.blobstore.domain.StorageType;
*
* @author Adrian Cole
*/
public class MutableBlobMetadataImpl extends MutableStorageMetadataImpl implements
MutableBlobMetadata {
public class MutableBlobMetadataImpl extends MutableStorageMetadataImpl implements MutableBlobMetadata {
/** The serialVersionUID */
private static final long serialVersionUID = -5932618957134612231L;
private String contentType;
private String contentDisposition;
private String contentEncoding;
private String contentLanguage;
private byte[] contentMD5;
public MutableBlobMetadataImpl() {
@ -45,6 +47,9 @@ public class MutableBlobMetadataImpl extends MutableStorageMetadataImpl implemen
public MutableBlobMetadataImpl(BlobMetadata from) {
super(from);
this.contentType = from.getContentType();
this.contentDisposition = from.getContentDisposition();
this.contentEncoding = from.getContentEncoding();
this.contentLanguage = from.getContentLanguage();
this.contentMD5 = from.getContentMD5();
}
@ -56,6 +61,62 @@ public class MutableBlobMetadataImpl extends MutableStorageMetadataImpl implemen
return contentType;
}
/**
* {@inheritDoc}
*/
@Override
public void setContentType(String contentType) {
this.contentType = contentType;
}
/**
* {@inheritDoc}
*/
@Override
public String getContentDisposition() {
return contentDisposition;
}
/**
* {@inheritDoc}
*/
@Override
public void setContentDisposition(String contentDisposition) {
this.contentDisposition = contentDisposition;
}
/**
* {@inheritDoc}
*/
@Override
public String getContentEncoding() {
return contentEncoding;
}
/**
* {@inheritDoc}
*/
@Override
public void setContentEncoding(String contentEncoding) {
this.contentEncoding = contentEncoding;
}
/**
* {@inheritDoc}
*/
@Override
public String getContentLanguage() {
return contentLanguage;
}
/**
* {@inheritDoc}
*/
@Override
public void setContentLanguage(String contentLanguage) {
this.contentLanguage = contentLanguage;
}
/**
* {@inheritDoc}
*/
@ -82,12 +143,4 @@ public class MutableBlobMetadataImpl extends MutableStorageMetadataImpl implemen
}
}
/**
* {@inheritDoc}
*/
@Override
public void setContentType(String type) {
this.contentType = type;
}
}

View File

@ -44,7 +44,7 @@ public class TransientBlobRequestSignerTest extends RestClientTest<TransientAsyn
private Factory blobFactory;
public void testSignGetBlob() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException,
NoSuchMethodException, IOException {
NoSuchMethodException, IOException {
HttpRequest request = signer.signGetBlob("container", "name");
assertRequestLineEquals(request, "GET http://localhost/container/name HTTP/1.1");
@ -55,7 +55,7 @@ public class TransientBlobRequestSignerTest extends RestClientTest<TransientAsyn
}
public void testSignRemoveBlob() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException,
NoSuchMethodException, IOException {
NoSuchMethodException, IOException {
HttpRequest request = signer.signRemoveBlob("container", "name");
assertRequestLineEquals(request, "DELETE http://localhost/container/name HTTP/1.1");
@ -66,7 +66,7 @@ public class TransientBlobRequestSignerTest extends RestClientTest<TransientAsyn
}
public void testSignPutBlob() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException,
NoSuchMethodException, IOException {
NoSuchMethodException, IOException {
Blob blob = blobFactory.create(null);
blob.getMetadata().setName("name");
blob.setPayload(new PhantomPayload(2l, new byte[] { 0, 2, 4, 8 }));
@ -75,8 +75,10 @@ public class TransientBlobRequestSignerTest extends RestClientTest<TransientAsyn
HttpRequest request = signer.signPutBlob("container", blob);
assertRequestLineEquals(request, "PUT http://localhost/container/name HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Authorization: Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==\nContent-Length: 2\nContent-MD5: AAIECA==\nContent-Type: text/plain\n");
assertContentHeadersEqual(request, "text/plain", (long) 2l, new byte[] { 0, 2, 4, 8 });
assertNonPayloadHeadersEqual(
request,
"Authorization: Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==\nContent-Length: 2\nContent-MD5: AAIECA==\nContent-Type: text/plain\n");
assertContentHeadersEqual(request, "text/plain", null, null, null, (long) 2l, new byte[] { 0, 2, 4, 8 });
assertEquals(request.getFilters().size(), 0);
}

View File

@ -45,6 +45,7 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.zip.GZIPInputStream;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import org.jclouds.blobstore.ContainerNotFoundException;
@ -155,13 +156,14 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
/**
* Methods for checking Content-Disposition. In this way, in implementations
* that do not support the new field, it is easy to override with empty,
* and allow the rest of the test to work.
* that do not support the new field, it is easy to override with empty, and
* allow the rest of the test to work.
*
* @param blob
* @param expected
*/
protected void checkContentDispostion(Blob blob, String expected){
assertEquals(blob.getPayload().getContentDisposition(), expected);
protected void checkContentDispostion(Blob blob, String expected) {
assertEquals(blob.getPayload().getContentDisposition(), expected);
}
@Test(groups = { "integration", "live" })
@ -456,6 +458,9 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
}
}));
blob.getMetadata().setContentType("text/csv");
blob.getMetadata().setContentDisposition("attachment; filename=photo.jpg");
blob.getMetadata().setContentEncoding("gzip");
blob.getMetadata().setContentLanguage("en");
String containerName = getContainerName();
try {
@ -465,7 +470,10 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
blob = context.getBlobStore().getBlob(containerName, blob.getMetadata().getName());
String returnedString = getContentAsStringOrNullAndClose(blob);
assertEquals(returnedString, "foo");
assert blob.getPayload().getContentType().startsWith("text/csv") : blob.getPayload().getContentType();
checkContentType(blob, "text/csv");
checkContentDisposition(blob, "attachment; filename=photo.jpg");
checkContentEncoding(blob, "gzip");
checkContentLanguage(blob, "en");
PageSet<? extends StorageMetadata> set = context.getBlobStore().list(containerName);
assert set.size() == 1 : set;
} finally {
@ -473,6 +481,40 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
}
}
protected void checkContentType(Blob blob, String contentType) {
assert blob.getPayload().getContentType().startsWith(contentType) : blob.getPayload().getContentType();
assert blob.getMetadata().getContentType().startsWith(contentType) : blob.getMetadata().getContentType();
assert Iterables.getOnlyElement(blob.getAllHeaders().get(HttpHeaders.CONTENT_TYPE)).startsWith(contentType) : blob
.getAllHeaders().get(HttpHeaders.CONTENT_TYPE);
}
protected void checkContentDisposition(Blob blob, String contentDisposition) {
assert blob.getPayload().getContentDisposition().startsWith(contentDisposition) : blob.getPayload()
.getContentDisposition();
assert blob.getMetadata().getContentDisposition().startsWith(contentDisposition) : blob.getMetadata()
.getContentDisposition();
assert Iterables.getOnlyElement(blob.getAllHeaders().get("Content-Disposition")).startsWith(contentDisposition) : blob
.getAllHeaders().get("Content-Disposition");
}
protected void checkContentEncoding(Blob blob, String contentEncoding) {
assert blob.getPayload().getContentEncoding().startsWith(contentEncoding) : blob.getPayload()
.getContentEncoding();
assert blob.getMetadata().getContentEncoding().startsWith(contentEncoding) : blob.getMetadata()
.getContentEncoding();
assert Iterables.getOnlyElement(blob.getAllHeaders().get(HttpHeaders.CONTENT_ENCODING)).startsWith(
contentEncoding) : blob.getAllHeaders().get(HttpHeaders.CONTENT_ENCODING);
}
protected void checkContentLanguage(Blob blob, String contentLanguage) {
assert blob.getPayload().getContentLanguage().startsWith(contentLanguage) : blob.getPayload()
.getContentLanguage();
assert blob.getMetadata().getContentLanguage().startsWith(contentLanguage) : blob.getMetadata()
.getContentLanguage();
assert Iterables.getOnlyElement(blob.getAllHeaders().get(HttpHeaders.CONTENT_LANGUAGE)).startsWith(
contentLanguage) : blob.getAllHeaders().get(HttpHeaders.CONTENT_LANGUAGE);
}
protected volatile static Crypto crypto;
static {
try {

View File

@ -72,12 +72,11 @@ public interface Payload extends InputSupplier<InputStream>, WriteTo, Closeable
@Nullable
String getContentType();
/**
* Set Content Disposition of the payload
* <p/>
* Not all providers may support it
*
*
* @param contentDisposition
*/
void setContentDisposition(@Nullable String contentDisposition);
@ -87,38 +86,42 @@ public interface Payload extends InputSupplier<InputStream>, WriteTo, Closeable
* <p/>
* Not all providers may support it
*/
@Nullable String getContentDisposition();
@Nullable
String getContentDisposition();
/**
* Set Content Language of the payload
* <p/>
* Not all providers may support it
*
*
* @param contentLanguage
*/
void setContentLanguage(@Nullable String contentLanguage);
/**
* Get Content Language of the payload
* <p/>
* Not all providers may support it
*/
@Nullable String getContentLanguage();
@Nullable
String getContentLanguage();
/**
* Set Content Encoding of the payload
* <p/>
* Not all providers may support it
*
*
* @param contentEncoding
*/
void setContentEncoding(@Nullable String contentEncoding);
/**
* Get Content Encoding of the payload
* <p/>
* Not all providers may support it
*/
@Nullable String getContentEncoding();
@Nullable
String getContentEncoding();
/**
* release resources used by this entity. This should be called when data is

View File

@ -38,6 +38,9 @@ import org.jclouds.io.WriteTo;
*/
public class StreamingPayload implements Payload {
protected String contentType;
protected String contentDisposition;
protected String contentEncoding;
protected String contentLanguage;
protected transient volatile boolean written;
protected final WriteTo writeTo;
@ -112,44 +115,20 @@ public class StreamingPayload implements Payload {
this.contentType = contentType;
}
/**
* {@inheritDoc}
*/
@Override
public void setContentDisposition(String contentDisposition) {
throw new UnsupportedOperationException("this payload is for streaming writes only");
}
/**
* {@inheritDoc}
*/
@Override
public String getContentDisposition() {
throw new UnsupportedOperationException("this payload is for streaming writes only");
return contentDisposition;
}
/**
* {@inheritDoc}
*/
@Override
public void setContentLanguage(String contentLanguage) {
throw new UnsupportedOperationException("this payload is for streaming writes only");
}
/**
* {@inheritDoc}
*/
@Override
public String getContentLanguage() {
throw new UnsupportedOperationException("this payload is for streaming writes only");
}
/**
* {@inheritDoc}
*/
@Override
public void setContentEncoding(String contentEncoding) {
throw new UnsupportedOperationException("this payload is for streaming writes only");
public void setContentDisposition(@Nullable String contentDisposition) {
this.contentDisposition = contentDisposition;
}
/**
@ -157,7 +136,31 @@ public class StreamingPayload implements Payload {
*/
@Override
public String getContentEncoding() {
throw new UnsupportedOperationException("this payload is for streaming writes only");
return contentEncoding;
}
/**
* {@inheritDoc}
*/
@Override
public void setContentEncoding(@Nullable String contentEncoding) {
this.contentEncoding = contentEncoding;
}
/**
* {@inheritDoc}
*/
@Override
public String getContentLanguage() {
return contentLanguage;
}
/**
* {@inheritDoc}
*/
@Override
public void setContentLanguage(@Nullable String contentLanguage) {
this.contentLanguage = contentLanguage;
}
/**

View File

@ -81,7 +81,7 @@ public class CloudFilesBlobRequestSignerTest extends RestClientTest<CloudFilesAs
assertRequestLineEquals(request, "PUT http://storageUrl/container/name HTTP/1.1");
assertNonPayloadHeadersEqual(request, "X-Auth-Token: testtoken\n");
assertContentHeadersEqual(request, "text/plain", (long) 2l, new byte[] { 0, 2, 4, 8 });
assertContentHeadersEqual(request, "text/plain", null, null, null, (long) 2l, new byte[] { 0, 2, 4, 8 });
assertEquals(request.getFilters().size(), 0);
}