mirror of https://github.com/apache/jclouds.git
Issue 301: refactored http payload data from blob -> core, added content length, type, md5; fixed length bug in ec2 and added more tests to ensure this doesn't happen again
This commit is contained in:
parent
c948e49183
commit
da3baf523c
|
@ -30,7 +30,7 @@ import javax.ws.rs.Path;
|
|||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.jclouds.atmosonline.saas.binders.BindAtmosObjectToPayloadAndMetadataToHeaders;
|
||||
import org.jclouds.atmosonline.saas.binders.BindMetadataToHeaders;
|
||||
import org.jclouds.atmosonline.saas.domain.AtmosObject;
|
||||
import org.jclouds.atmosonline.saas.domain.BoundedSet;
|
||||
import org.jclouds.atmosonline.saas.domain.DirectoryEntry;
|
||||
|
@ -113,7 +113,7 @@ public interface AtmosStorageAsyncClient {
|
|||
@Consumes(MediaType.WILDCARD)
|
||||
ListenableFuture<URI> createFile(
|
||||
@PathParam("parent") String parent,
|
||||
@PathParam("name") @ParamParser(AtmosObjectName.class) @BinderParam(BindAtmosObjectToPayloadAndMetadataToHeaders.class) AtmosObject object);
|
||||
@PathParam("name") @ParamParser(AtmosObjectName.class) @BinderParam(BindMetadataToHeaders.class) AtmosObject object);
|
||||
|
||||
/**
|
||||
* @see AtmosStorageClient#updateFile
|
||||
|
@ -124,7 +124,7 @@ public interface AtmosStorageAsyncClient {
|
|||
@Consumes(MediaType.WILDCARD)
|
||||
ListenableFuture<Void> updateFile(
|
||||
@PathParam("parent") String parent,
|
||||
@PathParam("name") @ParamParser(AtmosObjectName.class) @BinderParam(BindAtmosObjectToPayloadAndMetadataToHeaders.class) AtmosObject object);
|
||||
@PathParam("name") @ParamParser(AtmosObjectName.class) @BinderParam(BindMetadataToHeaders.class) AtmosObject object);
|
||||
|
||||
/**
|
||||
* @see AtmosStorageClient#readFile
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed 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.atmosonline.saas.binders;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
|
||||
import org.jclouds.atmosonline.saas.domain.AtmosObject;
|
||||
import org.jclouds.encryption.EncryptionService;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.rest.Binder;
|
||||
|
||||
public class BindAtmosObjectToPayloadAndMetadataToHeaders implements Binder {
|
||||
private final BindUserMetadataToHeaders metaBinder;
|
||||
private final EncryptionService encryptionService;
|
||||
|
||||
@Inject
|
||||
protected BindAtmosObjectToPayloadAndMetadataToHeaders(BindUserMetadataToHeaders metaBinder,
|
||||
EncryptionService encryptionService) {
|
||||
this.metaBinder = metaBinder;
|
||||
this.encryptionService = encryptionService;
|
||||
}
|
||||
|
||||
public void bindToRequest(HttpRequest request, Object payload) {
|
||||
AtmosObject object = (AtmosObject) payload;
|
||||
|
||||
request.setPayload(checkNotNull(object.getPayload(), "object.getPayload()"));
|
||||
request.getHeaders().put(
|
||||
HttpHeaders.CONTENT_TYPE,
|
||||
checkNotNull(object.getContentMetadata().getContentType(),
|
||||
"object.metadata.contentType()"));
|
||||
|
||||
request.getHeaders().put(HttpHeaders.CONTENT_LENGTH,
|
||||
object.getContentMetadata().getContentLength() + "");
|
||||
|
||||
if (object.getContentMetadata().getContentMD5() != null) {
|
||||
request.getHeaders().put("Content-MD5",
|
||||
encryptionService.base64(object.getContentMetadata().getContentMD5()));
|
||||
}
|
||||
metaBinder.bindToRequest(request, object.getUserMetadata());
|
||||
}
|
||||
}
|
|
@ -16,21 +16,28 @@
|
|||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.mezeo.pcs2.binders;
|
||||
package org.jclouds.atmosonline.saas.binders;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.atmosonline.saas.domain.AtmosObject;
|
||||
import org.jclouds.encryption.EncryptionService;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.mezeo.pcs2.domain.PCSFile;
|
||||
import org.jclouds.rest.Binder;
|
||||
|
||||
public class BindDataToPayload implements Binder {
|
||||
@Singleton
|
||||
public class BindMetadataToHeaders implements Binder {
|
||||
private final BindUserMetadataToHeaders metaBinder;
|
||||
|
||||
@Inject
|
||||
protected BindMetadataToHeaders(BindUserMetadataToHeaders metaBinder,
|
||||
EncryptionService encryptionService) {
|
||||
this.metaBinder = metaBinder;
|
||||
}
|
||||
|
||||
public void bindToRequest(HttpRequest request, Object payload) {
|
||||
PCSFile object = (PCSFile) payload;
|
||||
request.setPayload(checkNotNull(object.getPayload().getInput(), "object.getContent()"));
|
||||
request.getHeaders().put(HttpHeaders.CONTENT_LENGTH, object.getContentLength() + "");
|
||||
AtmosObject object = (AtmosObject) payload;
|
||||
metaBinder.bindToRequest(request, object.getUserMetadata());
|
||||
}
|
||||
}
|
|
@ -20,51 +20,34 @@ package org.jclouds.atmosonline.saas.binders;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Map.Entry;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.atmosonline.saas.domain.UserMetadata;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.rest.Binder;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
|
||||
@Singleton
|
||||
public class BindUserMetadataToHeaders implements Binder {
|
||||
|
||||
public void bindToRequest(HttpRequest request, Object payload) {
|
||||
UserMetadata md = (UserMetadata) checkNotNull(payload, "payload");
|
||||
if (md.getMetadata().size() > 0) {
|
||||
String header = join(md.getMetadata());
|
||||
String header = Joiner.on(',').withKeyValueSeparator("=").join(md.getMetadata());
|
||||
request.getHeaders().put("x-emc-meta", header);
|
||||
}
|
||||
if (md.getListableMetadata().size() > 0) {
|
||||
String header = join(md.getListableMetadata());
|
||||
String header = Joiner.on(',').withKeyValueSeparator("=").join(md.getListableMetadata());
|
||||
request.getHeaders().put("x-emc-listable-meta", header);
|
||||
}
|
||||
if (md.getTags().size() > 0) {
|
||||
String header = join(md.getTags());
|
||||
String header = Joiner.on(',').join(md.getTags());
|
||||
request.getHeaders().put("x-emc-tags", header);
|
||||
}
|
||||
if (md.getListableTags().size() > 0) {
|
||||
String header = join(md.getListableTags());
|
||||
String header = Joiner.on(',').join(md.getListableTags());
|
||||
request.getHeaders().put("x-emc-listable-tags", header);
|
||||
}
|
||||
}
|
||||
|
||||
private String join(Set<String> set) {
|
||||
StringBuffer header = new StringBuffer();
|
||||
for (String entry : set) {
|
||||
header.append(entry).append(",");
|
||||
}
|
||||
header.deleteCharAt(header.length() - 1);
|
||||
return header.toString();
|
||||
}
|
||||
|
||||
private String join(Map<String, String> map) {
|
||||
StringBuffer header = new StringBuffer();
|
||||
for (Entry<String, String> entry : map.entrySet()) {
|
||||
header.append(entry.getKey()).append("=").append(entry.getValue()).append(",");
|
||||
}
|
||||
header.deleteCharAt(header.length() - 1);
|
||||
return header.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,8 +44,6 @@ public class BlobToObject implements Function<Blob, AtmosObject> {
|
|||
if (from == null)
|
||||
return null;
|
||||
AtmosObject object = blobMd2Object.apply(from.getMetadata());
|
||||
if (from.getContentLength() != null)
|
||||
object.setContentLength(from.getContentLength());
|
||||
object.setPayload(checkNotNull(from.getPayload(), "payload: " + from));
|
||||
object.setAllHeaders(from.getAllHeaders());
|
||||
return object;
|
||||
|
|
|
@ -47,10 +47,10 @@ public class ObjectToBlob implements Function<AtmosObject, Blob> {
|
|||
if (from == null)
|
||||
return null;
|
||||
Blob blob = blobFactory.create(object2BlobMd.apply(from));
|
||||
if (from.getContentMetadata().getContentLength() != null)
|
||||
blob.setContentLength(from.getContentMetadata().getContentLength());
|
||||
blob.getMetadata().setContentMD5(from.getSystemMetadata().getContentMD5());
|
||||
blob.setPayload(checkNotNull(from.getPayload(), "payload: " + from));
|
||||
if (from.getContentMetadata().getContentLength() != null)
|
||||
blob.getMetadata().setSize(from.getContentMetadata().getContentLength());
|
||||
blob.getMetadata().setContentMD5(from.getSystemMetadata().getContentMD5());
|
||||
blob.setAllHeaders(from.getAllHeaders());
|
||||
return blob;
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ public class MutableContentMetadata {
|
|||
/**
|
||||
* @see #getContentLength
|
||||
*/
|
||||
public void setContentLength(long contentLength) {
|
||||
public void setContentLength(Long contentLength) {
|
||||
this.contentLength = contentLength;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,12 +20,17 @@ package org.jclouds.atmosonline.saas.domain.internal;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.jclouds.atmosonline.saas.domain.AtmosObject;
|
||||
import org.jclouds.atmosonline.saas.domain.MutableContentMetadata;
|
||||
import org.jclouds.atmosonline.saas.domain.SystemMetadata;
|
||||
import org.jclouds.atmosonline.saas.domain.UserMetadata;
|
||||
import org.jclouds.encryption.EncryptionService;
|
||||
import org.jclouds.http.internal.BasePayloadEnclosingImpl;
|
||||
import org.jclouds.http.Payload;
|
||||
import org.jclouds.http.PayloadEnclosing;
|
||||
import org.jclouds.http.internal.PayloadEnclosingImpl;
|
||||
import org.jclouds.http.payloads.DelegatingPayload;
|
||||
|
||||
import com.google.common.collect.LinkedHashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
@ -35,83 +40,11 @@ import com.google.common.collect.Multimap;
|
|||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class AtmosObjectImpl extends BasePayloadEnclosingImpl implements AtmosObject,
|
||||
public class AtmosObjectImpl extends PayloadEnclosingImpl implements AtmosObject,
|
||||
Comparable<AtmosObject> {
|
||||
private final UserMetadata userMetadata;
|
||||
private final MutableContentMetadata contentMetadata;
|
||||
private final SystemMetadata systemMetadata;
|
||||
|
||||
private Multimap<String, String> allHeaders = LinkedHashMultimap.create();
|
||||
|
||||
public AtmosObjectImpl(EncryptionService encryptionService,
|
||||
MutableContentMetadata contentMetadata) {
|
||||
this(encryptionService, contentMetadata, null, new UserMetadata());
|
||||
}
|
||||
|
||||
public AtmosObjectImpl(EncryptionService encryptionService,
|
||||
MutableContentMetadata contentMetadata, SystemMetadata systemMetadata,
|
||||
UserMetadata userMetadata) {
|
||||
super(encryptionService);
|
||||
this.contentMetadata = contentMetadata;
|
||||
this.systemMetadata = systemMetadata;
|
||||
this.userMetadata = userMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public MutableContentMetadata getContentMetadata() {
|
||||
return contentMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Multimap<String, String> getAllHeaders() {
|
||||
return allHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void setAllHeaders(Multimap<String, String> allHeaders) {
|
||||
this.allHeaders = checkNotNull(allHeaders, "allHeaders");
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return systemMetadata != null ? systemMetadata.hashCode() : super.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return systemMetadata != null ? systemMetadata.equals(obj) : super.equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[metadata=" + systemMetadata + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public int compareTo(AtmosObject o) {
|
||||
String name = getContentMetadata().getName() != null ? getContentMetadata().getName()
|
||||
: getSystemMetadata().getObjectName();
|
||||
if (name == null)
|
||||
return -1;
|
||||
String otherName = o.getContentMetadata().getName() != null ? o.getContentMetadata()
|
||||
.getName() : o.getSystemMetadata().getObjectName();
|
||||
return (this == o) ? 0 : name.compareTo(otherName);
|
||||
}
|
||||
|
||||
public SystemMetadata getSystemMetadata() {
|
||||
return systemMetadata;
|
||||
}
|
||||
|
@ -120,19 +53,186 @@ public class AtmosObjectImpl extends BasePayloadEnclosingImpl implements AtmosOb
|
|||
return userMetadata;
|
||||
}
|
||||
|
||||
private final MutableContentMetadata _contentMetadata;
|
||||
private final SetPayloadPropertiesMutableContentMetadata contentMetadata;
|
||||
private Multimap<String, String> allHeaders = LinkedHashMultimap.create();
|
||||
|
||||
public AtmosObjectImpl(EncryptionService encryptionService,
|
||||
MutableContentMetadata contentMetadata, SystemMetadata systemMetadata,
|
||||
UserMetadata userMetadata) {
|
||||
super(encryptionService);
|
||||
this.contentMetadata = linkMetadataToThis(contentMetadata);
|
||||
this._contentMetadata = this.contentMetadata.getDelegate();
|
||||
this.systemMetadata = systemMetadata;
|
||||
this.userMetadata = userMetadata;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public AtmosObjectImpl(EncryptionService encryptionService,
|
||||
MutableContentMetadata contentMetadata) {
|
||||
this(encryptionService, contentMetadata, null, new UserMetadata());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Long getContentLength() {
|
||||
return getContentMetadata().getContentLength();
|
||||
public MutableContentMetadata getContentMetadata() {
|
||||
return contentMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Multimap<String, String> getAllHeaders() {
|
||||
return allHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void setAllHeaders(Multimap<String, String> allHeaders) {
|
||||
this.allHeaders = checkNotNull(allHeaders, "allHeaders");
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(AtmosObject o) {
|
||||
if (getContentMetadata().getName() == null)
|
||||
return -1;
|
||||
return (this == o) ? 0 : getContentMetadata().getName().compareTo(
|
||||
o.getContentMetadata().getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentLength(long contentLength) {
|
||||
getContentMetadata().setContentLength(contentLength);
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + ((_contentMetadata == null) ? 0 : _contentMetadata.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setContentMD5(byte[] md5) {
|
||||
getContentMetadata().setContentMD5(md5);
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (!super.equals(obj))
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
AtmosObjectImpl other = (AtmosObjectImpl) obj;
|
||||
if (_contentMetadata == null) {
|
||||
if (other._contentMetadata != null)
|
||||
return false;
|
||||
} else if (!_contentMetadata.equals(other._contentMetadata))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[contentMetadata=" + _contentMetadata + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPayload(Payload data) {
|
||||
linkPayloadToMetadata(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* link the new payload to the contentMetadata object so that when content-related
|
||||
* contentMetadata is updated on the payload, it is also copied the contentMetadata object.
|
||||
*/
|
||||
void linkPayloadToMetadata(Payload data) {
|
||||
if (data instanceof DelegatingPayload)
|
||||
super.setPayload(new SetMetadataPropertiesPayload(DelegatingPayload.class.cast(data)
|
||||
.getDelegate(), _contentMetadata));
|
||||
else
|
||||
super.setPayload(new SetMetadataPropertiesPayload(data, _contentMetadata));
|
||||
}
|
||||
|
||||
static class SetMetadataPropertiesPayload extends DelegatingPayload {
|
||||
|
||||
private transient final MutableContentMetadata contentMetadata;
|
||||
|
||||
public SetMetadataPropertiesPayload(Payload delegate, MutableContentMetadata contentMetadata) {
|
||||
super(delegate);
|
||||
this.contentMetadata = contentMetadata;
|
||||
if (contentMetadata.getContentLength() != null)
|
||||
setContentLength(contentMetadata.getContentLength());
|
||||
setContentMD5(contentMetadata.getContentMD5());
|
||||
setContentType(contentMetadata.getContentType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentLength(Long contentLength) {
|
||||
super.setContentLength(contentLength);
|
||||
contentMetadata.setContentLength(contentLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentMD5(byte[] md5) {
|
||||
super.setContentMD5(md5);
|
||||
contentMetadata.setContentMD5(md5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentType(String md5) {
|
||||
super.setContentType(md5);
|
||||
contentMetadata.setContentType(md5);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* link the contentMetadata object to this so that when content-related contentMetadata is
|
||||
* updated, it is also copied the currentpayload object.
|
||||
*/
|
||||
SetPayloadPropertiesMutableContentMetadata linkMetadataToThis(
|
||||
MutableContentMetadata contentMetadata) {
|
||||
return contentMetadata instanceof DelegatingMutableContentMetadata ? new SetPayloadPropertiesMutableContentMetadata(
|
||||
DelegatingMutableContentMetadata.class.cast(contentMetadata).getDelegate(), this)
|
||||
: new SetPayloadPropertiesMutableContentMetadata(contentMetadata, this);
|
||||
}
|
||||
|
||||
static class SetPayloadPropertiesMutableContentMetadata extends DelegatingMutableContentMetadata {
|
||||
/** The serialVersionUID */
|
||||
private static final long serialVersionUID = -5072270546219814521L;
|
||||
private transient final PayloadEnclosing object;
|
||||
|
||||
public SetPayloadPropertiesMutableContentMetadata(MutableContentMetadata delegate,
|
||||
PayloadEnclosing object) {
|
||||
super(delegate);
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentMD5(byte[] md5) {
|
||||
super.setContentMD5(md5);
|
||||
if (canSetPayload())
|
||||
object.getPayload().setContentMD5(md5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentType(String type) {
|
||||
super.setContentType(type);
|
||||
if (canSetPayload())
|
||||
object.getPayload().setContentType(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentLength(Long size) {
|
||||
super.setContentLength(size);
|
||||
if (canSetPayload())
|
||||
object.getPayload().setContentLength(size);
|
||||
}
|
||||
|
||||
private boolean canSetPayload() {
|
||||
return object != null && object.getPayload() != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
package org.jclouds.atmosonline.saas.domain.internal;
|
||||
|
||||
import org.jclouds.atmosonline.saas.domain.MutableContentMetadata;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class DelegatingMutableContentMetadata extends MutableContentMetadata {
|
||||
private final MutableContentMetadata delegate;
|
||||
|
||||
public DelegatingMutableContentMetadata(MutableContentMetadata delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getContentLength() {
|
||||
return delegate.getContentLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getContentMD5() {
|
||||
return delegate.getContentMD5();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentType() {
|
||||
return delegate.getContentType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return delegate.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentLength(Long contentLength) {
|
||||
delegate.setContentLength(contentLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentMD5(byte[] contentMD5) {
|
||||
delegate.setContentMD5(contentMD5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentType(String contentType) {
|
||||
delegate.setContentType(contentType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
delegate.setName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return delegate.equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return delegate.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return delegate.toString();
|
||||
}
|
||||
|
||||
public MutableContentMetadata getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
}
|
|
@ -62,20 +62,19 @@ public class ParseObjectFromHeadersAndHttpContent implements Function<HttpRespon
|
|||
AtmosObject object = objectProvider.create(systemMetadataParser.apply(from),
|
||||
userMetadataParser.apply(from));
|
||||
addAllHeadersTo(from, object);
|
||||
if (from.getContent() != null) {
|
||||
object.setPayload(from.getContent());
|
||||
} else if (new Long(0).equals(object.getContentMetadata().getContentLength())) {
|
||||
object.setPayload(new byte[0]);
|
||||
} else {
|
||||
assert false : "no content in " + from;
|
||||
}
|
||||
|
||||
String contentLength = from.getFirstHeaderOrNull(HttpHeaders.CONTENT_LENGTH);
|
||||
if (contentLength != null) {
|
||||
object.getContentMetadata().setContentLength(Long.parseLong(contentLength));
|
||||
}
|
||||
|
||||
if (from.getContent() != null) {
|
||||
object.setPayload(from.getContent());
|
||||
} else if (object.getContentLength() != null && object.getContentLength() == 0) {
|
||||
object.setPayload(new byte[0]);
|
||||
} else {
|
||||
assert false : "no content in " + from;
|
||||
}
|
||||
|
||||
String contentType = from.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE);
|
||||
if (contentType != null) {
|
||||
object.getContentMetadata().setContentType(contentType);
|
||||
|
|
|
@ -116,10 +116,13 @@ public class AtmosStorageClientLiveTest {
|
|||
@BeforeGroups(groups = { "live" })
|
||||
public void setupClient() throws InterruptedException, ExecutionException, TimeoutException,
|
||||
IOException {
|
||||
String identity = checkNotNull(System.getProperty("jclouds.test.identity"), "jclouds.test.identity");
|
||||
String credential = checkNotNull(System.getProperty("jclouds.test.credential"), "jclouds.test.credential");
|
||||
String identity = checkNotNull(System.getProperty("jclouds.test.identity"),
|
||||
"jclouds.test.identity");
|
||||
String credential = checkNotNull(System.getProperty("jclouds.test.credential"),
|
||||
"jclouds.test.credential");
|
||||
BlobStoreContext blobStoreContext = new BlobStoreContextFactory().createContext(
|
||||
"atmosonline", identity, credential, ImmutableSet.<Module> of(new Log4JLoggingModule()));
|
||||
"atmosonline", identity, credential, ImmutableSet
|
||||
.<Module> of(new Log4JLoggingModule()));
|
||||
RestContext<AtmosStorageClient, AtmosStorageAsyncClient> context = blobStoreContext
|
||||
.getProviderSpecificContext();
|
||||
connection = context.getApi();
|
||||
|
@ -222,7 +225,7 @@ public class AtmosStorageClientLiveTest {
|
|||
AtmosObject object = connection.newObject();
|
||||
object.getContentMetadata().setName(name);
|
||||
object.setPayload(Payloads.newPayload(data));
|
||||
object.getContentMetadata().setContentLength(16);
|
||||
object.getContentMetadata().setContentLength(16l);
|
||||
object.generateMD5();
|
||||
object.getContentMetadata().setContentType("text/plain");
|
||||
object.getUserMetadata().getMetadata().put("Metadata", metadataValue);
|
||||
|
@ -269,7 +272,7 @@ public class AtmosStorageClientLiveTest {
|
|||
String metadataValue) throws InterruptedException, ExecutionException,
|
||||
TimeoutException, IOException {
|
||||
AtmosObject getBlob = connection.headFile(path);
|
||||
assertEquals(Utils.toStringAndClose(getBlob.getContent()), "");
|
||||
assertEquals(Utils.toStringAndClose(getBlob.getPayload().getInput()), "");
|
||||
verifyMetadata(metadataValue, getBlob);
|
||||
}
|
||||
|
||||
|
@ -277,7 +280,7 @@ public class AtmosStorageClientLiveTest {
|
|||
String metadataValue) throws InterruptedException, ExecutionException,
|
||||
TimeoutException, IOException {
|
||||
AtmosObject getBlob = connection.readFile(path);
|
||||
assertEquals(Utils.toStringAndClose(getBlob.getContent()), compare);
|
||||
assertEquals(Utils.toStringAndClose(getBlob.getPayload().getInput()), compare);
|
||||
verifyMetadata(metadataValue, getBlob);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@ import javax.inject.Named;
|
|||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.Constants;
|
||||
import org.jclouds.aws.config.AWSRestClientModule;
|
||||
import org.jclouds.aws.filters.FormSigner;
|
||||
import org.jclouds.date.DateService;
|
||||
import org.jclouds.date.TimeStamp;
|
||||
|
|
|
@ -56,6 +56,7 @@ import org.jclouds.util.Utils;
|
|||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
/**
|
||||
|
@ -132,6 +133,8 @@ public class FormSigner implements HttpRequestFilter, RequestSigner {
|
|||
return o1.getKey().compareTo(o2.getKey());
|
||||
}
|
||||
}));
|
||||
request.getHeaders().replaceValues(HttpHeaders.CONTENT_LENGTH,
|
||||
ImmutableSet.of(request.getPayload().getContentLength().toString()));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
|
@ -151,8 +154,8 @@ public class FormSigner implements HttpRequestFilter, RequestSigner {
|
|||
public String sign(String stringToSign) {
|
||||
String signature;
|
||||
try {
|
||||
signature = encryptionService.base64(encryptionService.hmacSha256(stringToSign,
|
||||
secretKey.getBytes()));
|
||||
signature = encryptionService.base64(encryptionService.hmacSha256(stringToSign, secretKey
|
||||
.getBytes()));
|
||||
if (signatureWire.enabled())
|
||||
signatureWire.input(Utils.toInputStream(signature));
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -22,11 +22,12 @@ import static com.google.common.base.Preconditions.checkArgument;
|
|||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
|
||||
import org.jclouds.aws.s3.blobstore.functions.ObjectToBlob;
|
||||
import org.jclouds.aws.s3.domain.S3Object;
|
||||
import org.jclouds.blobstore.binders.BindBlobToPayloadAndUserMetadataToHeadersWithPrefix;
|
||||
import org.jclouds.blobstore.binders.BindUserMetadataToHeadersWithPrefix;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.rest.Binder;
|
||||
|
||||
|
@ -34,21 +35,22 @@ import org.jclouds.rest.Binder;
|
|||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class BindS3ObjectToPayload implements Binder {
|
||||
private final BindBlobToPayloadAndUserMetadataToHeadersWithPrefix blobBinder;
|
||||
private final BindUserMetadataToHeadersWithPrefix blobBinder;
|
||||
private final ObjectToBlob object2Blob;
|
||||
|
||||
@Inject
|
||||
public BindS3ObjectToPayload(ObjectToBlob object2Blob,
|
||||
BindBlobToPayloadAndUserMetadataToHeadersWithPrefix blobBinder) {
|
||||
BindUserMetadataToHeadersWithPrefix blobBinder) {
|
||||
this.blobBinder = blobBinder;
|
||||
this.object2Blob = object2Blob;
|
||||
}
|
||||
|
||||
public void bindToRequest(HttpRequest request, Object payload) {
|
||||
S3Object s3Object = (S3Object) payload;
|
||||
checkNotNull(s3Object.getContentLength(), "contentLength");
|
||||
checkArgument(s3Object.getContentLength() <= 5l * 1024 * 1024 * 1024,
|
||||
checkNotNull(s3Object.getPayload().getContentLength(), "contentLength");
|
||||
checkArgument(s3Object.getPayload().getContentLength() <= 5l * 1024 * 1024 * 1024,
|
||||
"maximum size for put object is 5GB");
|
||||
blobBinder.bindToRequest(request, object2Blob.apply(s3Object));
|
||||
|
||||
|
|
|
@ -46,8 +46,6 @@ public class BlobToObject implements Function<Blob, S3Object> {
|
|||
if (from == null)
|
||||
return null;
|
||||
S3Object object = objectProvider.create(blob2ObjectMd.apply(from.getMetadata()));
|
||||
if (from.getContentLength() != null)
|
||||
object.setContentLength(from.getContentLength());
|
||||
object.setPayload(checkNotNull(from.getPayload(), "payload: " + from));
|
||||
object.setAllHeaders(from.getAllHeaders());
|
||||
return object;
|
||||
|
|
|
@ -47,8 +47,6 @@ public class ObjectToBlob implements Function<S3Object, Blob> {
|
|||
if (from == null)
|
||||
return null;
|
||||
Blob blob = blobFactory.create(object2BlobMd.apply(from.getMetadata()));
|
||||
if (from.getContentLength() != null)
|
||||
blob.setContentLength(from.getContentLength());
|
||||
blob.setPayload(checkNotNull(from.getPayload(), "payload: " + from));
|
||||
blob.setAllHeaders(from.getAllHeaders());
|
||||
return blob;
|
||||
|
|
|
@ -106,7 +106,7 @@ public interface MutableObjectMetadata extends ObjectMetadata {
|
|||
|
||||
void setETag(String eTag);
|
||||
|
||||
void setSize(long size);
|
||||
void setSize(Long size);
|
||||
|
||||
void setUserMetadata(Map<String, String> userMetadata);
|
||||
|
||||
|
|
|
@ -0,0 +1,183 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed 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.aws.s3.domain.internal;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jclouds.aws.s3.domain.CanonicalUser;
|
||||
import org.jclouds.aws.s3.domain.MutableObjectMetadata;
|
||||
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class DelegatingMutableObjectMetadata implements MutableObjectMetadata {
|
||||
private final MutableObjectMetadata delegate;
|
||||
|
||||
public DelegatingMutableObjectMetadata(MutableObjectMetadata delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ObjectMetadata o) {
|
||||
return delegate.compareTo(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return delegate.equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCacheControl() {
|
||||
return delegate.getCacheControl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentDisposition() {
|
||||
return delegate.getContentDisposition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentEncoding() {
|
||||
return delegate.getContentEncoding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getContentMD5() {
|
||||
return delegate.getContentMD5();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentType() {
|
||||
return delegate.getContentType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getETag() {
|
||||
return delegate.getETag();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return delegate.getKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getLastModified() {
|
||||
return delegate.getLastModified();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CanonicalUser getOwner() {
|
||||
return delegate.getOwner();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getSize() {
|
||||
return delegate.getSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageClass getStorageClass() {
|
||||
return delegate.getStorageClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getUserMetadata() {
|
||||
return delegate.getUserMetadata();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return delegate.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCacheControl(String cacheControl) {
|
||||
delegate.setCacheControl(cacheControl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentDisposition(String contentDisposition) {
|
||||
delegate.setContentDisposition(contentDisposition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentEncoding(String encoding) {
|
||||
delegate.setContentEncoding(encoding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentMD5(byte[] md5) {
|
||||
delegate.setContentMD5(md5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentType(String contentType) {
|
||||
delegate.setContentType(contentType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setETag(String eTag) {
|
||||
delegate.setETag(eTag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setKey(String key) {
|
||||
delegate.setKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastModified(Date lastModified) {
|
||||
delegate.setLastModified(lastModified);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOwner(CanonicalUser owner) {
|
||||
delegate.setOwner(owner);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSize(Long size) {
|
||||
delegate.setSize(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStorageClass(StorageClass storageClass) {
|
||||
delegate.setStorageClass(storageClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserMetadata(Map<String, String> userMetadata) {
|
||||
delegate.setUserMetadata(userMetadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return delegate.toString();
|
||||
}
|
||||
|
||||
public MutableObjectMetadata getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
}
|
|
@ -42,7 +42,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
|
|||
private String key;
|
||||
private Date lastModified;
|
||||
private String eTag;
|
||||
private long size;
|
||||
private Long size;
|
||||
private CanonicalUser owner;
|
||||
private StorageClass storageClass;
|
||||
private String contentType;
|
||||
|
@ -223,7 +223,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
|
|||
/**
|
||||
*{@inheritDoc}
|
||||
*/
|
||||
public void setSize(long size) {
|
||||
public void setSize(Long size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
|
@ -254,7 +254,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
|
|||
result = prime * result + ((key == null) ? 0 : key.hashCode());
|
||||
result = prime * result + ((lastModified == null) ? 0 : lastModified.hashCode());
|
||||
result = prime * result + ((owner == null) ? 0 : owner.hashCode());
|
||||
result = prime * result + (int) (size ^ (size >>> 32));
|
||||
result = prime * result + ((size == null) ? 0 : size.hashCode());
|
||||
result = prime * result + ((storageClass == null) ? 0 : storageClass.hashCode());
|
||||
result = prime * result + ((userMetadata == null) ? 0 : userMetadata.hashCode());
|
||||
return result;
|
||||
|
@ -311,7 +311,10 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
|
|||
return false;
|
||||
} else if (!owner.equals(other.owner))
|
||||
return false;
|
||||
if (size != other.size)
|
||||
if (size == null) {
|
||||
if (other.size != null)
|
||||
return false;
|
||||
} else if (!size.equals(other.size))
|
||||
return false;
|
||||
if (storageClass == null) {
|
||||
if (other.storageClass != null)
|
||||
|
|
|
@ -26,7 +26,10 @@ import org.jclouds.aws.s3.domain.AccessControlList;
|
|||
import org.jclouds.aws.s3.domain.MutableObjectMetadata;
|
||||
import org.jclouds.aws.s3.domain.S3Object;
|
||||
import org.jclouds.encryption.EncryptionService;
|
||||
import org.jclouds.http.internal.BasePayloadEnclosingImpl;
|
||||
import org.jclouds.http.Payload;
|
||||
import org.jclouds.http.PayloadEnclosing;
|
||||
import org.jclouds.http.internal.PayloadEnclosingImpl;
|
||||
import org.jclouds.http.payloads.DelegatingPayload;
|
||||
|
||||
import com.google.common.collect.LinkedHashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
@ -36,26 +39,14 @@ import com.google.common.collect.Multimap;
|
|||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class S3ObjectImpl extends BasePayloadEnclosingImpl implements S3Object,
|
||||
Comparable<S3Object> {
|
||||
private final MutableObjectMetadata metadata;
|
||||
private Multimap<String, String> allHeaders = LinkedHashMultimap.create();
|
||||
public class S3ObjectImpl extends PayloadEnclosingImpl implements S3Object, Comparable<S3Object> {
|
||||
|
||||
private AccessControlList accessControlList;
|
||||
|
||||
@Inject
|
||||
public S3ObjectImpl(EncryptionService encryptionService, MutableObjectMetadata metadata) {
|
||||
super(encryptionService);
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setContentMD5(byte[] md5) {
|
||||
getMetadata().setContentMD5(md5);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void setAccessControlList(AccessControlList acl) {
|
||||
this.accessControlList = acl;
|
||||
}
|
||||
|
@ -63,13 +54,26 @@ public class S3ObjectImpl extends BasePayloadEnclosingImpl implements S3Object,
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public AccessControlList getAccessControlList() {
|
||||
return this.accessControlList;
|
||||
}
|
||||
|
||||
private final MutableObjectMetadata _metadata;
|
||||
private final SetPayloadPropertiesMutableObjectMetadata metadata;
|
||||
private Multimap<String, String> allHeaders = LinkedHashMultimap.create();
|
||||
|
||||
@Inject
|
||||
public S3ObjectImpl(EncryptionService encryptionService, MutableObjectMetadata metadata) {
|
||||
super(encryptionService);
|
||||
this.metadata = linkMetadataToThis(metadata);
|
||||
this._metadata = this.metadata.getDelegate();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public MutableObjectMetadata getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
@ -77,6 +81,7 @@ public class S3ObjectImpl extends BasePayloadEnclosingImpl implements S3Object,
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Multimap<String, String> getAllHeaders() {
|
||||
return allHeaders;
|
||||
}
|
||||
|
@ -84,6 +89,7 @@ public class S3ObjectImpl extends BasePayloadEnclosingImpl implements S3Object,
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void setAllHeaders(Multimap<String, String> allHeaders) {
|
||||
this.allHeaders = checkNotNull(allHeaders, "allHeaders");
|
||||
}
|
||||
|
@ -91,6 +97,7 @@ public class S3ObjectImpl extends BasePayloadEnclosingImpl implements S3Object,
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(S3Object o) {
|
||||
if (getMetadata().getKey() == null)
|
||||
return -1;
|
||||
|
@ -100,12 +107,8 @@ public class S3ObjectImpl extends BasePayloadEnclosingImpl implements S3Object,
|
|||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((accessControlList == null) ? 0 : accessControlList.hashCode());
|
||||
result = prime * result + ((allHeaders == null) ? 0 : allHeaders.hashCode());
|
||||
result = prime * result + ((contentLength == null) ? 0 : contentLength.hashCode());
|
||||
result = prime * result + ((payload == null) ? 0 : payload.hashCode());
|
||||
result = prime * result + ((metadata == null) ? 0 : metadata.hashCode());
|
||||
int result = super.hashCode();
|
||||
result = prime * result + ((_metadata == null) ? 0 : _metadata.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -113,37 +116,123 @@ public class S3ObjectImpl extends BasePayloadEnclosingImpl implements S3Object,
|
|||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
if (!super.equals(obj))
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
S3ObjectImpl other = (S3ObjectImpl) obj;
|
||||
if (accessControlList == null) {
|
||||
if (other.accessControlList != null)
|
||||
if (_metadata == null) {
|
||||
if (other._metadata != null)
|
||||
return false;
|
||||
} else if (!accessControlList.equals(other.accessControlList))
|
||||
return false;
|
||||
if (allHeaders == null) {
|
||||
if (other.allHeaders != null)
|
||||
return false;
|
||||
} else if (!allHeaders.equals(other.allHeaders))
|
||||
return false;
|
||||
if (contentLength == null) {
|
||||
if (other.contentLength != null)
|
||||
return false;
|
||||
} else if (!contentLength.equals(other.contentLength))
|
||||
return false;
|
||||
if (payload == null) {
|
||||
if (other.payload != null)
|
||||
return false;
|
||||
} else if (!payload.equals(other.payload))
|
||||
return false;
|
||||
if (metadata == null) {
|
||||
if (other.metadata != null)
|
||||
return false;
|
||||
} else if (!metadata.equals(other.metadata))
|
||||
} else if (!_metadata.equals(other._metadata))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[metadata=" + _metadata + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPayload(Payload data) {
|
||||
linkPayloadToMetadata(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* metadata 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));
|
||||
else
|
||||
super.setPayload(new SetMetadataPropertiesPayload(data, _metadata));
|
||||
}
|
||||
|
||||
static class SetMetadataPropertiesPayload extends DelegatingPayload {
|
||||
|
||||
private transient final MutableObjectMetadata metadata;
|
||||
|
||||
public SetMetadataPropertiesPayload(Payload delegate, MutableObjectMetadata metadata) {
|
||||
super(delegate);
|
||||
this.metadata = checkNotNull(metadata, "metadata");
|
||||
if (metadata.getSize() != null)
|
||||
setContentLength(metadata.getSize());
|
||||
setContentMD5(metadata.getContentMD5());
|
||||
setContentType(metadata.getContentType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentLength(Long contentLength) {
|
||||
super.setContentLength(contentLength);
|
||||
try {
|
||||
metadata.setSize(contentLength);
|
||||
} catch (NullPointerException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentMD5(byte[] md5) {
|
||||
super.setContentMD5(md5);
|
||||
metadata.setContentMD5(md5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentType(String md5) {
|
||||
super.setContentType(md5);
|
||||
metadata.setContentType(md5);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* link the metadata object to this so that when content-related metadata is updated, it is also
|
||||
* copied the currentpayload object.
|
||||
*/
|
||||
SetPayloadPropertiesMutableObjectMetadata linkMetadataToThis(MutableObjectMetadata metadata) {
|
||||
return metadata instanceof DelegatingMutableObjectMetadata ? new SetPayloadPropertiesMutableObjectMetadata(
|
||||
DelegatingMutableObjectMetadata.class.cast(metadata).getDelegate(), this)
|
||||
: new SetPayloadPropertiesMutableObjectMetadata(metadata, this);
|
||||
}
|
||||
|
||||
static class SetPayloadPropertiesMutableObjectMetadata extends DelegatingMutableObjectMetadata {
|
||||
/** The serialVersionUID */
|
||||
private static final long serialVersionUID = -5072270546219814521L;
|
||||
private transient final PayloadEnclosing object;
|
||||
|
||||
public SetPayloadPropertiesMutableObjectMetadata(MutableObjectMetadata delegate,
|
||||
PayloadEnclosing object) {
|
||||
super(delegate);
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentMD5(byte[] md5) {
|
||||
super.setContentMD5(md5);
|
||||
if (canSetPayload())
|
||||
object.getPayload().setContentMD5(md5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentType(String type) {
|
||||
super.setContentType(type);
|
||||
if (canSetPayload())
|
||||
object.getPayload().setContentType(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSize(Long size) {
|
||||
super.setSize(size);
|
||||
if (canSetPayload())
|
||||
object.getPayload().setContentLength(size);
|
||||
}
|
||||
|
||||
private boolean canSetPayload() {
|
||||
return object != null && object.getPayload() != null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -59,24 +59,23 @@ public class ParseObjectFromHeadersAndHttpContent implements Function<HttpRespon
|
|||
public S3Object apply(HttpResponse from) {
|
||||
S3Object object = objectProvider.create(metadataParser.apply(from));
|
||||
object.getAllHeaders().putAll(from.getHeaders());
|
||||
|
||||
String contentLength = from.getFirstHeaderOrNull(HttpHeaders.CONTENT_LENGTH);
|
||||
String contentRange = from.getFirstHeaderOrNull("Content-Range");
|
||||
|
||||
if (contentLength != null) {
|
||||
object.setContentLength(Long.parseLong(contentLength));
|
||||
}
|
||||
|
||||
if (from.getContent() != null) {
|
||||
object.setPayload(from.getContent());
|
||||
} else if (object.getContentLength() != null && object.getContentLength() == 0) {
|
||||
} else if (new Long(0).equals(object.getMetadata().getSize())) {
|
||||
object.setPayload(new byte[0]);
|
||||
} else {
|
||||
assert false : "no content in " + from;
|
||||
}
|
||||
|
||||
String contentLength = from.getFirstHeaderOrNull(HttpHeaders.CONTENT_LENGTH);
|
||||
String contentRange = from.getFirstHeaderOrNull("Content-Range");
|
||||
|
||||
if (contentLength != null) {
|
||||
object.getPayload().setContentLength(Long.parseLong(contentLength));
|
||||
}
|
||||
|
||||
if (contentRange == null && contentLength != null) {
|
||||
object.getMetadata().setSize(object.getContentLength());
|
||||
object.getMetadata().setSize(object.getPayload().getContentLength());
|
||||
} else if (contentRange != null) {
|
||||
object.getMetadata().setSize(
|
||||
Long.parseLong(contentRange.substring(contentRange.lastIndexOf('/') + 1)));
|
||||
|
|
|
@ -313,7 +313,7 @@ public class AMIAsyncClientTest extends BaseEC2AsyncClientTest<AMIAsyncClient> {
|
|||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
||||
assertHeadersEqual(
|
||||
request,
|
||||
"Content-Length: 107\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
"Content-Length: 149\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
assertPayloadEquals(
|
||||
request,
|
||||
"Version=2009-11-30&Action=ModifyImageAttribute&OperationType=add&Attribute=launchPermission&ImageId=imageId&UserGroup.1=all&UserId.1=bob&UserId.2=sue");
|
||||
|
@ -339,7 +339,7 @@ public class AMIAsyncClientTest extends BaseEC2AsyncClientTest<AMIAsyncClient> {
|
|||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
||||
assertHeadersEqual(
|
||||
request,
|
||||
"Content-Length: 110\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
"Content-Length: 152\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
assertPayloadEquals(
|
||||
request,
|
||||
"Version=2009-11-30&Action=ModifyImageAttribute&OperationType=remove&Attribute=launchPermission&ImageId=imageId&UserGroup.1=all&UserId.1=bob&UserId.2=sue");
|
||||
|
@ -379,7 +379,7 @@ public class AMIAsyncClientTest extends BaseEC2AsyncClientTest<AMIAsyncClient> {
|
|||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
||||
assertHeadersEqual(
|
||||
request,
|
||||
"Content-Length: 103\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
"Content-Length: 143\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
assertPayloadEquals(
|
||||
request,
|
||||
"Version=2009-11-30&Action=ModifyImageAttribute&OperationType=add&Attribute=productCodes&ImageId=imageId&ProductCode.1=code1&ProductCode.2=code2");
|
||||
|
@ -401,7 +401,7 @@ public class AMIAsyncClientTest extends BaseEC2AsyncClientTest<AMIAsyncClient> {
|
|||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
||||
assertHeadersEqual(
|
||||
request,
|
||||
"Content-Length: 106\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
"Content-Length: 146\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
assertPayloadEquals(
|
||||
request,
|
||||
"Version=2009-11-30&Action=ModifyImageAttribute&OperationType=remove&Attribute=productCodes&ImageId=imageId&ProductCode.1=code1&ProductCode.2=code2");
|
||||
|
|
|
@ -160,7 +160,7 @@ public class ElasticBlockStoreAsyncClientTest extends
|
|||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
||||
assertHeadersEqual(
|
||||
request,
|
||||
"Content-Length: 41\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
"Content-Length: 67\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
assertPayloadEquals(request,
|
||||
"Version=2009-11-30&Action=DescribeVolumes&VolumeId.1=1&VolumeId.2=2");
|
||||
|
||||
|
@ -345,7 +345,7 @@ public class ElasticBlockStoreAsyncClientTest extends
|
|||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
||||
assertHeadersEqual(
|
||||
request,
|
||||
"Content-Length: 122\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
"Content-Length: 164\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
assertPayloadEquals(
|
||||
request,
|
||||
"Version=2009-11-30&Action=ModifySnapshotAttribute&OperationType=add&Attribute=createVolumePermission&SnapshotId=snapshotId&UserGroup.1=all&UserId.1=bob&UserId.2=sue");
|
||||
|
@ -368,7 +368,7 @@ public class ElasticBlockStoreAsyncClientTest extends
|
|||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
||||
assertHeadersEqual(
|
||||
request,
|
||||
"Content-Length: 125\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
"Content-Length: 167\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
assertPayloadEquals(
|
||||
request,
|
||||
"Version=2009-11-30&Action=ModifySnapshotAttribute&OperationType=remove&Attribute=createVolumePermission&SnapshotId=snapshotId&UserGroup.1=all&UserId.1=bob&UserId.2=sue");
|
||||
|
|
|
@ -106,7 +106,7 @@ public class ElasticIPAddressAsyncClientTest extends
|
|||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
||||
assertHeadersEqual(
|
||||
request,
|
||||
"Content-Length: 43\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
"Content-Length: 64\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
assertPayloadEquals(request,
|
||||
"Version=2009-11-30&Action=DescribeAddresses&PublicIp.1=127.0.0.1");
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ public class InstanceAsyncClientTest extends BaseEC2AsyncClientTest<InstanceAsyn
|
|||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
||||
assertHeadersEqual(
|
||||
request,
|
||||
"Content-Length: 43\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
"Content-Length: 73\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
assertPayloadEquals(request,
|
||||
"Version=2009-11-30&Action=DescribeInstances&InstanceId.1=1&InstanceId.2=2");
|
||||
|
||||
|
@ -100,7 +100,7 @@ public class InstanceAsyncClientTest extends BaseEC2AsyncClientTest<InstanceAsyn
|
|||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
||||
assertHeadersEqual(
|
||||
request,
|
||||
"Content-Length: 44\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
"Content-Length: 74\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
assertPayloadEquals(request,
|
||||
"Version=2009-11-30&Action=TerminateInstances&InstanceId.1=1&InstanceId.2=2");
|
||||
|
||||
|
@ -144,7 +144,7 @@ public class InstanceAsyncClientTest extends BaseEC2AsyncClientTest<InstanceAsyn
|
|||
assertRequestLineEquals(request, "POST https://ec2.eu-west-1.amazonaws.com/ HTTP/1.1");
|
||||
assertHeadersEqual(
|
||||
request,
|
||||
"Content-Length: 164\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.eu-west-1.amazonaws.com\n");
|
||||
"Content-Length: 202\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.eu-west-1.amazonaws.com\n");
|
||||
assertPayloadEquals(
|
||||
request,
|
||||
"Version=2009-11-30&Action=RunInstances&ImageId=ami-voo&MinCount=1&MaxCount=5&KernelId=kernelId&Monitoring.Enabled=true&SecurityGroup.1=group1&SecurityGroup.2=group2&Placement.AvailabilityZone=eu-west-1a");
|
||||
|
@ -164,7 +164,7 @@ public class InstanceAsyncClientTest extends BaseEC2AsyncClientTest<InstanceAsyn
|
|||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
||||
assertHeadersEqual(
|
||||
request,
|
||||
"Content-Length: 50\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
"Content-Length: 80\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
assertPayloadEquals(request,
|
||||
"Version=2009-11-30&Action=StopInstances&Force=true&InstanceId.1=1&InstanceId.2=2");
|
||||
|
||||
|
@ -183,7 +183,7 @@ public class InstanceAsyncClientTest extends BaseEC2AsyncClientTest<InstanceAsyn
|
|||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
||||
assertHeadersEqual(
|
||||
request,
|
||||
"Content-Length: 41\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
"Content-Length: 71\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
assertPayloadEquals(request,
|
||||
"Version=2009-11-30&Action=RebootInstances&InstanceId.1=1&InstanceId.2=2");
|
||||
|
||||
|
@ -202,7 +202,7 @@ public class InstanceAsyncClientTest extends BaseEC2AsyncClientTest<InstanceAsyn
|
|||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
||||
assertHeadersEqual(
|
||||
request,
|
||||
"Content-Length: 40\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
"Content-Length: 70\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
assertPayloadEquals(request,
|
||||
"Version=2009-11-30&Action=StartInstances&InstanceId.1=1&InstanceId.2=2");
|
||||
|
||||
|
@ -392,7 +392,6 @@ public class InstanceAsyncClientTest extends BaseEC2AsyncClientTest<InstanceAsyn
|
|||
assertPayloadEquals(
|
||||
request,
|
||||
"Action=ModifyInstanceAttribute&Attribute=userData&InstanceId=1&Signature=ch%2BpeYTRad241GAhjH9Wo2vKWlkgfNa3txM0lhPCBSM%3D&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2009-11-08T15%3A54%3A08.897Z&Value=dGVzdA%3D%3D&Version=2009-11-30&AWSAccessKeyId=identity");
|
||||
|
||||
assertResponseParserClassEquals(method, request, CloseContentAndReturn.class);
|
||||
assertSaxResponseParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, null);
|
||||
|
@ -518,7 +517,7 @@ public class InstanceAsyncClientTest extends BaseEC2AsyncClientTest<InstanceAsyn
|
|||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
||||
assertHeadersEqual(
|
||||
request,
|
||||
"Content-Length: 62\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
"Content-Length: 202\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
assertPayloadEquals(
|
||||
request,
|
||||
"Version=2009-11-30&Action=ModifyInstanceAttribute&InstanceId=1&BlockDeviceMapping.1.Ebs.VolumeId=vol-test1&BlockDeviceMapping.1.DeviceName=%2Fdev%2Fsda1&BlockDeviceMapping.1.Ebs.DeleteOnTermination=true");
|
||||
|
|
|
@ -84,7 +84,7 @@ public class KeyPairAsyncClientTest extends BaseEC2AsyncClientTest<KeyPairAsyncC
|
|||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
||||
assertHeadersEqual(
|
||||
request,
|
||||
"Content-Length: 42\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
"Content-Length: 66\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
assertPayloadEquals(request,
|
||||
"Version=2009-11-30&Action=DescribeKeyPairs&KeyName.1=1&KeyName.2=2");
|
||||
|
||||
|
|
|
@ -45,11 +45,14 @@ public class MonitoringAsyncClientTest extends BaseEC2AsyncClientTest<Monitoring
|
|||
HttpRequest request = processor.createRequest(method, null, "instance1", "instance2");
|
||||
|
||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
||||
String payload = "Version=2009-11-30&Action=UnmonitorInstances&InstanceId.0=instance1&InstanceId.1=instance2";
|
||||
assertHeadersEqual(
|
||||
request,
|
||||
"Content-Length: 67\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
assertPayloadEquals(request,
|
||||
"Version=2009-11-30&Action=UnmonitorInstances&InstanceId.0=instance1&InstanceId.1=instance2");
|
||||
String
|
||||
.format(
|
||||
"Content-Length: %d\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n",
|
||||
payload.getBytes().length));
|
||||
assertPayloadEquals(request, payload);
|
||||
|
||||
assertResponseParserClassEquals(method, request, ParseSax.class);
|
||||
assertSaxResponseParserClassEquals(method, MonitoringStateHandler.class);
|
||||
|
@ -66,7 +69,7 @@ public class MonitoringAsyncClientTest extends BaseEC2AsyncClientTest<Monitoring
|
|||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
||||
assertHeadersEqual(
|
||||
request,
|
||||
"Content-Length: 65\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
"Content-Length: 88\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
assertPayloadEquals(request,
|
||||
"Version=2009-11-30&Action=MonitorInstances&InstanceId.0=instance1&InstanceId.1=instance2");
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@ public class SecurityGroupAsyncClientTest extends BaseEC2AsyncClientTest<Securit
|
|||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
||||
assertHeadersEqual(
|
||||
request,
|
||||
"Content-Length: 48\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
"Content-Length: 76\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
assertPayloadEquals(request,
|
||||
"Version=2009-11-30&Action=DescribeSecurityGroups&GroupName.1=1&GroupName.2=2");
|
||||
|
||||
|
@ -131,7 +131,7 @@ public class SecurityGroupAsyncClientTest extends BaseEC2AsyncClientTest<Securit
|
|||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
||||
assertHeadersEqual(
|
||||
request,
|
||||
"Content-Length: 71\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
"Content-Length: 145\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
assertPayloadEquals(
|
||||
request,
|
||||
"Version=2009-11-30&Action=AuthorizeSecurityGroupIngress&GroupName=group&SourceSecurityGroupOwnerId=sourceUser&SourceSecurityGroupName=sourceGroup");
|
||||
|
@ -177,7 +177,7 @@ public class SecurityGroupAsyncClientTest extends BaseEC2AsyncClientTest<Securit
|
|||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
||||
assertHeadersEqual(
|
||||
request,
|
||||
"Content-Length: 68\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
"Content-Length: 142\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n");
|
||||
assertPayloadEquals(
|
||||
request,
|
||||
"Version=2009-11-30&Action=RevokeSecurityGroupIngress&GroupName=group&SourceSecurityGroupOwnerId=sourceUser&SourceSecurityGroupName=sourceGroup");
|
||||
|
|
|
@ -63,7 +63,7 @@ public class ELBAsyncClientTest extends RestClientTest<ELBAsyncClient> {
|
|||
"POST https://elasticloadbalancing.us-east-1.amazonaws.com/ HTTP/1.1");
|
||||
assertHeadersEqual(
|
||||
request,
|
||||
"Content-Length: 89\nContent-Type: application/x-www-form-urlencoded\nHost: elasticloadbalancing.us-east-1.amazonaws.com\n");
|
||||
"Content-Length: 130\nContent-Type: application/x-www-form-urlencoded\nHost: elasticloadbalancing.us-east-1.amazonaws.com\n");
|
||||
assertPayloadEquals(
|
||||
request,
|
||||
"Version=2009-11-25&Action=RegisterInstancesWithLoadBalancer&LoadBalancerName=ReferenceAP1&Instances.member.1.InstanceId=i-6055fa09");
|
||||
|
|
|
@ -111,8 +111,8 @@ public class S3ClientLiveTest extends BaseBlobStoreIntegrationTest {
|
|||
addBlobToContainer(containerName, sourceKey);
|
||||
validateContent(containerName, sourceKey);
|
||||
|
||||
getApi().copyObject(containerName, sourceKey, destinationContainer,
|
||||
destinationKey, overrideAcl(CannedAccessPolicy.PUBLIC_READ));
|
||||
getApi().copyObject(containerName, sourceKey, destinationContainer, destinationKey,
|
||||
overrideAcl(CannedAccessPolicy.PUBLIC_READ));
|
||||
|
||||
validateContent(destinationContainer, destinationKey);
|
||||
|
||||
|
@ -246,8 +246,7 @@ public class S3ClientLiveTest extends BaseBlobStoreIntegrationTest {
|
|||
assertConsistencyAware(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
AccessControlList acl = getApi().getObjectACL(containerName,
|
||||
publicReadObjectKey);
|
||||
AccessControlList acl = getApi().getObjectACL(containerName, publicReadObjectKey);
|
||||
|
||||
assertEquals(acl.getGrants().size(), 2);
|
||||
assertEquals(acl.getPermissions(GroupGranteeURI.ALL_USERS).size(), 1);
|
||||
|
@ -280,7 +279,7 @@ public class S3ClientLiveTest extends BaseBlobStoreIntegrationTest {
|
|||
assertConsistencyAwareContainerSize(sourceContainer, 1);
|
||||
S3Object newObject = getApi().getObject(sourceContainer, key);
|
||||
assert newObject != null;
|
||||
assertEquals(Utils.toStringAndClose(newObject.getContent()), TEST_STRING);
|
||||
assertEquals(Utils.toStringAndClose(newObject.getPayload().getInput()), TEST_STRING);
|
||||
return newObject;
|
||||
}
|
||||
|
||||
|
@ -332,8 +331,7 @@ public class S3ClientLiveTest extends BaseBlobStoreIntegrationTest {
|
|||
try {
|
||||
addToContainerAndValidate(containerName, sourceKey);
|
||||
|
||||
getApi()
|
||||
.copyObject(containerName, sourceKey, destinationContainer, destinationKey);
|
||||
getApi().copyObject(containerName, sourceKey, destinationContainer, destinationKey);
|
||||
|
||||
validateContent(destinationContainer, destinationKey);
|
||||
} finally {
|
||||
|
@ -387,8 +385,8 @@ public class S3ClientLiveTest extends BaseBlobStoreIntegrationTest {
|
|||
addToContainerAndValidate(containerName, sourceKey + "un");
|
||||
Date after = new Date(System.currentTimeMillis() + 1000);
|
||||
|
||||
getApi().copyObject(containerName, sourceKey + "un", destinationContainer,
|
||||
destinationKey, ifSourceUnmodifiedSince(after));
|
||||
getApi().copyObject(containerName, sourceKey + "un", destinationContainer, destinationKey,
|
||||
ifSourceUnmodifiedSince(after));
|
||||
validateContent(destinationContainer, destinationKey);
|
||||
|
||||
try {
|
||||
|
@ -410,13 +408,13 @@ public class S3ClientLiveTest extends BaseBlobStoreIntegrationTest {
|
|||
try {
|
||||
String goodETag = addToContainerAndValidate(containerName, sourceKey);
|
||||
|
||||
getApi().copyObject(containerName, sourceKey, destinationContainer,
|
||||
destinationKey, ifSourceETagMatches(goodETag));
|
||||
getApi().copyObject(containerName, sourceKey, destinationContainer, destinationKey,
|
||||
ifSourceETagMatches(goodETag));
|
||||
validateContent(destinationContainer, destinationKey);
|
||||
|
||||
try {
|
||||
getApi().copyObject(containerName, sourceKey, destinationContainer,
|
||||
destinationKey, ifSourceETagMatches("setsds"));
|
||||
getApi().copyObject(containerName, sourceKey, destinationContainer, destinationKey,
|
||||
ifSourceETagMatches("setsds"));
|
||||
} catch (HttpResponseException ex) {
|
||||
assertEquals(ex.getResponse().getStatusCode(), 412);
|
||||
}
|
||||
|
@ -433,13 +431,13 @@ public class S3ClientLiveTest extends BaseBlobStoreIntegrationTest {
|
|||
try {
|
||||
String goodETag = addToContainerAndValidate(containerName, sourceKey);
|
||||
|
||||
getApi().copyObject(containerName, sourceKey, destinationContainer,
|
||||
destinationKey, ifSourceETagDoesntMatch("asfasdf"));
|
||||
getApi().copyObject(containerName, sourceKey, destinationContainer, destinationKey,
|
||||
ifSourceETagDoesntMatch("asfasdf"));
|
||||
validateContent(destinationContainer, destinationKey);
|
||||
|
||||
try {
|
||||
getApi().copyObject(containerName, sourceKey, destinationContainer,
|
||||
destinationKey, ifSourceETagDoesntMatch(goodETag));
|
||||
getApi().copyObject(containerName, sourceKey, destinationContainer, destinationKey,
|
||||
ifSourceETagDoesntMatch(goodETag));
|
||||
} catch (HttpResponseException ex) {
|
||||
assertEquals(ex.getResponse().getStatusCode(), 412);
|
||||
}
|
||||
|
@ -459,13 +457,12 @@ public class S3ClientLiveTest extends BaseBlobStoreIntegrationTest {
|
|||
Map<String, String> metadata = Maps.newHashMap();
|
||||
metadata.put("adrian", "cole");
|
||||
|
||||
getApi().copyObject(containerName, sourceKey, destinationContainer,
|
||||
destinationKey, overrideMetadataWith(metadata));
|
||||
getApi().copyObject(containerName, sourceKey, destinationContainer, destinationKey,
|
||||
overrideMetadataWith(metadata));
|
||||
|
||||
validateContent(destinationContainer, destinationKey);
|
||||
|
||||
ObjectMetadata objectMeta = getApi().headObject(destinationContainer,
|
||||
destinationKey);
|
||||
ObjectMetadata objectMeta = getApi().headObject(destinationContainer, destinationKey);
|
||||
|
||||
assertEquals(objectMeta.getUserMetadata(), metadata);
|
||||
} finally {
|
||||
|
|
|
@ -20,18 +20,20 @@ package org.jclouds.aws.s3.binders;
|
|||
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.classextension.EasyMock.createMock;
|
||||
import static org.easymock.classextension.EasyMock.createNiceMock;
|
||||
import static org.easymock.classextension.EasyMock.replay;
|
||||
import static org.easymock.classextension.EasyMock.verify;
|
||||
|
||||
import org.jclouds.aws.s3.blobstore.functions.ObjectToBlob;
|
||||
import org.jclouds.aws.s3.domain.MutableObjectMetadata;
|
||||
import org.jclouds.aws.s3.domain.S3Object;
|
||||
import org.jclouds.blobstore.binders.BindBlobToPayloadAndUserMetadataToHeadersWithPrefix;
|
||||
import org.jclouds.blobstore.binders.BindUserMetadataToHeadersWithPrefix;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.Payload;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
/**
|
||||
* Tests behavior of {@code BindS3ObjectToPayload}
|
||||
*
|
||||
|
@ -40,36 +42,95 @@ import org.testng.annotations.Test;
|
|||
@Test(groups = "unit", testName = "s3.BindS3ObjectToPayloadTest")
|
||||
public class BindS3ObjectToPayloadTest {
|
||||
@Test
|
||||
public void test5GBIsOk() {
|
||||
public void testPassWithMinimumDetailsAndPayload5GB() {
|
||||
|
||||
BindBlobToPayloadAndUserMetadataToHeadersWithPrefix blobBinder = createMock(BindBlobToPayloadAndUserMetadataToHeadersWithPrefix.class);
|
||||
BindUserMetadataToHeadersWithPrefix mdBinder = createMock(BindUserMetadataToHeadersWithPrefix.class);
|
||||
ObjectToBlob object2Blob = createMock(ObjectToBlob.class);
|
||||
HttpRequest request = createMock(HttpRequest.class);
|
||||
S3Object s3Object = createMock(S3Object.class);
|
||||
S3Object object = createMock(S3Object.class);
|
||||
Payload payload = createMock(Payload.class);
|
||||
Blob blob = createMock(Blob.class);
|
||||
MutableObjectMetadata md = createNiceMock(MutableObjectMetadata.class);
|
||||
MutableObjectMetadata md = createMock(MutableObjectMetadata.class);
|
||||
|
||||
expect(s3Object.getContentLength()).andReturn(5368709120l).atLeastOnce();
|
||||
expect(object2Blob.apply(s3Object)).andReturn(blob);
|
||||
blobBinder.bindToRequest(request, blob);
|
||||
expect(s3Object.getMetadata()).andReturn(md).atLeastOnce();
|
||||
expect(object.getPayload()).andReturn(payload).atLeastOnce();
|
||||
expect(payload.getContentLength()).andReturn(5368709120l).atLeastOnce();
|
||||
expect(object2Blob.apply(object)).andReturn(blob);
|
||||
mdBinder.bindToRequest(request, blob);
|
||||
expect(object.getMetadata()).andReturn(md).atLeastOnce();
|
||||
expect(md.getCacheControl()).andReturn(null).atLeastOnce();
|
||||
expect(md.getContentDisposition()).andReturn(null).atLeastOnce();
|
||||
expect(md.getContentEncoding()).andReturn(null).atLeastOnce();
|
||||
|
||||
replay(blobBinder);
|
||||
replay(payload);
|
||||
replay(mdBinder);
|
||||
replay(object2Blob);
|
||||
replay(request);
|
||||
replay(s3Object);
|
||||
replay(object);
|
||||
replay(blob);
|
||||
replay(md);
|
||||
|
||||
BindS3ObjectToPayload bindS3ObjectToPayload = new BindS3ObjectToPayload(object2Blob,
|
||||
blobBinder);
|
||||
BindS3ObjectToPayload binder = new BindS3ObjectToPayload(object2Blob, mdBinder);
|
||||
|
||||
bindS3ObjectToPayload.bindToRequest(request, s3Object);
|
||||
binder.bindToRequest(request, object);
|
||||
|
||||
verify(blobBinder);
|
||||
verify(payload);
|
||||
verify(mdBinder);
|
||||
verify(object2Blob);
|
||||
verify(request);
|
||||
verify(s3Object);
|
||||
verify(object);
|
||||
verify(blob);
|
||||
verify(md);
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testExtendedPropertiesBind() {
|
||||
|
||||
BindUserMetadataToHeadersWithPrefix mdBinder = createMock(BindUserMetadataToHeadersWithPrefix.class);
|
||||
ObjectToBlob object2Blob = createMock(ObjectToBlob.class);
|
||||
HttpRequest request = createMock(HttpRequest.class);
|
||||
S3Object object = createMock(S3Object.class);
|
||||
Payload payload = createMock(Payload.class);
|
||||
Blob blob = createMock(Blob.class);
|
||||
MutableObjectMetadata md = createMock(MutableObjectMetadata.class);
|
||||
Multimap<String, String> headers = createMock(Multimap.class);
|
||||
|
||||
expect(object.getPayload()).andReturn(payload).atLeastOnce();
|
||||
expect(payload.getContentLength()).andReturn(5368709120l).atLeastOnce();
|
||||
expect(object2Blob.apply(object)).andReturn(blob);
|
||||
mdBinder.bindToRequest(request, blob);
|
||||
expect(object.getMetadata()).andReturn(md).atLeastOnce();
|
||||
expect(request.getHeaders()).andReturn(headers).atLeastOnce();
|
||||
expect(md.getCacheControl()).andReturn("no-cache").atLeastOnce();
|
||||
expect(headers.put("Cache-Control", "no-cache")).andReturn(true);
|
||||
|
||||
expect(md.getContentDisposition()).andReturn("attachment; filename=\"fname.ext\"")
|
||||
.atLeastOnce();
|
||||
expect(headers.put("Content-Disposition", "attachment; filename=\"fname.ext\"")).andReturn(true);
|
||||
|
||||
expect(md.getContentEncoding()).andReturn("gzip").atLeastOnce();
|
||||
expect(headers.put("Content-Encoding", "gzip")).andReturn(true);
|
||||
|
||||
replay(headers);
|
||||
replay(payload);
|
||||
replay(mdBinder);
|
||||
replay(object2Blob);
|
||||
replay(request);
|
||||
replay(object);
|
||||
replay(blob);
|
||||
replay(md);
|
||||
|
||||
BindS3ObjectToPayload binder = new BindS3ObjectToPayload(object2Blob, mdBinder);
|
||||
|
||||
binder.bindToRequest(request, object);
|
||||
|
||||
verify(headers);
|
||||
verify(payload);
|
||||
verify(mdBinder);
|
||||
verify(object2Blob);
|
||||
verify(request);
|
||||
verify(object);
|
||||
verify(blob);
|
||||
verify(md);
|
||||
|
||||
|
@ -78,34 +139,40 @@ public class BindS3ObjectToPayloadTest {
|
|||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testOver5GBIsBad() {
|
||||
|
||||
BindBlobToPayloadAndUserMetadataToHeadersWithPrefix blobBinder = createMock(BindBlobToPayloadAndUserMetadataToHeadersWithPrefix.class);
|
||||
BindUserMetadataToHeadersWithPrefix mdBinder = createMock(BindUserMetadataToHeadersWithPrefix.class);
|
||||
ObjectToBlob object2Blob = createMock(ObjectToBlob.class);
|
||||
HttpRequest request = createMock(HttpRequest.class);
|
||||
S3Object s3Object = createMock(S3Object.class);
|
||||
S3Object object = createMock(S3Object.class);
|
||||
Payload payload = createMock(Payload.class);
|
||||
Blob blob = createMock(Blob.class);
|
||||
MutableObjectMetadata md = createNiceMock(MutableObjectMetadata.class);
|
||||
MutableObjectMetadata md = createMock(MutableObjectMetadata.class);
|
||||
|
||||
expect(s3Object.getContentLength()).andReturn(5368709121l).atLeastOnce();
|
||||
expect(object2Blob.apply(s3Object)).andReturn(blob);
|
||||
blobBinder.bindToRequest(request, blob);
|
||||
expect(s3Object.getMetadata()).andReturn(md).atLeastOnce();
|
||||
expect(object.getPayload()).andReturn(payload).atLeastOnce();
|
||||
expect(payload.getContentLength()).andReturn(5368709121l).atLeastOnce();
|
||||
expect(object2Blob.apply(object)).andReturn(blob);
|
||||
mdBinder.bindToRequest(request, blob);
|
||||
expect(object.getMetadata()).andReturn(md).atLeastOnce();
|
||||
expect(md.getCacheControl()).andReturn(null).atLeastOnce();
|
||||
expect(md.getContentDisposition()).andReturn(null).atLeastOnce();
|
||||
expect(md.getContentEncoding()).andReturn(null).atLeastOnce();
|
||||
|
||||
replay(blobBinder);
|
||||
replay(payload);
|
||||
replay(mdBinder);
|
||||
replay(object2Blob);
|
||||
replay(request);
|
||||
replay(s3Object);
|
||||
replay(object);
|
||||
replay(blob);
|
||||
replay(md);
|
||||
|
||||
BindS3ObjectToPayload bindS3ObjectToPayload = new BindS3ObjectToPayload(object2Blob,
|
||||
blobBinder);
|
||||
BindS3ObjectToPayload bindS3ObjectToPayload = new BindS3ObjectToPayload(object2Blob, mdBinder);
|
||||
|
||||
bindS3ObjectToPayload.bindToRequest(request, s3Object);
|
||||
bindS3ObjectToPayload.bindToRequest(request, object);
|
||||
|
||||
verify(blobBinder);
|
||||
verify(payload);
|
||||
verify(mdBinder);
|
||||
verify(object2Blob);
|
||||
verify(request);
|
||||
verify(s3Object);
|
||||
verify(object);
|
||||
verify(blob);
|
||||
verify(md);
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@ public class ParseObjectMetadataFromHeadersTest {
|
|||
md.setETag(etag);
|
||||
md.setName("key");
|
||||
md.setLastModified(now);
|
||||
md.setSize(1025);
|
||||
md.setSize(1025l);
|
||||
md.setUserMetadata(userMetadata);
|
||||
expect(parser.apply(response)).andReturn(md);
|
||||
replay(parser);
|
||||
|
@ -110,7 +110,7 @@ public class ParseObjectMetadataFromHeadersTest {
|
|||
expects.setKey("key");
|
||||
expects.setLastModified(now);
|
||||
expects.setOwner(null);
|
||||
expects.setSize(1025);
|
||||
expects.setSize(1025l);
|
||||
expects.setStorageClass(StorageClass.STANDARD);
|
||||
expects.setUserMetadata(userMetadata);
|
||||
}
|
||||
|
|
|
@ -190,7 +190,7 @@ public class StubS3AsyncClient implements S3AsyncClient {
|
|||
|
||||
newMd.setLastModified(new Date());
|
||||
Blob newBlob = blobProvider.create(newMd);
|
||||
newBlob.setPayload(sourceS3.getContent());
|
||||
newBlob.setPayload(sourceS3.getPayload());
|
||||
dest.put(destinationObject, newBlob);
|
||||
return immediateFuture((ObjectMetadata) blob2ObjectMetadata.apply(TransientAsyncBlobStore
|
||||
.copy(newMd)));
|
||||
|
|
|
@ -108,8 +108,8 @@ public class Util {
|
|||
|
||||
public static S3Object convertObject(org.jclouds.aws.s3.domain.S3Object jcObject) {
|
||||
S3Object jsObject = convertObjectHead(jcObject.getMetadata());
|
||||
if (jcObject.getContent() != null) {
|
||||
jsObject.setDataInputStream(jcObject.getContent());
|
||||
if (jcObject.getPayload().getInput() != null) {
|
||||
jsObject.setDataInputStream(jcObject.getPayload().getInput());
|
||||
}
|
||||
return jsObject;
|
||||
}
|
||||
|
@ -125,12 +125,18 @@ public class Util {
|
|||
@SuppressWarnings("unchecked")
|
||||
public static org.jclouds.aws.s3.domain.S3Object convertObject(S3Object jsObject,
|
||||
org.jclouds.aws.s3.domain.S3Object jcObject) throws S3ServiceException {
|
||||
if (jsObject.getDataInputStream() != null) {
|
||||
jcObject.setPayload(jsObject.getDataInputStream());
|
||||
} else {
|
||||
jcObject.setPayload(""); // Must explicitly set data for empty jClouds objects.
|
||||
}
|
||||
jcObject.getPayload().setContentLength(jsObject.getContentLength());
|
||||
|
||||
jcObject.getMetadata().setKey(jsObject.getKey());
|
||||
jcObject.getMetadata().setCacheControl((String) jsObject.getMetadata("Cache-Control"));
|
||||
jcObject.getMetadata().setContentDisposition(jsObject.getContentDisposition());
|
||||
jcObject.getMetadata().setContentEncoding(jsObject.getContentEncoding());
|
||||
jcObject.getMetadata().setLastModified(jsObject.getLastModifiedDate());
|
||||
jcObject.setContentLength(jsObject.getContentLength());
|
||||
if (jsObject.getStorageClass() != null)
|
||||
jcObject.getMetadata().setStorageClass(StorageClass.valueOf(jsObject.getStorageClass()));
|
||||
|
||||
|
@ -142,12 +148,6 @@ public class Util {
|
|||
jcObject.getMetadata().setOwner(new CanonicalUser(jsObject.getOwner().getId()));
|
||||
}
|
||||
|
||||
if (jsObject.getDataInputStream() != null) {
|
||||
jcObject.setPayload(jsObject.getDataInputStream());
|
||||
} else {
|
||||
jcObject.setPayload(""); // Must explicitly set data for empty jClouds objects.
|
||||
}
|
||||
|
||||
if (jsObject.getContentType() != null) {
|
||||
jcObject.getMetadata().setContentType(jsObject.getContentType());
|
||||
} else {
|
||||
|
|
|
@ -22,72 +22,55 @@ import static com.google.common.base.Preconditions.checkArgument;
|
|||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
|
||||
import org.jclouds.azure.storage.blob.blobstore.functions.AzureBlobToBlob;
|
||||
import org.jclouds.azure.storage.blob.domain.AzureBlob;
|
||||
import org.jclouds.blobstore.reference.BlobStoreConstants;
|
||||
import org.jclouds.encryption.EncryptionService;
|
||||
import org.jclouds.blobstore.binders.BindUserMetadataToHeadersWithPrefix;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.rest.Binder;
|
||||
|
||||
@Singleton
|
||||
public class BindAzureBlobToPayload implements Binder {
|
||||
|
||||
private final String metadataPrefix;
|
||||
private final EncryptionService encryptionService;
|
||||
private final AzureBlobToBlob azureBlob2Blob;
|
||||
private final BindUserMetadataToHeadersWithPrefix blobBinder;
|
||||
|
||||
@Inject
|
||||
public BindAzureBlobToPayload(
|
||||
@Named(BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX) String prefix,
|
||||
EncryptionService encryptionService) {
|
||||
this.metadataPrefix = prefix;
|
||||
this.encryptionService = encryptionService;
|
||||
public BindAzureBlobToPayload(AzureBlobToBlob azureBlob2Blob,
|
||||
BindUserMetadataToHeadersWithPrefix blobBinder) {
|
||||
this.azureBlob2Blob = azureBlob2Blob;
|
||||
this.blobBinder = blobBinder;
|
||||
}
|
||||
|
||||
public void bindToRequest(HttpRequest request, Object payload) {
|
||||
AzureBlob object = (AzureBlob) payload;
|
||||
checkArgument(object.getProperties().getContentLength() >= 0, "size must be set");
|
||||
request.getHeaders().put("x-ms-blob-type", object.getProperties().getType().toString());
|
||||
AzureBlob blob = (AzureBlob) payload;
|
||||
checkArgument(blob.getPayload().getContentLength() >= 0, "size must be set");
|
||||
request.getHeaders().put("x-ms-blob-type", blob.getProperties().getType().toString());
|
||||
|
||||
switch (object.getProperties().getType()) {
|
||||
switch (blob.getProperties().getType()) {
|
||||
case PAGE_BLOB:
|
||||
request.getHeaders().put(HttpHeaders.CONTENT_LENGTH, "0");
|
||||
request.getHeaders().put("x-ms-blob-content-length", object.getContentLength() + "");
|
||||
request.getHeaders().put("x-ms-blob-content-length",
|
||||
blob.getPayload().getContentLength().toString());
|
||||
break;
|
||||
case BLOCK_BLOB:
|
||||
checkArgument(
|
||||
checkNotNull(object.getContentLength(), "object.getContentLength()") <= 64 * 1024 * 1024,
|
||||
checkArgument(checkNotNull(blob.getPayload().getContentLength(),
|
||||
"blob.getContentLength()") <= 64l * 1024 * 1024,
|
||||
"maximum size for put Blob is 64MB");
|
||||
request.getHeaders().put(HttpHeaders.CONTENT_LENGTH, object.getContentLength() + "");
|
||||
break;
|
||||
}
|
||||
blobBinder.bindToRequest(request, azureBlob2Blob.apply(blob));
|
||||
|
||||
for (String key : object.getProperties().getMetadata().keySet()) {
|
||||
request.getHeaders().put(key.startsWith(metadataPrefix) ? key : metadataPrefix + key,
|
||||
object.getProperties().getMetadata().get(key));
|
||||
}
|
||||
|
||||
request.setPayload(checkNotNull(object.getContent(), "object.getContent()"));
|
||||
|
||||
// in azure content-type is optional
|
||||
if (object.getProperties().getContentType() != null)
|
||||
request.getHeaders()
|
||||
.put(HttpHeaders.CONTENT_TYPE, object.getProperties().getContentType());
|
||||
|
||||
if (object.getProperties().getContentMD5() != null) {
|
||||
request.getHeaders().put("Content-MD5",
|
||||
encryptionService.base64(object.getProperties().getContentMD5()));
|
||||
}
|
||||
if (object.getProperties().getContentLanguage() != null) {
|
||||
if (blob.getProperties().getContentLanguage() != null) {
|
||||
request.getHeaders().put(HttpHeaders.CONTENT_LANGUAGE,
|
||||
object.getProperties().getContentLanguage());
|
||||
blob.getProperties().getContentLanguage());
|
||||
}
|
||||
|
||||
if (object.getProperties().getContentEncoding() != null) {
|
||||
if (blob.getProperties().getContentEncoding() != null) {
|
||||
request.getHeaders().put(HttpHeaders.CONTENT_ENCODING,
|
||||
object.getProperties().getContentEncoding());
|
||||
blob.getProperties().getContentEncoding());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -47,8 +47,6 @@ public class AzureBlobToBlob implements Function<AzureBlob, Blob> {
|
|||
if (from == null)
|
||||
return null;
|
||||
Blob blob = blobFactory.create(blobPr2BlobMd.apply(from.getProperties()));
|
||||
if (from.getContentLength() != null)
|
||||
blob.setContentLength(from.getContentLength());
|
||||
blob.setPayload(checkNotNull(from.getPayload(), "payload: " + from));
|
||||
blob.setAllHeaders(from.getAllHeaders());
|
||||
return blob;
|
||||
|
|
|
@ -46,8 +46,6 @@ public class BlobToAzureBlob implements Function<Blob, AzureBlob> {
|
|||
if (from == null)
|
||||
return null;
|
||||
AzureBlob object = objectProvider.create(blob2ObjectMd.apply(from.getMetadata()));
|
||||
if (from.getContentLength() != null)
|
||||
object.setContentLength(from.getContentLength());
|
||||
object.setPayload(checkNotNull(from.getPayload(), "payload: " + from));
|
||||
object.setAllHeaders(from.getAllHeaders());
|
||||
return object;
|
||||
|
|
|
@ -56,7 +56,7 @@ public interface MutableBlobProperties extends BlobProperties {
|
|||
/**
|
||||
* @see ListableContainerProperties#getContentLength
|
||||
*/
|
||||
void setContentLength(long size);
|
||||
void setContentLength(Long size);
|
||||
|
||||
/**
|
||||
* @see ListableContainerProperties#getContentMD5
|
||||
|
|
|
@ -25,7 +25,10 @@ import javax.inject.Inject;
|
|||
import org.jclouds.azure.storage.blob.domain.AzureBlob;
|
||||
import org.jclouds.azure.storage.blob.domain.MutableBlobProperties;
|
||||
import org.jclouds.encryption.EncryptionService;
|
||||
import org.jclouds.http.internal.BasePayloadEnclosingImpl;
|
||||
import org.jclouds.http.Payload;
|
||||
import org.jclouds.http.PayloadEnclosing;
|
||||
import org.jclouds.http.internal.PayloadEnclosingImpl;
|
||||
import org.jclouds.http.payloads.DelegatingPayload;
|
||||
|
||||
import com.google.common.collect.LinkedHashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
@ -35,25 +38,23 @@ import com.google.common.collect.Multimap;
|
|||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class AzureBlobImpl extends BasePayloadEnclosingImpl implements AzureBlob,
|
||||
Comparable<AzureBlob> {
|
||||
private final MutableBlobProperties properties;
|
||||
public class AzureBlobImpl extends PayloadEnclosingImpl implements AzureBlob, Comparable<AzureBlob> {
|
||||
|
||||
private final MutableBlobProperties _properties;
|
||||
private final SetPayloadPropertiesMutableBlobProperties properties;
|
||||
private Multimap<String, String> allHeaders = LinkedHashMultimap.create();
|
||||
|
||||
@Inject
|
||||
public AzureBlobImpl(EncryptionService encryptionService, MutableBlobProperties properties) {
|
||||
super(encryptionService);
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setContentMD5(byte[] md5) {
|
||||
getProperties().setContentMD5(md5);
|
||||
this.properties = linkMetadataToThis(properties);
|
||||
this._properties = this.properties.getDelegate();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public MutableBlobProperties getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
@ -61,6 +62,7 @@ public class AzureBlobImpl extends BasePayloadEnclosingImpl implements AzureBlob
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Multimap<String, String> getAllHeaders() {
|
||||
return allHeaders;
|
||||
}
|
||||
|
@ -68,6 +70,7 @@ public class AzureBlobImpl extends BasePayloadEnclosingImpl implements AzureBlob
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void setAllHeaders(Multimap<String, String> allHeaders) {
|
||||
this.allHeaders = checkNotNull(allHeaders, "allHeaders");
|
||||
}
|
||||
|
@ -75,6 +78,7 @@ public class AzureBlobImpl extends BasePayloadEnclosingImpl implements AzureBlob
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(AzureBlob o) {
|
||||
if (getProperties().getName() == null)
|
||||
return -1;
|
||||
|
@ -84,11 +88,8 @@ public class AzureBlobImpl extends BasePayloadEnclosingImpl implements AzureBlob
|
|||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((allHeaders == null) ? 0 : allHeaders.hashCode());
|
||||
result = prime * result + ((contentLength == null) ? 0 : contentLength.hashCode());
|
||||
result = prime * result + ((payload == null) ? 0 : payload.hashCode());
|
||||
result = prime * result + ((properties == null) ? 0 : properties.hashCode());
|
||||
int result = super.hashCode();
|
||||
result = prime * result + ((_properties == null) ? 0 : _properties.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -96,37 +97,118 @@ public class AzureBlobImpl extends BasePayloadEnclosingImpl implements AzureBlob
|
|||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
if (!super.equals(obj))
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
AzureBlobImpl other = (AzureBlobImpl) obj;
|
||||
if (allHeaders == null) {
|
||||
if (other.allHeaders != null)
|
||||
if (_properties == null) {
|
||||
if (other._properties != null)
|
||||
return false;
|
||||
} else if (!allHeaders.equals(other.allHeaders))
|
||||
return false;
|
||||
if (contentLength == null) {
|
||||
if (other.contentLength != null)
|
||||
return false;
|
||||
} else if (!contentLength.equals(other.contentLength))
|
||||
return false;
|
||||
if (payload == null) {
|
||||
if (other.payload != null)
|
||||
return false;
|
||||
} else if (!payload.equals(other.payload))
|
||||
return false;
|
||||
if (properties == null) {
|
||||
if (other.properties != null)
|
||||
return false;
|
||||
} else if (!properties.equals(other.properties))
|
||||
} else if (!_properties.equals(other._properties))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[properties=" + properties + "]";
|
||||
return "[properties=" + _properties + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPayload(Payload data) {
|
||||
linkPayloadToMetadata(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* link the new payload to the properties object so that when content-related properties is
|
||||
* updated on the payload, it is also copied the properties object.
|
||||
*/
|
||||
void linkPayloadToMetadata(Payload data) {
|
||||
if (data instanceof DelegatingPayload)
|
||||
super.setPayload(new SetMetadataPropertiesPayload(DelegatingPayload.class.cast(data)
|
||||
.getDelegate(), _properties));
|
||||
else
|
||||
super.setPayload(new SetMetadataPropertiesPayload(data, _properties));
|
||||
}
|
||||
|
||||
static class SetMetadataPropertiesPayload extends DelegatingPayload {
|
||||
|
||||
private transient final MutableBlobProperties properties;
|
||||
|
||||
public SetMetadataPropertiesPayload(Payload delegate, MutableBlobProperties properties) {
|
||||
super(delegate);
|
||||
this.properties = properties;
|
||||
if (properties.getContentLength() != null)
|
||||
setContentLength(properties.getContentLength());
|
||||
setContentMD5(properties.getContentMD5());
|
||||
setContentType(properties.getContentType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentLength(Long contentLength) {
|
||||
super.setContentLength(contentLength);
|
||||
properties.setContentLength(contentLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentMD5(byte[] md5) {
|
||||
super.setContentMD5(md5);
|
||||
properties.setContentMD5(md5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentType(String md5) {
|
||||
super.setContentType(md5);
|
||||
properties.setContentType(md5);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* link the properties object to this so that when content-related properties is updated, it is
|
||||
* also copied the currentpayload object.
|
||||
*/
|
||||
SetPayloadPropertiesMutableBlobProperties linkMetadataToThis(MutableBlobProperties properties) {
|
||||
return properties instanceof DelegatingMutableBlobProperties ? new SetPayloadPropertiesMutableBlobProperties(
|
||||
DelegatingMutableBlobProperties.class.cast(properties).getDelegate(), this)
|
||||
: new SetPayloadPropertiesMutableBlobProperties(properties, this);
|
||||
}
|
||||
|
||||
static class SetPayloadPropertiesMutableBlobProperties extends DelegatingMutableBlobProperties {
|
||||
/** The serialVersionUID */
|
||||
private static final long serialVersionUID = -5072270546219814521L;
|
||||
private transient final PayloadEnclosing blob;
|
||||
|
||||
public SetPayloadPropertiesMutableBlobProperties(MutableBlobProperties delegate,
|
||||
PayloadEnclosing blob) {
|
||||
super(delegate);
|
||||
this.blob = blob;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentMD5(byte[] md5) {
|
||||
super.setContentMD5(md5);
|
||||
if (canSetPayload())
|
||||
blob.getPayload().setContentMD5(md5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentType(String type) {
|
||||
super.setContentType(type);
|
||||
if (canSetPayload())
|
||||
blob.getPayload().setContentType(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentLength(Long size) {
|
||||
super.setContentLength(size);
|
||||
if (canSetPayload())
|
||||
blob.getPayload().setContentLength(size);
|
||||
}
|
||||
|
||||
private boolean canSetPayload() {
|
||||
return blob != null && blob.getPayload() != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed 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.azure.storage.blob.domain.internal;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.net.URI;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jclouds.azure.storage.blob.domain.BlobProperties;
|
||||
import org.jclouds.azure.storage.blob.domain.BlobType;
|
||||
import org.jclouds.azure.storage.blob.domain.LeaseStatus;
|
||||
import org.jclouds.azure.storage.blob.domain.MutableBlobProperties;
|
||||
|
||||
/**
|
||||
* Allows you to manipulate metadata.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class DelegatingMutableBlobProperties implements Serializable, MutableBlobProperties {
|
||||
|
||||
/** The serialVersionUID */
|
||||
private static final long serialVersionUID = 9136392820647068818L;
|
||||
|
||||
private final MutableBlobProperties delegate;
|
||||
|
||||
public DelegatingMutableBlobProperties(MutableBlobProperties delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(BlobProperties o) {
|
||||
return delegate.compareTo(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return delegate.equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentEncoding() {
|
||||
return delegate.getContentEncoding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentLanguage() {
|
||||
return delegate.getContentLanguage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getContentLength() {
|
||||
return delegate.getContentLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getContentMD5() {
|
||||
return delegate.getContentMD5();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentType() {
|
||||
return delegate.getContentType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getETag() {
|
||||
return delegate.getETag();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getLastModified() {
|
||||
return delegate.getLastModified();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LeaseStatus getLeaseStatus() {
|
||||
return delegate.getLeaseStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getMetadata() {
|
||||
return delegate.getMetadata();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return delegate.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlobType getType() {
|
||||
return delegate.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getUrl() {
|
||||
return delegate.getUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return delegate.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentEncoding(String encoding) {
|
||||
delegate.setContentEncoding(encoding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentLanguage(String contentLanguage) {
|
||||
delegate.setContentLanguage(contentLanguage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentLength(Long size) {
|
||||
delegate.setContentLength(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentMD5(byte[] md5) {
|
||||
delegate.setContentMD5(md5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentType(String contentType) {
|
||||
delegate.setContentType(contentType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setETag(String eTag) {
|
||||
delegate.setETag(eTag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastModified(Date lastModified) {
|
||||
delegate.setLastModified(lastModified);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMetadata(Map<String, String> metadata) {
|
||||
delegate.setMetadata(metadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
delegate.setName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUrl(URI url) {
|
||||
delegate.setUrl(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return delegate.toString();
|
||||
}
|
||||
|
||||
public static long getSerialversionuid() {
|
||||
return serialVersionUID;
|
||||
}
|
||||
|
||||
public MutableBlobProperties getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
}
|
|
@ -48,7 +48,7 @@ public class MutableBlobPropertiesImpl implements Serializable, MutableBlobPrope
|
|||
private URI url;
|
||||
private Date lastModified;
|
||||
private String eTag;
|
||||
private long size;
|
||||
private Long size;
|
||||
private String contentType;
|
||||
private byte[] contentMD5;
|
||||
private String contentEncoding;
|
||||
|
@ -198,7 +198,7 @@ public class MutableBlobPropertiesImpl implements Serializable, MutableBlobPrope
|
|||
/**
|
||||
*{@inheritDoc}
|
||||
*/
|
||||
public void setContentLength(long size) {
|
||||
public void setContentLength(Long size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
|
|
|
@ -62,23 +62,23 @@ public class ParseBlobFromHeadersAndHttpContent implements Function<HttpResponse
|
|||
AzureBlob object = objectProvider.create(metadataParser.apply(from));
|
||||
object.getAllHeaders().putAll(from.getHeaders());
|
||||
|
||||
String contentLength = from.getFirstHeaderOrNull(HttpHeaders.CONTENT_LENGTH);
|
||||
String contentRange = from.getFirstHeaderOrNull("Content-Range");
|
||||
|
||||
if (contentLength != null) {
|
||||
object.setContentLength(Long.parseLong(contentLength));
|
||||
}
|
||||
|
||||
if (from.getContent() != null) {
|
||||
object.setPayload(from.getContent());
|
||||
} else if (object.getContentLength() != null && object.getContentLength() == 0) {
|
||||
} else if (new Long(0).equals(object.getProperties().getContentLength())) {
|
||||
object.setPayload(new byte[0]);
|
||||
} else {
|
||||
assert false : "no content in " + from;
|
||||
}
|
||||
|
||||
String contentLength = from.getFirstHeaderOrNull(HttpHeaders.CONTENT_LENGTH);
|
||||
String contentRange = from.getFirstHeaderOrNull("Content-Range");
|
||||
|
||||
if (contentLength != null) {
|
||||
object.getPayload().setContentLength(Long.parseLong(contentLength));
|
||||
}
|
||||
|
||||
if (contentRange == null && contentLength != null) {
|
||||
object.getProperties().setContentLength(object.getContentLength());
|
||||
object.getProperties().setContentLength(object.getPayload().getContentLength());
|
||||
} else if (contentRange != null) {
|
||||
object.getProperties().setContentLength(
|
||||
Long.parseLong(contentRange.substring(contentRange.lastIndexOf('/') + 1)));
|
||||
|
|
|
@ -231,7 +231,6 @@ public class AzureBlobClientLiveTest {
|
|||
AzureBlob object = client.newBlob();
|
||||
object.getProperties().setName("object");
|
||||
object.setPayload(data);
|
||||
object.setContentLength(data.length());
|
||||
object.generateMD5();
|
||||
object.getProperties().setContentType("text/plain");
|
||||
object.getProperties().getMetadata().put("mykey", "metadata-value");
|
||||
|
@ -273,9 +272,9 @@ public class AzureBlobClientLiveTest {
|
|||
|
||||
// Test GET of object (including updated metadata)
|
||||
AzureBlob getBlob = client.getBlob(privateContainer, object.getProperties().getName());
|
||||
assertEquals(Utils.toStringAndClose(getBlob.getContent()), data);
|
||||
assertEquals(Utils.toStringAndClose(getBlob.getPayload().getInput()), data);
|
||||
// TODO assertEquals(getBlob.getName(), object.getProperties().getName());
|
||||
assertEquals(getBlob.getContentLength(), new Long(data.length()));
|
||||
assertEquals(getBlob.getPayload().getContentLength(), new Long(data.length()));
|
||||
assertEquals(getBlob.getProperties().getContentType(), "text/plain");
|
||||
assertEquals(encryptionService.hex(md5), encryptionService.hex(getBlob.getProperties()
|
||||
.getContentMD5()));
|
||||
|
@ -317,7 +316,7 @@ public class AzureBlobClientLiveTest {
|
|||
object = client.newBlob();
|
||||
object.getProperties().setName("chunked-object");
|
||||
object.setPayload(bais);
|
||||
object.setContentLength(new Long(data.getBytes().length));
|
||||
object.getPayload().setContentLength(new Long(data.getBytes().length));
|
||||
newEtag = client.putBlob(privateContainer, object);
|
||||
assertEquals(encryptionService.hex(md5), encryptionService.hex(getBlob.getProperties()
|
||||
.getContentMD5()));
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
package org.jclouds.azure.storage.blob.binders;
|
||||
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.classextension.EasyMock.createMock;
|
||||
import static org.easymock.classextension.EasyMock.replay;
|
||||
import static org.easymock.classextension.EasyMock.verify;
|
||||
|
||||
import org.jclouds.azure.storage.blob.blobstore.functions.AzureBlobToBlob;
|
||||
import org.jclouds.azure.storage.blob.domain.AzureBlob;
|
||||
import org.jclouds.azure.storage.blob.domain.BlobType;
|
||||
import org.jclouds.azure.storage.blob.domain.MutableBlobProperties;
|
||||
import org.jclouds.blobstore.binders.BindUserMetadataToHeadersWithPrefix;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.Payload;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
/**
|
||||
* Tests behavior of {@code BindAzureBlobToPayload}
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "azure.BindAzureBlobToPayloadTest")
|
||||
public class BindAzureBlobToPayloadTest {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testPassBlockWithMinimumDetailsAndPayload64MB() {
|
||||
|
||||
BindUserMetadataToHeadersWithPrefix mdBinder = createMock(BindUserMetadataToHeadersWithPrefix.class);
|
||||
AzureBlobToBlob object2Blob = createMock(AzureBlobToBlob.class);
|
||||
HttpRequest request = createMock(HttpRequest.class);
|
||||
AzureBlob object = createMock(AzureBlob.class);
|
||||
Payload payload = createMock(Payload.class);
|
||||
Blob blob = createMock(Blob.class);
|
||||
MutableBlobProperties md = createMock(MutableBlobProperties.class);
|
||||
Multimap<String, String> headers = createMock(Multimap.class);
|
||||
|
||||
expect(object.getPayload()).andReturn(payload).atLeastOnce();
|
||||
expect(payload.getContentLength()).andReturn(1024l).atLeastOnce();
|
||||
expect(object2Blob.apply(object)).andReturn(blob);
|
||||
mdBinder.bindToRequest(request, blob);
|
||||
expect(object.getProperties()).andReturn(md).atLeastOnce();
|
||||
expect(md.getType()).andReturn(BlobType.BLOCK_BLOB).atLeastOnce();
|
||||
expect(request.getHeaders()).andReturn(headers).atLeastOnce();
|
||||
expect(headers.put("x-ms-blob-type", "BlockBlob")).andReturn(true);
|
||||
|
||||
expect(md.getContentLanguage()).andReturn(null).atLeastOnce();
|
||||
expect(md.getContentEncoding()).andReturn(null).atLeastOnce();
|
||||
|
||||
replay(headers);
|
||||
replay(payload);
|
||||
replay(mdBinder);
|
||||
replay(object2Blob);
|
||||
replay(request);
|
||||
replay(object);
|
||||
replay(blob);
|
||||
replay(md);
|
||||
|
||||
BindAzureBlobToPayload binder = new BindAzureBlobToPayload(object2Blob, mdBinder);
|
||||
|
||||
binder.bindToRequest(request, object);
|
||||
|
||||
verify(headers);
|
||||
verify(payload);
|
||||
verify(mdBinder);
|
||||
verify(object2Blob);
|
||||
verify(request);
|
||||
verify(object);
|
||||
verify(blob);
|
||||
verify(md);
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testBlockExtendedPropertiesBind() {
|
||||
|
||||
BindUserMetadataToHeadersWithPrefix mdBinder = createMock(BindUserMetadataToHeadersWithPrefix.class);
|
||||
AzureBlobToBlob object2Blob = createMock(AzureBlobToBlob.class);
|
||||
HttpRequest request = createMock(HttpRequest.class);
|
||||
AzureBlob object = createMock(AzureBlob.class);
|
||||
Payload payload = createMock(Payload.class);
|
||||
Blob blob = createMock(Blob.class);
|
||||
MutableBlobProperties md = createMock(MutableBlobProperties.class);
|
||||
Multimap<String, String> headers = createMock(Multimap.class);
|
||||
|
||||
expect(object.getPayload()).andReturn(payload).atLeastOnce();
|
||||
expect(payload.getContentLength()).andReturn(1024l).atLeastOnce();
|
||||
expect(object2Blob.apply(object)).andReturn(blob);
|
||||
mdBinder.bindToRequest(request, blob);
|
||||
expect(object.getProperties()).andReturn(md).atLeastOnce();
|
||||
expect(md.getType()).andReturn(BlobType.BLOCK_BLOB).atLeastOnce();
|
||||
expect(request.getHeaders()).andReturn(headers).atLeastOnce();
|
||||
expect(headers.put("x-ms-blob-type", "BlockBlob")).andReturn(true);
|
||||
|
||||
expect(md.getContentLanguage()).andReturn("en").atLeastOnce();
|
||||
expect(headers.put("Content-Language", "en")).andReturn(true);
|
||||
|
||||
expect(md.getContentEncoding()).andReturn("gzip").atLeastOnce();
|
||||
expect(headers.put("Content-Encoding", "gzip")).andReturn(true);
|
||||
|
||||
replay(headers);
|
||||
replay(payload);
|
||||
replay(mdBinder);
|
||||
replay(object2Blob);
|
||||
replay(request);
|
||||
replay(object);
|
||||
replay(blob);
|
||||
replay(md);
|
||||
|
||||
BindAzureBlobToPayload binder = new BindAzureBlobToPayload(object2Blob, mdBinder);
|
||||
|
||||
binder.bindToRequest(request, object);
|
||||
|
||||
verify(headers);
|
||||
verify(payload);
|
||||
verify(mdBinder);
|
||||
verify(object2Blob);
|
||||
verify(request);
|
||||
verify(object);
|
||||
verify(blob);
|
||||
verify(md);
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testBlockOver64MBIsBad() {
|
||||
|
||||
BindUserMetadataToHeadersWithPrefix mdBinder = createMock(BindUserMetadataToHeadersWithPrefix.class);
|
||||
AzureBlobToBlob object2Blob = createMock(AzureBlobToBlob.class);
|
||||
HttpRequest request = createMock(HttpRequest.class);
|
||||
AzureBlob object = createMock(AzureBlob.class);
|
||||
Payload payload = createMock(Payload.class);
|
||||
Blob blob = createMock(Blob.class);
|
||||
MutableBlobProperties md = createMock(MutableBlobProperties.class);
|
||||
Multimap<String, String> headers = createMock(Multimap.class);
|
||||
|
||||
expect(object.getPayload()).andReturn(payload).atLeastOnce();
|
||||
expect(payload.getContentLength()).andReturn(5368709121l).atLeastOnce();
|
||||
expect(object2Blob.apply(object)).andReturn(blob);
|
||||
mdBinder.bindToRequest(request, blob);
|
||||
expect(object.getProperties()).andReturn(md).atLeastOnce();
|
||||
expect(md.getType()).andReturn(BlobType.BLOCK_BLOB).atLeastOnce();
|
||||
expect(request.getHeaders()).andReturn(headers).atLeastOnce();
|
||||
expect(headers.put("x-ms-blob-type", "BlockBlob")).andReturn(true);
|
||||
|
||||
expect(md.getContentLanguage()).andReturn(null).atLeastOnce();
|
||||
expect(md.getContentEncoding()).andReturn(null).atLeastOnce();
|
||||
|
||||
replay(headers);
|
||||
replay(payload);
|
||||
replay(mdBinder);
|
||||
replay(object2Blob);
|
||||
replay(request);
|
||||
replay(object);
|
||||
replay(blob);
|
||||
replay(md);
|
||||
|
||||
BindAzureBlobToPayload bindAzureBlobToPayload = new BindAzureBlobToPayload(object2Blob,
|
||||
mdBinder);
|
||||
|
||||
bindAzureBlobToPayload.bindToRequest(request, object);
|
||||
|
||||
verify(headers);
|
||||
verify(payload);
|
||||
verify(mdBinder);
|
||||
verify(object2Blob);
|
||||
verify(request);
|
||||
verify(object);
|
||||
verify(blob);
|
||||
verify(md);
|
||||
|
||||
}
|
||||
}
|
|
@ -32,14 +32,13 @@ import static com.google.common.collect.Maps.newHashMap;
|
|||
import static com.google.common.collect.Sets.filter;
|
||||
import static com.google.common.collect.Sets.newTreeSet;
|
||||
import static com.google.common.io.ByteStreams.toByteArray;
|
||||
import static com.google.common.io.Closeables.closeQuietly;
|
||||
import static com.google.common.util.concurrent.Futures.immediateFailedFuture;
|
||||
import static com.google.common.util.concurrent.Futures.immediateFuture;
|
||||
import static org.jclouds.http.Payloads.newByteArrayPayload;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutput;
|
||||
|
@ -85,12 +84,15 @@ import org.jclouds.http.HttpCommand;
|
|||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.http.Payload;
|
||||
import org.jclouds.http.options.HttpRequestOptions;
|
||||
import org.jclouds.http.payloads.ByteArrayPayload;
|
||||
import org.jclouds.http.payloads.DelegatingPayload;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Multimaps;
|
||||
import com.google.common.io.Closeables;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.inject.internal.Nullable;
|
||||
|
||||
|
@ -461,38 +463,47 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
|
|||
if (container == null) {
|
||||
new RuntimeException("containerName not found: " + containerName);
|
||||
}
|
||||
Payload payload = object.getPayload();
|
||||
if (!payload.isRepeatable()) {
|
||||
try {
|
||||
payload = newByteArrayPayload(toByteArray(payload.getInput()));
|
||||
} catch (IOException e) {
|
||||
propagate(e);
|
||||
} finally {
|
||||
closeQuietly(payload.getInput());
|
||||
}
|
||||
}
|
||||
object.getMetadata().setSize(payload.calculateSize());
|
||||
MutableBlobMetadata newMd = copy(object.getMetadata());
|
||||
newMd.setLastModified(new Date());
|
||||
byte[] md5 = encryptionService.md5(payload.getInput());
|
||||
String eTag = encryptionService.hex(md5);
|
||||
newMd.setETag(eTag);
|
||||
newMd.setContentMD5(md5);
|
||||
newMd.setContentType(object.getMetadata().getContentType());
|
||||
|
||||
Blob blob = blobFactory.create(newMd);
|
||||
ByteArrayPayload payload = (object.getPayload() instanceof ByteArrayPayload) ? ByteArrayPayload.class
|
||||
.cast(object.getPayload())
|
||||
: null;
|
||||
if (payload == null)
|
||||
payload = (object.getPayload() instanceof DelegatingPayload) ? (DelegatingPayload.class
|
||||
.cast(object.getPayload()).getDelegate() instanceof ByteArrayPayload) ? ByteArrayPayload.class
|
||||
.cast(DelegatingPayload.class.cast(object.getPayload()).getDelegate())
|
||||
: null
|
||||
: null;
|
||||
if (payload == null || !(payload instanceof ByteArrayPayload)) {
|
||||
InputStream input = object.getPayload().getInput();
|
||||
try {
|
||||
String oldContentType = object.getPayload().getContentType();
|
||||
payload = encryptionService.generatePayloadWithMD5For(input);
|
||||
payload.setContentType(oldContentType);
|
||||
} finally {
|
||||
Closeables.closeQuietly(input);
|
||||
}
|
||||
} else {
|
||||
if (payload.getContentMD5() == null)
|
||||
payload = (ByteArrayPayload) encryptionService
|
||||
.generateMD5BufferingIfNotRepeatable(payload);
|
||||
}
|
||||
|
||||
Blob blob = blobFactory.create(copy(object.getMetadata()));
|
||||
blob.setPayload(payload);
|
||||
blob.getMetadata().setLastModified(new Date());
|
||||
String eTag = encryptionService.hex(payload.getContentMD5());
|
||||
blob.getMetadata().setETag(eTag);
|
||||
container.put(blob.getMetadata().getName(), blob);
|
||||
|
||||
// Set HTTP headers to match metadata
|
||||
blob.getAllHeaders().put(HttpHeaders.LAST_MODIFIED,
|
||||
dateService.rfc822DateFormat(newMd.getLastModified()));
|
||||
dateService.rfc822DateFormat(blob.getMetadata().getLastModified()));
|
||||
blob.getAllHeaders().put(HttpHeaders.ETAG, eTag);
|
||||
blob.getAllHeaders().put(HttpHeaders.CONTENT_TYPE, newMd.getContentType());
|
||||
blob.getAllHeaders().put(HttpHeaders.CONTENT_LENGTH, newMd.getSize() + "");
|
||||
for (Entry<String, String> userMD : newMd.getUserMetadata().entrySet()) {
|
||||
blob.getAllHeaders().put(userMD.getKey(), userMD.getValue());
|
||||
}
|
||||
blob.getAllHeaders().put(HttpHeaders.CONTENT_TYPE, blob.getMetadata().getContentType());
|
||||
blob.getAllHeaders().put(HttpHeaders.CONTENT_LENGTH, blob.getMetadata().getSize() + "");
|
||||
blob.getAllHeaders().put("Content-MD5", encryptionService.base64(payload.getContentMD5()));
|
||||
blob.getAllHeaders().putAll(Multimaps.forMap(blob.getMetadata().getUserMetadata()));
|
||||
|
||||
return immediateFuture(eTag);
|
||||
}
|
||||
|
||||
|
@ -580,7 +591,6 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
|
|||
|
||||
}
|
||||
returnVal.setPayload(out.toByteArray());
|
||||
returnVal.setContentLength(out.size());
|
||||
returnVal.getMetadata().setSize(new Long(data.length));
|
||||
}
|
||||
checkNotNull(returnVal.getPayload(), "payload " + returnVal);
|
||||
|
|
|
@ -18,33 +18,28 @@
|
|||
*/
|
||||
package org.jclouds.blobstore.binders;
|
||||
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.MultipartForm;
|
||||
import org.jclouds.http.MultipartForm.Part;
|
||||
import org.jclouds.http.MultipartForm.Part.PartOptions;
|
||||
import org.jclouds.http.payloads.MultipartForm;
|
||||
import org.jclouds.http.payloads.Part;
|
||||
import org.jclouds.http.payloads.Part.PartOptions;
|
||||
import org.jclouds.rest.Binder;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class BindBlobToMultipartForm implements Binder {
|
||||
|
||||
public static final String BOUNDARY = "--JCLOUDS--";
|
||||
|
||||
public void bindToRequest(HttpRequest request, Object payload) {
|
||||
Blob object = (Blob) payload;
|
||||
Blob blob = (Blob) payload;
|
||||
|
||||
Part part = Part.create(object.getMetadata().getName(), object.getPayload(),
|
||||
new PartOptions().contentType(object.getMetadata().getContentType()));
|
||||
Part part = Part.create(blob.getMetadata().getName(), blob.getPayload(),
|
||||
new PartOptions().contentType(blob.getMetadata().getContentType()));
|
||||
|
||||
MultipartForm form = new MultipartForm(BOUNDARY, part);
|
||||
request.setPayload(form.getInput());
|
||||
request.getHeaders().put(HttpHeaders.CONTENT_TYPE,
|
||||
"multipart/form-data; boundary=" + BOUNDARY);
|
||||
request.getHeaders().put(HttpHeaders.CONTENT_LENGTH, form.calculateSize() + "");
|
||||
request.setPayload(new MultipartForm(part));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed 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.blobstore.binders;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.encryption.EncryptionService;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.rest.Binder;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class BindBlobToPayload implements Binder {
|
||||
private final EncryptionService encryptionService;
|
||||
|
||||
@Inject
|
||||
public BindBlobToPayload(EncryptionService encryptionService) {
|
||||
this.encryptionService = encryptionService;
|
||||
}
|
||||
|
||||
public void bindToRequest(HttpRequest request, Object payload) {
|
||||
Blob object = (Blob) payload;
|
||||
request.setPayload(checkNotNull(object.getPayload(), "object.getPayload()"));
|
||||
request.getHeaders()
|
||||
.put(
|
||||
HttpHeaders.CONTENT_TYPE,
|
||||
checkNotNull(object.getMetadata().getContentType(),
|
||||
"object.metadata.contentType()"));
|
||||
|
||||
request.getHeaders().put(HttpHeaders.CONTENT_LENGTH, object.getContentLength() + "");
|
||||
|
||||
if (object.getMetadata().getContentMD5() != null) {
|
||||
request.getHeaders().put("Content-MD5",
|
||||
encryptionService.base64(object.getMetadata().getContentMD5()));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,10 +25,16 @@ import java.util.Map.Entry;
|
|||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.rest.Binder;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class BindMapToHeadersWithPrefix implements Binder {
|
||||
private final String metadataPrefix;
|
||||
|
||||
|
|
|
@ -22,23 +22,23 @@ import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_M
|
|||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.encryption.EncryptionService;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.rest.Binder;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class BindBlobToPayloadAndUserMetadataToHeadersWithPrefix extends BindBlobToPayload {
|
||||
@Singleton
|
||||
public class BindUserMetadataToHeadersWithPrefix implements Binder {
|
||||
private final String metadataPrefix;
|
||||
|
||||
@Inject
|
||||
public BindBlobToPayloadAndUserMetadataToHeadersWithPrefix(
|
||||
@Named(PROPERTY_USER_METADATA_PREFIX) String metadataPrefix,
|
||||
EncryptionService encryptionService) {
|
||||
super(encryptionService);
|
||||
public BindUserMetadataToHeadersWithPrefix(
|
||||
@Named(PROPERTY_USER_METADATA_PREFIX) String metadataPrefix) {
|
||||
this.metadataPrefix = metadataPrefix;
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,5 @@ public class BindBlobToPayloadAndUserMetadataToHeadersWithPrefix extends BindBlo
|
|||
request.getHeaders().put(key.startsWith(metadataPrefix) ? key : metadataPrefix + key,
|
||||
object.getMetadata().getUserMetadata().get(key));
|
||||
}
|
||||
super.bindToRequest(request, payload);
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed 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.blobstore.domain;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class MD5InputStreamResult {
|
||||
public final byte[] data;
|
||||
public final byte[] md5;
|
||||
public final long length;
|
||||
|
||||
public MD5InputStreamResult(byte[] data, byte[] md5, long length) {
|
||||
this.data = checkNotNull(data, "data");
|
||||
this.md5 = checkNotNull(md5, "md5");
|
||||
checkArgument(length >= 0, "length cannot me negative");
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
}
|
|
@ -18,6 +18,8 @@
|
|||
*/
|
||||
package org.jclouds.blobstore.domain;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.jclouds.blobstore.domain.internal.MutableBlobMetadataImpl;
|
||||
|
||||
import com.google.inject.ImplementedBy;
|
||||
|
@ -36,8 +38,8 @@ public interface MutableBlobMetadata extends BlobMetadata, MutableStorageMetadat
|
|||
*
|
||||
* @see <a href= "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html?sec14.17." />
|
||||
*/
|
||||
void setContentType(String type);
|
||||
void setContentType(@Nullable String type);
|
||||
|
||||
void setContentMD5(byte[] md5);
|
||||
void setContentMD5(@Nullable byte[] md5);
|
||||
|
||||
}
|
|
@ -20,6 +20,8 @@ package org.jclouds.blobstore.domain;
|
|||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.jclouds.blobstore.domain.internal.MutableStorageMetadataImpl;
|
||||
import org.jclouds.domain.MutableResourceMetadata;
|
||||
|
||||
|
@ -42,7 +44,7 @@ public interface MutableStorageMetadata extends MutableResourceMetadata<StorageT
|
|||
/**
|
||||
* @see #getSize
|
||||
*/
|
||||
void setSize(long size);
|
||||
void setSize(@Nullable Long size);
|
||||
|
||||
/**
|
||||
* @see #getLastModified
|
||||
|
|
|
@ -26,7 +26,10 @@ import org.jclouds.blobstore.domain.Blob;
|
|||
import org.jclouds.blobstore.domain.MutableBlobMetadata;
|
||||
import org.jclouds.blobstore.domain.StorageMetadata;
|
||||
import org.jclouds.encryption.EncryptionService;
|
||||
import org.jclouds.http.internal.BasePayloadEnclosingImpl;
|
||||
import org.jclouds.http.Payload;
|
||||
import org.jclouds.http.PayloadEnclosing;
|
||||
import org.jclouds.http.internal.PayloadEnclosingImpl;
|
||||
import org.jclouds.http.payloads.DelegatingPayload;
|
||||
|
||||
import com.google.common.collect.LinkedHashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
@ -39,22 +42,17 @@ import com.google.common.collect.Multimap;
|
|||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class BlobImpl extends BasePayloadEnclosingImpl implements Blob, Comparable<Blob> {
|
||||
private final MutableBlobMetadata metadata;
|
||||
public class BlobImpl extends PayloadEnclosingImpl implements Blob, Comparable<Blob> {
|
||||
|
||||
private final MutableBlobMetadata _metadata;
|
||||
private final SetPayloadPropertiesMutableBlobMetadata metadata;
|
||||
private Multimap<String, String> allHeaders = LinkedHashMultimap.create();
|
||||
|
||||
@Inject
|
||||
public BlobImpl(EncryptionService encryptionService, MutableBlobMetadata metadata) {
|
||||
super(encryptionService);
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected void setContentMD5(byte[] md5) {
|
||||
getMetadata().setContentMD5(checkNotNull(md5, "md5"));
|
||||
this.metadata = linkMetadataToThis(metadata);
|
||||
this._metadata = this.metadata.getDelegate();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -91,25 +89,130 @@ public class BlobImpl extends BasePayloadEnclosingImpl implements Blob, Comparab
|
|||
return (this == o) ? 0 : getMetadata().getName().compareTo(o.getMetadata().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return metadata.hashCode();
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + ((_metadata == null) ? 0 : _metadata.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return metadata.equals(obj);
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (!super.equals(obj))
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
BlobImpl other = (BlobImpl) obj;
|
||||
if (_metadata == null) {
|
||||
if (other._metadata != null)
|
||||
return false;
|
||||
} else if (!_metadata.equals(other._metadata))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[metadata=" + metadata + "]";
|
||||
return "[metadata=" + _metadata + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPayload(Payload data) {
|
||||
linkPayloadToMetadata(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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));
|
||||
else
|
||||
super.setPayload(new SetMetadataPropertiesPayload(data, _metadata));
|
||||
}
|
||||
|
||||
static class SetMetadataPropertiesPayload extends DelegatingPayload {
|
||||
|
||||
private transient final MutableBlobMetadata metadata;
|
||||
|
||||
public SetMetadataPropertiesPayload(Payload delegate, MutableBlobMetadata metadata) {
|
||||
super(delegate);
|
||||
this.metadata = metadata;
|
||||
if (metadata.getSize() != null)
|
||||
setContentLength(metadata.getSize());
|
||||
setContentMD5(metadata.getContentMD5());
|
||||
setContentType(metadata.getContentType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentLength(Long contentLength) {
|
||||
super.setContentLength(contentLength);
|
||||
metadata.setSize(contentLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentMD5(byte[] md5) {
|
||||
super.setContentMD5(md5);
|
||||
metadata.setContentMD5(md5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentType(String md5) {
|
||||
super.setContentType(md5);
|
||||
metadata.setContentType(md5);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
static class SetPayloadPropertiesMutableBlobMetadata extends DelegatingMutableBlobMetadata {
|
||||
/** The serialVersionUID */
|
||||
private static final long serialVersionUID = -5072270546219814521L;
|
||||
private transient final PayloadEnclosing blob;
|
||||
|
||||
public SetPayloadPropertiesMutableBlobMetadata(MutableBlobMetadata delegate,
|
||||
PayloadEnclosing blob) {
|
||||
super(delegate);
|
||||
this.blob = blob;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentMD5(byte[] md5) {
|
||||
super.setContentMD5(md5);
|
||||
if (canSetPayload())
|
||||
blob.getPayload().setContentMD5(md5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentType(String type) {
|
||||
super.setContentType(type);
|
||||
if (canSetPayload())
|
||||
blob.getPayload().setContentType(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSize(Long size) {
|
||||
super.setSize(size);
|
||||
if (canSetPayload())
|
||||
blob.getPayload().setContentLength(size);
|
||||
}
|
||||
|
||||
private boolean canSetPayload() {
|
||||
return blob != null && blob.getPayload() != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed 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.blobstore.domain.internal;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.net.URI;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jclouds.blobstore.domain.MutableBlobMetadata;
|
||||
import org.jclouds.blobstore.domain.StorageType;
|
||||
import org.jclouds.domain.Location;
|
||||
import org.jclouds.domain.ResourceMetadata;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class DelegatingMutableBlobMetadata implements MutableBlobMetadata, Serializable {
|
||||
/** The serialVersionUID */
|
||||
private static final long serialVersionUID = -2739517840958218727L;
|
||||
protected final MutableBlobMetadata delegate;
|
||||
|
||||
public DelegatingMutableBlobMetadata(MutableBlobMetadata delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentMD5(byte[] md5) {
|
||||
delegate.setContentMD5(md5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentType(String type) {
|
||||
delegate.setContentType(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getContentMD5() {
|
||||
return delegate.getContentMD5();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentType() {
|
||||
return delegate.getContentType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setETag(String eTag) {
|
||||
delegate.setETag(eTag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastModified(Date lastModified) {
|
||||
delegate.setLastModified(lastModified);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSize(Long size) {
|
||||
delegate.setSize(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getETag() {
|
||||
return delegate.getETag();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getLastModified() {
|
||||
return delegate.getLastModified();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return delegate.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProviderId() {
|
||||
return delegate.getProviderId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getSize() {
|
||||
return delegate.getSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageType getType() {
|
||||
return delegate.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getUri() {
|
||||
return delegate.getUri();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getUserMetadata() {
|
||||
return delegate.getUserMetadata();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(String id) {
|
||||
delegate.setId(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLocation(Location location) {
|
||||
delegate.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
delegate.setName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setType(StorageType type) {
|
||||
delegate.setType(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUri(URI url) {
|
||||
delegate.setUri(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserMetadata(Map<String, String> userMetadata) {
|
||||
delegate.setUserMetadata(userMetadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getLocation() {
|
||||
return delegate.getLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ResourceMetadata<StorageType> o) {
|
||||
return delegate.compareTo(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return delegate.equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return delegate.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return delegate.toString();
|
||||
}
|
||||
|
||||
public MutableBlobMetadata getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
}
|
|
@ -18,8 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.blobstore.domain.internal;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
import org.jclouds.blobstore.domain.MutableBlobMetadata;
|
||||
|
@ -35,7 +33,7 @@ public class MutableBlobMetadataImpl extends MutableStorageMetadataImpl implemen
|
|||
/** The serialVersionUID */
|
||||
private static final long serialVersionUID = -5932618957134612231L;
|
||||
|
||||
private String contentType = MediaType.APPLICATION_OCTET_STREAM;
|
||||
private String contentType;
|
||||
private byte[] contentMD5;
|
||||
|
||||
public MutableBlobMetadataImpl() {
|
||||
|
@ -45,7 +43,6 @@ public class MutableBlobMetadataImpl extends MutableStorageMetadataImpl implemen
|
|||
|
||||
public MutableBlobMetadataImpl(BlobMetadata from) {
|
||||
super(from);
|
||||
this.setType(StorageType.BLOB);
|
||||
this.contentType = from.getContentType();
|
||||
this.contentMD5 = from.getContentMD5();
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ public class MutableStorageMetadataImpl extends MutableResourceMetadataImpl<Stor
|
|||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void setSize(long size) {
|
||||
public void setSize(Long size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ public class ObjectMD5 implements Function<Object, byte[]> {
|
|||
}
|
||||
if (object.getMetadata().getContentMD5() == null)
|
||||
object.generateMD5();
|
||||
return object.getMetadata().getContentMD5();
|
||||
return object.getPayload().getContentMD5();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -73,11 +73,11 @@ public class ParseBlobFromHeadersAndHttpContent implements Function<HttpResponse
|
|||
String contentRange = from.getFirstHeaderOrNull("Content-Range");
|
||||
|
||||
if (contentLength != null) {
|
||||
object.setContentLength(Long.parseLong(contentLength));
|
||||
object.getPayload().setContentLength(Long.parseLong(contentLength));
|
||||
}
|
||||
|
||||
if (contentRange == null && contentLength != null) {
|
||||
object.getMetadata().setSize(object.getContentLength());
|
||||
object.getMetadata().setSize(object.getPayload().getContentLength());
|
||||
} else if (contentRange != null) {
|
||||
object.getMetadata().setSize(
|
||||
Long.parseLong(contentRange.substring(contentRange.lastIndexOf('/') + 1)));
|
||||
|
|
|
@ -18,6 +18,10 @@
|
|||
*/
|
||||
package org.jclouds.blobstore.internal;
|
||||
|
||||
import static com.google.common.collect.Iterables.transform;
|
||||
import static com.google.common.collect.Lists.newArrayList;
|
||||
import static org.jclouds.http.Payloads.newPayload;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collection;
|
||||
|
@ -35,7 +39,6 @@ import org.jclouds.blobstore.strategy.GetBlobsInListStrategy;
|
|||
import org.jclouds.blobstore.strategy.PutBlobsStrategy;
|
||||
import org.jclouds.blobstore.strategy.internal.ListContainerAndRecurseThroughFolders;
|
||||
import org.jclouds.http.Payload;
|
||||
import org.jclouds.http.Payloads;
|
||||
import org.jclouds.http.payloads.ByteArrayPayload;
|
||||
import org.jclouds.http.payloads.FilePayload;
|
||||
import org.jclouds.http.payloads.InputStreamPayload;
|
||||
|
@ -43,8 +46,6 @@ import org.jclouds.http.payloads.StringPayload;
|
|||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
/**
|
||||
* Map representation of a live connection to a BlobStore. All put operations will result in ETag
|
||||
|
@ -71,7 +72,11 @@ public class InputStreamMapImpl extends BaseBlobMap<InputStream> implements Inpu
|
|||
public InputStream get(Object o) {
|
||||
String realKey = prefixer.apply(o.toString());
|
||||
Blob blob = blobstore.getBlob(containerName, realKey);
|
||||
return blob != null ? blob.getContent() : null;
|
||||
return getInputStreamOrNull(blob);
|
||||
}
|
||||
|
||||
private InputStream getInputStreamOrNull(Blob blob) {
|
||||
return blob != null ? blob.getPayload() != null ? blob.getPayload().getInput() : null : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -84,10 +89,10 @@ public class InputStreamMapImpl extends BaseBlobMap<InputStream> implements Inpu
|
|||
|
||||
@Override
|
||||
public Collection<InputStream> values() {
|
||||
return Lists.newArrayList(Iterables.transform(getAllBlobs.execute(containerName, options),
|
||||
return newArrayList(transform(getAllBlobs.execute(containerName, options),
|
||||
new Function<Blob, InputStream>() {
|
||||
public InputStream apply(Blob from) {
|
||||
return from.getContent();
|
||||
return getInputStreamOrNull(from);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
@ -120,12 +125,12 @@ public class InputStreamMapImpl extends BaseBlobMap<InputStream> implements Inpu
|
|||
*/
|
||||
@VisibleForTesting
|
||||
void putAllInternal(Map<? extends String, ? extends Object> map) {
|
||||
putBlobsStrategy.execute(containerName, Iterables.transform(map.entrySet(),
|
||||
putBlobsStrategy.execute(containerName, transform(map.entrySet(),
|
||||
new Function<Map.Entry<? extends String, ? extends Object>, Blob>() {
|
||||
@Override
|
||||
public Blob apply(Map.Entry<? extends String, ? extends Object> from) {
|
||||
Blob blob = blobstore.newBlob(prefixer.apply(from.getKey()));
|
||||
blob.setPayload(Payloads.newPayload(from.getValue()));
|
||||
blob.setPayload(newPayload(from.getValue()));
|
||||
blob.generateMD5();
|
||||
return blob;
|
||||
}
|
||||
|
|
|
@ -23,8 +23,10 @@ import javax.inject.Singleton;
|
|||
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.StorageType;
|
||||
import org.jclouds.blobstore.reference.BlobStoreConstants;
|
||||
import org.jclouds.blobstore.strategy.MkdirStrategy;
|
||||
import org.jclouds.http.Payloads;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
|
@ -50,8 +52,9 @@ public class MarkerFileMkdirStrategy implements MkdirStrategy {
|
|||
|
||||
public void execute(String containerName, String directory) {
|
||||
Blob blob = connection.newBlob(directory + directorySuffix);
|
||||
blob.setPayload("");
|
||||
blob.getMetadata().setContentType("application/directory");
|
||||
blob.setPayload(Payloads.newByteArrayPayload(new byte[] {}));
|
||||
blob.getPayload().setContentType("application/directory");
|
||||
blob.getMetadata().setType(StorageType.RELATIVE_PATH);
|
||||
connection.putBlob(containerName, blob);
|
||||
}
|
||||
}
|
|
@ -19,6 +19,8 @@
|
|||
package org.jclouds.blobstore.util;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static org.jclouds.util.Utils.getSupportedProvidersOfType;
|
||||
import static org.jclouds.util.Utils.toStringAndClose;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -36,7 +38,6 @@ import org.jclouds.blobstore.domain.StorageMetadata;
|
|||
import org.jclouds.functions.ExceptionToValueOrPropagate;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
||||
import org.jclouds.util.Utils;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -118,11 +119,12 @@ public class BlobStoreUtils {
|
|||
|
||||
public static String getContentAsStringOrNullAndClose(Blob blob) throws IOException {
|
||||
checkNotNull(blob, "blob");
|
||||
if (blob.getContent() == null)
|
||||
checkNotNull(blob.getPayload(), "blob.payload");
|
||||
if (blob.getPayload().getInput() == null)
|
||||
return null;
|
||||
Object o = blob.getContent();
|
||||
Object o = blob.getPayload().getInput();
|
||||
if (o instanceof InputStream) {
|
||||
return Utils.toStringAndClose((InputStream) o);
|
||||
return toStringAndClose((InputStream) o);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Object type not supported: " + o.getClass().getName());
|
||||
}
|
||||
|
@ -137,6 +139,6 @@ public class BlobStoreUtils {
|
|||
}
|
||||
|
||||
public static Iterable<String> getSupportedProviders() {
|
||||
return Utils.getSupportedProvidersOfType(BlobStoreContextBuilder.class);
|
||||
return getSupportedProvidersOfType(BlobStoreContextBuilder.class);
|
||||
}
|
||||
}
|
|
@ -18,20 +18,19 @@
|
|||
*/
|
||||
package org.jclouds.blobstore.binders;
|
||||
|
||||
import static org.jclouds.http.payloads.MultipartForm.BOUNDARY;
|
||||
import static org.jclouds.util.Utils.toStringAndClose;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.Blob.Factory;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.rest.RestContextFactory;
|
||||
import org.jclouds.util.Utils;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
|
@ -42,8 +41,6 @@ import org.testng.annotations.Test;
|
|||
@Test(testName = "blobstore.BindBlobToMultipartFormTest")
|
||||
public class BindBlobToMultipartFormTest {
|
||||
private static Factory blobProvider;
|
||||
|
||||
public static String BOUNDRY = BindBlobToMultipartForm.BOUNDARY;
|
||||
public static final String EXPECTS;
|
||||
public static final Blob TEST_BLOB;
|
||||
|
||||
|
@ -51,8 +48,8 @@ public class BindBlobToMultipartFormTest {
|
|||
blobProvider = new RestContextFactory().createContextBuilder("transient", "identity",
|
||||
"credential").buildInjector().getInstance(Blob.Factory.class);
|
||||
StringBuilder builder = new StringBuilder("--");
|
||||
addData(BOUNDRY, "hello", builder);
|
||||
builder.append("--").append(BOUNDRY).append("--").append("\r\n");
|
||||
addData(BOUNDARY, "hello", builder);
|
||||
builder.append("--").append(BOUNDARY).append("--").append("\r\n");
|
||||
EXPECTS = builder.toString();
|
||||
TEST_BLOB = blobProvider.create(null);
|
||||
TEST_BLOB.getMetadata().setName("hello");
|
||||
|
@ -69,12 +66,11 @@ public class BindBlobToMultipartFormTest {
|
|||
HttpRequest request = new HttpRequest("GET", URI.create("http://localhost:8001"));
|
||||
binder.bindToRequest(request, TEST_BLOB);
|
||||
|
||||
assertEquals(Utils.toStringAndClose((InputStream) request.getPayload().getRawContent()),
|
||||
EXPECTS);
|
||||
assertEquals(request.getFirstHeaderOrNull(HttpHeaders.CONTENT_LENGTH), 113 + "");
|
||||
assertEquals(toStringAndClose(request.getPayload().getInput()), EXPECTS);
|
||||
assertEquals(request.getPayload().getContentLength(), new Long(113));
|
||||
|
||||
assertEquals(request.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE),
|
||||
"multipart/form-data; boundary=" + BOUNDRY);
|
||||
assertEquals(request.getPayload().getContentType(), "multipart/form-data; boundary="
|
||||
+ BOUNDARY);
|
||||
}
|
||||
|
||||
private static void addData(String boundary, String data, StringBuilder builder) {
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed 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.blobstore.domain.internal;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.jclouds.blobstore.domain.MutableBlobMetadata;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
@Test(groups = "unit", testName = "blobstore.MutableBlobMetadataImpl")
|
||||
public class MutableBlobMetadataImplTest {
|
||||
|
||||
@Test
|
||||
void testSetNoContentType() {
|
||||
MutableBlobMetadata object = new MutableBlobMetadataImpl();
|
||||
assertEquals(object.getContentType(), MediaType.APPLICATION_OCTET_STREAM);
|
||||
}
|
||||
|
||||
}
|
|
@ -102,7 +102,7 @@ public class ParseBlobFromHeadersAndHttpContentTest {
|
|||
expect(response.getHeaders()).andReturn(
|
||||
ImmutableMultimap.of("Content-Length", "10485760", "Content-Range",
|
||||
"0-10485759/20232760"));
|
||||
meta.setSize(20232760);
|
||||
meta.setSize(20232760l);
|
||||
|
||||
expect(response.getStatusCode()).andReturn(200).atLeastOnce();
|
||||
expect(response.getContent()).andReturn(test);
|
||||
|
@ -112,7 +112,7 @@ public class ParseBlobFromHeadersAndHttpContentTest {
|
|||
replay(metadataParser);
|
||||
|
||||
Blob object = callable.apply(response);
|
||||
assertEquals(object.getContentLength(), new Long(10485760));
|
||||
assertEquals(object.getPayload().getContentLength(), new Long(10485760));
|
||||
assertEquals(object.getMetadata().getSize(), new Long(20232760));
|
||||
assertEquals(object.getAllHeaders().get("Content-Range"), Collections
|
||||
.singletonList("0-10485759/20232760"));
|
||||
|
|
|
@ -48,10 +48,10 @@ import org.jclouds.blobstore.domain.PageSet;
|
|||
import org.jclouds.blobstore.domain.StorageMetadata;
|
||||
import org.jclouds.blobstore.domain.StorageType;
|
||||
import org.jclouds.encryption.EncryptionService;
|
||||
import org.jclouds.encryption.EncryptionService.MD5InputStreamResult;
|
||||
import org.jclouds.encryption.internal.JCEEncryptionService;
|
||||
import org.jclouds.http.BaseJettyTest;
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.http.Payload;
|
||||
import org.jclouds.http.Payloads;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.util.Utils;
|
||||
|
@ -77,17 +77,15 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
|
|||
private byte[] oneHundredOneConstitutions;
|
||||
private EncryptionService encryptionService;
|
||||
private byte[] oneHundredOneConstitutionsMD5;
|
||||
private long oneHundredOneConstitutionsLength;
|
||||
|
||||
@BeforeClass(groups = { "integration", "live" })
|
||||
@Override
|
||||
public void setUpResourcesOnThisThread(ITestContext testContext) throws Exception {
|
||||
encryptionService = Guice.createInjector().getInstance(EncryptionService.class);
|
||||
MD5InputStreamResult result = encryptionService.md5Result(getTestDataSupplier()
|
||||
.getInput());
|
||||
oneHundredOneConstitutions = result.data;
|
||||
oneHundredOneConstitutionsMD5 = result.md5;
|
||||
oneHundredOneConstitutionsLength = result.length;
|
||||
Payload result = encryptionService
|
||||
.generatePayloadWithMD5For(getTestDataSupplier().getInput());
|
||||
oneHundredOneConstitutions = (byte[]) result.getRawContent();
|
||||
oneHundredOneConstitutionsMD5 = result.getContentMD5();
|
||||
super.setUpResourcesOnThisThread(testContext);
|
||||
}
|
||||
|
||||
|
@ -121,7 +119,7 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
|
|||
|
||||
@Override
|
||||
public Void apply(Blob from) {
|
||||
assertEquals(encryptionService.md5(from.getContent()),
|
||||
assertEquals(encryptionService.md5(from.getPayload().getInput()),
|
||||
oneHundredOneConstitutionsMD5);
|
||||
return null;
|
||||
}
|
||||
|
@ -142,7 +140,6 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
|
|||
Blob sourceObject = context.getBlobStore().newBlob(key);
|
||||
sourceObject.getMetadata().setContentType("text/plain");
|
||||
sourceObject.getMetadata().setContentMD5(oneHundredOneConstitutionsMD5);
|
||||
sourceObject.setContentLength(oneHundredOneConstitutionsLength);
|
||||
sourceObject.setPayload(oneHundredOneConstitutions);
|
||||
context.getBlobStore().putBlob(containerName, sourceObject);
|
||||
}
|
||||
|
|
|
@ -62,14 +62,13 @@ public class BaseBlobLiveTest extends BaseBlobStoreIntegrationTest {
|
|||
byte[] md5 = new JCEEncryptionService().fromHex(httpStreamETag);
|
||||
|
||||
URLConnection connection = url.openConnection();
|
||||
int length = connection.getContentLength();
|
||||
long length = connection.getContentLength();
|
||||
InputStream input = connection.getInputStream();
|
||||
|
||||
Blob object = context.getBlobStore().newBlob(key);
|
||||
object.setPayload(input);
|
||||
object.setContentLength(length);
|
||||
object.getMetadata().setContentMD5(md5);
|
||||
object.getMetadata().setSize(new Long(length));
|
||||
object.getPayload().setContentLength(length);
|
||||
object.getPayload().setContentMD5(md5);
|
||||
String bucketName = getContainerName();
|
||||
try {
|
||||
context.getBlobStore().putBlob(bucketName, object);
|
||||
|
|
|
@ -195,7 +195,7 @@ public abstract class BaseBlobMapIntegrationTest extends BaseMapIntegrationTest<
|
|||
for (String key : fiveInputs.keySet()) {
|
||||
Blob object = context.getBlobStore().newBlob(key);
|
||||
object.setPayload(fiveInputs.get(key));
|
||||
object.setContentLength(new Long(fiveBytes.get(key).length));
|
||||
object.getPayload().setContentLength((long) fiveBytes.get(key).length);
|
||||
newMap.put(key, object);
|
||||
}
|
||||
map.putAll(newMap);
|
||||
|
|
|
@ -243,8 +243,8 @@ public class BaseBlobStoreIntegrationTest {
|
|||
|
||||
protected String addBlobToContainer(String sourceContainer, String key) {
|
||||
Blob sourceObject = context.getBlobStore().newBlob(key);
|
||||
sourceObject.getMetadata().setContentType("text/xml");
|
||||
sourceObject.setPayload(TEST_STRING);
|
||||
sourceObject.getMetadata().setContentType("text/xml");
|
||||
return addBlobToContainer(sourceContainer, sourceObject);
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ import org.jclouds.chef.binders.BindIsCompletedToJsonPayload;
|
|||
import org.jclouds.chef.binders.BindHexEncodedMD5sToJsonPayload;
|
||||
import org.jclouds.chef.domain.CookbookVersion;
|
||||
import org.jclouds.chef.domain.Sandbox;
|
||||
import org.jclouds.chef.domain.UploadSite;
|
||||
import org.jclouds.chef.domain.UploadSandbox;
|
||||
import org.jclouds.chef.filters.SignedHeaderAuth;
|
||||
import org.jclouds.chef.functions.ParseCookbookVersionFromJson;
|
||||
import org.jclouds.chef.functions.ParseKeyFromJson;
|
||||
|
@ -76,21 +76,25 @@ public interface ChefAsyncClient {
|
|||
public static final String VERSION = "0.9.6";
|
||||
|
||||
/**
|
||||
* @see ChefClient#getUploadUrisForChecksums
|
||||
* @see ChefClient#getUploadSandboxForChecksums
|
||||
*/
|
||||
@POST
|
||||
@Path("sandboxes")
|
||||
@ResponseParser(ParseUploadSiteFromJson.class)
|
||||
ListenableFuture<UploadSite> getUploadSiteForHexEncodedChecksums(
|
||||
ListenableFuture<UploadSandbox> getUploadSandboxForChecksums(
|
||||
@BinderParam(BindHexEncodedMD5sToJsonPayload.class) Set<String> hexEncodedmd5s);
|
||||
|
||||
@PUT
|
||||
ListenableFuture<Void> uploadContent(
|
||||
@BinderParam(BindHexEncodedMD5sToJsonPayload.class) Set<String> hexEncodedmd5s);
|
||||
|
||||
/**
|
||||
* @see ChefClient#closeSandbox
|
||||
* @see ChefClient#commitSandbox
|
||||
*/
|
||||
@PUT
|
||||
@Path("sandboxes/{id}")
|
||||
@ResponseParser(ParseSandboxFromJson.class)
|
||||
ListenableFuture<Sandbox> closeSandbox(@PathParam("id") String id,
|
||||
ListenableFuture<Sandbox> commitSandbox(@PathParam("id") String id,
|
||||
@BinderParam(BindIsCompletedToJsonPayload.class) boolean isCompleted);
|
||||
|
||||
/**
|
||||
|
|
|
@ -46,7 +46,7 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import org.jclouds.chef.domain.CookbookVersion;
|
||||
import org.jclouds.chef.domain.Sandbox;
|
||||
import org.jclouds.chef.domain.UploadSite;
|
||||
import org.jclouds.chef.domain.UploadSandbox;
|
||||
import org.jclouds.concurrent.Timeout;
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.rest.AuthorizationException;
|
||||
|
@ -61,9 +61,9 @@ import org.jclouds.rest.AuthorizationException;
|
|||
*/
|
||||
@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
|
||||
public interface ChefClient {
|
||||
UploadSite getUploadSiteForHexEncodedChecksums(Set<String> hexEncodedmd5s);
|
||||
UploadSandbox getUploadSandboxForChecksums(Set<String> hexEncodedmd5s);
|
||||
|
||||
Sandbox closeSandbox(String id, boolean isCompleted);
|
||||
Sandbox commitSandbox(String id, boolean isCompleted);
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -28,19 +28,19 @@ import com.google.gson.annotations.SerializedName;
|
|||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class UploadSite {
|
||||
public class UploadSandbox {
|
||||
private URI uri;
|
||||
private Map<String, ChecksumStatus> checksums = Maps.newLinkedHashMap();
|
||||
@SerializedName("sandbox_id")
|
||||
private String sandboxId;
|
||||
|
||||
public UploadSite(URI uri, Map<String, ChecksumStatus> checksums, String sandboxId) {
|
||||
public UploadSandbox(URI uri, Map<String, ChecksumStatus> checksums, String sandboxId) {
|
||||
this.uri = uri;
|
||||
this.checksums.putAll(checksums);
|
||||
this.sandboxId = sandboxId;
|
||||
}
|
||||
|
||||
public UploadSite() {
|
||||
public UploadSandbox() {
|
||||
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,7 @@ public class UploadSite {
|
|||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
UploadSite other = (UploadSite) obj;
|
||||
UploadSandbox other = (UploadSandbox) obj;
|
||||
if (checksums == null) {
|
||||
if (other.checksums != null)
|
||||
return false;
|
|
@ -43,11 +43,11 @@ import org.jclouds.http.HttpException;
|
|||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpRequestFilter;
|
||||
import org.jclouds.http.HttpUtils;
|
||||
import org.jclouds.http.MultipartForm;
|
||||
import org.jclouds.http.Payload;
|
||||
import org.jclouds.http.Payloads;
|
||||
import org.jclouds.http.MultipartForm.Part;
|
||||
import org.jclouds.http.internal.SignatureWire;
|
||||
import org.jclouds.http.payloads.MultipartForm;
|
||||
import org.jclouds.http.payloads.Part;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.util.Utils;
|
||||
|
||||
|
@ -169,7 +169,7 @@ public class SignedHeaderAuth implements HttpRequestFilter {
|
|||
|
||||
private Payload useTheFilePartIfForm(Payload payload) {
|
||||
if (payload instanceof MultipartForm) {
|
||||
Iterable<? extends Part> parts = MultipartForm.class.cast(payload).getParts();
|
||||
Iterable<? extends Part> parts = MultipartForm.class.cast(payload).getRawContent();
|
||||
try {
|
||||
payload = Iterables.find(parts, new Predicate<Part>() {
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ import java.io.UnsupportedEncodingException;
|
|||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.chef.domain.UploadSite;
|
||||
import org.jclouds.chef.domain.UploadSandbox;
|
||||
import org.jclouds.http.functions.ParseJson;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
@ -41,17 +41,17 @@ import com.google.gson.Gson;
|
|||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class ParseUploadSiteFromJson extends ParseJson<UploadSite> {
|
||||
public class ParseUploadSiteFromJson extends ParseJson<UploadSandbox> {
|
||||
@Inject
|
||||
public ParseUploadSiteFromJson(Gson gson) {
|
||||
super(gson);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UploadSite apply(InputStream stream) {
|
||||
protected UploadSandbox apply(InputStream stream) {
|
||||
try {
|
||||
return gson.fromJson(new InputStreamReader(stream, "UTF-8"),
|
||||
UploadSite.class);
|
||||
UploadSandbox.class);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException("jclouds requires UTF-8 encoding", e);
|
||||
}
|
||||
|
|
|
@ -69,9 +69,9 @@ import com.google.inject.TypeLiteral;
|
|||
@Test(groups = "unit", testName = "chef.ChefAsyncClientTest")
|
||||
public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
|
||||
|
||||
public void testCloseSandbox() throws SecurityException, NoSuchMethodException, IOException {
|
||||
public void testCommitSandbox() throws SecurityException, NoSuchMethodException, IOException {
|
||||
|
||||
Method method = ChefAsyncClient.class.getMethod("closeSandbox", String.class, boolean.class);
|
||||
Method method = ChefAsyncClient.class.getMethod("commitSandbox", String.class, boolean.class);
|
||||
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method,
|
||||
"0189e76ccc476701d6b374e5a1a27347", true);
|
||||
assertRequestLineEquals(httpRequest,
|
||||
|
@ -89,10 +89,10 @@ public class ChefAsyncClientTest extends RestClientTest<ChefAsyncClient> {
|
|||
|
||||
}
|
||||
|
||||
public void testGetUploadSiteForHexEncodedChecksums() throws SecurityException,
|
||||
public void testGetUploadSandboxForChecksums() throws SecurityException,
|
||||
NoSuchMethodException, IOException {
|
||||
|
||||
Method method = ChefAsyncClient.class.getMethod("getUploadSiteForHexEncodedChecksums",
|
||||
Method method = ChefAsyncClient.class.getMethod("getUploadSandboxForChecksums",
|
||||
Set.class);
|
||||
GeneratedHttpRequest<ChefAsyncClient> httpRequest = processor.createRequest(method,
|
||||
ImmutableSet.of("0189e76ccc476701d6b374e5a1a27347",
|
||||
|
|
|
@ -37,7 +37,7 @@ import javax.ws.rs.core.HttpHeaders;
|
|||
import org.jclouds.chef.domain.ChecksumStatus;
|
||||
import org.jclouds.chef.domain.CookbookVersion;
|
||||
import org.jclouds.chef.domain.Resource;
|
||||
import org.jclouds.chef.domain.UploadSite;
|
||||
import org.jclouds.chef.domain.UploadSandbox;
|
||||
import org.jclouds.http.Payload;
|
||||
import org.jclouds.http.Payloads;
|
||||
import org.jclouds.http.options.BaseHttpRequestOptions;
|
||||
|
@ -142,7 +142,7 @@ public class ChefClientLiveTest {
|
|||
|
||||
// request an upload site for this file
|
||||
// TODO: this json ball is not named, and is different than SandBox, using UploadSite for now
|
||||
UploadSite site = adminConnection.getApi().getUploadSiteForHexEncodedChecksums(ImmutableSet.of(md5Hex));
|
||||
UploadSandbox site = adminConnection.getApi().getUploadSandboxForChecksums(ImmutableSet.of(md5Hex));
|
||||
|
||||
try {
|
||||
assert site.getChecksums().containsKey(md5Hex) : md5Hex + " not in " + site.getChecksums();
|
||||
|
@ -156,10 +156,10 @@ public class ChefClientLiveTest {
|
|||
}
|
||||
|
||||
// if we were able to get here, close the sandbox
|
||||
adminConnection.getApi().closeSandbox(site.getSandboxId(), true);
|
||||
adminConnection.getApi().commitSandbox(site.getSandboxId(), true);
|
||||
|
||||
} catch (RuntimeException e) {
|
||||
adminConnection.getApi().closeSandbox(site.getSandboxId(), false);
|
||||
adminConnection.getApi().commitSandbox(site.getSandboxId(), false);
|
||||
}
|
||||
|
||||
// create a new cookbook
|
||||
|
|
|
@ -6,7 +6,7 @@ import java.io.IOException;
|
|||
import java.net.URI;
|
||||
|
||||
import org.jclouds.chef.domain.ChecksumStatus;
|
||||
import org.jclouds.chef.domain.UploadSite;
|
||||
import org.jclouds.chef.domain.UploadSandbox;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.functions.config.ParserModule;
|
||||
import org.testng.annotations.BeforeTest;
|
||||
|
@ -36,7 +36,7 @@ public class ParseUploadSiteFromJsonTest {
|
|||
assertEquals(
|
||||
handler.apply(new HttpResponse(ParseUploadSiteFromJsonTest.class
|
||||
.getResourceAsStream("/upload-site.json"))),
|
||||
new UploadSite(
|
||||
new UploadSandbox(
|
||||
URI
|
||||
.create("https://api.opscode.com/organizations/jclouds/sandboxes/d454f71e2a5f400c808d0c5d04c2c88c"),
|
||||
ImmutableMap
|
||||
|
|
|
@ -189,33 +189,33 @@ public class MutableResourceMetadataImpl<T extends Enum<T>> implements MutableRe
|
|||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
if (!(obj instanceof MutableResourceMetadata<?>))
|
||||
return false;
|
||||
MutableResourceMetadataImpl<?> other = (MutableResourceMetadataImpl<?>) obj;
|
||||
MutableResourceMetadata<?> other = (MutableResourceMetadata<?>) obj;
|
||||
if (id == null) {
|
||||
if (other.id != null)
|
||||
if (other.getProviderId() != null)
|
||||
return false;
|
||||
} else if (!id.equals(other.id))
|
||||
} else if (!id.equals(other.getProviderId()))
|
||||
return false;
|
||||
if (location == null) {
|
||||
if (other.location != null)
|
||||
if (other.getLocation() != null)
|
||||
return false;
|
||||
} else if (!location.equals(other.location))
|
||||
} else if (!location.equals(other.getLocation()))
|
||||
return false;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
if (other.getName() != null)
|
||||
return false;
|
||||
} else if (!name.equals(other.name))
|
||||
} else if (!name.equals(other.getName()))
|
||||
return false;
|
||||
if (type == null) {
|
||||
if (other.type != null)
|
||||
if (other.getType() != null)
|
||||
return false;
|
||||
} else if (!type.equals(other.type))
|
||||
} else if (!type.equals(other.getType()))
|
||||
return false;
|
||||
if (uri == null) {
|
||||
if (other.uri != null)
|
||||
if (other.getUri() != null)
|
||||
return false;
|
||||
} else if (!uri.equals(other.uri))
|
||||
} else if (!uri.equals(other.getUri()))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -18,15 +18,14 @@
|
|||
*/
|
||||
package org.jclouds.encryption;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.security.Key;
|
||||
|
||||
import org.jclouds.encryption.internal.JCEEncryptionService;
|
||||
import org.jclouds.http.Payload;
|
||||
import org.jclouds.http.payloads.ByteArrayPayload;
|
||||
|
||||
import com.google.inject.ImplementedBy;
|
||||
|
||||
|
@ -56,7 +55,9 @@ public interface EncryptionService {
|
|||
|
||||
byte[] md5(InputStream toEncode);
|
||||
|
||||
MD5InputStreamResult md5Result(InputStream toEncode);
|
||||
Payload generateMD5BufferingIfNotRepeatable(Payload in);
|
||||
|
||||
ByteArrayPayload generatePayloadWithMD5For(InputStream toEncode);
|
||||
|
||||
MD5OutputStream md5OutputStream(OutputStream out);
|
||||
|
||||
|
@ -68,18 +69,4 @@ public interface EncryptionService {
|
|||
public abstract byte[] getMD5();
|
||||
}
|
||||
|
||||
public static class MD5InputStreamResult {
|
||||
public final byte[] data;
|
||||
public final byte[] md5;
|
||||
public final long length;
|
||||
|
||||
public MD5InputStreamResult(byte[] data, byte[] md5, long length) {
|
||||
this.data = checkNotNull(data, "data");
|
||||
this.md5 = checkNotNull(md5, "md5");
|
||||
checkArgument(length >= 0, "length cannot me negative");
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -18,9 +18,12 @@
|
|||
*/
|
||||
package org.jclouds.encryption.internal;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import org.jclouds.encryption.EncryptionService;
|
||||
import org.jclouds.http.Payload;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -60,4 +63,17 @@ public abstract class BaseEncryptionService implements EncryptionService {
|
|||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Payload generateMD5BufferingIfNotRepeatable(Payload payload) {
|
||||
checkNotNull(payload, "payload");
|
||||
if (!payload.isRepeatable()) {
|
||||
String oldContentType = payload.getContentType();
|
||||
payload = generatePayloadWithMD5For(payload.getInput());
|
||||
payload.setContentType(oldContentType);
|
||||
} else {
|
||||
payload.setContentMD5(md5(payload.getInput()));
|
||||
}
|
||||
return payload;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,8 @@ import javax.crypto.Cipher;
|
|||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import org.jclouds.http.payloads.ByteArrayPayload;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.io.Closeables;
|
||||
|
||||
|
@ -99,7 +101,7 @@ public class JCEEncryptionService extends BaseEncryptionService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public MD5InputStreamResult md5Result(InputStream toEncode) {
|
||||
public ByteArrayPayload generatePayloadWithMD5For(InputStream toEncode) {
|
||||
MessageDigest eTag = getDigest();
|
||||
byte[] buffer = new byte[1024];
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
|
@ -120,7 +122,7 @@ public class JCEEncryptionService extends BaseEncryptionService {
|
|||
Closeables.closeQuietly(out);
|
||||
Closeables.closeQuietly(toEncode);
|
||||
}
|
||||
return new MD5InputStreamResult(out.toByteArray(), eTag.digest(), length);
|
||||
return new ByteArrayPayload(out.toByteArray(), eTag.digest());
|
||||
}
|
||||
|
||||
private static MessageDigest getDigest() {
|
||||
|
@ -201,4 +203,5 @@ public class JCEEncryptionService extends BaseEncryptionService {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ package org.jclouds.http;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.io.Closeables.closeQuietly;
|
||||
import static com.google.inject.internal.Lists.newArrayList;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
|
@ -27,11 +29,7 @@ import java.net.URI;
|
|||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.io.Closeables;
|
||||
import com.google.inject.internal.Lists;
|
||||
import com.google.inject.internal.Nullable;
|
||||
|
||||
/**
|
||||
|
@ -41,7 +39,7 @@ import com.google.inject.internal.Nullable;
|
|||
*/
|
||||
public class HttpRequest extends HttpMessage {
|
||||
|
||||
private List<HttpRequestFilter> requestFilters = Lists.newArrayList();
|
||||
private List<HttpRequestFilter> requestFilters = newArrayList();
|
||||
private String method;
|
||||
private URI endpoint;
|
||||
private Payload payload;
|
||||
|
@ -113,7 +111,6 @@ public class HttpRequest extends HttpMessage {
|
|||
public void setPayload(Payload data) {
|
||||
closeContentIfPresent();
|
||||
this.payload = checkNotNull(data, "data");
|
||||
setLength();
|
||||
}
|
||||
|
||||
public void setPayload(InputStream data) {
|
||||
|
@ -132,13 +129,6 @@ public class HttpRequest extends HttpMessage {
|
|||
setPayload(Payloads.newPayload(checkNotNull(data, "data")));
|
||||
}
|
||||
|
||||
private void setLength() {
|
||||
Long size = getPayload().calculateSize();
|
||||
if (size != null && this.getFirstHeaderOrNull(HttpHeaders.CONTENT_LENGTH) == null) {
|
||||
getHeaders().put(HttpHeaders.CONTENT_LENGTH, size.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* characters to skip encoding on.
|
||||
*/
|
||||
|
@ -178,7 +168,7 @@ public class HttpRequest extends HttpMessage {
|
|||
|
||||
private void closeContentIfPresent() {
|
||||
if (getPayload() != null && getPayload().getInput() != null) {
|
||||
Closeables.closeQuietly(getPayload().getInput());
|
||||
closeQuietly(getPayload().getInput());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,8 +19,14 @@
|
|||
package org.jclouds.http;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.base.Throwables.propagate;
|
||||
import static com.google.common.collect.Lists.newArrayList;
|
||||
import static com.google.common.collect.Sets.newTreeSet;
|
||||
import static com.google.common.io.ByteStreams.toByteArray;
|
||||
import static com.google.common.io.Closeables.closeQuietly;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static javax.ws.rs.core.HttpHeaders.HOST;
|
||||
import static org.jclouds.http.Payloads.newUrlEncodedFormPayload;
|
||||
import static org.jclouds.util.Patterns.CHAR_TO_ENCODED_PATTERN;
|
||||
import static org.jclouds.util.Patterns.PATTERN_THAT_BREAKS_URI;
|
||||
import static org.jclouds.util.Patterns.PLUS_PATTERN;
|
||||
|
@ -28,6 +34,7 @@ import static org.jclouds.util.Patterns.STAR_PATTERN;
|
|||
import static org.jclouds.util.Patterns.URI_PATTERN;
|
||||
import static org.jclouds.util.Patterns.URL_ENCODED_PATTERN;
|
||||
import static org.jclouds.util.Patterns._7E_PATTERN;
|
||||
import static org.jclouds.util.Utils.replaceAll;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -50,24 +57,18 @@ import javax.annotation.Nullable;
|
|||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import javax.ws.rs.HttpMethod;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
|
||||
import org.jclouds.Constants;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.util.Utils;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.LinkedListMultimap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.SortedSetMultimap;
|
||||
import com.google.common.collect.TreeMultimap;
|
||||
import com.google.common.io.Closeables;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
|
@ -186,11 +187,11 @@ public class HttpUtils {
|
|||
return in;
|
||||
try {
|
||||
String returnVal = URLEncoder.encode(in, "UTF-8");
|
||||
returnVal = Utils.replaceAll(returnVal, '+', PLUS_PATTERN, "%20");
|
||||
returnVal = Utils.replaceAll(returnVal, '*', STAR_PATTERN, "%2A");
|
||||
returnVal = Utils.replaceAll(returnVal, _7E_PATTERN, "~");
|
||||
returnVal = replaceAll(returnVal, '+', PLUS_PATTERN, "%20");
|
||||
returnVal = replaceAll(returnVal, '*', STAR_PATTERN, "%2A");
|
||||
returnVal = replaceAll(returnVal, _7E_PATTERN, "~");
|
||||
for (char c : skipEncode) {
|
||||
returnVal = Utils.replaceAll(returnVal, CHAR_TO_ENCODED_PATTERN.get(c), c + "");
|
||||
returnVal = replaceAll(returnVal, CHAR_TO_ENCODED_PATTERN.get(c), c + "");
|
||||
}
|
||||
return returnVal;
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
|
@ -218,9 +219,9 @@ public class HttpUtils {
|
|||
try {
|
||||
toByteArray(response.getContent());
|
||||
} catch (IOException e) {
|
||||
Throwables.propagate(e);
|
||||
propagate(e);
|
||||
} finally {
|
||||
Closeables.closeQuietly(response.getContent());
|
||||
closeQuietly(response.getContent());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -235,9 +236,9 @@ public class HttpUtils {
|
|||
response.setContent(new ByteArrayInputStream(data));
|
||||
return data;
|
||||
} catch (IOException e) {
|
||||
Throwables.propagate(e);
|
||||
propagate(e);
|
||||
} finally {
|
||||
Closeables.closeQuietly(response.getContent());
|
||||
closeQuietly(response.getContent());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -270,21 +271,21 @@ public class HttpUtils {
|
|||
*
|
||||
*/
|
||||
public static URI createUri(String uriPath) {
|
||||
List<String> onQuery = Lists.newArrayList(Splitter.on('?').split(uriPath));
|
||||
List<String> onQuery = newArrayList(Splitter.on('?').split(uriPath));
|
||||
if (onQuery.size() == 2) {
|
||||
onQuery.add(urlEncode(onQuery.remove(1), '=', '&'));
|
||||
uriPath = Joiner.on('?').join(onQuery);
|
||||
}
|
||||
if (uriPath.indexOf('@') != 1) {
|
||||
List<String> parts = Lists.newArrayList(Splitter.on('@').split(uriPath));
|
||||
List<String> parts = newArrayList(Splitter.on('@').split(uriPath));
|
||||
String path = parts.remove(parts.size() - 1);
|
||||
if (parts.size() > 1) {
|
||||
parts = Lists.newArrayList(urlEncode(Joiner.on('@').join(parts), '/', ':'));
|
||||
parts = newArrayList(urlEncode(Joiner.on('@').join(parts), '/', ':'));
|
||||
}
|
||||
parts.add(urlEncode(path, '/', ':'));
|
||||
uriPath = Joiner.on('@').join(parts);
|
||||
} else {
|
||||
List<String> parts = Lists.newArrayList(Splitter.on('/').split(uriPath));
|
||||
List<String> parts = newArrayList(Splitter.on('/').split(uriPath));
|
||||
String path = parts.remove(parts.size() - 1);
|
||||
parts.add(urlEncode(path, ':'));
|
||||
uriPath = Joiner.on('/').join(parts);
|
||||
|
@ -341,7 +342,7 @@ public class HttpUtils {
|
|||
} while (numRead != -1);
|
||||
} finally {
|
||||
output.close();
|
||||
Closeables.closeQuietly(input);
|
||||
closeQuietly(input);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -368,7 +369,7 @@ public class HttpUtils {
|
|||
builder.host(host);
|
||||
builder.port(port);
|
||||
request.setEndpoint(builder.build());
|
||||
request.getHeaders().replaceValues(HttpHeaders.HOST, singletonList(host));
|
||||
request.getHeaders().replaceValues(HOST, singletonList(host));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -425,10 +426,11 @@ public class HttpUtils {
|
|||
}
|
||||
|
||||
public static void addFormParamTo(HttpRequest request, String key, Iterable<?> values) {
|
||||
Multimap<String, String> map = parseQueryToMap(request.getPayload().toString());
|
||||
Multimap<String, String> map;
|
||||
map = parseQueryToMap(request.getPayload().getRawContent().toString());
|
||||
for (Object o : values)
|
||||
map.put(key, o.toString());
|
||||
request.setPayload(makeQueryLine(map, null));
|
||||
request.setPayload(newUrlEncodedFormPayload(map));
|
||||
}
|
||||
|
||||
public static Multimap<String, String> parseQueryToMap(String in) {
|
||||
|
@ -440,7 +442,7 @@ public class HttpUtils {
|
|||
else
|
||||
map.put(in, null);
|
||||
} else {
|
||||
String[] parts = HttpUtils.urlDecode(in).split("&");
|
||||
String[] parts = urlDecode(in).split("&");
|
||||
for (String part : parts) {
|
||||
parseKeyValueFromStringToMap(part, map);
|
||||
}
|
||||
|
@ -461,23 +463,22 @@ public class HttpUtils {
|
|||
|
||||
public static SortedSet<Entry<String, String>> sortEntries(
|
||||
Collection<Map.Entry<String, String>> in, Comparator<Map.Entry<String, String>> sorter) {
|
||||
SortedSet<Entry<String, String>> entries = Sets.newTreeSet(sorter);
|
||||
SortedSet<Entry<String, String>> entries = newTreeSet(sorter);
|
||||
entries.addAll(in);
|
||||
return entries;
|
||||
}
|
||||
|
||||
public static String makeQueryLine(Multimap<String, String> params,
|
||||
@Nullable Comparator<Map.Entry<String, String>> sorter, char... skips) {
|
||||
|
||||
Iterator<Map.Entry<String, String>> pairs = ((sorter == null) ? params.entries()
|
||||
: sortEntries(params.entries(), sorter)).iterator();
|
||||
StringBuilder formBuilder = new StringBuilder();
|
||||
while (pairs.hasNext()) {
|
||||
Map.Entry<String, String> pair = pairs.next();
|
||||
formBuilder.append(HttpUtils.urlEncode(pair.getKey(), skips));
|
||||
formBuilder.append(urlEncode(pair.getKey(), skips));
|
||||
if (pair.getValue() != null && !pair.getValue().equals("")) {
|
||||
formBuilder.append("=");
|
||||
formBuilder.append(HttpUtils.urlEncode(pair.getValue(), skips));
|
||||
formBuilder.append(urlEncode(pair.getValue(), skips));
|
||||
}
|
||||
if (pairs.hasNext())
|
||||
formBuilder.append("&");
|
||||
|
|
|
@ -1,314 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed 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.http;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
|
||||
import org.jclouds.http.payloads.FilePayload;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Multimaps;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.google.common.io.Closeables;
|
||||
import com.google.common.io.InputSupplier;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class MultipartForm implements Payload {
|
||||
private static final String rn = "\r\n";
|
||||
private static final String dd = "--";
|
||||
|
||||
private final InputSupplier<? extends InputStream> chain;
|
||||
private long size;
|
||||
private boolean isRepeatable;
|
||||
private boolean written;
|
||||
private final Iterable<? extends Part> parts;
|
||||
|
||||
public MultipartForm(String boundary, Part... parts) {
|
||||
this(boundary, Lists.newArrayList(parts));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public MultipartForm(String boundary, Iterable<? extends Part> parts) {
|
||||
this.parts = parts;
|
||||
String boundaryrn = boundary + rn;
|
||||
isRepeatable = true;
|
||||
InputSupplier<? extends InputStream> chain = ByteStreams.join();
|
||||
for (Part part : parts) {
|
||||
if (!part.isRepeatable())
|
||||
isRepeatable = false;
|
||||
size += part.calculateSize();
|
||||
chain = ByteStreams.join(chain, addLengthAndReturnHeaders(boundaryrn, part), part,
|
||||
addLengthAndReturnRn());
|
||||
}
|
||||
chain = ByteStreams.join(chain, addLengthAndReturnFooter(boundary));
|
||||
this.chain = chain;
|
||||
}
|
||||
|
||||
private InputSupplier<? extends InputStream> addLengthAndReturnRn() {
|
||||
size += rn.length();
|
||||
return ByteStreams.newInputStreamSupplier(rn.getBytes());
|
||||
}
|
||||
|
||||
private InputSupplier<? extends InputStream> addLengthAndReturnHeaders(String boundaryrn,
|
||||
Part part) {
|
||||
StringBuilder builder = new StringBuilder(dd).append(boundaryrn);
|
||||
for (Entry<String, String> entry : part.getHeaders().entries()) {
|
||||
String header = String.format("%s: %s%s", entry.getKey(), entry.getValue(), rn);
|
||||
builder.append(header);
|
||||
}
|
||||
builder.append(rn);
|
||||
size += builder.length();
|
||||
return ByteStreams.newInputStreamSupplier(builder.toString().getBytes());
|
||||
}
|
||||
|
||||
private InputSupplier<? extends InputStream> addLengthAndReturnFooter(String boundary) {
|
||||
String end = dd + boundary + dd + rn;
|
||||
size += end.length();
|
||||
return ByteStreams.newInputStreamSupplier(end.getBytes());
|
||||
}
|
||||
|
||||
public MultipartForm(Part... parts) {
|
||||
this("__redrose__", parts);
|
||||
}
|
||||
|
||||
public static class Part implements Payload {
|
||||
private final String name;
|
||||
private final Multimap<String, String> headers;
|
||||
private final Payload delegate;
|
||||
|
||||
private static class PartMap extends LinkedHashMap<String, String> {
|
||||
|
||||
/** The serialVersionUID */
|
||||
private static final long serialVersionUID = -287387556008320212L;
|
||||
|
||||
static PartMap create(String name) {
|
||||
PartMap map = new PartMap();
|
||||
map.put("Content-Disposition", String.format("form-data; name=\"%s\"", checkNotNull(
|
||||
name, "name")));
|
||||
return map;
|
||||
}
|
||||
|
||||
static PartMap create(String name, String filename) {
|
||||
PartMap map = new PartMap();
|
||||
map.put("Content-Disposition", String.format("form-data; name=\"%s\"; filename=\"%s\"",
|
||||
checkNotNull(name, "name"), checkNotNull(filename, "filename")));
|
||||
return map;
|
||||
}
|
||||
|
||||
PartMap contentType(@Nullable String type) {
|
||||
if (type != null)
|
||||
put(HttpHeaders.CONTENT_TYPE, checkNotNull(type, "type"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public static PartMap create(String name, Payload delegate, PartOptions options) {
|
||||
String filename = options != null ? options.getFilename() : null;
|
||||
if (delegate instanceof FilePayload)
|
||||
filename = FilePayload.class.cast(delegate).getRawContent().getName();
|
||||
PartMap returnVal;
|
||||
returnVal = (filename != null) ? create(name, filename) : create(name);
|
||||
if (options != null)
|
||||
returnVal.contentType(options.getContentType());
|
||||
return returnVal;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private Part(String name, PartMap map, Payload delegate) {
|
||||
this.name = name;
|
||||
this.delegate = checkNotNull(delegate, "delegate");
|
||||
this.headers = ImmutableMultimap.copyOf(Multimaps.forMap((checkNotNull(map, "headers"))));
|
||||
}
|
||||
|
||||
public static class PartOptions {
|
||||
private String contentType;
|
||||
private String filename;
|
||||
|
||||
public PartOptions contentType(String contentType) {
|
||||
this.contentType = checkNotNull(contentType, "contentType");
|
||||
return this;
|
||||
}
|
||||
|
||||
public PartOptions filename(String filename) {
|
||||
this.filename = checkNotNull(filename, "filename");
|
||||
return this;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
public static PartOptions contentType(String contentType) {
|
||||
return new PartOptions().contentType(contentType);
|
||||
}
|
||||
|
||||
public static PartOptions filename(String filename) {
|
||||
return new PartOptions().filename(filename);
|
||||
}
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
}
|
||||
|
||||
public static Part create(String name, String value) {
|
||||
return new Part(name, PartMap.create(name), Payloads.newStringPayload(value));
|
||||
}
|
||||
|
||||
public static Part create(String name, Payload delegate, PartOptions options) {
|
||||
return new Part(name, PartMap.create(name, delegate, options), delegate);
|
||||
}
|
||||
|
||||
public Multimap<String, String> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long calculateSize() {
|
||||
return delegate.calculateSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInput() {
|
||||
return delegate.getInput();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getRawContent() {
|
||||
return delegate.getInput();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRepeatable() {
|
||||
return delegate.isRepeatable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(OutputStream outstream) throws IOException {
|
||||
delegate.writeTo(outstream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((delegate == null) ? 0 : delegate.hashCode());
|
||||
result = prime * result + ((headers == null) ? 0 : headers.hashCode());
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Part other = (Part) obj;
|
||||
if (delegate == null) {
|
||||
if (other.delegate != null)
|
||||
return false;
|
||||
} else if (!delegate.equals(other.delegate))
|
||||
return false;
|
||||
if (headers == null) {
|
||||
if (other.headers != null)
|
||||
return false;
|
||||
} else if (!headers.equals(other.headers))
|
||||
return false;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!name.equals(other.name))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long calculateSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInput() {
|
||||
try {
|
||||
return chain.getInput();
|
||||
} catch (IOException e) {
|
||||
Throwables.propagate(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getRawContent() {
|
||||
return getInput();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRepeatable() {
|
||||
return isRepeatable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(OutputStream outstream) throws IOException {
|
||||
checkState(!written || !isRepeatable,
|
||||
"InputStreams can only be writted to an outputstream once");
|
||||
written = true;
|
||||
InputStream in = getInput();
|
||||
try {
|
||||
ByteStreams.copy(getInput(), outstream);
|
||||
} finally {
|
||||
Closeables.closeQuietly(in);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MultipartForm [chain=" + chain + ", isRepeatable=" + isRepeatable + ", size=" + size
|
||||
+ ", written=" + written + "]";
|
||||
}
|
||||
|
||||
public Iterable<? extends Part> getParts() {
|
||||
return parts;
|
||||
}
|
||||
}
|
|
@ -22,6 +22,8 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.io.InputSupplier;
|
||||
|
||||
/**
|
||||
|
@ -51,9 +53,29 @@ public interface Payload extends InputSupplier<InputStream> {
|
|||
*/
|
||||
void writeTo(OutputStream outstream) throws IOException;
|
||||
|
||||
void setContentLength(@Nullable Long contentLength);
|
||||
|
||||
/**
|
||||
* Attempts to determine the size of the payload
|
||||
* Returns the total size of the payload, or the chunk that's available.
|
||||
* <p/>
|
||||
* Chunking is only used when {@link org.jclouds.http.GetOptions} is called with options like
|
||||
* tail, range, or startAt.
|
||||
*
|
||||
* @return the length in bytes that can be be obtained from {@link #getInput()}
|
||||
* @see javax.ws.rs.core.HttpHeaders#CONTENT_LENGTH
|
||||
* @see org.jclouds.http.options.GetOptions
|
||||
*/
|
||||
Long calculateSize();
|
||||
@Nullable
|
||||
Long getContentLength();
|
||||
|
||||
void setContentMD5(@Nullable byte[] md5);
|
||||
|
||||
@Nullable
|
||||
byte[] getContentMD5();
|
||||
|
||||
void setContentType(@Nullable String md5);
|
||||
|
||||
@Nullable
|
||||
String getContentType();
|
||||
|
||||
}
|
|
@ -47,25 +47,6 @@ public interface PayloadEnclosing {
|
|||
|
||||
Payload getPayload();
|
||||
|
||||
/**
|
||||
* @return InputStream, if downloading, or whatever was set during {@link #setPayload(Payload)}
|
||||
*/
|
||||
InputStream getContent();
|
||||
|
||||
void setContentLength(long contentLength);
|
||||
|
||||
/**
|
||||
* Returns the total size of the downloaded object, or the chunk that's available.
|
||||
* <p/>
|
||||
* Chunking is only used when org.jclouds.http.GetOptions is called with options like tail,
|
||||
* range, or startAt.
|
||||
*
|
||||
* @return the length in bytes that can be be obtained from {@link #getContent()}
|
||||
* @see javax.ws.rs.core.HttpHeaders#CONTENT_LENGTH
|
||||
* @see org.jclouds.http.options.GetOptions
|
||||
*/
|
||||
Long getContentLength();
|
||||
|
||||
/**
|
||||
* generate an MD5 Hash for the current data.
|
||||
* <p/>
|
||||
|
|
|
@ -22,11 +22,18 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.jclouds.http.payloads.ByteArrayPayload;
|
||||
import org.jclouds.http.payloads.FilePayload;
|
||||
import org.jclouds.http.payloads.InputStreamPayload;
|
||||
import org.jclouds.http.payloads.StringPayload;
|
||||
import org.jclouds.http.payloads.UrlEncodedFormPayload;
|
||||
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -67,4 +74,14 @@ public class Payloads {
|
|||
return new FilePayload(checkNotNull(data, "data"));
|
||||
}
|
||||
|
||||
public static UrlEncodedFormPayload newUrlEncodedFormPayload(
|
||||
Multimap<String, String> formParams, char... skips) {
|
||||
return new UrlEncodedFormPayload(formParams, skips);
|
||||
}
|
||||
|
||||
public static UrlEncodedFormPayload newUrlEncodedFormPayload(
|
||||
Multimap<String, String> formParams,
|
||||
@Nullable Comparator<Map.Entry<String, String>> sorter, char... skips) {
|
||||
return new UrlEncodedFormPayload(formParams, sorter, skips);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,32 +20,33 @@ package org.jclouds.http.internal;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.io.Closeables.closeQuietly;
|
||||
import static org.jclouds.http.Payloads.newPayload;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.jclouds.encryption.EncryptionService;
|
||||
import org.jclouds.encryption.EncryptionService.MD5InputStreamResult;
|
||||
import org.jclouds.http.Payload;
|
||||
import org.jclouds.http.PayloadEnclosing;
|
||||
import org.jclouds.http.Payloads;
|
||||
|
||||
import com.google.common.io.Closeables;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public abstract class BasePayloadEnclosingImpl implements PayloadEnclosing {
|
||||
public class PayloadEnclosingImpl implements PayloadEnclosing {
|
||||
private final EncryptionService encryptionService;
|
||||
protected Payload payload;
|
||||
protected Long contentLength;
|
||||
|
||||
@Inject
|
||||
public BasePayloadEnclosingImpl(EncryptionService encryptionService) {
|
||||
public PayloadEnclosingImpl(EncryptionService encryptionService, @Nullable Payload payload) {
|
||||
this.encryptionService = encryptionService;
|
||||
this.payload = payload;
|
||||
}
|
||||
|
||||
public PayloadEnclosingImpl(EncryptionService encryptionService) {
|
||||
this(encryptionService, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -54,24 +55,9 @@ public abstract class BasePayloadEnclosingImpl implements PayloadEnclosing {
|
|||
@Override
|
||||
public void generateMD5() {
|
||||
checkState(payload != null, "payload");
|
||||
if (!payload.isRepeatable()) {
|
||||
MD5InputStreamResult result = encryptionService.md5Result(payload.getInput());
|
||||
setContentMD5(result.md5);
|
||||
setContentLength(result.length);
|
||||
setPayload(result.data);
|
||||
} else {
|
||||
setContentMD5(encryptionService.md5(payload.getInput()));
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void setContentMD5(byte[] md5);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public InputStream getContent() {
|
||||
return payload != null ? payload.getInput() : null;
|
||||
Payload newPayload = encryptionService.generateMD5BufferingIfNotRepeatable(payload);
|
||||
if (newPayload != payload)
|
||||
setPayload(newPayload);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -89,7 +75,6 @@ public abstract class BasePayloadEnclosingImpl implements PayloadEnclosing {
|
|||
public void setPayload(Payload data) {
|
||||
closeContentIfPresent();
|
||||
this.payload = checkNotNull(data, "data");
|
||||
setLength();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,7 +82,7 @@ public abstract class BasePayloadEnclosingImpl implements PayloadEnclosing {
|
|||
*/
|
||||
@Override
|
||||
public void setPayload(InputStream data) {
|
||||
setPayload(Payloads.newPayload(checkNotNull(data, "data")));
|
||||
setPayload(newPayload(checkNotNull(data, "data")));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,7 +90,7 @@ public abstract class BasePayloadEnclosingImpl implements PayloadEnclosing {
|
|||
*/
|
||||
@Override
|
||||
public void setPayload(byte[] data) {
|
||||
setPayload(Payloads.newPayload(checkNotNull(data, "data")));
|
||||
setPayload(newPayload(checkNotNull(data, "data")));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -113,7 +98,7 @@ public abstract class BasePayloadEnclosingImpl implements PayloadEnclosing {
|
|||
*/
|
||||
@Override
|
||||
public void setPayload(String data) {
|
||||
setPayload(Payloads.newPayload(checkNotNull(data, "data")));
|
||||
setPayload(newPayload(checkNotNull(data, "data")));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -121,34 +106,12 @@ public abstract class BasePayloadEnclosingImpl implements PayloadEnclosing {
|
|||
*/
|
||||
@Override
|
||||
public void setPayload(File data) {
|
||||
setPayload(Payloads.newPayload(checkNotNull(data, "data")));
|
||||
}
|
||||
|
||||
private void setLength() {
|
||||
Long size = payload.calculateSize();
|
||||
if (size != null)
|
||||
this.setContentLength(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Long getContentLength() {
|
||||
return contentLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void setContentLength(long contentLength) {
|
||||
this.contentLength = contentLength;
|
||||
setPayload(newPayload(checkNotNull(data, "data")));
|
||||
}
|
||||
|
||||
private void closeContentIfPresent() {
|
||||
if (getContent() != null) {
|
||||
Closeables.closeQuietly(getContent());
|
||||
if (payload != null && payload.getInput() != null) {
|
||||
closeQuietly(payload.getInput());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,8 +119,6 @@ public abstract class BasePayloadEnclosingImpl implements PayloadEnclosing {
|
|||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((contentLength == null) ? 0 : contentLength.hashCode());
|
||||
result = prime * result + ((encryptionService == null) ? 0 : encryptionService.hashCode());
|
||||
result = prime * result + ((payload == null) ? 0 : payload.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
@ -170,17 +131,7 @@ public abstract class BasePayloadEnclosingImpl implements PayloadEnclosing {
|
|||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
BasePayloadEnclosingImpl other = (BasePayloadEnclosingImpl) obj;
|
||||
if (contentLength == null) {
|
||||
if (other.contentLength != null)
|
||||
return false;
|
||||
} else if (!contentLength.equals(other.contentLength))
|
||||
return false;
|
||||
if (encryptionService == null) {
|
||||
if (other.encryptionService != null)
|
||||
return false;
|
||||
} else if (!encryptionService.equals(other.encryptionService))
|
||||
return false;
|
||||
PayloadEnclosingImpl other = (PayloadEnclosingImpl) obj;
|
||||
if (payload == null) {
|
||||
if (other.payload != null)
|
||||
return false;
|
|
@ -0,0 +1,159 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed 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.http.payloads;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.io.ByteStreams.copy;
|
||||
import static com.google.common.io.Closeables.closeQuietly;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.jclouds.http.Payload;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public abstract class BasePayload<V> implements Payload {
|
||||
protected final V content;
|
||||
protected String contentType;
|
||||
protected Long contentLength;
|
||||
protected byte[] contentMD5;
|
||||
protected transient volatile boolean written;
|
||||
|
||||
protected BasePayload(V content, @Nullable String contentType, @Nullable Long contentLength,
|
||||
@Nullable byte[] contentMD5) {
|
||||
this.content = checkNotNull(content, "content");
|
||||
this.contentType = contentType == null ? "application/unknown" : contentType;
|
||||
this.contentLength = contentLength;
|
||||
if (contentMD5 != null)
|
||||
setContentMD5(contentMD5);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public V getRawContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Long getContentLength() {
|
||||
return contentLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void setContentLength(@Nullable Long contentLength) {
|
||||
this.contentLength = contentLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void setContentMD5(byte[] md5) {
|
||||
if (md5 != null) {
|
||||
byte[] retval = new byte[md5.length];
|
||||
System.arraycopy(md5, 0, retval, 0, md5.length);
|
||||
this.contentMD5 = md5;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void setContentType(@Nullable String contentType) {
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void writeTo(OutputStream outstream) throws IOException {
|
||||
checkState(!written || isRepeatable(), "can only be writted to an outputstream once");
|
||||
written = true;
|
||||
InputStream in = getInput();
|
||||
try {
|
||||
copy(in, outstream);
|
||||
} finally {
|
||||
closeQuietly(in);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((content == null) ? 0 : content.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (!(obj instanceof Payload))
|
||||
return false;
|
||||
Payload other = (Payload) obj;
|
||||
if (content == null) {
|
||||
if (other.getRawContent() != null)
|
||||
return false;
|
||||
} else if (!content.equals(other.getRawContent()))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -18,31 +18,23 @@
|
|||
*/
|
||||
package org.jclouds.http.payloads;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.jclouds.http.Payload;
|
||||
import org.jclouds.util.Utils;
|
||||
|
||||
import com.google.common.io.ByteStreams;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class ByteArrayPayload implements Payload {
|
||||
|
||||
private final byte[] content;
|
||||
|
||||
public class ByteArrayPayload extends BasePayload<byte[]> {
|
||||
public ByteArrayPayload(byte[] content) {
|
||||
this.content = checkNotNull(content, "content");
|
||||
this(content, null);
|
||||
}
|
||||
|
||||
public byte[] getRawContent() {
|
||||
return content;
|
||||
public ByteArrayPayload(byte[] content, byte[] md5) {
|
||||
super(content, null, new Long(checkNotNull(content, "content").length), md5);
|
||||
checkArgument(content.length >= 0, "length cannot me negative");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -61,16 +53,4 @@ public class ByteArrayPayload implements Payload {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void writeTo(OutputStream outstream) throws IOException {
|
||||
ByteStreams.write(content, Utils.newOutputStreamSupplier(outstream));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long calculateSize() {
|
||||
return new Long(content.length);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed 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.http.payloads;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.jclouds.http.Payload;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class DelegatingPayload implements Payload {
|
||||
|
||||
private final Payload delegate;
|
||||
|
||||
public DelegatingPayload(Payload delegate) {
|
||||
this.delegate = checkNotNull(delegate, "delegate");
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public InputStream getInput() {
|
||||
return delegate.getInput();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Object getRawContent() {
|
||||
return delegate.getInput();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean isRepeatable() {
|
||||
return delegate.isRepeatable();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void writeTo(OutputStream outstream) throws IOException {
|
||||
delegate.writeTo(outstream);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Long getContentLength() {
|
||||
return delegate.getContentLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public byte[] getContentMD5() {
|
||||
return delegate.getContentMD5();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void setContentLength(Long contentLength) {
|
||||
delegate.setContentLength(contentLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void setContentMD5(byte[] md5) {
|
||||
delegate.setContentMD5(md5);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String getContentType() {
|
||||
return delegate.getContentType();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void setContentType(String md5) {
|
||||
delegate.setContentType(md5);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return delegate.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return delegate.equals(obj);
|
||||
|
||||
}
|
||||
|
||||
public Payload getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
}
|
|
@ -23,32 +23,19 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.jclouds.http.Payload;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.io.Closeables;
|
||||
import com.google.common.io.Files;
|
||||
import com.google.common.io.InputSupplier;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class FilePayload implements Payload {
|
||||
private final File content;
|
||||
private final InputSupplier<FileInputStream> delegate;
|
||||
public class FilePayload extends BasePayload<File> {
|
||||
|
||||
public FilePayload(File content) {
|
||||
super(content, null, content.length(), null);
|
||||
checkArgument(checkNotNull(content, "content").exists(), "file must exist: " + content);
|
||||
this.delegate = Files.newInputStreamSupplier(content);
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public File getRawContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -57,8 +44,8 @@ public class FilePayload implements Payload {
|
|||
@Override
|
||||
public InputStream getInput() {
|
||||
try {
|
||||
return delegate.getInput();
|
||||
} catch (IOException e) {
|
||||
return new FileInputStream(content);
|
||||
} catch (FileNotFoundException e) {
|
||||
Throwables.propagate(e);
|
||||
return null;
|
||||
}
|
||||
|
@ -72,24 +59,4 @@ public class FilePayload implements Payload {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void writeTo(OutputStream outstream) throws IOException {
|
||||
InputStream in = getInput();
|
||||
try {
|
||||
Files.copy(content, outstream);
|
||||
} finally {
|
||||
Closeables.closeQuietly(in);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Long calculateSize() {
|
||||
return content.length();
|
||||
}
|
||||
}
|
|
@ -18,31 +18,15 @@
|
|||
*/
|
||||
package org.jclouds.http.payloads;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.jclouds.http.Payload;
|
||||
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.google.common.io.Closeables;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class InputStreamPayload implements Payload {
|
||||
private final InputStream content;
|
||||
private boolean written;
|
||||
public class InputStreamPayload extends BasePayload<InputStream> {
|
||||
|
||||
public InputStreamPayload(InputStream content) {
|
||||
this.content = checkNotNull(content, "content");
|
||||
}
|
||||
|
||||
public InputStream getRawContent() {
|
||||
return content;
|
||||
super(content, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -61,26 +45,4 @@ public class InputStreamPayload implements Payload {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void writeTo(OutputStream outstream) throws IOException {
|
||||
checkState(!written, "InputStreams can only be writted to an outputstream once");
|
||||
written = true;
|
||||
InputStream in = getInput();
|
||||
try {
|
||||
ByteStreams.copy(getInput(), outstream);
|
||||
} finally {
|
||||
Closeables.closeQuietly(in);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Long calculateSize() {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed 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.http.payloads;
|
||||
|
||||
import static com.google.common.base.Throwables.propagate;
|
||||
import static com.google.common.collect.Lists.newArrayList;
|
||||
import static com.google.common.io.ByteStreams.join;
|
||||
import static com.google.common.io.ByteStreams.newInputStreamSupplier;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.jclouds.http.payloads.BasePayload;
|
||||
import org.jclouds.http.payloads.Part;
|
||||
|
||||
import com.google.common.io.InputSupplier;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class MultipartForm extends BasePayload<Iterable<? extends Part>> {
|
||||
public static final String BOUNDARY = "--JCLOUDS--";
|
||||
private static final String rn = "\r\n";
|
||||
private static final String dd = "--";
|
||||
|
||||
private boolean isRepeatable;
|
||||
private final InputSupplier<? extends InputStream> chain;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public MultipartForm(String boundary, Iterable<? extends Part> content) {
|
||||
super(content,"multipart/form-data; boundary="+boundary, 0l, null);
|
||||
String boundaryrn = boundary + rn;
|
||||
isRepeatable = true;
|
||||
InputSupplier<? extends InputStream> chain = join();
|
||||
for (Part part : content) {
|
||||
if (!part.isRepeatable())
|
||||
isRepeatable = false;
|
||||
contentLength += part.getContentLength();
|
||||
chain = join(chain, addLengthAndReturnHeaders(boundaryrn, part), part,
|
||||
addLengthAndReturnRn());
|
||||
}
|
||||
chain = join(chain, addLengthAndReturnFooter(boundary));
|
||||
this.chain = chain;
|
||||
}
|
||||
|
||||
public MultipartForm(String boundary, Part... parts) {
|
||||
this(boundary, newArrayList(parts));
|
||||
}
|
||||
|
||||
public MultipartForm(Part... parts) {
|
||||
this(BOUNDARY, parts);
|
||||
}
|
||||
|
||||
private InputSupplier<? extends InputStream> addLengthAndReturnRn() {
|
||||
contentLength += rn.length();
|
||||
return newInputStreamSupplier(rn.getBytes());
|
||||
}
|
||||
|
||||
private InputSupplier<? extends InputStream> addLengthAndReturnHeaders(String boundaryrn,
|
||||
Part part) {
|
||||
StringBuilder builder = new StringBuilder(dd).append(boundaryrn);
|
||||
for (Entry<String, String> entry : part.getHeaders().entries()) {
|
||||
String header = String.format("%s: %s%s", entry.getKey(), entry.getValue(), rn);
|
||||
builder.append(header);
|
||||
}
|
||||
builder.append(rn);
|
||||
contentLength += builder.length();
|
||||
return newInputStreamSupplier(builder.toString().getBytes());
|
||||
}
|
||||
|
||||
private InputSupplier<? extends InputStream> addLengthAndReturnFooter(String boundary) {
|
||||
String end = dd + boundary + dd + rn;
|
||||
contentLength += end.length();
|
||||
return newInputStreamSupplier(end.getBytes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInput() {
|
||||
try {
|
||||
return chain.getInput();
|
||||
} catch (IOException e) {
|
||||
propagate(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRepeatable() {
|
||||
return isRepeatable;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed 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.http.payloads;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.collect.Multimaps.forMap;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
|
||||
import org.jclouds.http.Payload;
|
||||
import org.jclouds.http.Payloads;
|
||||
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class Part extends DelegatingPayload {
|
||||
final String name;
|
||||
final Multimap<String, String> headers;
|
||||
|
||||
private static class PartMap extends LinkedHashMap<String, String> {
|
||||
|
||||
/** The serialVersionUID */
|
||||
private static final long serialVersionUID = -287387556008320212L;
|
||||
|
||||
static Part.PartMap create(String name) {
|
||||
Part.PartMap map = new PartMap();
|
||||
map.put("Content-Disposition", String.format("form-data; name=\"%s\"", checkNotNull(name,
|
||||
"name")));
|
||||
return map;
|
||||
}
|
||||
|
||||
static Part.PartMap create(String name, String filename) {
|
||||
Part.PartMap map = new PartMap();
|
||||
map.put("Content-Disposition", String.format("form-data; name=\"%s\"; filename=\"%s\"",
|
||||
checkNotNull(name, "name"), checkNotNull(filename, "filename")));
|
||||
return map;
|
||||
}
|
||||
|
||||
Part.PartMap contentType(@Nullable String type) {
|
||||
if (type != null)
|
||||
put(HttpHeaders.CONTENT_TYPE, checkNotNull(type, "type"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public static Part.PartMap create(String name, Payload delegate, Part.PartOptions options) {
|
||||
String filename = options != null ? options.getFilename() : null;
|
||||
if (delegate instanceof FilePayload)
|
||||
filename = FilePayload.class.cast(delegate).getRawContent().getName();
|
||||
Part.PartMap returnVal;
|
||||
returnVal = (filename != null) ? create(name, filename) : create(name);
|
||||
if (options != null)
|
||||
returnVal.contentType(options.getContentType());
|
||||
return returnVal;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private Part(String name, Part.PartMap map, Payload delegate) {
|
||||
super(delegate);
|
||||
this.name = name;
|
||||
this.headers = ImmutableMultimap.copyOf(forMap((checkNotNull(map, "headers"))));
|
||||
}
|
||||
|
||||
public static class PartOptions {
|
||||
private String contentType;
|
||||
private String filename;
|
||||
|
||||
public Part.PartOptions contentType(String contentType) {
|
||||
this.contentType = checkNotNull(contentType, "contentType");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Part.PartOptions filename(String filename) {
|
||||
this.filename = checkNotNull(filename, "filename");
|
||||
return this;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
public static Part.PartOptions contentType(String contentType) {
|
||||
return new PartOptions().contentType(contentType);
|
||||
}
|
||||
|
||||
public static Part.PartOptions filename(String filename) {
|
||||
return new PartOptions().filename(filename);
|
||||
}
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
}
|
||||
|
||||
public static Part create(String name, String value) {
|
||||
return new Part(name, PartMap.create(name), Payloads.newStringPayload(value));
|
||||
}
|
||||
|
||||
public static Part create(String name, Payload delegate, Part.PartOptions options) {
|
||||
return new Part(name, PartMap.create(name, delegate, options), delegate);
|
||||
}
|
||||
|
||||
public Multimap<String, String> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
|
@ -18,29 +18,17 @@
|
|||
*/
|
||||
package org.jclouds.http.payloads;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.jclouds.http.Payload;
|
||||
import org.jclouds.util.Utils;
|
||||
|
||||
import com.google.common.io.ByteStreams;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class StringPayload implements Payload {
|
||||
private final String content;
|
||||
public class StringPayload extends BasePayload<String> {
|
||||
|
||||
public StringPayload(String content) {
|
||||
this.content = checkNotNull(content, "content");
|
||||
}
|
||||
|
||||
public String getRawContent() {
|
||||
return content;
|
||||
super(content, null, new Long(content.length()), null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -59,24 +47,4 @@ public class StringPayload implements Payload {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void writeTo(OutputStream outstream) throws IOException {
|
||||
ByteStreams.copy(Utils.toInputStream(content), outstream);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Long calculateSize() {
|
||||
return new Long(content.length());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return content;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed 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.http.payloads;
|
||||
|
||||
import static org.jclouds.http.HttpUtils.makeQueryLine;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.jclouds.util.Utils;
|
||||
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class UrlEncodedFormPayload extends BasePayload<String> {
|
||||
public UrlEncodedFormPayload(Multimap<String, String> formParams, char... skips) {
|
||||
this(formParams, null, skips);
|
||||
}
|
||||
|
||||
public UrlEncodedFormPayload(Multimap<String, String> formParams,
|
||||
@Nullable Comparator<Map.Entry<String, String>> sorter, char... skips) {
|
||||
super(makeQueryLine(formParams, sorter, skips), MediaType.APPLICATION_FORM_URLENCODED, null,
|
||||
null);
|
||||
setContentLength(new Long(content.length()));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public InputStream getInput() {
|
||||
return Utils.toInputStream(content);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean isRepeatable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -18,10 +18,7 @@
|
|||
*/
|
||||
package org.jclouds.rest.binders;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.rest.Binder;
|
||||
|
@ -34,10 +31,6 @@ import org.jclouds.rest.Binder;
|
|||
@Singleton
|
||||
public class BindToStringPayload implements Binder {
|
||||
public void bindToRequest(HttpRequest request, Object payload) {
|
||||
String stringPayload = payload.toString();
|
||||
if (request.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE) == null)
|
||||
request.getHeaders().put(HttpHeaders.CONTENT_TYPE, "application/unknown");
|
||||
request.getHeaders().replaceValues(HttpHeaders.CONTENT_LENGTH,Collections.singletonList(stringPayload.getBytes().length + ""));
|
||||
request.setPayload(stringPayload);
|
||||
request.setPayload(payload.toString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,8 +20,27 @@ package org.jclouds.rest.internal;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.collect.Collections2.filter;
|
||||
import static com.google.common.collect.Collections2.transform;
|
||||
import static com.google.common.collect.Iterables.concat;
|
||||
import static com.google.common.collect.Lists.newArrayList;
|
||||
import static com.google.common.collect.Lists.newLinkedList;
|
||||
import static com.google.common.collect.Maps.filterValues;
|
||||
import static com.google.common.collect.Maps.newHashMap;
|
||||
import static com.google.common.collect.Maps.newLinkedHashMap;
|
||||
import static com.google.common.collect.Sets.difference;
|
||||
import static com.google.common.collect.Sets.newHashSet;
|
||||
import static java.util.Arrays.asList;
|
||||
import static javax.ws.rs.core.HttpHeaders.ACCEPT;
|
||||
import static javax.ws.rs.core.HttpHeaders.CONTENT_LENGTH;
|
||||
import static javax.ws.rs.core.HttpHeaders.CONTENT_TYPE;
|
||||
import static javax.ws.rs.core.HttpHeaders.HOST;
|
||||
import static org.jclouds.http.HttpUtils.makeQueryLine;
|
||||
import static org.jclouds.http.HttpUtils.parseQueryToMap;
|
||||
import static org.jclouds.http.HttpUtils.urlEncode;
|
||||
import static org.jclouds.http.Payloads.newPayload;
|
||||
import static org.jclouds.http.Payloads.newStringPayload;
|
||||
import static org.jclouds.http.Payloads.newUrlEncodedFormPayload;
|
||||
import static org.jclouds.util.Utils.replaceTokens;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
@ -29,7 +48,6 @@ import java.lang.annotation.Annotation;
|
|||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
@ -51,21 +69,16 @@ import javax.ws.rs.Path;
|
|||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import javax.ws.rs.core.UriBuilderException;
|
||||
|
||||
import org.jboss.resteasy.util.IsHttpMethod;
|
||||
import org.jclouds.encryption.EncryptionService;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpRequestFilter;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.HttpUtils;
|
||||
import org.jclouds.http.MultipartForm;
|
||||
import org.jclouds.http.Payload;
|
||||
import org.jclouds.http.Payloads;
|
||||
import org.jclouds.http.MultipartForm.Part;
|
||||
import org.jclouds.http.MultipartForm.Part.PartOptions;
|
||||
import org.jclouds.http.PayloadEnclosing;
|
||||
import org.jclouds.http.functions.CloseContentAndReturn;
|
||||
import org.jclouds.http.functions.ParseSax;
|
||||
import org.jclouds.http.functions.ParseURIFromListOrLocationHeaderIf20x;
|
||||
|
@ -74,6 +87,9 @@ import org.jclouds.http.functions.ReturnStringIf200;
|
|||
import org.jclouds.http.functions.ReturnTrueIf2xx;
|
||||
import org.jclouds.http.functions.ParseSax.HandlerWithResult;
|
||||
import org.jclouds.http.options.HttpRequestOptions;
|
||||
import org.jclouds.http.payloads.MultipartForm;
|
||||
import org.jclouds.http.payloads.Part;
|
||||
import org.jclouds.http.payloads.Part.PartOptions;
|
||||
import org.jclouds.internal.ClassMethodArgs;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.rest.Binder;
|
||||
|
@ -104,15 +120,10 @@ import org.jclouds.rest.functions.MapHttp4xxCodesToExceptions;
|
|||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Collections2;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.LinkedHashMultimap;
|
||||
import com.google.common.collect.LinkedListMultimap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.MapMaker;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
|
@ -151,7 +162,7 @@ public class RestAnnotationProcessor<T> {
|
|||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToPostParamAnnotations = createMethodToIndexOfParamToAnnotation(MapPayloadParam.class);
|
||||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToPartParamAnnotations = createMethodToIndexOfParamToAnnotation(PartParam.class);
|
||||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToParamParserAnnotations = createMethodToIndexOfParamToAnnotation(ParamParser.class);
|
||||
private final Map<MethodKey, Method> delegationMap = Maps.newHashMap();
|
||||
private final Map<MethodKey, Method> delegationMap = newHashMap();
|
||||
|
||||
static Map<Method, Map<Integer, Set<Annotation>>> createMethodToIndexOfParamToAnnotation(
|
||||
final Class<? extends Annotation> annotation) {
|
||||
|
@ -174,9 +185,8 @@ public class RestAnnotationProcessor<T> {
|
|||
|
||||
public Set<Annotation> apply(final Integer index) {
|
||||
Set<Annotation> keys = new HashSet<Annotation>();
|
||||
List<Annotation> parameterAnnotations = Lists.newArrayList(method
|
||||
.getParameterAnnotations()[index]);
|
||||
Collection<Annotation> filtered = Collections2.filter(parameterAnnotations,
|
||||
List<Annotation> parameterAnnotations = newArrayList(method.getParameterAnnotations()[index]);
|
||||
Collection<Annotation> filtered = filter(parameterAnnotations,
|
||||
new Predicate<Annotation>() {
|
||||
public boolean apply(Annotation input) {
|
||||
return input.annotationType().equals(clazz);
|
||||
|
@ -205,7 +215,7 @@ public class RestAnnotationProcessor<T> {
|
|||
private final Map<Method, Set<Integer>> methodToIndexesOfOptions = new MapMaker()
|
||||
.makeComputingMap(new Function<Method, Set<Integer>>() {
|
||||
public Set<Integer> apply(final Method method) {
|
||||
Set<Integer> toReturn = Sets.newHashSet();
|
||||
Set<Integer> toReturn = newHashSet();
|
||||
for (int index = 0; index < method.getParameterTypes().length; index++) {
|
||||
Class<?> type = method.getParameterTypes()[index];
|
||||
if (HttpRequestOptions.class.isAssignableFrom(type)
|
||||
|
@ -217,6 +227,7 @@ public class RestAnnotationProcessor<T> {
|
|||
});
|
||||
|
||||
private final ParseSax.Factory parserFactory;
|
||||
private final EncryptionService encryptionService;
|
||||
private final Provider<UriBuilder> uriBuilderProvider;
|
||||
|
||||
private char[] skips;
|
||||
|
@ -253,10 +264,11 @@ public class RestAnnotationProcessor<T> {
|
|||
@SuppressWarnings("unchecked")
|
||||
@Inject
|
||||
public RestAnnotationProcessor(Injector injector, ParseSax.Factory parserFactory,
|
||||
TypeLiteral<T> typeLiteral) {
|
||||
EncryptionService encryptionService, TypeLiteral<T> typeLiteral) {
|
||||
this.declaring = (Class<T>) typeLiteral.getRawType();
|
||||
this.injector = injector;
|
||||
this.parserFactory = parserFactory;
|
||||
this.encryptionService = encryptionService;
|
||||
this.uriBuilderProvider = injector.getProvider(UriBuilder.class);
|
||||
seedCache(declaring);
|
||||
if (declaring.isAnnotationPresent(SkipEncoding.class)) {
|
||||
|
@ -271,8 +283,8 @@ public class RestAnnotationProcessor<T> {
|
|||
}
|
||||
|
||||
private void seedCache(Class<?> declaring) {
|
||||
Set<Method> methods = Sets.newHashSet(declaring.getMethods());
|
||||
methods = Sets.difference(methods, Sets.newHashSet(Object.class.getMethods()));
|
||||
Set<Method> methods = newHashSet(declaring.getMethods());
|
||||
methods = difference(methods, newHashSet(Object.class.getMethods()));
|
||||
for (Method method : methods) {
|
||||
if (isHttpMethod(method)) {
|
||||
for (int index = 0; index < method.getParameterTypes().length; index++) {
|
||||
|
@ -405,10 +417,9 @@ public class RestAnnotationProcessor<T> {
|
|||
}
|
||||
String stringPayload = options.buildStringPayload();
|
||||
if (stringPayload != null)
|
||||
payload = Payloads.newStringPayload(stringPayload);
|
||||
payload = newStringPayload(stringPayload);
|
||||
}
|
||||
if (payload == null)
|
||||
payload = findPayloadInArgs(args);
|
||||
|
||||
if (queryParams.size() > 0) {
|
||||
builder.replaceQuery(makeQueryLine(queryParams, null, skips));
|
||||
}
|
||||
|
@ -426,31 +437,20 @@ public class RestAnnotationProcessor<T> {
|
|||
addHostHeaderIfAnnotatedWithVirtualHost(headers, request.getEndpoint().getHost(), method);
|
||||
addFiltersIfAnnotated(method, request);
|
||||
|
||||
List<? extends Part> parts = getParts(method, args, Iterables.concat(tokenValues.entries(),
|
||||
formParams.entries()));
|
||||
if (payload == null)
|
||||
payload = findPayloadInArgs(args);
|
||||
List<? extends Part> parts = getParts(method, args, concat(tokenValues.entries(), formParams
|
||||
.entries()));
|
||||
if (parts.size() > 0) {
|
||||
if (formParams.size() > 0) {
|
||||
parts = Lists.newLinkedList(Iterables.concat(Iterables
|
||||
.<Entry<String, String>, Part> transform(formParams.entries(), ENTRY_TO_PART),
|
||||
parts));
|
||||
parts = newLinkedList(concat(transform(formParams.entries(), ENTRY_TO_PART), parts));
|
||||
}
|
||||
MultipartForm form = new MultipartForm(BOUNDARY, parts);
|
||||
|
||||
request.setPayload(form);
|
||||
request.getHeaders().put(HttpHeaders.CONTENT_TYPE,
|
||||
"multipart/form-data; boundary=" + BOUNDARY);
|
||||
|
||||
request.getHeaders().put(HttpHeaders.CONTENT_LENGTH, form.calculateSize() + "");
|
||||
payload = new MultipartForm(BOUNDARY, parts);
|
||||
} else if (formParams.size() > 0) {
|
||||
if (headers.get(HttpHeaders.CONTENT_TYPE).size() == 0)
|
||||
headers.put(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED);
|
||||
request.setPayload(makeQueryLine(formParams, null, skips));
|
||||
} else if (payload != null) {
|
||||
payload = newUrlEncodedFormPayload(formParams, skips);
|
||||
}
|
||||
if (payload != null) {
|
||||
request.setPayload(payload);
|
||||
if (headers.get(HttpHeaders.CONTENT_LENGTH).size() == 0)
|
||||
headers.put(HttpHeaders.CONTENT_LENGTH, payload.calculateSize() + "");
|
||||
if (headers.get(HttpHeaders.CONTENT_TYPE).size() == 0)
|
||||
headers.put(HttpHeaders.CONTENT_TYPE, "application/unknown");
|
||||
}
|
||||
request.getHeaders().putAll(headers);
|
||||
decorateRequest(request);
|
||||
|
@ -755,7 +755,7 @@ public class RestAnnotationProcessor<T> {
|
|||
String host, Method method) {
|
||||
if (declaring.isAnnotationPresent(VirtualHost.class)
|
||||
|| method.isAnnotationPresent(VirtualHost.class)) {
|
||||
headers.put(HttpHeaders.HOST, host);
|
||||
headers.put(HOST, host);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -770,10 +770,8 @@ public class RestAnnotationProcessor<T> {
|
|||
// parameters.
|
||||
if (mapBinder != null) {
|
||||
mapBinder.bindToRequest(request, mapParams);
|
||||
return;
|
||||
}
|
||||
|
||||
OUTER: for (Entry<Integer, Set<Annotation>> entry : Maps.filterValues(
|
||||
} else {
|
||||
OUTER: for (Entry<Integer, Set<Annotation>> entry : filterValues(
|
||||
methodToIndexOfParamToDecoratorParamAnnotation.get(request.getJavaMethod()),
|
||||
new Predicate<Set<Annotation>>() {
|
||||
public boolean apply(Set<Annotation> input) {
|
||||
|
@ -794,8 +792,8 @@ public class RestAnnotationProcessor<T> {
|
|||
- request.getJavaMethod().getParameterTypes().length + 1;
|
||||
if (arrayLength == 0)
|
||||
break OUTER;
|
||||
input = (Object[]) Array.newInstance(request.getArgs()[entry.getKey()].getClass(),
|
||||
arrayLength);
|
||||
input = (Object[]) Array.newInstance(
|
||||
request.getArgs()[entry.getKey()].getClass(), arrayLength);
|
||||
System.arraycopy(request.getArgs(), entry.getKey(), input, 0, arrayLength);
|
||||
shouldBreak = true;
|
||||
} else if (argType.isArray() && request.getJavaMethod().isVarArgs()
|
||||
|
@ -815,18 +813,36 @@ public class RestAnnotationProcessor<T> {
|
|||
break OUTER;
|
||||
}
|
||||
}
|
||||
if (request.getMethod().equals("PUT") && request.getPayload() == null) {
|
||||
request.getHeaders().replaceValues(HttpHeaders.CONTENT_LENGTH,
|
||||
Collections.singletonList(0 + ""));
|
||||
}
|
||||
if (request.getPayload() != null)
|
||||
assert request.getFirstHeaderOrNull(HttpHeaders.CONTENT_LENGTH) != null : "no content length";
|
||||
if (request.getMethod().equals("PUT") && request.getPayload() == null) {
|
||||
request.getHeaders().replaceValues(CONTENT_LENGTH, Collections.singletonList(0 + ""));
|
||||
}
|
||||
if (request.getPayload() != null) {
|
||||
if ("chunked".equalsIgnoreCase(request.getFirstHeaderOrNull("Transfer-Encoding"))) {
|
||||
request.getHeaders().get(CONTENT_LENGTH).clear();
|
||||
} else {
|
||||
if (request.getHeaders().get(CONTENT_LENGTH).size() == 0
|
||||
&& request.getPayload().getContentLength() != null)
|
||||
request.getHeaders().put(CONTENT_LENGTH,
|
||||
request.getPayload().getContentLength() + "");
|
||||
checkArgument(request.getFirstHeaderOrNull(CONTENT_LENGTH) != null,
|
||||
"no content length on payload!");
|
||||
}
|
||||
if (request.getHeaders().get("Content-MD5").size() == 0
|
||||
&& request.getPayload().getContentMD5() != null)
|
||||
request.getHeaders().put("Content-MD5",
|
||||
encryptionService.base64(request.getPayload().getContentMD5()));
|
||||
if (request.getHeaders().get(CONTENT_TYPE).size() == 0
|
||||
&& request.getPayload().getContentType() != null)
|
||||
request.getHeaders().put(CONTENT_TYPE, request.getPayload().getContentType());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protected Map<Integer, Set<Annotation>> indexWithOnlyOneAnnotation(Method method,
|
||||
String description, Map<Method, Map<Integer, Set<Annotation>>> toRefine) {
|
||||
Map<Integer, Set<Annotation>> indexToPayloadAnnotation = Maps.filterValues(toRefine
|
||||
.get(method), new Predicate<Set<Annotation>>() {
|
||||
Map<Integer, Set<Annotation>> indexToPayloadAnnotation = filterValues(toRefine.get(method),
|
||||
new Predicate<Set<Annotation>>() {
|
||||
public boolean apply(Set<Annotation> input) {
|
||||
return input.size() == 1;
|
||||
}
|
||||
|
@ -888,22 +904,22 @@ public class RestAnnotationProcessor<T> {
|
|||
void addConsumesIfPresentOnTypeOrMethod(Multimap<String, String> headers, Method method) {
|
||||
if (declaring.isAnnotationPresent(Consumes.class)) {
|
||||
Consumes header = declaring.getAnnotation(Consumes.class);
|
||||
headers.replaceValues(HttpHeaders.ACCEPT, Arrays.asList(header.value()));
|
||||
headers.replaceValues(ACCEPT, asList(header.value()));
|
||||
}
|
||||
if (method.isAnnotationPresent(Consumes.class)) {
|
||||
Consumes header = method.getAnnotation(Consumes.class);
|
||||
headers.replaceValues(HttpHeaders.ACCEPT, Arrays.asList(header.value()));
|
||||
headers.replaceValues(ACCEPT, asList(header.value()));
|
||||
}
|
||||
}
|
||||
|
||||
void addProducesIfPresentOnTypeOrMethod(Multimap<String, String> headers, Method method) {
|
||||
if (declaring.isAnnotationPresent(Produces.class)) {
|
||||
Produces header = declaring.getAnnotation(Produces.class);
|
||||
headers.replaceValues(HttpHeaders.CONTENT_TYPE, Arrays.asList(header.value()));
|
||||
headers.replaceValues(CONTENT_TYPE, asList(header.value()));
|
||||
}
|
||||
if (method.isAnnotationPresent(Produces.class)) {
|
||||
Produces header = method.getAnnotation(Produces.class);
|
||||
headers.replaceValues(HttpHeaders.CONTENT_TYPE, Arrays.asList(header.value()));
|
||||
headers.replaceValues(CONTENT_TYPE, asList(header.value()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -930,7 +946,7 @@ public class RestAnnotationProcessor<T> {
|
|||
}
|
||||
|
||||
private Map<String, String> convertUnsafe(Multimap<String, String> in) {
|
||||
Map<String, String> out = Maps.newLinkedHashMap();
|
||||
Map<String, String> out = newLinkedHashMap();
|
||||
for (Entry<String, String> entry : in.entries()) {
|
||||
out.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
@ -939,7 +955,7 @@ public class RestAnnotationProcessor<T> {
|
|||
|
||||
List<? extends Part> getParts(Method method, Object[] args,
|
||||
Iterable<Entry<String, String>> iterable) {
|
||||
List<Part> parts = Lists.newLinkedList();
|
||||
List<Part> parts = newLinkedList();
|
||||
Map<Integer, Set<Annotation>> indexToPartParam = methodToIndexOfParamToPartParamAnnotations
|
||||
.get(method);
|
||||
for (Entry<Integer, Set<Annotation>> entry : indexToPartParam.entrySet()) {
|
||||
|
@ -950,8 +966,7 @@ public class RestAnnotationProcessor<T> {
|
|||
options.contentType(param.contentType());
|
||||
if (!PartParam.NO_FILENAME.equals(param.filename()))
|
||||
options.filename(replaceTokens(param.filename(), iterable));
|
||||
Part part = Part.create(param.name(), Payloads.newPayload(args[entry.getKey()]),
|
||||
options);
|
||||
Part part = Part.create(param.name(), newPayload(args[entry.getKey()]), options);
|
||||
parts.add(part);
|
||||
}
|
||||
}
|
||||
|
@ -964,6 +979,8 @@ public class RestAnnotationProcessor<T> {
|
|||
for (int i = 0; i < args.length; i++)
|
||||
if (args[i] instanceof Payload)
|
||||
return Payload.class.cast(args[i]);
|
||||
else if (args[i] instanceof PayloadEnclosing)
|
||||
return PayloadEnclosing.class.cast(args[i]).getPayload();
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -1004,7 +1021,7 @@ public class RestAnnotationProcessor<T> {
|
|||
private Multimap<String, String> encodeValues(Multimap<String, String> unencoded, char... skips) {
|
||||
Multimap<String, String> encoded = LinkedHashMultimap.create();
|
||||
for (Entry<String, String> entry : unencoded.entries()) {
|
||||
encoded.put(entry.getKey(), HttpUtils.urlEncode(entry.getValue(), skips));
|
||||
encoded.put(entry.getKey(), urlEncode(entry.getValue(), skips));
|
||||
}
|
||||
return encoded;
|
||||
}
|
||||
|
@ -1112,7 +1129,7 @@ public class RestAnnotationProcessor<T> {
|
|||
}
|
||||
|
||||
private Map<String, String> buildPostParams(Method method, Object... args) {
|
||||
Map<String, String> postParams = Maps.newHashMap();
|
||||
Map<String, String> postParams = newHashMap();
|
||||
Map<Integer, Set<Annotation>> indexToPathParam = methodToIndexOfParamToPostParamAnnotations
|
||||
.get(method);
|
||||
Map<Integer, Set<Annotation>> indexToParamExtractor = methodToIndexOfParamToParamParserAnnotations
|
||||
|
|
|
@ -28,9 +28,13 @@ import static com.google.common.collect.Iterables.filter;
|
|||
import static com.google.common.collect.Iterables.find;
|
||||
import static com.google.common.collect.Iterables.get;
|
||||
import static com.google.common.collect.Iterables.transform;
|
||||
import static com.google.common.collect.Lists.newArrayList;
|
||||
import static com.google.common.io.ByteStreams.toByteArray;
|
||||
import static com.google.common.io.Closeables.closeQuietly;
|
||||
import static org.jclouds.util.Patterns.CHAR_TO_PATTERN;
|
||||
import static org.jclouds.util.Patterns.TOKEN_TO_PATTERN;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
@ -60,11 +64,7 @@ import com.google.common.base.Function;
|
|||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.google.common.io.Closeables;
|
||||
import com.google.common.io.OutputSupplier;
|
||||
import com.google.inject.ProvisionException;
|
||||
import com.google.inject.spi.Message;
|
||||
|
@ -80,7 +80,7 @@ public class Utils {
|
|||
AuthorizationException aex = getFirstThrowableOfType(e, AuthorizationException.class);
|
||||
if (aex != null)
|
||||
throw aex;
|
||||
Throwables.propagate(e);
|
||||
propagate(e);
|
||||
assert false : "exception should have propogated " + e;
|
||||
return null;
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ public class Utils {
|
|||
@SuppressWarnings("unchecked")
|
||||
public static <T, E extends T> List<E> multiMax(Comparator<T> ordering, Iterable<E> iterable) {
|
||||
Iterator<E> iterator = iterable.iterator();
|
||||
List<E> maxes = Lists.newArrayList(iterator.next());
|
||||
List<E> maxes = newArrayList(iterator.next());
|
||||
E maxSoFar = maxes.get(0);
|
||||
while (iterator.hasNext()) {
|
||||
E current = iterator.next();
|
||||
|
@ -99,7 +99,7 @@ public class Utils {
|
|||
if (comparison == 0) {
|
||||
maxes.add(current);
|
||||
} else if (comparison < 0) {
|
||||
maxes = Lists.newArrayList(current);
|
||||
maxes = newArrayList(current);
|
||||
maxSoFar = current;
|
||||
}
|
||||
}
|
||||
|
@ -203,24 +203,19 @@ public class Utils {
|
|||
public static String toStringAndClose(InputStream input) throws IOException {
|
||||
checkNotNull(input, "input");
|
||||
try {
|
||||
return new String(ByteStreams.toByteArray(input), Charsets.UTF_8);
|
||||
return new String(toByteArray(input), Charsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
logger.warn(e, "Failed to read from stream");
|
||||
return null;
|
||||
} catch (NullPointerException e) {
|
||||
return null;
|
||||
} finally {
|
||||
Closeables.closeQuietly(input);
|
||||
closeQuietly(input);
|
||||
}
|
||||
}
|
||||
|
||||
public static InputStream toInputStream(String in) {
|
||||
try {
|
||||
return ByteStreams.newInputStreamSupplier(in.getBytes(Charsets.UTF_8)).getInput();
|
||||
} catch (IOException e) {
|
||||
logger.warn(e, "Failed to convert %s to an inputStream", in);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return new ByteArrayInputStream(in.getBytes(Charsets.UTF_8));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -176,8 +176,8 @@ public abstract class BaseHttpCommandExecutorServiceIntegrationTest extends Base
|
|||
}
|
||||
|
||||
// upload and verify the response
|
||||
assertEquals(client.postWithMd5("fileso", this.encryptionService.base64(eTag.digest()),
|
||||
f).trim(), "created");
|
||||
assertEquals(client.postWithMd5("fileso", this.encryptionService.base64(eTag.digest()), f)
|
||||
.trim(), "created");
|
||||
|
||||
} finally {
|
||||
if (os != null)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue