code cleanup: http request immutability (except payload), builders, test backfill

This commit is contained in:
Adrian Cole 2010-12-30 23:40:23 +01:00
parent a23c2dd815
commit 60b6b68556
865 changed files with 8904 additions and 5432 deletions

View File

@ -82,7 +82,6 @@ public interface AtmosStorageAsyncClient {
* @see AtmosStorageClient#listDirectories * @see AtmosStorageClient#listDirectories
*/ */
@GET @GET
@Path("")
@ResponseParser(ParseDirectoryListFromContentAndHeaders.class) @ResponseParser(ParseDirectoryListFromContentAndHeaders.class)
@Consumes(MediaType.TEXT_XML) @Consumes(MediaType.TEXT_XML)
ListenableFuture<BoundedSet<? extends DirectoryEntry>> listDirectories(ListOptions... options); ListenableFuture<BoundedSet<? extends DirectoryEntry>> listDirectories(ListOptions... options);

View File

@ -41,7 +41,7 @@ public class AtmosStorageResponseException extends HttpResponseException {
public AtmosStorageResponseException(HttpCommand command, HttpResponse response, public AtmosStorageResponseException(HttpCommand command, HttpResponse response,
AtmosStorageError error) { AtmosStorageError error) {
super(String.format("command %s failed with code %s, error: %s", command.getRequest() super(String.format("command %s failed with code %s, error: %s", command.getCurrentRequest()
.getRequestLine(), response.getStatusCode(), error.toString()), command, response); .getRequestLine(), response.getStatusCode(), error.toString()), command, response);
this.setError(error); this.setError(error);
@ -49,7 +49,7 @@ public class AtmosStorageResponseException extends HttpResponseException {
public AtmosStorageResponseException(HttpCommand command, HttpResponse response, public AtmosStorageResponseException(HttpCommand command, HttpResponse response,
AtmosStorageError error, Throwable cause) { AtmosStorageError error, Throwable cause) {
super(String.format("command %1$s failed with error: %2$s", command.getRequest() super(String.format("command %1$s failed with error: %2$s", command.getCurrentRequest()
.getRequestLine(), error.toString()), command, response, cause); .getRequestLine(), error.toString()), command, response, cause);
this.setError(error); this.setError(error);

View File

@ -20,28 +20,36 @@
package org.jclouds.atmosonline.saas.binders; package org.jclouds.atmosonline.saas.binders;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.atmosonline.saas.domain.AtmosObject; import org.jclouds.atmosonline.saas.domain.AtmosObject;
import org.jclouds.crypto.Crypto;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.rest.Binder; import org.jclouds.rest.Binder;
/**
* @author Adrian Cole
*/
@Singleton @Singleton
public class BindMetadataToHeaders implements Binder { public class BindMetadataToHeaders implements Binder {
private final BindUserMetadataToHeaders metaBinder; private final BindUserMetadataToHeaders metaBinder;
@Inject @Inject
protected BindMetadataToHeaders(BindUserMetadataToHeaders metaBinder, Crypto crypto) { protected BindMetadataToHeaders(BindUserMetadataToHeaders metaBinder) {
this.metaBinder = metaBinder; this.metaBinder = metaBinder;
} }
public void bindToRequest(HttpRequest request, Object payload) { @Override
AtmosObject object = (AtmosObject) payload; public <R extends HttpRequest> R bindToRequest(R request, Object input) {
checkArgument(checkNotNull(input, "input") instanceof AtmosObject, "this binder is only valid for AtmosObject!");
checkNotNull(request, "request");
AtmosObject object = AtmosObject.class.cast(input);
checkNotNull(object.getPayload(), "object payload");
checkArgument(object.getPayload().getContentMetadata().getContentLength() != null, checkArgument(object.getPayload().getContentMetadata().getContentLength() != null,
"contentLength must be set, streaming not supported"); "contentLength must be set, streaming not supported");
metaBinder.bindToRequest(request, object.getUserMetadata()); return metaBinder.bindToRequest(request, object.getUserMetadata());
} }
} }

View File

@ -19,36 +19,57 @@
package org.jclouds.atmosonline.saas.binders; package org.jclouds.atmosonline.saas.binders;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.atmosonline.saas.domain.UserMetadata; import org.jclouds.atmosonline.saas.domain.UserMetadata;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.utils.ModifyRequest;
import org.jclouds.rest.Binder; import org.jclouds.rest.Binder;
import com.google.common.base.Function;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.Multimaps;
/**
* @author Adrian Cole
*/
@Singleton @Singleton
public class BindUserMetadataToHeaders implements Binder { public class BindUserMetadataToHeaders implements Binder, Function<UserMetadata, Map<String, String>> {
@Override
public <R extends HttpRequest> R bindToRequest(R request, Object input) {
checkArgument(checkNotNull(input, "input") instanceof UserMetadata,
"this binder is only valid for UserMetadatas!");
checkNotNull(request, "request");
public void bindToRequest(HttpRequest request, Object payload) { return ModifyRequest.putHeaders(request, Multimaps.forMap(apply(UserMetadata.class.cast(input))));
UserMetadata md = (UserMetadata) checkNotNull(payload, "payload"); }
@Override
public Map<String, String> apply(UserMetadata md) {
Builder<String, String> headers = ImmutableMap.<String, String> builder();
if (md.getMetadata().size() > 0) { if (md.getMetadata().size() > 0) {
String header = Joiner.on(',').withKeyValueSeparator("=").join(md.getMetadata()); String header = Joiner.on(',').withKeyValueSeparator("=").join(md.getMetadata());
request.getHeaders().put("x-emc-meta", header); headers.put("x-emc-meta", header);
} }
if (md.getListableMetadata().size() > 0) { if (md.getListableMetadata().size() > 0) {
String header = Joiner.on(',').withKeyValueSeparator("=").join(md.getListableMetadata()); String header = Joiner.on(',').withKeyValueSeparator("=").join(md.getListableMetadata());
request.getHeaders().put("x-emc-listable-meta", header); headers.put("x-emc-listable-meta", header);
} }
if (md.getTags().size() > 0) { if (md.getTags().size() > 0) {
String header = Joiner.on(',').join(md.getTags()); String header = Joiner.on(',').join(md.getTags());
request.getHeaders().put("x-emc-tags", header); headers.put("x-emc-tags", header);
} }
if (md.getListableTags().size() > 0) { if (md.getListableTags().size() > 0) {
String header = Joiner.on(',').join(md.getListableTags()); String header = Joiner.on(',').join(md.getListableTags());
request.getHeaders().put("x-emc-listable-tags", header); headers.put("x-emc-listable-tags", header);
} }
return headers.build();
} }
} }

View File

@ -73,21 +73,22 @@ public class FindMD5InUserMetadata implements ContainsValueInListStrategy {
protected Long maxTime; protected Long maxTime;
@Inject @Inject
private FindMD5InUserMetadata(@Named(Constants.PROPERTY_USER_THREADS) ExecutorService userExecutor, FindMD5InUserMetadata(@Named(Constants.PROPERTY_USER_THREADS) ExecutorService userExecutor, ObjectMD5 objectMD5,
ObjectMD5 objectMD5, ListBlobsInContainer getAllBlobMetadata, AtmosStorageAsyncClient client) { ListBlobsInContainer getAllBlobMetadata, AtmosStorageAsyncClient client) {
this.objectMD5 = objectMD5; this.objectMD5 = objectMD5;
this.getAllBlobMetadata = getAllBlobMetadata; this.getAllBlobMetadata = getAllBlobMetadata;
this.client = client; this.client = client;
this.userExecutor = userExecutor; this.userExecutor = userExecutor;
} }
@Override
public boolean execute(final String containerName, Object value, ListContainerOptions options) { public boolean execute(final String containerName, Object value, ListContainerOptions options) {
final byte[] toSearch = objectMD5.apply(value); final byte[] toSearch = objectMD5.apply(value);
final BlockingQueue<Boolean> queue = new SynchronousQueue<Boolean>(); final BlockingQueue<Boolean> queue = new SynchronousQueue<Boolean>();
Map<String, Future<?>> responses = Maps.newHashMap(); Map<String, Future<?>> responses = Maps.newHashMap();
for (BlobMetadata md : getAllBlobMetadata.execute(containerName, options)) { for (BlobMetadata md : getAllBlobMetadata.execute(containerName, options)) {
final ListenableFuture<AtmosObject> future = Futures.makeListenable(client.headFile(containerName final ListenableFuture<AtmosObject> future = Futures.makeListenable(
+ "/" + md.getName()), userExecutor); client.headFile(containerName + "/" + md.getName()), userExecutor);
future.addListener(new Runnable() { future.addListener(new Runnable() {
public void run() { public void run() {
try { try {
@ -109,8 +110,8 @@ public class FindMD5InUserMetadata implements ContainsValueInListStrategy {
}, userExecutor); }, userExecutor);
responses.put(md.getName(), future); responses.put(md.getName(), future);
} }
Map<String, Exception> exceptions = awaitCompletion(responses, userExecutor, maxTime, logger, String.format( Map<String, Exception> exceptions = awaitCompletion(responses, userExecutor, maxTime, logger,
"searching for md5 in container %s", containerName)); String.format("searching for md5 in container %s", containerName));
if (exceptions.size() > 0) if (exceptions.size() > 0)
throw new BlobRuntimeException(String.format("searching for md5 in container %s: %s", containerName, throw new BlobRuntimeException(String.format("searching for md5 in container %s: %s", containerName,
exceptions)); exceptions));

View File

@ -19,19 +19,12 @@
package org.jclouds.atmosonline.saas.config; package org.jclouds.atmosonline.saas.config;
import javax.inject.Inject;
import javax.inject.Provider;
import org.jclouds.atmosonline.saas.domain.AtmosObject; import org.jclouds.atmosonline.saas.domain.AtmosObject;
import org.jclouds.atmosonline.saas.domain.MutableContentMetadata; import org.jclouds.atmosonline.saas.domain.MutableContentMetadata;
import org.jclouds.atmosonline.saas.domain.SystemMetadata;
import org.jclouds.atmosonline.saas.domain.UserMetadata;
import org.jclouds.atmosonline.saas.domain.internal.AtmosObjectImpl;
import org.jclouds.blobstore.config.BlobStoreObjectModule; import org.jclouds.blobstore.config.BlobStoreObjectModule;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Provides; import com.google.inject.Provides;
import com.google.inject.Scopes;
/** /**
* Configures the domain object mappings needed for all Atmos implementations * Configures the domain object mappings needed for all Atmos implementations
@ -48,27 +41,6 @@ public class AtmosObjectModule extends AbstractModule {
protected void configure() { protected void configure() {
// for converters // for converters
install(new BlobStoreObjectModule()); install(new BlobStoreObjectModule());
bind(AtmosObject.Factory.class).to(AtmosObjectFactory.class).in(Scopes.SINGLETON);
}
private static class AtmosObjectFactory implements AtmosObject.Factory {
@Inject
Provider<MutableContentMetadata> metadataProvider;
public AtmosObject create(MutableContentMetadata contentMetadata) {
return new AtmosObjectImpl(contentMetadata != null ? contentMetadata : metadataProvider
.get());
}
public AtmosObject create(SystemMetadata systemMetadata, UserMetadata userMetadata) {
return new AtmosObjectImpl(metadataProvider.get(), systemMetadata, userMetadata);
}
public AtmosObject create(MutableContentMetadata contentMetadata,
SystemMetadata systemMetadata, UserMetadata userMetadata) {
return new AtmosObjectImpl(contentMetadata, systemMetadata, userMetadata);
}
} }
@Provides @Provides

View File

@ -21,21 +21,18 @@ package org.jclouds.atmosonline.saas.domain;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.jclouds.atmosonline.saas.domain.internal.AtmosObjectImpl.AtmosObjectFactory;
import org.jclouds.io.PayloadEnclosing; import org.jclouds.io.PayloadEnclosing;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.google.inject.ImplementedBy;
/** /**
* Amazon Atmos is designed to store objects. Objects are stored in buckets and consist of a
* {@link ObjectMetadataAtmosObject#getInput() value}, a {@link ObjectMetadata#getKey key},
* {@link ObjectMetadata#getUserMetadata() metadata}, and an access control policy.
* *
* @author Adrian Cole * @author Adrian Cole
* @see <a
* href="http://docs.amazonwebservices.com/AmazonAtmos/2006-03-01/index.html?UsingObjects.html"
* />
*/ */
public interface AtmosObject extends PayloadEnclosing, Comparable<AtmosObject> { public interface AtmosObject extends PayloadEnclosing, Comparable<AtmosObject> {
@ImplementedBy(AtmosObjectFactory.class)
public interface Factory { public interface Factory {
AtmosObject create(@Nullable MutableContentMetadata contentMetadata); AtmosObject create(@Nullable MutableContentMetadata contentMetadata);

View File

@ -21,7 +21,9 @@ package org.jclouds.atmosonline.saas.domain;
import java.util.Set; import java.util.Set;
import org.jclouds.atmosonline.saas.domain.internal.BoundedHashSet; import javax.annotation.Nullable;
import org.jclouds.atmosonline.saas.domain.internal.BoundedLinkedHashSet;
import com.google.inject.ImplementedBy; import com.google.inject.ImplementedBy;
@ -30,9 +32,10 @@ import com.google.inject.ImplementedBy;
* @author Adrian Cole * @author Adrian Cole
* *
*/ */
@ImplementedBy(BoundedHashSet.class) @ImplementedBy(BoundedLinkedHashSet.class)
public interface BoundedSet<T> extends Set<T> { public interface BoundedSet<T> extends Set<T> {
@Nullable
String getToken(); String getToken();
} }

View File

@ -19,10 +19,10 @@
package org.jclouds.atmosonline.saas.domain; package org.jclouds.atmosonline.saas.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
@ -33,10 +33,25 @@ import com.google.common.collect.Sets;
* @author Adrian Cole * @author Adrian Cole
*/ */
public class UserMetadata { public class UserMetadata {
private final SortedMap<String, String> metadata = Maps.newTreeMap(); private final Map<String, String> metadata;
private final SortedMap<String, String> listableMetadata = Maps.newTreeMap(); private final Map<String, String> listableMetadata;
private final SortedSet<String> tags = Sets.newTreeSet(); private final Set<String> tags;
private final SortedSet<String> listableTags = Sets.newTreeSet(); private final Set<String> listableTags;
public UserMetadata(Map<String, String> metadata, Map<String, String> listableMetadata, Iterable<String> tags,
Iterable<String> listableTags) {
this.metadata = Maps.newLinkedHashMap(checkNotNull(metadata, "metadata"));
this.listableMetadata = Maps.newLinkedHashMap(checkNotNull(listableMetadata, "listableMetadata"));
this.tags = Sets.newLinkedHashSet(checkNotNull(tags, "tags"));
this.listableTags = Sets.newLinkedHashSet(checkNotNull(listableTags, "listableTags"));
}
public UserMetadata() {
this.metadata = Maps.newLinkedHashMap();
this.listableMetadata = Maps.newLinkedHashMap();
this.tags = Sets.newLinkedHashSet();
this.listableTags = Sets.newLinkedHashSet();
}
public Map<String, String> getMetadata() { public Map<String, String> getMetadata() {
return metadata; return metadata;
@ -54,4 +69,53 @@ public class UserMetadata {
return listableTags; return listableTags;
} }
@Override
public String toString() {
return "[metadata=" + metadata + ", listableMetadata=" + listableMetadata + ", tags=" + tags + ", listableTags="
+ listableTags + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((listableMetadata == null) ? 0 : listableMetadata.hashCode());
result = prime * result + ((listableTags == null) ? 0 : listableTags.hashCode());
result = prime * result + ((metadata == null) ? 0 : metadata.hashCode());
result = prime * result + ((tags == null) ? 0 : tags.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;
UserMetadata other = (UserMetadata) obj;
if (listableMetadata == null) {
if (other.listableMetadata != null)
return false;
} else if (!listableMetadata.equals(other.listableMetadata))
return false;
if (listableTags == null) {
if (other.listableTags != null)
return false;
} else if (!listableTags.equals(other.listableTags))
return false;
if (metadata == null) {
if (other.metadata != null)
return false;
} else if (!metadata.equals(other.metadata))
return false;
if (tags == null) {
if (other.tags != null)
return false;
} else if (!tags.equals(other.tags))
return false;
return true;
}
} }

View File

@ -22,6 +22,8 @@ package org.jclouds.atmosonline.saas.domain.internal;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.atmosonline.saas.domain.AtmosObject; import org.jclouds.atmosonline.saas.domain.AtmosObject;
import org.jclouds.atmosonline.saas.domain.MutableContentMetadata; import org.jclouds.atmosonline.saas.domain.MutableContentMetadata;
@ -39,6 +41,26 @@ import com.google.common.collect.Multimap;
* @author Adrian Cole * @author Adrian Cole
*/ */
public class AtmosObjectImpl extends PayloadEnclosingImpl implements AtmosObject, Comparable<AtmosObject> { public class AtmosObjectImpl extends PayloadEnclosingImpl implements AtmosObject, Comparable<AtmosObject> {
@Singleton
public static class AtmosObjectFactory implements AtmosObject.Factory {
@Inject
Provider<MutableContentMetadata> metadataProvider;
public AtmosObject create(MutableContentMetadata contentMetadata) {
return new AtmosObjectImpl(contentMetadata != null ? contentMetadata : metadataProvider.get());
}
public AtmosObject create(SystemMetadata systemMetadata, UserMetadata userMetadata) {
return new AtmosObjectImpl(metadataProvider.get(), systemMetadata, userMetadata);
}
public AtmosObject create(MutableContentMetadata contentMetadata, SystemMetadata systemMetadata,
UserMetadata userMetadata) {
return new AtmosObjectImpl(contentMetadata, systemMetadata, userMetadata);
}
}
private final UserMetadata userMetadata; private final UserMetadata userMetadata;
private final SystemMetadata systemMetadata; private final SystemMetadata systemMetadata;
@ -55,7 +77,6 @@ public class AtmosObjectImpl extends PayloadEnclosingImpl implements AtmosObject
public AtmosObjectImpl(MutableContentMetadata contentMetadata, SystemMetadata systemMetadata, public AtmosObjectImpl(MutableContentMetadata contentMetadata, SystemMetadata systemMetadata,
UserMetadata userMetadata) { UserMetadata userMetadata) {
super();
this.contentMetadata = contentMetadata; this.contentMetadata = contentMetadata;
this.systemMetadata = systemMetadata; this.systemMetadata = systemMetadata;
this.userMetadata = userMetadata; this.userMetadata = userMetadata;
@ -145,6 +166,7 @@ public class AtmosObjectImpl extends PayloadEnclosingImpl implements AtmosObject
@Override @Override
public void setPayload(Payload data) { public void setPayload(Payload data) {
this.payload = data; this.payload = data;
this.contentMetadata = new DelegatingMutableContentMetadata(contentMetadata.getName(), payload.getContentMetadata()); this.contentMetadata = new DelegatingMutableContentMetadata(contentMetadata.getName(),
payload.getContentMetadata());
} }
} }

View File

@ -0,0 +1,83 @@
/**
*
* Copyright (C) 2010 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.domain.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.LinkedHashSet;
import javax.annotation.Nullable;
import org.jclouds.atmosonline.saas.domain.BoundedSet;
import com.google.common.collect.Iterables;
/**
*
* @author Adrian Cole
*
*/
public class BoundedLinkedHashSet<T> extends LinkedHashSet<T> implements BoundedSet<T> {
/** The serialVersionUID */
private static final long serialVersionUID = -7133632087734650835L;
protected final String token;
public BoundedLinkedHashSet(Iterable<T> contents, @Nullable String token) {
Iterables.addAll(this, checkNotNull(contents, "contents"));
this.token = token;
}
@Nullable
public String getToken() {
return token;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((token == null) ? 0 : token.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
BoundedLinkedHashSet<?> other = (BoundedLinkedHashSet<?>) obj;
if (token == null) {
if (other.token != null)
return false;
} else if (!token.equals(other.token))
return false;
return true;
}
@Override
public String toString() {
return "[token=" + token + ", contents=" + super.toString() + "]";
}
}

View File

@ -22,6 +22,8 @@ package org.jclouds.atmosonline.saas.domain.internal;
import org.jclouds.atmosonline.saas.domain.MutableContentMetadata; import org.jclouds.atmosonline.saas.domain.MutableContentMetadata;
import org.jclouds.io.payloads.BaseMutableContentMetadata; import org.jclouds.io.payloads.BaseMutableContentMetadata;
import com.google.common.collect.Multimap;
/** /**
* *
* @author Adrian Cole * @author Adrian Cole
@ -150,4 +152,9 @@ public class DelegatingMutableContentMetadata implements MutableContentMetadata
return delegate.getContentLanguage(); return delegate.getContentLanguage();
} }
@Override
public void setPropertiesFromHttpHeaders(Multimap<String, String> headers) {
delegate.setPropertiesFromHttpHeaders(headers);
}
} }

View File

@ -25,7 +25,6 @@ import static org.jclouds.Constants.PROPERTY_IDENTITY;
import static org.jclouds.util.Patterns.NEWLINE_PATTERN; import static org.jclouds.util.Patterns.NEWLINE_PATTERN;
import static org.jclouds.util.Patterns.TWO_SPACE_PATTERN; import static org.jclouds.util.Patterns.TWO_SPACE_PATTERN;
import java.util.Collections;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
@ -45,11 +44,15 @@ import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpRequestFilter; import org.jclouds.http.HttpRequestFilter;
import org.jclouds.http.HttpUtils; import org.jclouds.http.HttpUtils;
import org.jclouds.http.internal.SignatureWire; import org.jclouds.http.internal.SignatureWire;
import org.jclouds.http.utils.ModifyRequest;
import org.jclouds.io.InputSuppliers; import org.jclouds.io.InputSuppliers;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.util.Utils; import org.jclouds.util.Strings2;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.Multimaps;
/** /**
* Signs the EMC Atmos Online Storage request. * Signs the EMC Atmos Online Storage request.
@ -77,8 +80,8 @@ public class SignRequest implements HttpRequestFilter {
@Inject @Inject
public SignRequest(SignatureWire signatureWire, @Named(PROPERTY_IDENTITY) String uid, public SignRequest(SignatureWire signatureWire, @Named(PROPERTY_IDENTITY) String uid,
@Named(PROPERTY_CREDENTIAL) String encodedKey, @TimeStamp Provider<String> timeStampProvider, @Named(PROPERTY_CREDENTIAL) String encodedKey, @TimeStamp Provider<String> timeStampProvider, Crypto crypto,
Crypto crypto, HttpUtils utils) { HttpUtils utils) {
this.signatureWire = signatureWire; this.signatureWire = signatureWire;
this.uid = uid; this.uid = uid;
this.key = CryptoStreams.base64(encodedKey); this.key = CryptoStreams.base64(encodedKey);
@ -87,16 +90,19 @@ public class SignRequest implements HttpRequestFilter {
this.utils = utils; this.utils = utils;
} }
public void filter(HttpRequest request) throws HttpException { @Override
String toSign = replaceUIDHeader(request).removeOldSignature(request).replaceDateHeader(request) public HttpRequest filter(HttpRequest request) throws HttpException {
.createStringToSign(request); Builder<String, String> builder = ImmutableMap.builder();
calculateAndReplaceAuthHeader(request, toSign); builder.put(AtmosStorageHeaders.UID, uid);
String date = timeStampProvider.get();
builder.put(HttpHeaders.DATE, date);
if (request.getHeaders().containsKey(AtmosStorageHeaders.DATE))
builder.put(AtmosStorageHeaders.DATE, date);
request = ModifyRequest.replaceHeaders(request, Multimaps.forMap(builder.build()));
String signature = calculateSignature(createStringToSign(request));
request = ModifyRequest.replaceHeader(request, AtmosStorageHeaders.SIGNATURE, signature);
utils.logRequest(signatureLog, request, "<<"); utils.logRequest(signatureLog, request, "<<");
} return request;
private SignRequest removeOldSignature(HttpRequest request) {
request.getHeaders().removeAll(AtmosStorageHeaders.SIGNATURE);
return this;
} }
public String createStringToSign(HttpRequest request) { public String createStringToSign(HttpRequest request) {
@ -113,11 +119,11 @@ public class SignRequest implements HttpRequestFilter {
return buffer.toString(); return buffer.toString();
} }
private void calculateAndReplaceAuthHeader(HttpRequest request, String toSign) throws HttpException { private String calculateSignature(String toSign) {
String signature = signString(toSign); String signature = signString(toSign);
if (signatureWire.enabled()) if (signatureWire.enabled())
signatureWire.input(Utils.toInputStream(signature)); signatureWire.input(Strings2.toInputStream(signature));
request.getHeaders().replaceValues(AtmosStorageHeaders.SIGNATURE, Collections.singletonList(signature)); return signature;
} }
public String signString(String toSign) { public String signString(String toSign) {
@ -134,16 +140,6 @@ public class SignRequest implements HttpRequestFilter {
toSign.append(request.getMethod()).append("\n"); toSign.append(request.getMethod()).append("\n");
} }
SignRequest replaceUIDHeader(HttpRequest request) {
request.getHeaders().replaceValues(AtmosStorageHeaders.UID, Collections.singletonList(uid));
return this;
}
SignRequest replaceDateHeader(HttpRequest request) {
request.getHeaders().replaceValues(HttpHeaders.DATE, Collections.singletonList(timeStampProvider.get()));
return this;
}
private void appendCanonicalizedHeaders(HttpRequest request, StringBuilder toSign) { private void appendCanonicalizedHeaders(HttpRequest request, StringBuilder toSign) {
// TreeSet == Sort the headers alphabetically. // TreeSet == Sort the headers alphabetically.
Set<String> headers = new TreeSet<String>(request.getHeaders().keySet()); Set<String> headers = new TreeSet<String>(request.getHeaders().keySet());
@ -155,8 +151,8 @@ public class SignRequest implements HttpRequestFilter {
// replacing any // replacing any
// newline characters and extra embedded white spaces in the value. // newline characters and extra embedded white spaces in the value.
for (String value : request.getHeaders().get(header)) { for (String value : request.getHeaders().get(header)) {
value = Utils.replaceAll(value, TWO_SPACE_PATTERN, " "); value = Strings2.replaceAll(value, TWO_SPACE_PATTERN, " ");
value = Utils.replaceAll(value, NEWLINE_PATTERN, ""); value = Strings2.replaceAll(value, NEWLINE_PATTERN, "");
toSign.append(value).append(' '); toSign.append(value).append(' ');
} }
toSign.deleteCharAt(toSign.lastIndexOf(" ")); toSign.deleteCharAt(toSign.lastIndexOf(" "));
@ -171,8 +167,9 @@ public class SignRequest implements HttpRequestFilter {
} }
private void appendPayloadMetadata(HttpRequest request, StringBuilder buffer) { private void appendPayloadMetadata(HttpRequest request, StringBuilder buffer) {
buffer.append(utils.valueOrEmpty(request.getPayload() == null ? null : request.getPayload().getContentMetadata().getContentType())) buffer.append(
.append("\n"); utils.valueOrEmpty(request.getPayload() == null ? null : request.getPayload().getContentMetadata()
.getContentType())).append("\n");
} }
@VisibleForTesting @VisibleForTesting

View File

@ -19,6 +19,9 @@
package org.jclouds.atmosonline.saas.functions; package org.jclouds.atmosonline.saas.functions;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.atmosonline.saas.domain.AtmosObject; import org.jclouds.atmosonline.saas.domain.AtmosObject;
@ -31,11 +34,14 @@ import com.google.common.base.Function;
*/ */
@Singleton @Singleton
public class AtmosObjectName implements Function<Object, String> { public class AtmosObjectName implements Function<Object, String> {
@Override
public String apply(Object input) {
checkArgument(checkNotNull(input, "input") instanceof AtmosObject,
"this function is only valid for AtmosObjects!");
AtmosObject object = AtmosObject.class.cast(input);
public String apply(Object in) { return checkNotNull(object.getContentMetadata().getName() != null ? object.getContentMetadata().getName()
AtmosObject from = (AtmosObject) in; : object.getSystemMetadata().getObjectName(), "objectName");
return from.getContentMetadata().getName() != null ? from.getContentMetadata().getName()
: from.getSystemMetadata().getObjectName();
} }
} }

View File

@ -19,13 +19,15 @@
package org.jclouds.atmosonline.saas.functions; package org.jclouds.atmosonline.saas.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Provider; import javax.inject.Provider;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.atmosonline.saas.domain.BoundedSet; import org.jclouds.atmosonline.saas.domain.BoundedSet;
import org.jclouds.atmosonline.saas.domain.DirectoryEntry; import org.jclouds.atmosonline.saas.domain.DirectoryEntry;
import org.jclouds.atmosonline.saas.domain.internal.BoundedHashSet; import org.jclouds.atmosonline.saas.domain.internal.BoundedLinkedHashSet;
import org.jclouds.atmosonline.saas.reference.AtmosStorageHeaders; import org.jclouds.atmosonline.saas.reference.AtmosStorageHeaders;
import org.jclouds.atmosonline.saas.xml.ListDirectoryResponseHandler; import org.jclouds.atmosonline.saas.xml.ListDirectoryResponseHandler;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
@ -40,25 +42,24 @@ import com.google.common.base.Function;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Singleton @Singleton
public class ParseDirectoryListFromContentAndHeaders implements public class ParseDirectoryListFromContentAndHeaders implements Function<HttpResponse, BoundedSet<DirectoryEntry>> {
Function<HttpResponse, BoundedSet<DirectoryEntry>> {
private final ParseSax.Factory factory; private final ParseSax.Factory factory;
private final Provider<ListDirectoryResponseHandler> listHandlerProvider; private final Provider<ListDirectoryResponseHandler> listHandlerProvider;
@Inject @Inject
private ParseDirectoryListFromContentAndHeaders(Factory factory, ParseDirectoryListFromContentAndHeaders(Factory factory, Provider<ListDirectoryResponseHandler> listHandlerProvider) {
Provider<ListDirectoryResponseHandler> orgHandlerProvider) { this.factory = checkNotNull(factory, "factory");
this.factory = factory; this.listHandlerProvider = checkNotNull(listHandlerProvider, "listHandlerProvider");
this.listHandlerProvider = orgHandlerProvider;
} }
/** /**
* parses the http response headers to create a new {@link BoundedSet} object. * parses the http response headers to create a new {@link BoundedSet} object.
*/ */
public BoundedSet<DirectoryEntry> apply(HttpResponse from) { public BoundedSet<DirectoryEntry> apply(HttpResponse from) {
checkNotNull(from, "http response");
String token = from.getFirstHeaderOrNull(AtmosStorageHeaders.TOKEN); String token = from.getFirstHeaderOrNull(AtmosStorageHeaders.TOKEN);
return new BoundedHashSet<DirectoryEntry>(factory.create(listHandlerProvider.get()).parse( return new BoundedLinkedHashSet<DirectoryEntry>(factory.create(listHandlerProvider.get()).parse(
from.getPayload().getInput()), token); from.getPayload().getInput()), token);
} }
} }

View File

@ -19,6 +19,7 @@
package org.jclouds.atmosonline.saas.functions; package org.jclouds.atmosonline.saas.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.http.HttpUtils.attemptToParseSizeAndRangeFromHeaders; import static org.jclouds.http.HttpUtils.attemptToParseSizeAndRangeFromHeaders;
import javax.inject.Inject; import javax.inject.Inject;
@ -44,11 +45,11 @@ public class ParseObjectFromHeadersAndHttpContent implements Function<HttpRespon
private final AtmosObject.Factory objectProvider; private final AtmosObject.Factory objectProvider;
@Inject @Inject
public ParseObjectFromHeadersAndHttpContent(ParseSystemMetadataFromHeaders metadataParser, public ParseObjectFromHeadersAndHttpContent(ParseSystemMetadataFromHeaders systemMetadataParser,
ParseUserMetadataFromHeaders userMetadataParser, AtmosObject.Factory objectProvider) { ParseUserMetadataFromHeaders userMetadataParser, AtmosObject.Factory objectProvider) {
this.systemMetadataParser = metadataParser; this.systemMetadataParser = checkNotNull(systemMetadataParser, "systemMetadataParser");
this.userMetadataParser = userMetadataParser; this.userMetadataParser = checkNotNull(userMetadataParser, "userMetadataParser");
this.objectProvider = objectProvider; this.objectProvider = checkNotNull(objectProvider, "objectProvider");
} }
/** /**
@ -60,8 +61,9 @@ public class ParseObjectFromHeadersAndHttpContent implements Function<HttpRespon
* @throws org.jclouds.http.HttpException * @throws org.jclouds.http.HttpException
*/ */
public AtmosObject apply(HttpResponse from) { public AtmosObject apply(HttpResponse from) {
AtmosObject object = objectProvider.create(systemMetadataParser.apply(from), checkNotNull(from, "http response");
userMetadataParser.apply(from)); AtmosObject object = objectProvider.create(systemMetadataParser.apply(from), userMetadataParser.apply(from));
object.getContentMetadata().setName(object.getSystemMetadata().getObjectName());
object.getAllHeaders().putAll(from.getHeaders()); object.getAllHeaders().putAll(from.getHeaders());
object.setPayload(from.getPayload()); object.setPayload(from.getPayload());
object.getContentMetadata().setContentLength(attemptToParseSizeAndRangeFromHeaders(from)); object.getContentMetadata().setContentLength(attemptToParseSizeAndRangeFromHeaders(from));

View File

@ -45,10 +45,11 @@ public class ParseSystemMetadataFromHeaders implements Function<HttpResponse, Sy
@Inject @Inject
public ParseSystemMetadataFromHeaders(DateService dateService) { public ParseSystemMetadataFromHeaders(DateService dateService) {
this.dateService = dateService; this.dateService = checkNotNull(dateService, "dateService");
} }
public SystemMetadata apply(HttpResponse from) { public SystemMetadata apply(HttpResponse from) {
checkNotNull(from, "http response");
String meta = checkNotNull(from.getFirstHeaderOrNull(AtmosStorageHeaders.META), AtmosStorageHeaders.META); String meta = checkNotNull(from.getFirstHeaderOrNull(AtmosStorageHeaders.META), AtmosStorageHeaders.META);
Map<String, String> metaMap = Maps.newHashMap(); Map<String, String> metaMap = Maps.newHashMap();
String[] metas = meta.split(", "); String[] metas = meta.split(", ");
@ -59,12 +60,12 @@ public class ParseSystemMetadataFromHeaders implements Function<HttpResponse, Sy
assert metaMap.size() >= 12 : String.format("Should be 12 entries in %s", metaMap); assert metaMap.size() >= 12 : String.format("Should be 12 entries in %s", metaMap);
byte[] md5 = metaMap.containsKey("content-md5") ? CryptoStreams.hex(metaMap.get("content-md5")) : null; byte[] md5 = metaMap.containsKey("content-md5") ? CryptoStreams.hex(metaMap.get("content-md5")) : null;
return new SystemMetadata(md5, dateService.iso8601SecondsDateParse(checkNotNull(metaMap.get("atime"), "atime")), return new SystemMetadata(md5, dateService.iso8601SecondsDateParse(checkNotNull(metaMap.get("atime"), "atime")),
dateService.iso8601SecondsDateParse(checkNotNull(metaMap.get("ctime"), "ctime")), checkNotNull(metaMap dateService.iso8601SecondsDateParse(checkNotNull(metaMap.get("ctime"), "ctime")), checkNotNull(
.get("gid"), "gid"), dateService.iso8601SecondsDateParse(checkNotNull(metaMap.get("itime"), metaMap.get("gid"), "gid"), dateService.iso8601SecondsDateParse(checkNotNull(metaMap.get("itime"),
"itime")), dateService.iso8601SecondsDateParse(checkNotNull(metaMap.get("mtime"), "mtime")), "itime")), dateService.iso8601SecondsDateParse(checkNotNull(metaMap.get("mtime"), "mtime")),
Integer.parseInt(checkNotNull(metaMap.get("nlink"), "nlink")), checkNotNull(metaMap.get("objectid"), Integer.parseInt(checkNotNull(metaMap.get("nlink"), "nlink")), checkNotNull(metaMap.get("objectid"),
"objectid"), checkNotNull(metaMap.get("objname"), "objname"), checkNotNull(metaMap "objectid"), checkNotNull(metaMap.get("objname"), "objname"), checkNotNull(metaMap.get("policyname"),
.get("policyname"), "policyname"), Long.parseLong(checkNotNull(metaMap.get("size"), "size")), "policyname"), Long.parseLong(checkNotNull(metaMap.get("size"), "size")),
FileType.fromValue(checkNotNull(metaMap.get("type"), "type")), checkNotNull(metaMap.get("uid"), "uid")); FileType.fromValue(checkNotNull(metaMap.get("type"), "type")), checkNotNull(metaMap.get("uid"), "uid"));
} }
} }

View File

@ -31,54 +31,55 @@ import org.jclouds.atmosonline.saas.reference.AtmosStorageHeaders;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
/** /**
* @author Adrian Cole * @author Adrian Cole
*/ */
@Singleton @Singleton
public class ParseUserMetadataFromHeaders implements Function<HttpResponse, UserMetadata> { public class ParseUserMetadataFromHeaders implements Function<HttpResponse, UserMetadata> {
private final Set<String> sysKeys = ImmutableSet.of("atime", "ctime", "gid", "itime", "mtime", private static final Set<String> sysKeys = ImmutableSet.of("atime", "ctime", "gid", "itime", "mtime", "nlink",
"nlink", "policyname", "size", "uid"); "policyname", "size", "uid", "content-md5", "objectid", "objname", "type");
private static final Predicate<String> filter = new Predicate<String>() {
@Override
public boolean apply(String arg0) {
return !sysKeys.contains(arg0);
}
};
public UserMetadata apply(HttpResponse from) { public UserMetadata apply(HttpResponse from) {
UserMetadata md = new UserMetadata(); checkNotNull(from, "http response");
Map<String, String> metaMap = getMetaMap(checkNotNull(from
.getFirstHeaderOrNull(AtmosStorageHeaders.META), AtmosStorageHeaders.META));
Set<String> keys = Sets.difference(metaMap.keySet(), sysKeys); Map<String, String> meta = Maps.filterKeys(
for (String key : keys) { getMetaMap(checkNotNull(from.getFirstHeaderOrNull(AtmosStorageHeaders.META), AtmosStorageHeaders.META)),
md.getMetadata().put(key, metaMap.get(key)); filter);
}
if (from.getFirstHeaderOrNull(AtmosStorageHeaders.LISTABLE_META) != null)
md.getListableMetadata().putAll(
getMetaMap(from.getFirstHeaderOrNull(AtmosStorageHeaders.LISTABLE_META)));
if (from.getFirstHeaderOrNull(AtmosStorageHeaders.TAGS) != null) Map<String, String> listableMeta = (from.getFirstHeaderOrNull(AtmosStorageHeaders.LISTABLE_META) != null) ? getMetaMap(from
md.getTags().addAll(getTags(from.getFirstHeaderOrNull(AtmosStorageHeaders.TAGS))); .getFirstHeaderOrNull(AtmosStorageHeaders.LISTABLE_META)) : ImmutableMap.<String, String> of();
if (from.getFirstHeaderOrNull(AtmosStorageHeaders.LISTABLE_TAGS) != null)
md.getTags().addAll(getTags(from.getFirstHeaderOrNull(AtmosStorageHeaders.LISTABLE_TAGS))); Iterable<String> tags = (from.getFirstHeaderOrNull(AtmosStorageHeaders.TAGS) != null) ? Splitter.on(", ").split(
return md; from.getFirstHeaderOrNull(AtmosStorageHeaders.TAGS)) : ImmutableSet.<String> of();
}
Iterable<String> listableTags = (from.getFirstHeaderOrNull(AtmosStorageHeaders.LISTABLE_TAGS) != null) ? Splitter
private Set<String> getTags(String meta) { .on(", ").split(from.getFirstHeaderOrNull(AtmosStorageHeaders.LISTABLE_TAGS)) : ImmutableSet.<String> of();
Set<String> tags = Sets.newTreeSet();
String[] metas = meta.split(", "); return new UserMetadata(meta, listableMeta, tags, listableTags);
for (String entry : metas) {
tags.add(entry);
}
return tags;
} }
// TODO: change to guava
private Map<String, String> getMetaMap(String meta) { private Map<String, String> getMetaMap(String meta) {
Map<String, String> metaMap = Maps.newHashMap(); Builder<String, String> metaMap = ImmutableMap.<String, String> builder();
String[] metas = meta.split(", "); for (String entry : Splitter.on(", ").split(meta)) {
for (String entry : metas) {
String[] entrySplit = entry.split("="); String[] entrySplit = entry.split("=");
metaMap.put(entrySplit[0], entrySplit[1]); metaMap.put(entrySplit[0], entrySplit[1]);
} }
return metaMap; return metaMap.build();
} }
} }

View File

@ -19,26 +19,31 @@
package org.jclouds.atmosonline.saas.functions; package org.jclouds.atmosonline.saas.functions;
import static org.jclouds.util.Utils.propagateOrNull; import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.util.Throwables2.propagateOrNull;
import java.net.URI; import java.net.URI;
import javax.annotation.Nullable;
import org.jclouds.blobstore.KeyAlreadyExistsException; import org.jclouds.blobstore.KeyAlreadyExistsException;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.rest.InvocationContext; import org.jclouds.rest.InvocationContext;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function; import com.google.common.base.Function;
/** /**
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public class ReturnEndpointIfAlreadyExists implements Function<Exception, URI>, InvocationContext { public class ReturnEndpointIfAlreadyExists implements Function<Exception, URI>,
InvocationContext<ReturnEndpointIfAlreadyExists> {
private URI endpoint; private URI endpoint;
public URI apply(Exception from) { public URI apply(Exception from) {
if (from instanceof KeyAlreadyExistsException) { if (checkNotNull(from, "exception") instanceof KeyAlreadyExistsException) {
return endpoint; return endpoint;
} }
return URI.class.cast(propagateOrNull(from)); return URI.class.cast(propagateOrNull(from));
@ -46,7 +51,12 @@ public class ReturnEndpointIfAlreadyExists implements Function<Exception, URI>,
@Override @Override
public ReturnEndpointIfAlreadyExists setContext(HttpRequest request) { public ReturnEndpointIfAlreadyExists setContext(HttpRequest request) {
this.endpoint = request == null ? null : request.getEndpoint(); return setEndpoint(request == null ? null : request.getEndpoint());
}
@VisibleForTesting
ReturnEndpointIfAlreadyExists setEndpoint(@Nullable URI endpoint) {
this.endpoint = endpoint;
return this; return this;
} }

View File

@ -60,7 +60,7 @@ public class AtmosStorageClientErrorRetryHandler implements HttpRetryHandler {
public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) { public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) {
if (command.getFailureCount() > retryCountLimit) if (command.getFailureCount() > retryCountLimit)
return false; return false;
if (response.getStatusCode() == 404 && command.getRequest().getMethod().equals("DELETE")) { if (response.getStatusCode() == 404 && command.getCurrentRequest().getMethod().equals("DELETE")) {
command.incrementFailureCount(); command.incrementFailureCount();
return true; return true;
} else if (response.getStatusCode() == 409 || response.getStatusCode() == 400) { } else if (response.getStatusCode() == 409 || response.getStatusCode() == 400) {

View File

@ -42,7 +42,7 @@ import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpResponseException; import org.jclouds.http.HttpResponseException;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.AuthorizationException;
import org.jclouds.util.Utils; import org.jclouds.util.Strings2;
/** /**
* This will parse and set an appropriate exception on the command object. * This will parse and set an appropriate exception on the command object.
@ -72,9 +72,9 @@ public class ParseAtmosStorageErrorFromXmlContent implements HttpErrorHandler {
AtmosStorageError error = null; AtmosStorageError error = null;
if (response.getPayload() != null) { if (response.getPayload() != null) {
try { try {
String content = Utils.toStringAndClose(response.getPayload().getInput()); String content = Strings2.toStringAndClose(response.getPayload().getInput());
if (content != null && content.indexOf('<') >= 0) { if (content != null && content.indexOf('<') >= 0) {
error = utils.parseAtmosStorageErrorFromContent(command, response, Utils.toInputStream(content)); error = utils.parseAtmosStorageErrorFromContent(command, response, Strings2.toInputStream(content));
} else { } else {
exception = content != null ? new HttpResponseException(command, response, content) : exception; exception = content != null ? new HttpResponseException(command, response, content) : exception;
} }
@ -83,7 +83,7 @@ public class ParseAtmosStorageErrorFromXmlContent implements HttpErrorHandler {
} }
} }
if (error != null && error.getCode() == 1016) { if (error != null && error.getCode() == 1016) {
File file = new File(command.getRequest().getEndpoint().getPath()); File file = new File(command.getCurrentRequest().getEndpoint().getPath());
exception = new KeyAlreadyExistsException(file.getParentFile().getAbsolutePath(), file.getName()); exception = new KeyAlreadyExistsException(file.getParentFile().getAbsolutePath(), file.getName());
} else { } else {
switch (response.getStatusCode()) { switch (response.getStatusCode()) {
@ -91,10 +91,10 @@ public class ParseAtmosStorageErrorFromXmlContent implements HttpErrorHandler {
exception = new AuthorizationException(exception.getMessage(), exception); exception = new AuthorizationException(exception.getMessage(), exception);
break; break;
case 404: case 404:
if (!command.getRequest().getMethod().equals("DELETE")) { if (!command.getCurrentRequest().getMethod().equals("DELETE")) {
String message = error != null ? error.getMessage() : String.format("%s -> %s", command.getRequest() String message = error != null ? error.getMessage() : String.format("%s -> %s", command.getCurrentRequest()
.getRequestLine(), response.getStatusLine()); .getRequestLine(), response.getStatusLine());
String path = command.getRequest().getEndpoint().getPath(); String path = command.getCurrentRequest().getEndpoint().getPath();
Matcher matcher = DIRECTORY_PATH.matcher(path); Matcher matcher = DIRECTORY_PATH.matcher(path);
if (matcher.find()) { if (matcher.find()) {
exception = new ContainerNotFoundException(matcher.group(1), message); exception = new ContainerNotFoundException(matcher.group(1), message);

View File

@ -36,7 +36,7 @@ import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpException; import org.jclouds.http.HttpException;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.util.Utils; import org.jclouds.util.Assertions;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
@ -61,7 +61,7 @@ public class AtmosStorageUtils {
InputStream content) throws HttpException { InputStream content) throws HttpException {
AtmosStorageError error = (AtmosStorageError) factory.create(errorHandlerProvider.get()).parse(content); AtmosStorageError error = (AtmosStorageError) factory.create(errorHandlerProvider.get()).parse(content);
if (error.getCode() == 1032) { if (error.getCode() == 1032) {
error.setStringSigned(signer.createStringToSign(command.getRequest())); error.setStringSigned(signer.createStringToSign(command.getCurrentRequest()));
} }
return error; return error;
@ -77,7 +77,7 @@ public class AtmosStorageUtils {
public static void deleteAndEnsureGone(final AtmosStorageClient sync, final String path) { public static void deleteAndEnsureGone(final AtmosStorageClient sync, final String path) {
try { try {
if (!Utils.eventuallyTrue(new Supplier<Boolean>() { if (!Assertions.eventuallyTrue(new Supplier<Boolean>() {
public Boolean get() { public Boolean get() {
sync.deletePath(path); sync.deletePath(path);
return !sync.pathExists(path); return !sync.pathExists(path);

View File

@ -19,7 +19,7 @@
package org.jclouds.atmosonline.saas.xml; package org.jclouds.atmosonline.saas.xml;
import java.util.SortedSet; import java.util.Set;
import org.jclouds.atmosonline.saas.domain.DirectoryEntry; import org.jclouds.atmosonline.saas.domain.DirectoryEntry;
import org.jclouds.atmosonline.saas.domain.FileType; import org.jclouds.atmosonline.saas.domain.FileType;
@ -34,17 +34,16 @@ import com.google.common.collect.Sets;
* @see <a href="https://community.emc.com/community/labs/atmos_online" /> * @see <a href="https://community.emc.com/community/labs/atmos_online" />
* @author Adrian Cole * @author Adrian Cole
*/ */
public class ListDirectoryResponseHandler extends public class ListDirectoryResponseHandler extends ParseSax.HandlerWithResult<Set<DirectoryEntry>> {
ParseSax.HandlerWithResult<SortedSet<DirectoryEntry>> {
private SortedSet<DirectoryEntry> entries = Sets.newTreeSet(); private Set<DirectoryEntry> entries = Sets.newLinkedHashSet();
private String currentObjectId; private String currentObjectId;
private FileType currentType; private FileType currentType;
private String currentName; private String currentName;
private StringBuilder currentText = new StringBuilder(); private StringBuilder currentText = new StringBuilder();
public SortedSet<DirectoryEntry> getResult() { public Set<DirectoryEntry> getResult() {
return entries; return entries;
} }

View File

@ -61,11 +61,12 @@ import com.google.inject.Module;
import com.google.inject.TypeLiteral; import com.google.inject.TypeLiteral;
/** /**
* Tests behavior of {@code AtmosStorageClient} * Tests behavior of {@code AtmosStorageAsyncClient}
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit", testName = "emcsaas.AtmosStorageClientTest") // NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
@Test(groups = "unit", testName = "AtmosStorageAsyncClientTest")
public class AtmosStorageAsyncClientTest extends RestClientTest<AtmosStorageAsyncClient> { public class AtmosStorageAsyncClientTest extends RestClientTest<AtmosStorageAsyncClient> {
private BlobToObject blobToObject; private BlobToObject blobToObject;

View File

@ -40,7 +40,8 @@ import org.jclouds.blobstore.integration.internal.BaseBlobStoreIntegrationTest;
import org.jclouds.http.HttpResponseException; import org.jclouds.http.HttpResponseException;
import org.jclouds.io.Payloads; import org.jclouds.io.Payloads;
import org.jclouds.io.payloads.InputStreamPayload; import org.jclouds.io.payloads.InputStreamPayload;
import org.jclouds.util.Utils; import org.jclouds.util.Assertions;
import org.jclouds.util.Strings2;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
@ -53,7 +54,7 @@ import com.google.common.collect.Sets;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "live", sequential = true, testName = "emcsaas.AtmosStorageClientLiveTest") @Test(groups = "live", sequential = true)
public class AtmosStorageClientLiveTest extends BaseBlobStoreIntegrationTest { public class AtmosStorageClientLiveTest extends BaseBlobStoreIntegrationTest {
public AtmosStorageClient getApi() { public AtmosStorageClient getApi() {
@ -187,7 +188,7 @@ public class AtmosStorageClientLiveTest extends BaseBlobStoreIntegrationTest {
} }
Object makeData(String in, boolean stream) { Object makeData(String in, boolean stream) {
return stream ? Utils.toInputStream(in) : in; return stream ? Strings2.toInputStream(in) : in;
} }
private void createOrReplaceObject(String name, Object data, String metadataValue) throws Exception { private void createOrReplaceObject(String name, Object data, String metadataValue) throws Exception {
@ -239,14 +240,14 @@ public class AtmosStorageClientLiveTest extends BaseBlobStoreIntegrationTest {
private static void verifyHeadObject(AtmosStorageClient connection, String path, String metadataValue) private static void verifyHeadObject(AtmosStorageClient connection, String path, String metadataValue)
throws InterruptedException, ExecutionException, TimeoutException, IOException { throws InterruptedException, ExecutionException, TimeoutException, IOException {
AtmosObject getBlob = connection.headFile(path); AtmosObject getBlob = connection.headFile(path);
assertEquals(Utils.toStringAndClose(getBlob.getPayload().getInput()), ""); assertEquals(Strings2.toStringAndClose(getBlob.getPayload().getInput()), "");
verifyMetadata(metadataValue, getBlob); verifyMetadata(metadataValue, getBlob);
} }
private static void verifyObject(AtmosStorageClient connection, String path, String compare, String metadataValue) private static void verifyObject(AtmosStorageClient connection, String path, String compare, String metadataValue)
throws InterruptedException, ExecutionException, TimeoutException, IOException { throws InterruptedException, ExecutionException, TimeoutException, IOException {
AtmosObject getBlob = connection.readFile(path); AtmosObject getBlob = connection.readFile(path);
assertEquals(Utils.toStringAndClose(getBlob.getPayload().getInput()), compare); assertEquals(Strings2.toStringAndClose(getBlob.getPayload().getInput()), compare);
verifyMetadata(metadataValue, getBlob); verifyMetadata(metadataValue, getBlob);
} }
@ -269,7 +270,7 @@ public class AtmosStorageClientLiveTest extends BaseBlobStoreIntegrationTest {
assert md.getUserID() != null; assert md.getUserID() != null;
try { try {
Utils.toStringAndClose(URI.create( Strings2.toStringAndClose(URI.create(
"http://accesspoint.emccis.com/rest/objects/" + getBlob.getSystemMetadata().getObjectID()).toURL() "http://accesspoint.emccis.com/rest/objects/" + getBlob.getSystemMetadata().getObjectID()).toURL()
.openStream()); .openStream());
assert false : "shouldn't have worked, since it is private"; assert false : "shouldn't have worked, since it is private";
@ -325,7 +326,7 @@ public class AtmosStorageClientLiveTest extends BaseBlobStoreIntegrationTest {
getApi().deletePath(path); getApi().deletePath(path);
} catch (KeyNotFoundException ex) { } catch (KeyNotFoundException ex) {
} }
assert Utils.eventuallyTrue(new Supplier<Boolean>() { assert Assertions.eventuallyTrue(new Supplier<Boolean>() {
public Boolean get() { public Boolean get() {
return !getApi().pathExists(path); return !getApi().pathExists(path);
} }

View File

@ -20,7 +20,7 @@
package org.jclouds.atmosonline.saas; package org.jclouds.atmosonline.saas;
import org.jclouds.blobstore.util.BlobStoreUtils; import org.jclouds.blobstore.util.BlobStoreUtils;
import org.jclouds.util.Utils; import org.jclouds.rest.Providers;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
@ -35,7 +35,7 @@ public class ProvidersInPropertiesTest {
@Test @Test
public void testSupportedProviders() { public void testSupportedProviders() {
Iterable<String> providers = Utils.getSupportedProviders(); Iterable<String> providers = Providers.getSupportedProviders();
assert Iterables.contains(providers, "atmosonline") : providers; assert Iterables.contains(providers, "atmosonline") : providers;
assert Iterables.contains(providers, "synaptic") : providers; assert Iterables.contains(providers, "synaptic") : providers;
} }

View File

@ -0,0 +1,89 @@
/**
*
* Copyright (C) 2010 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 org.testng.Assert.assertEquals;
import java.io.File;
import java.net.URI;
import javax.ws.rs.HttpMethod;
import org.jclouds.atmosonline.saas.domain.AtmosObject;
import org.jclouds.http.HttpRequest;
import org.jclouds.io.Payload;
import org.jclouds.io.Payloads;
import org.testng.annotations.Test;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
* Tests behavior of {@code BindMetadataToHeaders}
*
* @author Adrian Cole
*/
@Test(groups = "unit")
public class BindMetadataToHeadersTest {
Injector injector = Guice.createInjector();
BindMetadataToHeaders binder = injector.getInstance(BindMetadataToHeaders.class);
public void testGood() {
AtmosObject object = injector.getInstance(AtmosObject.Factory.class).create(null);
Payload payload = Payloads.newStringPayload("");
object.setPayload(payload);
object.getUserMetadata().getListableMetadata().put("apple", "bear");
object.getUserMetadata().getListableMetadata().put("sushi", "king");
HttpRequest request = new HttpRequest("GET", URI.create("http://localhost"));
request = binder.bindToRequest(request, object);
assertEquals(request.getFirstHeaderOrNull("x-emc-listable-meta"), "apple=bear,sushi=king");
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testMustBeAtmosObject() {
HttpRequest request = new HttpRequest(HttpMethod.POST, URI.create("http://localhost"));
binder.bindToRequest(request, new File("foo"));
}
@Test(expectedExceptions = NullPointerException.class)
public void testNullIsBad() {
HttpRequest request = HttpRequest.builder().method("GET").endpoint(URI.create("http://momma")).build();
binder.bindToRequest(request, null);
}
@Test(expectedExceptions = NullPointerException.class)
public void testNullPayloadIsBad() {
AtmosObject object = injector.getInstance(AtmosObject.Factory.class).create(null);
HttpRequest request = new HttpRequest("GET", URI.create("http://localhost"));
binder.bindToRequest(request, object);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testNullContentLengthIllegal() {
AtmosObject object = injector.getInstance(AtmosObject.Factory.class).create(null);
Payload payload = Payloads.newStringPayload("");
payload.getContentMetadata().setContentLength(null);
object.setPayload(payload);
HttpRequest request = new HttpRequest("GET", URI.create("http://localhost"));
binder.bindToRequest(request, object);
}
}

View File

@ -21,8 +21,11 @@ package org.jclouds.atmosonline.saas.binders;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.File;
import java.net.URI; import java.net.URI;
import javax.ws.rs.HttpMethod;
import org.jclouds.atmosonline.saas.domain.UserMetadata; import org.jclouds.atmosonline.saas.domain.UserMetadata;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -35,59 +38,56 @@ import com.google.inject.Injector;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit", testName = "atmossaas.BindUserMetadataToHeadersTest") @Test(groups = "unit")
public class BindUserMetadataToHeadersTest { public class BindUserMetadataToHeadersTest {
Injector injector = Guice.createInjector();
BindUserMetadataToHeaders binder = injector.getInstance(BindUserMetadataToHeaders.class);
public void testMeta() { public void testMeta() {
Injector injector = Guice.createInjector();
BindUserMetadataToHeaders binder = injector
.getInstance(BindUserMetadataToHeaders.class);
UserMetadata metadata = new UserMetadata(); UserMetadata metadata = new UserMetadata();
metadata.getMetadata().put("apple", "bear"); metadata.getMetadata().put("apple", "bear");
metadata.getMetadata().put("sushi", "king"); metadata.getMetadata().put("sushi", "king");
HttpRequest request = new HttpRequest("GET", URI.create("http://localhost")); HttpRequest request = new HttpRequest("GET", URI.create("http://localhost"));
binder.bindToRequest(request, metadata); request = binder.bindToRequest(request, metadata);
assertEquals(request.getFirstHeaderOrNull("x-emc-meta"), "apple=bear,sushi=king"); assertEquals(request.getFirstHeaderOrNull("x-emc-meta"), "apple=bear,sushi=king");
} }
public void testListableMeta() { public void testListableMeta() {
Injector injector = Guice.createInjector();
BindUserMetadataToHeaders binder = injector
.getInstance(BindUserMetadataToHeaders.class);
UserMetadata metadata = new UserMetadata(); UserMetadata metadata = new UserMetadata();
metadata.getListableMetadata().put("apple", "bear"); metadata.getListableMetadata().put("apple", "bear");
metadata.getListableMetadata().put("sushi", "king"); metadata.getListableMetadata().put("sushi", "king");
HttpRequest request = new HttpRequest("GET", URI.create("http://localhost")); HttpRequest request = new HttpRequest("GET", URI.create("http://localhost"));
binder.bindToRequest(request, metadata); request = binder.bindToRequest(request, metadata);
assertEquals(request.getFirstHeaderOrNull("x-emc-listable-meta"), "apple=bear,sushi=king"); assertEquals(request.getFirstHeaderOrNull("x-emc-listable-meta"), "apple=bear,sushi=king");
} }
public void testTags() { public void testTags() {
Injector injector = Guice.createInjector();
BindUserMetadataToHeaders binder = injector
.getInstance(BindUserMetadataToHeaders.class);
UserMetadata tagsdata = new UserMetadata(); UserMetadata tagsdata = new UserMetadata();
tagsdata.getTags().add("apple"); tagsdata.getTags().add("apple");
tagsdata.getTags().add("sushi"); tagsdata.getTags().add("sushi");
HttpRequest request = new HttpRequest("GET", URI.create("http://localhost")); HttpRequest request = new HttpRequest("GET", URI.create("http://localhost"));
binder.bindToRequest(request, tagsdata); request = binder.bindToRequest(request, tagsdata);
assertEquals(request.getFirstHeaderOrNull("x-emc-tags"), "apple,sushi"); assertEquals(request.getFirstHeaderOrNull("x-emc-tags"), "apple,sushi");
} }
public void testListableTags() { public void testListableTags() {
Injector injector = Guice.createInjector();
BindUserMetadataToHeaders binder = injector
.getInstance(BindUserMetadataToHeaders.class);
UserMetadata tagsdata = new UserMetadata(); UserMetadata tagsdata = new UserMetadata();
tagsdata.getListableTags().add("apple"); tagsdata.getListableTags().add("apple");
tagsdata.getListableTags().add("sushi"); tagsdata.getListableTags().add("sushi");
HttpRequest request = new HttpRequest("GET", URI.create("http://localhost")); HttpRequest request = new HttpRequest("GET", URI.create("http://localhost"));
binder.bindToRequest(request, tagsdata); request = binder.bindToRequest(request, tagsdata);
assertEquals(request.getFirstHeaderOrNull("x-emc-listable-tags"), "apple,sushi"); assertEquals(request.getFirstHeaderOrNull("x-emc-listable-tags"), "apple,sushi");
} }
@Test(expectedExceptions = IllegalArgumentException.class)
public void testMustBeUserMetadata() {
HttpRequest request = new HttpRequest(HttpMethod.POST, URI.create("http://localhost"));
binder.bindToRequest(request, new File("foo"));
}
@Test(expectedExceptions = { NullPointerException.class, IllegalStateException.class })
public void testNullIsBad() {
HttpRequest request = HttpRequest.builder().method("GET").endpoint(URI.create("http://momma")).build();
binder.bindToRequest(request, null);
}
} }

View File

@ -45,7 +45,13 @@ import com.google.common.base.Supplier;
import com.google.inject.Module; import com.google.inject.Module;
import com.google.inject.TypeLiteral; import com.google.inject.TypeLiteral;
@Test(groups = "unit", testName = "emcsaas.AtmosBlobRequestSignerTest") /**
* Tests behavior of {@code AtmosBlobRequestSigner}
*
* @author Adrian Cole
*/
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
@Test(groups = "unit", testName = "AtmosBlobRequestSignerTest")
public class AtmosBlobRequestSignerTest extends RestClientTest<AtmosStorageAsyncClient> { public class AtmosBlobRequestSignerTest extends RestClientTest<AtmosStorageAsyncClient> {
private BlobRequestSigner signer; private BlobRequestSigner signer;

View File

@ -37,7 +37,7 @@ import com.google.inject.Module;
/** /**
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit", testName = "emcsaas.AtmosBlobStoreModuleTest") @Test(groups = "unit")
public class AtmosBlobStoreModuleTest { public class AtmosBlobStoreModuleTest {
Injector createInjector() { Injector createInjector() {

View File

@ -31,7 +31,7 @@ import com.google.inject.Injector;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit", testName = "atmossaas.ObjectToBlobMetadataTest") @Test(groups = "unit")
public class ObjectToBlobMetadataTest { public class ObjectToBlobMetadataTest {
public void testFromWhenTypeIsDirectory() { public void testFromWhenTypeIsDirectory() {

View File

@ -24,7 +24,7 @@ import javax.inject.Singleton;
import org.jclouds.atmosonline.saas.domain.BoundedSet; import org.jclouds.atmosonline.saas.domain.BoundedSet;
import org.jclouds.atmosonline.saas.domain.DirectoryEntry; import org.jclouds.atmosonline.saas.domain.DirectoryEntry;
import org.jclouds.atmosonline.saas.domain.FileType; import org.jclouds.atmosonline.saas.domain.FileType;
import org.jclouds.atmosonline.saas.domain.internal.BoundedHashSet; import org.jclouds.atmosonline.saas.domain.internal.BoundedLinkedHashSet;
import org.jclouds.blobstore.domain.StorageMetadata; import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.domain.StorageType; import org.jclouds.blobstore.domain.StorageType;
@ -42,7 +42,7 @@ public class ResourceMetadataListToDirectoryEntryList
public BoundedSet<DirectoryEntry> apply( public BoundedSet<DirectoryEntry> apply(
org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata> from) { org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata> from) {
return new BoundedHashSet<DirectoryEntry>(Iterables.transform(from, return new BoundedLinkedHashSet<DirectoryEntry>(Iterables.transform(from,
new Function<StorageMetadata, DirectoryEntry>() { new Function<StorageMetadata, DirectoryEntry>() {
public DirectoryEntry apply(StorageMetadata from) { public DirectoryEntry apply(StorageMetadata from) {
FileType type = (from.getType() == StorageType.FOLDER || from.getType() == StorageType.RELATIVE_PATH) ? FileType.DIRECTORY FileType type = (from.getType() == StorageType.FOLDER || from.getType() == StorageType.RELATIVE_PATH) ? FileType.DIRECTORY

View File

@ -26,7 +26,7 @@ import org.testng.annotations.Test;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = { "live" }, testName = "emcsaas.AtmosBlobSignerLiveTest") @Test(groups = { "live" })
public class AtmosBlobSignerLiveTest extends BaseBlobSignerLiveTest { public class AtmosBlobSignerLiveTest extends BaseBlobSignerLiveTest {
} }

View File

@ -31,7 +31,7 @@ import org.testng.annotations.Test;
/** /**
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "live", testName = "emcsaas.AtmosStorageContainerIntegrationTest") @Test(groups = "live")
public class AtmosStorageContainerIntegrationLiveTest extends BaseContainerIntegrationTest { public class AtmosStorageContainerIntegrationLiveTest extends BaseContainerIntegrationTest {
@Override @Override

View File

@ -25,7 +25,7 @@ import org.testng.annotations.Test;
/** /**
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = { "live" }, testName = "emcsaas.AtmosStorageContainerLiveTest") @Test(groups = { "live" })
public class AtmosStorageContainerLiveTest extends BaseContainerLiveTest { public class AtmosStorageContainerLiveTest extends BaseContainerLiveTest {
} }

View File

@ -28,7 +28,7 @@ import org.testng.annotations.Test;
/** /**
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "live", testName = "emcsaas.AtmosStorageInputStreamMapIntegrationTest") @Test(groups = "live")
public class AtmosStorageInputStreamMapIntegrationLiveTest extends BaseInputStreamMapIntegrationTest { public class AtmosStorageInputStreamMapIntegrationLiveTest extends BaseInputStreamMapIntegrationTest {
@Override @Override

View File

@ -34,7 +34,7 @@ import org.testng.annotations.Test;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = { "integration", "live" }, testName = "emcsaas.AtmosStorageIntegrationTest") @Test(groups = { "integration", "live" })
public class AtmosStorageIntegrationLiveTest extends BaseBlobIntegrationTest { public class AtmosStorageIntegrationLiveTest extends BaseBlobIntegrationTest {
@DataProvider(name = "delete") @DataProvider(name = "delete")

View File

@ -28,7 +28,7 @@ import org.testng.annotations.Test;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = { "live" }, testName = "emcsaas.AtmosStorageLiveTest") @Test(groups = { "live" })
public class AtmosStorageLiveTest extends BaseBlobLiveTest { public class AtmosStorageLiveTest extends BaseBlobLiveTest {
protected void checkMD5(String container, String name, byte[] md5) { protected void checkMD5(String container, String name, byte[] md5) {
// atmos does not support content-md5 yet // atmos does not support content-md5 yet

View File

@ -29,7 +29,7 @@ import org.testng.annotations.Test;
/** /**
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "live", testName = "emcsaas.AtmosStorageMapIntegrationTest") @Test(groups = "live")
public class AtmosStorageMapIntegrationLiveTest extends BaseBlobMapIntegrationTest { public class AtmosStorageMapIntegrationLiveTest extends BaseBlobMapIntegrationTest {
@Override @Override

View File

@ -25,7 +25,7 @@ import org.testng.annotations.Test;
/** /**
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "live", testName = "emcsaas.AtmosStorageServiceIntegrationTest") @Test(groups = "live")
public class AtmosStorageServiceIntegrationLiveTest extends BaseServiceIntegrationTest { public class AtmosStorageServiceIntegrationLiveTest extends BaseServiceIntegrationTest {
} }

View File

@ -36,55 +36,73 @@ import org.jclouds.date.TimeStamp;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.RequiresHttp; import org.jclouds.http.RequiresHttp;
import org.jclouds.logging.config.NullLoggingModule; import org.jclouds.logging.config.NullLoggingModule;
import org.jclouds.rest.BaseRestClientTest.MockModule;
import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.RestContextFactory; import org.jclouds.rest.RestContextFactory;
import org.jclouds.rest.BaseRestClientTest.MockModule; import org.jclouds.util.Strings2;
import org.jclouds.util.Utils;
import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableMultimap.Builder;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.inject.Injector; import com.google.inject.Injector;
import com.google.inject.Module; import com.google.inject.Module;
@Test(groups = "unit", testName = "emcsaas.SignRequestTest") /**
*
* @author Adrian Cole
*/
@Test(groups = "unit")
public class SignRequestTest { public class SignRequestTest {
private static final String EXPECTED_SIGNATURE = "WHJo1MFevMnK4jCthJ974L3YHoo=";
private static final String UID = "6039ac182f194e15b9261d73ce044939/user1";
private static final String DEFAULT_DATE = "Thu, 05 Jun 2008 16:38:19 GMT";
private static final String KEY = "LJLuryj6zs8ste6Y3jTGQp71xq0="; private static final String KEY = "LJLuryj6zs8ste6Y3jTGQp71xq0=";
private SignRequest filter; private SignRequest filter;
@Test @Test
void testCreateStringToSign() throws IOException { void testCreateStringToSign() throws IOException {
String expects = Utils.toStringAndClose(getClass().getResourceAsStream("/hashstring.txt")); String expects = Strings2.toStringAndClose(getClass().getResourceAsStream("/hashstring.txt"));
HttpRequest request = newRequest(); HttpRequest request = newRequest(preconstructedHeaders().build());
String toSign = filter.replaceDateHeader(request).createStringToSign(request); String toSign = filter.createStringToSign(request);
assertEquals(toSign, expects); assertEquals(toSign, expects);
} }
@Test @Test
void testUid() throws IOException, NoSuchAlgorithmException, InvalidKeyException { void testSignString() throws IOException, NoSuchAlgorithmException, InvalidKeyException {
HttpRequest request = newRequest(); HttpRequest request = newRequest(preconstructedHeaders().build());
filter.replaceUIDHeader(request); String toSign = filter.createStringToSign(request);
assertEquals(request.getFirstHeaderOrNull(AtmosStorageHeaders.UID), "user"); String signature = filter.signString(toSign);
assertEquals(signature, EXPECTED_SIGNATURE);
} }
@Test @Test
void testSignString() throws IOException, NoSuchAlgorithmException, InvalidKeyException { void testFilter() throws IOException, NoSuchAlgorithmException, InvalidKeyException {
String expects = "WHJo1MFevMnK4jCthJ974L3YHoo="; HttpRequest request = newRequest(inputHeaders().build());
request = filter.filter(request);
assertEquals(request.getFirstHeaderOrNull(AtmosStorageHeaders.SIGNATURE), EXPECTED_SIGNATURE);
}
HttpRequest request = newRequest(); @Test
String toSign = filter.replaceDateHeader(request).createStringToSign(request); void testFilterReplacesOldValues() throws IOException, NoSuchAlgorithmException, InvalidKeyException {
String signature = filter.signString(toSign); HttpRequest request = newRequest(inputHeaders().put(AtmosStorageHeaders.SIGNATURE, "foo")
assertEquals(signature, expects); .put(HttpHeaders.DATE, "foo").put(AtmosStorageHeaders.DATE, "foo").put(AtmosStorageHeaders.UID, "foo")
.build());
request = filter.filter(request);
assertEquals(request.getFirstHeaderOrNull(AtmosStorageHeaders.SIGNATURE), EXPECTED_SIGNATURE);
} }
@BeforeClass @BeforeClass
protected void createFilter() { protected void createFilter() {
Injector injector = new RestContextFactory().createContextBuilder( Injector injector = new RestContextFactory()
.createContextBuilder(
"atmosonline", "atmosonline",
"user", UID,
KEY, KEY,
ImmutableSet.<Module> of(new MockModule(), new TestAtmosStorageRestClientModule(), ImmutableSet.<Module> of(new MockModule(), new TestAtmosStorageRestClientModule(),
new NullLoggingModule()), new Properties()).buildInjector(); new NullLoggingModule()), new Properties()).buildInjector();
@ -96,6 +114,7 @@ public class SignRequestTest {
@RequiresHttp @RequiresHttp
@ConfiguresRestClient @ConfiguresRestClient
private static final class TestAtmosStorageRestClientModule extends AtmosStorageRestClientModule { private static final class TestAtmosStorageRestClientModule extends AtmosStorageRestClientModule {
@Override @Override
protected void configure() { protected void configure() {
super.configure(); super.configure();
@ -103,24 +122,34 @@ public class SignRequestTest {
@Override @Override
protected String provideTimeStamp(@TimeStamp Supplier<String> cache) { protected String provideTimeStamp(@TimeStamp Supplier<String> cache) {
return "Thu, 05 Jun 2008 16:38:19 GMT"; return DEFAULT_DATE;
} }
} }
public HttpRequest newRequest() { public HttpRequest newRequest(Multimap<String, String> headers) {
HttpRequest request = new HttpRequest("POST", URI.create("http://localhost/rest/objects")); HttpRequest request = new HttpRequest("POST", URI.create("http://localhost/rest/objects"), headers);
request.setPayload(""); request.setPayload("");
request.getPayload().getContentMetadata().setContentLength(4286l); request.getPayload().getContentMetadata().setContentLength(4286l);
request.getPayload().getContentMetadata().setContentType(MediaType.APPLICATION_OCTET_STREAM); request.getPayload().getContentMetadata().setContentType(MediaType.APPLICATION_OCTET_STREAM);
request.getHeaders().put(AtmosStorageHeaders.LISTABLE_META, "part4/part7/part8=quick");
request.getHeaders().put(AtmosStorageHeaders.META, "part1=buy");
request.getHeaders().put(HttpHeaders.ACCEPT, "*/*");
request.getHeaders().put(AtmosStorageHeaders.USER_ACL, "john=FULL_CONTROL,mary=WRITE");
request.getHeaders().put(AtmosStorageHeaders.DATE, "Thu, 05 Jun 2008 16:38:19 GMT");
request.getHeaders().put(AtmosStorageHeaders.GROUP_ACL, "other=NONE");
request.getHeaders().put(HttpHeaders.HOST, "10.5.115.118");
request.getHeaders().put(AtmosStorageHeaders.UID, "6039ac182f194e15b9261d73ce044939/user1");
return request; return request;
} }
protected Builder<String, String> preconstructedHeaders() {
Builder<String, String> builder = inputHeaders();
builder.put(HttpHeaders.DATE, DEFAULT_DATE);
builder.put(AtmosStorageHeaders.UID, UID);
return builder;
}
protected Builder<String, String> inputHeaders() {
Builder<String, String> builder = ImmutableMultimap.builder();
builder.put(AtmosStorageHeaders.LISTABLE_META, "part4/part7/part8=quick");
builder.put(AtmosStorageHeaders.META, "part1=buy");
builder.put(HttpHeaders.ACCEPT, "*/*");
builder.put(AtmosStorageHeaders.USER_ACL, "john=FULL_CONTROL,mary=WRITE");
builder.put(AtmosStorageHeaders.GROUP_ACL, "other=NONE");
builder.put(AtmosStorageHeaders.DATE, DEFAULT_DATE);
builder.put(HttpHeaders.HOST, "10.5.115.118");
return builder;
}
} }

View File

@ -0,0 +1,69 @@
/**
*
* Copyright (C) 2010 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.functions;
import static org.testng.Assert.assertEquals;
import java.io.File;
import org.jclouds.atmosonline.saas.domain.AtmosObject;
import org.jclouds.atmosonline.saas.domain.AtmosObject.Factory;
import org.jclouds.atmosonline.saas.domain.SystemMetadata;
import org.jclouds.atmosonline.saas.domain.UserMetadata;
import org.testng.annotations.Test;
import com.google.inject.Guice;
/**
*
* @author Adrian Cole
*/
@Test(groups = "unit")
public class AtmosObjectNameTest {
AtmosObjectName fn = new AtmosObjectName();
private static final Factory BLOB_FACTORY = Guice.createInjector().getInstance(AtmosObject.Factory.class);
@Test
public void testCorrectContentMetadataName() throws SecurityException, NoSuchMethodException {
AtmosObject blob = BLOB_FACTORY.create(null);
blob.getContentMetadata().setName("foo");
assertEquals(fn.apply(blob), "foo");
}
@Test
public void testCorrectSystemMetadataObjectName() throws SecurityException, NoSuchMethodException {
AtmosObject blob = BLOB_FACTORY.create(new SystemMetadata(null, null, null, null, null, null, 0, null, "foo",
null, 0, null, null), new UserMetadata());
assertEquals(fn.apply(blob), "foo");
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testMustBeAtmosObject() {
fn.apply(new File("foo"));
}
@Test(expectedExceptions = { NullPointerException.class, IllegalStateException.class })
public void testNullIsBad() {
fn.apply(null);
}
}

View File

@ -0,0 +1,79 @@
/**
*
* Copyright (C) 2010 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.functions;
import static org.testng.Assert.assertEquals;
import java.util.Set;
import org.jclouds.atmosonline.saas.domain.BoundedSet;
import org.jclouds.atmosonline.saas.domain.DirectoryEntry;
import org.jclouds.atmosonline.saas.domain.FileType;
import org.jclouds.atmosonline.saas.domain.internal.BoundedLinkedHashSet;
import org.jclouds.atmosonline.saas.reference.AtmosStorageHeaders;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.functions.BaseHandlerTest;
import org.jclouds.io.Payloads;
import org.testng.annotations.Test;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Sets;
/**
* Tests behavior of {@code ParseDirectoryListFromContentAndHeaders}
*
* @author Adrian Cole
*/
//NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
@Test(groups = "unit", testName = "ParseDirectoryListFromContentAndHeadersTest")
public class ParseDirectoryListFromContentAndHeadersTest extends BaseHandlerTest {
Function<HttpResponse, BoundedSet<DirectoryEntry>> createFn() {
return injector.getInstance(ParseDirectoryListFromContentAndHeaders.class);
}
public void testWithToken() {
HttpResponse response = new HttpResponse(200, "ok", Payloads.newPayload(getClass().getResourceAsStream(
"/list_basic.xml")), ImmutableMultimap.of(AtmosStorageHeaders.TOKEN, "token"));
BoundedSet<DirectoryEntry> result = createFn().apply(response);
assertEquals(result, new BoundedLinkedHashSet<DirectoryEntry>(values(), "token"));
assertEquals(result.getToken(), "token");
}
public void testWithoutToken() {
HttpResponse response = new HttpResponse(200, "ok", Payloads.newPayload(getClass().getResourceAsStream(
"/list_basic.xml")));
BoundedSet<DirectoryEntry> result = createFn().apply(response);
assertEquals(result, values());
assertEquals(result.getToken(), null);
}
protected Set<DirectoryEntry> values() {
Set<DirectoryEntry> expected = Sets.newLinkedHashSet();
expected.add(new DirectoryEntry("4980cdb2a411106a04a4538c92a1b204ad92077de6e3", FileType.DIRECTORY,
"adriancole-blobstore-2096685753"));
expected.add(new DirectoryEntry("4980cdb2a410105404980d99e53a0504ad93939e7dc3", FileType.DIRECTORY,
"adriancole-blobstore247496608"));
return expected;
}
}

View File

@ -0,0 +1,66 @@
/**
*
* Copyright (C) 2010 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.functions;
import static org.testng.Assert.assertEquals;
import org.jclouds.atmosonline.saas.domain.AtmosObject;
import org.jclouds.atmosonline.saas.reference.AtmosStorageHeaders;
import org.jclouds.http.HttpResponse;
import org.jclouds.io.Payloads;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap;
import com.google.inject.Guice;
/**
* Tests behavior of {@code ParseObjectFromHeadersAndHttpContent}
*
* @author Adrian Cole
*/
@Test(groups = "unit")
public class ParseObjectFromHeadersAndHttpContentTest {
static final HttpResponse RESPONSE = new HttpResponse(200, "ok", Payloads.newStringPayload(""),
ImmutableMultimap.of(AtmosStorageHeaders.TAGS, "tag1, tag2", AtmosStorageHeaders.LISTABLE_TAGS,
"listabletag1, listabletag2", AtmosStorageHeaders.META,
"meta1=foo1, content-md5=1f3870be274f6c49b3e31a0c6728957f, atime=2009-10-12T16:09:42Z, mtime=2009-10-19T04:37:00Z,"
+ " ctime=2009-10-19T04:37:00Z, itime=2009-10-12T16:09:42Z, type=directory, uid=root, "
+ "gid=rootr, objectid=4980cdb2b010109b04a44f7bb83f5f04ad354c638ae5, "
+ "objname=e913e09366364e9ba384b8fead643d43, size=4096, nlink=1, policyname=default",
AtmosStorageHeaders.LISTABLE_META, "listablemeta1=listablefoo1, listablemeta2=listablefoo2"));
public static final AtmosObject EXPECTED;
static {
EXPECTED = Guice.createInjector().getInstance(AtmosObject.Factory.class)
.create(ParseSystemMetadataFromHeadersTest.EXPECTED, ParseUserMetadataFromHeadersTest.EXPECTED);
EXPECTED.getContentMetadata().setName("e913e09366364e9ba384b8fead643d43");
EXPECTED.setPayload(RESPONSE.getPayload());
}
public void test() {
ParseObjectFromHeadersAndHttpContent parser = Guice.createInjector().getInstance(
ParseObjectFromHeadersAndHttpContent.class);
AtmosObject data = parser.apply(RESPONSE);
assertEquals(data, EXPECTED);
}
}

View File

@ -25,44 +25,35 @@ import org.jclouds.atmosonline.saas.domain.FileType;
import org.jclouds.atmosonline.saas.domain.SystemMetadata; import org.jclouds.atmosonline.saas.domain.SystemMetadata;
import org.jclouds.crypto.CryptoStreams; import org.jclouds.crypto.CryptoStreams;
import org.jclouds.date.DateService; import org.jclouds.date.DateService;
import org.jclouds.http.HttpResponse; import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.io.Payloads;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.Injector;
/** /**
* Tests behavior of {@code ParseSystemMetadataFromHeaders} * Tests behavior of {@code ParseSystemMetadataFromHeaders}
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit", testName = "atmossaas.ParseSystemMetadataFromHeadersTest") @Test(groups = "unit")
public class ParseSystemMetadataFromHeadersTest { public class ParseSystemMetadataFromHeadersTest {
static final DateService dateService = new SimpleDateFormatDateService();
static final SystemMetadata EXPECTED = new SystemMetadata(CryptoStreams.hex("1f3870be274f6c49b3e31a0c6728957f"),
public void test() { dateService.iso8601SecondsDateParse("2009-10-12T16:09:42Z"),
Injector injector = Guice.createInjector(); dateService.iso8601SecondsDateParse("2009-10-19T04:37:00Z"), "rootr",
ParseSystemMetadataFromHeaders parser = injector.getInstance(ParseSystemMetadataFromHeaders.class); dateService.iso8601SecondsDateParse("2009-10-12T16:09:42Z"),
DateService dateService = injector.getInstance(DateService.class); dateService.iso8601SecondsDateParse("2009-10-19T04:37:00Z"), 1,
"4980cdb2b010109b04a44f7bb83f5f04ad354c638ae5", "e913e09366364e9ba384b8fead643d43", "default", 4096l,
HttpResponse response = new HttpResponse(200, "ok", Payloads.newStringPayload("")); FileType.DIRECTORY, "root"
response.getHeaders().put(
"x-emc-meta",
"content-md5=1f3870be274f6c49b3e31a0c6728957f, atime=2009-10-12T16:09:42Z, mtime=2009-10-19T04:37:00Z,"
+ " ctime=2009-10-19T04:37:00Z, itime=2009-10-12T16:09:42Z, type=directory, uid=root, "
+ "gid=rootr, objectid=4980cdb2b010109b04a44f7bb83f5f04ad354c638ae5, "
+ "objname=e913e09366364e9ba384b8fead643d43, size=4096, nlink=1, policyname=default");
SystemMetadata expected = new SystemMetadata(CryptoStreams.hex("1f3870be274f6c49b3e31a0c6728957f"),
dateService.iso8601SecondsDateParse("2009-10-12T16:09:42Z"), dateService
.iso8601SecondsDateParse("2009-10-19T04:37:00Z"), "rootr", dateService
.iso8601SecondsDateParse("2009-10-12T16:09:42Z"), dateService
.iso8601SecondsDateParse("2009-10-19T04:37:00Z"), 1, "4980cdb2b010109b04a44f7bb83f5f04ad354c638ae5",
"e913e09366364e9ba384b8fead643d43", "default", 4096l, FileType.DIRECTORY, "root"
); );
SystemMetadata data = parser.apply(response);
assertEquals(data, expected); public void test() {
ParseSystemMetadataFromHeaders parser = Guice.createInjector().getInstance(ParseSystemMetadataFromHeaders.class);
SystemMetadata data = parser.apply(ParseObjectFromHeadersAndHttpContentTest.RESPONSE);
assertEquals(data, EXPECTED);
} }
} }

View File

@ -0,0 +1,48 @@
/**
*
* Copyright (C) 2010 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.functions;
import static org.testng.Assert.assertEquals;
import org.jclouds.atmosonline.saas.domain.UserMetadata;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Guice;
/**
* Tests behavior of {@code ParseUserMetadataFromHeaders}
*
* @author Adrian Cole
*/
@Test(groups = "unit")
public class ParseUserMetadataFromHeadersTest {
static final UserMetadata EXPECTED = new UserMetadata(ImmutableMap.<String, String> of("meta1", "foo1"),
ImmutableMap.of("listablemeta1", "listablefoo1", "listablemeta2", "listablefoo2"), ImmutableSet.of("tag1",
"tag2"), ImmutableSet.of("listabletag1", "listabletag2"));
public void test() {
ParseUserMetadataFromHeaders parser = Guice.createInjector().getInstance(ParseUserMetadataFromHeaders.class);
UserMetadata data = parser.apply(ParseObjectFromHeadersAndHttpContentTest.RESPONSE);
assertEquals(data, EXPECTED);
}
}

View File

@ -0,0 +1,38 @@
package org.jclouds.atmosonline.saas.functions;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import org.jclouds.blobstore.KeyAlreadyExistsException;
import org.testng.annotations.Test;
/**
*
* @author Adrian Cole
*/
@Test(groups = "unit")
public class ReturnEndpointIfAlreadyExistsTest {
@Test
public void testFoundIsNullWhenEndpointNotSet() {
assertEquals(new ReturnEndpointIfAlreadyExists().apply(new KeyAlreadyExistsException()), null);
}
@Test
public void testFoundIsEndpointWhenSet() {
assertEquals(
new ReturnEndpointIfAlreadyExists().setEndpoint(URI.create("foo")).apply(new KeyAlreadyExistsException()),
URI.create("foo"));
}
@Test(expectedExceptions = RuntimeException.class)
public void testNotFoundPropagates() {
new ReturnEndpointIfAlreadyExists().apply(new RuntimeException());
}
@Test(expectedExceptions = NullPointerException.class)
public void testNullIsBad() {
new ReturnEndpointIfAlreadyExists().apply(null);
}
}

View File

@ -30,7 +30,7 @@ import com.google.common.collect.ImmutableList;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit", testName = "emcsaas.ListOptionsTest") @Test(groups = "unit")
public class ListOptionsTest { public class ListOptionsTest {
public void testToken() { public void testToken() {

View File

@ -33,7 +33,8 @@ import org.testng.annotations.Test;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit", testName = "atmossaas.ErrorHandlerTest") // NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
@Test(groups = "unit", testName = "ErrorHandlerTest")
public class ErrorHandlerTest extends BaseHandlerTest { public class ErrorHandlerTest extends BaseHandlerTest {
ParseSax<AtmosStorageError> createParser() { ParseSax<AtmosStorageError> createParser() {

View File

@ -22,7 +22,7 @@ package org.jclouds.atmosonline.saas.xml;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.InputStream; import java.io.InputStream;
import java.util.SortedSet; import java.util.Set;
import org.jclouds.atmosonline.saas.domain.DirectoryEntry; import org.jclouds.atmosonline.saas.domain.DirectoryEntry;
import org.jclouds.atmosonline.saas.domain.FileType; import org.jclouds.atmosonline.saas.domain.FileType;
@ -37,24 +37,25 @@ import com.google.common.collect.Sets;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit", testName = "atmossaas.ListDirectoryResponseHandlerTest") //NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
@Test(groups = "unit", testName = "ListDirectoryResponseHandlerTest")
public class ListDirectoryResponseHandlerTest extends BaseHandlerTest { public class ListDirectoryResponseHandlerTest extends BaseHandlerTest {
ParseSax<SortedSet<DirectoryEntry>> createParser() { ParseSax<Set<DirectoryEntry>> createParser() {
ParseSax<SortedSet<DirectoryEntry>> parser = (ParseSax<SortedSet<DirectoryEntry>>) factory ParseSax<Set<DirectoryEntry>> parser = (ParseSax<Set<DirectoryEntry>>) factory
.create(injector.getInstance(ListDirectoryResponseHandler.class)); .create(injector.getInstance(ListDirectoryResponseHandler.class));
return parser; return parser;
} }
public void testApplyInputStreamBase() { public void testApplyInputStreamBase() {
InputStream is = getClass().getResourceAsStream("/list_basic.xml"); InputStream is = getClass().getResourceAsStream("/list_basic.xml");
ParseSax<SortedSet<DirectoryEntry>> parser = createParser(); ParseSax<Set<DirectoryEntry>> parser = createParser();
SortedSet<DirectoryEntry> expected = Sets.newTreeSet(); Set<DirectoryEntry> expected = Sets.newTreeSet();
expected.add(new DirectoryEntry("4980cdb2a411106a04a4538c92a1b204ad92077de6e3", expected.add(new DirectoryEntry("4980cdb2a411106a04a4538c92a1b204ad92077de6e3",
FileType.DIRECTORY, "adriancole-blobstore-2096685753")); FileType.DIRECTORY, "adriancole-blobstore-2096685753"));
expected.add(new DirectoryEntry("4980cdb2a410105404980d99e53a0504ad93939e7dc3", expected.add(new DirectoryEntry("4980cdb2a410105404980d99e53a0504ad93939e7dc3",
FileType.DIRECTORY, "adriancole-blobstore247496608")); FileType.DIRECTORY, "adriancole-blobstore247496608"));
SortedSet<DirectoryEntry> result = parser.parse(is); Set<DirectoryEntry> result = parser.parse(is);
assertEquals(result, expected); assertEquals(result, expected);
} }
} }

View File

@ -40,7 +40,7 @@ public class AWSResponseException extends HttpResponseException {
private AWSError error = new AWSError(); private AWSError error = new AWSError();
public AWSResponseException(HttpCommand command, HttpResponse response, AWSError error) { public AWSResponseException(HttpCommand command, HttpResponse response, AWSError error) {
super(String.format("request %s failed with code %s, error: %s", command.getRequest().getRequestLine(), response super(String.format("request %s failed with code %s, error: %s", command.getCurrentRequest().getRequestLine(), response
.getStatusCode(), error.toString()), command, response); .getStatusCode(), error.toString()), command, response);
this.setError(error); this.setError(error);
@ -48,7 +48,7 @@ public class AWSResponseException extends HttpResponseException {
public AWSResponseException(HttpCommand command, HttpResponse response, AWSError error, public AWSResponseException(HttpCommand command, HttpResponse response, AWSError error,
Throwable cause) { Throwable cause) {
super(String.format("request %1$s failed with error: %2$s", command.getRequest().getRequestLine(), error super(String.format("request %1$s failed with error: %2$s", command.getCurrentRequest().getRequestLine(), error
.toString()), command, response, cause); .toString()), command, response, cause);
this.setError(error); this.setError(error);

View File

@ -22,47 +22,52 @@ package org.jclouds.aws.ec2.binders;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static java.lang.String.format; import static java.lang.String.format;
import static org.jclouds.http.HttpUtils.addFormParamTo;
import org.jclouds.aws.ec2.domain.BlockDeviceMapping; import org.jclouds.aws.ec2.domain.BlockDeviceMapping;
import org.jclouds.aws.ec2.domain.RunningInstance; import org.jclouds.aws.ec2.domain.RunningInstance;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.utils.ModifyRequest;
import org.jclouds.rest.Binder; import org.jclouds.rest.Binder;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableMultimap.Builder;
/** /**
* @author Oleksiy Yarmula * @author Oleksiy Yarmula
* @author Adrian Cole
*/ */
public class BindBlockDeviceMappingToIndexedFormParams implements Binder { public class BindBlockDeviceMappingToIndexedFormParams implements Binder {
private final String deviceNamePattern = "BlockDeviceMapping.%d.DeviceName"; private static final String deviceNamePattern = "BlockDeviceMapping.%d.DeviceName";
private final String volumeIdPattern = "BlockDeviceMapping.%d.Ebs.VolumeId"; private static final String volumeIdPattern = "BlockDeviceMapping.%d.Ebs.VolumeId";
private final String deleteOnTerminationPattern = "BlockDeviceMapping.%d.Ebs.DeleteOnTermination"; private static final String deleteOnTerminationPattern = "BlockDeviceMapping.%d.Ebs.DeleteOnTermination";
public void bindToRequest(HttpRequest request, Object input) { @Override
public <R extends HttpRequest> R bindToRequest(R request, Object input) {
checkArgument(checkNotNull(input, "input") instanceof BlockDeviceMapping, checkArgument(checkNotNull(input, "input") instanceof BlockDeviceMapping,
"this binder is only valid for BlockDeviceMapping"); "this binder is only valid for BlockDeviceMapping");
BlockDeviceMapping blockDeviceMapping = (BlockDeviceMapping) input; BlockDeviceMapping blockDeviceMapping = (BlockDeviceMapping) input;
Builder<String, String> builder = ImmutableMultimap.<String, String> builder();
int amazonOneBasedIndex = 1; // according to docs, counters must start with 1 int amazonOneBasedIndex = 1; // according to docs, counters must start with 1
for (String ebsBlockDeviceName : blockDeviceMapping.getEbsBlockDevices().keySet()) { for (String ebsBlockDeviceName : blockDeviceMapping.getEbsBlockDevices().keySet()) {
for (RunningInstance.EbsBlockDevice ebsBlockDevice : blockDeviceMapping for (RunningInstance.EbsBlockDevice ebsBlockDevice : blockDeviceMapping.getEbsBlockDevices().get(
.getEbsBlockDevices().get(ebsBlockDeviceName)) { ebsBlockDeviceName)) {
// not null by contract // not null by contract
addFormParamTo(request, format(volumeIdPattern, amazonOneBasedIndex), ebsBlockDevice builder.put(format(volumeIdPattern, amazonOneBasedIndex), ebsBlockDevice.getVolumeId());
.getVolumeId());
if (ebsBlockDeviceName != null) { if (ebsBlockDeviceName != null) {
addFormParamTo(request, format(deviceNamePattern, amazonOneBasedIndex), builder.put(format(deviceNamePattern, amazonOneBasedIndex), ebsBlockDeviceName);
ebsBlockDeviceName);
} }
addFormParamTo(request, format(deleteOnTerminationPattern, amazonOneBasedIndex), String builder.put(format(deleteOnTerminationPattern, amazonOneBasedIndex),
.valueOf(ebsBlockDevice.isDeleteOnTermination())); String.valueOf(ebsBlockDevice.isDeleteOnTermination()));
amazonOneBasedIndex++; amazonOneBasedIndex++;
} }
} }
ImmutableMultimap<String, String> forms = builder.build();
return forms.size() == 0 ? request : ModifyRequest.putFormParams(request, forms);
} }
} }

View File

@ -33,9 +33,9 @@ import org.jclouds.rest.Binder;
*/ */
@Singleton @Singleton
public class BindBundleIdsToIndexedFormParams implements Binder { public class BindBundleIdsToIndexedFormParams implements Binder {
@Override
public void bindToRequest(HttpRequest request, Object input) { public <R extends HttpRequest> R bindToRequest(R request, Object input) {
indexStringArrayToFormValuesWithPrefix(request, "BundleId", input); return indexStringArrayToFormValuesWithPrefix(request, "BundleId", input);
} }
} }

View File

@ -32,10 +32,10 @@ import org.jclouds.rest.Binder;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Singleton @Singleton
public class BindGroupNameToIndexedFormParams implements Binder { public class BindGroupNamesToIndexedFormParams implements Binder {
@Override
public void bindToRequest(HttpRequest request, Object input) { public <R extends HttpRequest> R bindToRequest(R request, Object input) {
indexStringArrayToFormValuesWithPrefix(request, "GroupName", input); return indexStringArrayToFormValuesWithPrefix(request, "GroupName", input);
} }
} }

View File

@ -33,9 +33,9 @@ import org.jclouds.rest.Binder;
*/ */
@Singleton @Singleton
public class BindInstanceIdsToIndexedFormParams implements Binder { public class BindInstanceIdsToIndexedFormParams implements Binder {
@Override
public void bindToRequest(HttpRequest request, Object input) { public <R extends HttpRequest> R bindToRequest(R request, Object input) {
indexStringArrayToFormValuesWithPrefix(request, "InstanceId", input); return indexStringArrayToFormValuesWithPrefix(request, "InstanceId", input);
} }
} }

View File

@ -32,10 +32,10 @@ import org.jclouds.rest.Binder;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Singleton @Singleton
public class BindKeyNameToIndexedFormParams implements Binder { public class BindKeyNamesToIndexedFormParams implements Binder {
@Override
public void bindToRequest(HttpRequest request, Object input) { public <R extends HttpRequest> R bindToRequest(R request, Object input) {
indexStringArrayToFormValuesWithPrefix(request, "KeyName", input); return indexStringArrayToFormValuesWithPrefix(request, "KeyName", input);
} }
} }

View File

@ -27,15 +27,15 @@ import org.jclouds.http.HttpRequest;
import org.jclouds.rest.Binder; import org.jclouds.rest.Binder;
/** /**
* Binds the String [] to form parameters named with ProductCode.index * Binds the Iterable to form parameters named with ProductCode.index
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Singleton @Singleton
public class BindProductCodesToIndexedFormParams implements Binder { public class BindProductCodesToIndexedFormParams implements Binder {
@Override
public void bindToRequest(HttpRequest request, Object input) { public <R extends HttpRequest> R bindToRequest(R request, Object input) {
indexIterableToFormValuesWithPrefix(request, "ProductCode", input); return indexIterableToFormValuesWithPrefix(request, "ProductCode", input);
} }
} }

View File

@ -35,11 +35,11 @@ import org.jclouds.rest.Binder;
*/ */
@Singleton @Singleton
public class BindPublicIpsToIndexedFormParams implements Binder { public class BindPublicIpsToIndexedFormParams implements Binder {
@Override
public void bindToRequest(HttpRequest request, Object input) { public <R extends HttpRequest> R bindToRequest(R request, Object input) {
checkArgument(checkNotNull(input, "input") instanceof String[], checkArgument(checkNotNull(input, "input") instanceof String[], "this binder is only valid for String[] : "
"this binder is only valid for String[] : " + input.getClass()); + input.getClass());
String[] addressStrings = (String[]) input; String[] addressStrings = (String[]) input;
indexStringArrayToFormValuesWithPrefix(request, "PublicIp", addressStrings); return indexStringArrayToFormValuesWithPrefix(request, "PublicIp", addressStrings);
} }
} }

View File

@ -20,18 +20,19 @@
package org.jclouds.aws.ec2.binders; package org.jclouds.aws.ec2.binders;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.http.HttpUtils.addFormParamTo;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.aws.filters.FormSigner; import org.jclouds.aws.filters.FormSigner;
import org.jclouds.crypto.Crypto;
import org.jclouds.crypto.CryptoStreams; import org.jclouds.crypto.CryptoStreams;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.utils.ModifyRequest;
import org.jclouds.rest.Binder; import org.jclouds.rest.Binder;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableMultimap.Builder;
/** /**
* *
@ -42,15 +43,18 @@ public class BindS3UploadPolicyAndSignature implements Binder {
private final FormSigner signer; private final FormSigner signer;
@Inject @Inject
BindS3UploadPolicyAndSignature(FormSigner signer, Crypto crypto) { BindS3UploadPolicyAndSignature(FormSigner signer) {
this.signer = signer; this.signer = signer;
} }
public void bindToRequest(HttpRequest request, Object input) { @Override
public <R extends HttpRequest> R bindToRequest(R request, Object input) {
String encodedJson = CryptoStreams.base64(checkNotNull(input, "json").toString().getBytes(Charsets.UTF_8)); String encodedJson = CryptoStreams.base64(checkNotNull(input, "json").toString().getBytes(Charsets.UTF_8));
addFormParamTo(request, "Storage.S3.UploadPolicy", encodedJson); Builder<String, String> builder = ImmutableMultimap.<String, String> builder();
builder.put("Storage.S3.UploadPolicy", encodedJson);
String signature = signer.sign(encodedJson); String signature = signer.sign(encodedJson);
addFormParamTo(request, "Storage.S3.UploadPolicySignature", signature); builder.put("Storage.S3.UploadPolicySignature", signature);
return ModifyRequest.putFormParams(request, builder.build());
} }
} }

View File

@ -37,12 +37,12 @@ import com.google.common.collect.Iterables;
*/ */
@Singleton @Singleton
public class BindUserGroupsToIndexedFormParams implements Binder { public class BindUserGroupsToIndexedFormParams implements Binder {
@Override
public void bindToRequest(HttpRequest request, Object input) { public <R extends HttpRequest> R bindToRequest(R request, Object input) {
checkArgument(checkNotNull(input, "input") instanceof Iterable<?>, checkArgument(checkNotNull(input, "input") instanceof Iterable<?>, "this binder is only valid for Iterable<?>: "
"this binder is only valid for Iterable<?>: " + input.getClass()); + input.getClass());
checkValidUserGroup(input); checkValidUserGroup(input);
indexIterableToFormValuesWithPrefix(request, "UserGroup", input); return indexIterableToFormValuesWithPrefix(request, "UserGroup", input);
} }
private void checkValidUserGroup(Object input) { private void checkValidUserGroup(Object input) {

View File

@ -21,14 +21,17 @@ package org.jclouds.aws.ec2.binders;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.http.HttpUtils.addFormParamTo;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.aws.ec2.domain.UserIdGroupPair; import org.jclouds.aws.ec2.domain.UserIdGroupPair;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.utils.ModifyRequest;
import org.jclouds.rest.Binder; import org.jclouds.rest.Binder;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableMultimap.Builder;
/** /**
* Binds the String [] to query parameters named with GroupName.index * Binds the String [] to query parameters named with GroupName.index
* *
@ -36,12 +39,15 @@ import org.jclouds.rest.Binder;
*/ */
@Singleton @Singleton
public class BindUserIdGroupPairToSourceSecurityGroupFormParams implements Binder { public class BindUserIdGroupPairToSourceSecurityGroupFormParams implements Binder {
@Override
public void bindToRequest(HttpRequest request, Object input) { public <R extends HttpRequest> R bindToRequest(R request, Object input) {
checkArgument(checkNotNull(input, "input") instanceof UserIdGroupPair, checkArgument(checkNotNull(input, "input") instanceof UserIdGroupPair,
"this binder is only valid for UserIdGroupPair!"); "this binder is only valid for UserIdGroupPair!");
UserIdGroupPair pair = (UserIdGroupPair) input; UserIdGroupPair pair = (UserIdGroupPair) input;
addFormParamTo(request, "SourceSecurityGroupOwnerId", pair.getUserId()); Builder<String, String> builder = ImmutableMultimap.<String, String> builder();
addFormParamTo(request, "SourceSecurityGroupName", pair.getGroupName()); builder.put("SourceSecurityGroupOwnerId", pair.getUserId());
builder.put("SourceSecurityGroupName", pair.getGroupName());
return ModifyRequest.putFormParams(request, builder.build());
} }
} }

View File

@ -27,14 +27,15 @@ import org.jclouds.http.HttpRequest;
import org.jclouds.rest.Binder; import org.jclouds.rest.Binder;
/** /**
* Binds the String [] to form parameters named with UserId.index * Binds the Iterable to form parameters named with UserId.index
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Singleton @Singleton
public class BindUserIdsToIndexedFormParams implements Binder { public class BindUserIdsToIndexedFormParams implements Binder {
public void bindToRequest(HttpRequest request, Object input) { @Override
indexIterableToFormValuesWithPrefix(request, "UserId", input); public <R extends HttpRequest> R bindToRequest(R request, Object input) {
return indexIterableToFormValuesWithPrefix(request, "UserId", input);
} }
} }

View File

@ -33,9 +33,9 @@ import org.jclouds.rest.Binder;
*/ */
@Singleton @Singleton
public class BindVolumeIdsToIndexedFormParams implements Binder { public class BindVolumeIdsToIndexedFormParams implements Binder {
@Override
public void bindToRequest(HttpRequest request, Object input) { public <R extends HttpRequest> R bindToRequest(R request, Object input) {
indexStringArrayToFormValuesWithPrefix(request, "VolumeId", input); return indexStringArrayToFormValuesWithPrefix(request, "VolumeId", input);
} }
} }

View File

@ -20,11 +20,11 @@
package org.jclouds.aws.ec2.binders; package org.jclouds.aws.ec2.binders;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static org.jclouds.http.HttpUtils.addFormParamTo;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.utils.ModifyRequest;
import org.jclouds.rest.Binder; import org.jclouds.rest.Binder;
/** /**
@ -34,11 +34,13 @@ import org.jclouds.rest.Binder;
*/ */
@Singleton @Singleton
public class IfNotNullBindAvailabilityZoneToFormParam implements Binder { public class IfNotNullBindAvailabilityZoneToFormParam implements Binder {
public void bindToRequest(HttpRequest request, Object input) { @Override
public <R extends HttpRequest> R bindToRequest(R request, Object input) {
if (input != null) { if (input != null) {
checkArgument(input instanceof String, "this binder is only valid for AvailabilityZone!"); checkArgument(input instanceof String, "this binder is only valid for AvailabilityZone!");
addFormParamTo(request, "Placement.AvailabilityZone", (String) input); return ModifyRequest.addFormParam(request, "Placement.AvailabilityZone", (String) input);
} }
return request;
} }
} }

View File

@ -21,7 +21,6 @@ package org.jclouds.aws.ec2.compute;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
import static org.jclouds.aws.ec2.util.EC2Utils.parseHandle; import static org.jclouds.aws.ec2.util.EC2Utils.parseHandle;
import static org.jclouds.util.Utils.checkNotEmpty;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
@ -62,6 +61,7 @@ import org.jclouds.compute.util.ComputeUtils;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.http.HttpResponseException; import org.jclouds.http.HttpResponseException;
import org.jclouds.util.Preconditions2;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
@ -107,7 +107,7 @@ public class EC2ComputeService extends BaseComputeService {
@VisibleForTesting @VisibleForTesting
void deletePlacementGroup(String region, String tag) { void deletePlacementGroup(String region, String tag) {
checkNotEmpty(tag, "tag"); Preconditions2.checkNotEmpty(tag, "tag");
String group = String.format("jclouds#%s#%s", tag, region); String group = String.format("jclouds#%s#%s", tag, region);
try { try {
if (ec2Client.getPlacementGroupServices().describePlacementGroupsInRegion(region, group).size() > 0) { if (ec2Client.getPlacementGroupServices().describePlacementGroupsInRegion(region, group).size() > 0) {
@ -137,7 +137,7 @@ public class EC2ComputeService extends BaseComputeService {
@VisibleForTesting @VisibleForTesting
void deleteSecurityGroup(String region, String tag) { void deleteSecurityGroup(String region, String tag) {
checkNotEmpty(tag, "tag"); Preconditions2.checkNotEmpty(tag, "tag");
String group = String.format("jclouds#%s#%s", tag, region); String group = String.format("jclouds#%s#%s", tag, region);
if (ec2Client.getSecurityGroupServices().describeSecurityGroupsInRegion(region, group).size() > 0) { if (ec2Client.getSecurityGroupServices().describeSecurityGroupsInRegion(region, group).size() > 0) {
logger.debug(">> deleting securityGroup(%s)", group); logger.debug(">> deleting securityGroup(%s)", group);

View File

@ -20,13 +20,12 @@
package org.jclouds.aws.ec2.compute.functions; package org.jclouds.aws.ec2.compute.functions;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.util.Utils.nullSafeSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Set; import java.util.Set;
import java.util.Map.Entry;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
@ -49,6 +48,7 @@ import org.jclouds.compute.domain.internal.VolumeImpl;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.util.NullSafeCollections;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function; import com.google.common.base.Function;
@ -93,8 +93,8 @@ public class RunningInstanceToNodeMetadata implements Function<RunningInstance,
builder.tag(tag); builder.tag(tag);
builder.credentials(credentialStore.get("node#" + instance.getRegion() + "/" + providerId)); builder.credentials(credentialStore.get("node#" + instance.getRegion() + "/" + providerId));
builder.state(instanceToNodeState.get(instance.getInstanceState())); builder.state(instanceToNodeState.get(instance.getInstanceState()));
builder.publicAddresses(nullSafeSet(instance.getIpAddress())); builder.publicAddresses(NullSafeCollections.nullSafeSet(instance.getIpAddress()));
builder.privateAddresses(nullSafeSet(instance.getPrivateIpAddress())); builder.privateAddresses(NullSafeCollections.nullSafeSet(instance.getPrivateIpAddress()));
builder.hardware(parseHardware(instance)); builder.hardware(parseHardware(instance));
Location location = getLocationForAvailabilityZoneOrRegion(instance); Location location = getLocationForAvailabilityZoneOrRegion(instance);
builder.location(location); builder.location(location);

View File

@ -31,7 +31,7 @@ import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.io.Payload; import org.jclouds.io.Payload;
import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.util.Utils; import org.jclouds.util.Preconditions2;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
@ -80,7 +80,7 @@ public class EC2TemplateOptions extends TemplateOptions {
public EC2TemplateOptions securityGroups(Iterable<String> groupIds) { public EC2TemplateOptions securityGroups(Iterable<String> groupIds) {
checkArgument(Iterables.size(groupIds) > 0, "you must specify at least one security group"); checkArgument(Iterables.size(groupIds) > 0, "you must specify at least one security group");
for (String groupId : groupIds) for (String groupId : groupIds)
Utils.checkNotEmpty(groupId, "all security groups must be non-empty"); Preconditions2.checkNotEmpty(groupId, "all security groups must be non-empty");
this.groupIds = ImmutableSet.copyOf(groupIds); this.groupIds = ImmutableSet.copyOf(groupIds);
return this; return this;
} }
@ -112,7 +112,7 @@ public class EC2TemplateOptions extends TemplateOptions {
public EC2TemplateOptions keyPair(String keyPair) { public EC2TemplateOptions keyPair(String keyPair) {
checkNotNull(keyPair, "use noKeyPair option to request boot without a keypair"); checkNotNull(keyPair, "use noKeyPair option to request boot without a keypair");
checkState(!noKeyPair, "you cannot specify both options keyPair and noKeyPair"); checkState(!noKeyPair, "you cannot specify both options keyPair and noKeyPair");
Utils.checkNotEmpty(keyPair, "keypair must be non-empty"); Preconditions2.checkNotEmpty(keyPair, "keypair must be non-empty");
this.keyPair = keyPair; this.keyPair = keyPair;
return this; return this;
} }
@ -132,7 +132,7 @@ public class EC2TemplateOptions extends TemplateOptions {
public EC2TemplateOptions placementGroup(String placementGroup) { public EC2TemplateOptions placementGroup(String placementGroup) {
checkNotNull(placementGroup, "use noPlacementGroup option to request boot without a keypair"); checkNotNull(placementGroup, "use noPlacementGroup option to request boot without a keypair");
checkState(!noPlacementGroup, "you cannot specify both options placementGroup and noPlacementGroup"); checkState(!noPlacementGroup, "you cannot specify both options placementGroup and noPlacementGroup");
Utils.checkNotEmpty(placementGroup, "placementGroup must be non-empty"); Preconditions2.checkNotEmpty(placementGroup, "placementGroup must be non-empty");
this.placementGroup = placementGroup; this.placementGroup = placementGroup;
return this; return this;
} }
@ -151,7 +151,7 @@ public class EC2TemplateOptions extends TemplateOptions {
*/ */
public EC2TemplateOptions subnetId(String subnetId) { public EC2TemplateOptions subnetId(String subnetId) {
checkNotNull(subnetId, "subnetId cannot be null"); checkNotNull(subnetId, "subnetId cannot be null");
Utils.checkNotEmpty(subnetId, "subnetId must be non-empty"); Preconditions2.checkNotEmpty(subnetId, "subnetId must be non-empty");
this.subnetId = subnetId; this.subnetId = subnetId;
return this; return this;
} }

View File

@ -19,7 +19,7 @@
package org.jclouds.aws.ec2.functions; package org.jclouds.aws.ec2.functions;
import static org.jclouds.util.Utils.propagateOrNull; import static org.jclouds.util.Throwables2.propagateOrNull;
import javax.inject.Singleton; import javax.inject.Singleton;

View File

@ -30,7 +30,7 @@ import javax.ws.rs.POST;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import org.jclouds.aws.ec2.EC2AsyncClient; import org.jclouds.aws.ec2.EC2AsyncClient;
import org.jclouds.aws.ec2.binders.BindKeyNameToIndexedFormParams; import org.jclouds.aws.ec2.binders.BindKeyNamesToIndexedFormParams;
import org.jclouds.aws.ec2.domain.KeyPair; import org.jclouds.aws.ec2.domain.KeyPair;
import org.jclouds.aws.ec2.xml.DescribeKeyPairsResponseHandler; import org.jclouds.aws.ec2.xml.DescribeKeyPairsResponseHandler;
import org.jclouds.aws.ec2.xml.KeyPairResponseHandler; import org.jclouds.aws.ec2.xml.KeyPairResponseHandler;
@ -79,7 +79,7 @@ public interface KeyPairAsyncClient {
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class) @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<? extends Set<KeyPair>> describeKeyPairsInRegion( ListenableFuture<? extends Set<KeyPair>> describeKeyPairsInRegion(
@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region, @EndpointParam(parser = RegionToEndpoint.class) @Nullable String region,
@BinderParam(BindKeyNameToIndexedFormParams.class) String... keyPairNames); @BinderParam(BindKeyNamesToIndexedFormParams.class) String... keyPairNames);
/** /**
* @see KeyPairClient#deleteKeyPairInRegion * @see KeyPairClient#deleteKeyPairInRegion

View File

@ -30,7 +30,7 @@ import javax.ws.rs.POST;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import org.jclouds.aws.ec2.EC2AsyncClient; import org.jclouds.aws.ec2.EC2AsyncClient;
import org.jclouds.aws.ec2.binders.BindGroupNameToIndexedFormParams; import org.jclouds.aws.ec2.binders.BindGroupNamesToIndexedFormParams;
import org.jclouds.aws.ec2.domain.PlacementGroup; import org.jclouds.aws.ec2.domain.PlacementGroup;
import org.jclouds.aws.ec2.xml.DescribePlacementGroupsResponseHandler; import org.jclouds.aws.ec2.xml.DescribePlacementGroupsResponseHandler;
import org.jclouds.aws.filters.FormSigner; import org.jclouds.aws.filters.FormSigner;
@ -97,6 +97,6 @@ public interface PlacementGroupAsyncClient {
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class) @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<? extends Set<PlacementGroup>> describePlacementGroupsInRegion( ListenableFuture<? extends Set<PlacementGroup>> describePlacementGroupsInRegion(
@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region, @EndpointParam(parser = RegionToEndpoint.class) @Nullable String region,
@BinderParam(BindGroupNameToIndexedFormParams.class) String... placementGroupIds); @BinderParam(BindGroupNamesToIndexedFormParams.class) String... placementGroupIds);
} }

View File

@ -30,7 +30,7 @@ import javax.ws.rs.POST;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import org.jclouds.aws.ec2.EC2AsyncClient; import org.jclouds.aws.ec2.EC2AsyncClient;
import org.jclouds.aws.ec2.binders.BindGroupNameToIndexedFormParams; import org.jclouds.aws.ec2.binders.BindGroupNamesToIndexedFormParams;
import org.jclouds.aws.ec2.binders.BindUserIdGroupPairToSourceSecurityGroupFormParams; import org.jclouds.aws.ec2.binders.BindUserIdGroupPairToSourceSecurityGroupFormParams;
import org.jclouds.aws.ec2.domain.IpProtocol; import org.jclouds.aws.ec2.domain.IpProtocol;
import org.jclouds.aws.ec2.domain.SecurityGroup; import org.jclouds.aws.ec2.domain.SecurityGroup;
@ -91,7 +91,7 @@ public interface SecurityGroupAsyncClient {
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class) @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<? extends Set<SecurityGroup>> describeSecurityGroupsInRegion( ListenableFuture<? extends Set<SecurityGroup>> describeSecurityGroupsInRegion(
@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region, @EndpointParam(parser = RegionToEndpoint.class) @Nullable String region,
@BinderParam(BindGroupNameToIndexedFormParams.class) String... securityGroupNames); @BinderParam(BindGroupNamesToIndexedFormParams.class) String... securityGroupNames);
/** /**
* @see SecurityGroupClient#authorizeSecurityGroupIngressInRegion(@Nullable Region, * @see SecurityGroupClient#authorizeSecurityGroupIngressInRegion(@Nullable Region,

View File

@ -21,7 +21,6 @@ package org.jclouds.aws.ec2.util;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.http.HttpUtils.addFormParamTo;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
@ -38,10 +37,13 @@ import org.jclouds.aws.ec2.services.InstanceClient;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.domain.LocationScope; import org.jclouds.domain.LocationScope;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.utils.ModifyRequest;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableMultimap.Builder;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
/** /**
@ -52,14 +54,12 @@ public class EC2Utils {
@Singleton @Singleton
public static class GetRegionFromLocation implements Function<Location, String> { public static class GetRegionFromLocation implements Function<Location, String> {
public String apply(Location location) { public String apply(Location location) {
String region = location.getScope() == LocationScope.REGION ? location.getId() : location String region = location.getScope() == LocationScope.REGION ? location.getId() : location.getParent().getId();
.getParent().getId();
return region; return region;
} }
} }
public static String[] getAvailabilityZonesForRegion(String region) public static String[] getAvailabilityZonesForRegion(String region) {
{
Set<String> availabilityZones = new HashSet<String>(); Set<String> availabilityZones = new HashSet<String>();
for (String az : AvailabilityZone.zones) { for (String az : AvailabilityZone.zones) {
if (az.startsWith(region)) if (az.startsWith(region))
@ -69,20 +69,20 @@ public class EC2Utils {
return (String[]) availabilityZones.toArray(new String[availabilityZones.size()]); return (String[]) availabilityZones.toArray(new String[availabilityZones.size()]);
} }
public static void indexStringArrayToFormValuesWithPrefix(HttpRequest request, String prefix, public static <R extends HttpRequest> R indexStringArrayToFormValuesWithPrefix(R request, String prefix, Object input) {
Object input) { checkArgument(checkNotNull(input, "input") instanceof String[], "this binder is only valid for String[] : "
checkArgument(checkNotNull(input, "input") instanceof String[], + input.getClass());
"this binder is only valid for String[] : " + input.getClass());
String[] values = (String[]) input; String[] values = (String[]) input;
Builder<String, String> builder = ImmutableMultimap.<String, String> builder();
for (int i = 0; i < values.length; i++) { for (int i = 0; i < values.length; i++) {
addFormParamTo(request, prefix + "." + (i + 1), checkNotNull(values[i], prefix builder.put(prefix + "." + (i + 1), checkNotNull(values[i], prefix.toLowerCase() + "s[" + i + "]"));
.toLowerCase()
+ "s[" + i + "]"));
} }
ImmutableMultimap<String, String> forms = builder.build();
return forms.size() == 0 ? request : ModifyRequest.putFormParams(request, forms);
} }
public static Iterable<RunningInstance> getAllRunningInstancesInRegion(InstanceClient client, public static Iterable<RunningInstance> getAllRunningInstancesInRegion(InstanceClient client, String region,
String region, String id) { String id) {
return Iterables.concat(client.describeInstancesInRegion(region, id)); return Iterables.concat(client.describeInstancesInRegion(region, id));
} }
@ -92,17 +92,17 @@ public class EC2Utils {
return parts; return parts;
} }
public static void indexIterableToFormValuesWithPrefix(HttpRequest request, String prefix, public static <R extends HttpRequest> R indexIterableToFormValuesWithPrefix(R request, String prefix, Object input) {
Object input) { checkArgument(checkNotNull(input, "input") instanceof Iterable<?>, "this binder is only valid for Iterable<?>: "
checkArgument(checkNotNull(input, "input") instanceof Iterable<?>, + input.getClass());
"this binder is only valid for Iterable<?>: " + input.getClass());
Iterable<?> values = (Iterable<?>) input; Iterable<?> values = (Iterable<?>) input;
Builder<String, String> builder = ImmutableMultimap.<String, String> builder();
int i = 0; int i = 0;
for (Object o : values) { for (Object o : values) {
addFormParamTo(request, prefix + "." + (i++ + 1), checkNotNull(o.toString(), prefix builder.put(prefix + "." + (i++ + 1), checkNotNull(o.toString(), prefix.toLowerCase() + "s[" + i + "]"));
.toLowerCase()
+ "s[" + i + "]"));
} }
ImmutableMultimap<String, String> forms = builder.build();
return forms.size() == 0 ? request : ModifyRequest.putFormParams(request, forms);
} }
public static String findRegionInArgsOrNull(GeneratedHttpRequest<?> gRequest) { public static String findRegionInArgsOrNull(GeneratedHttpRequest<?> gRequest) {
@ -133,29 +133,28 @@ public class EC2Utils {
return null; return null;
} }
public static void indexStringArrayToFormValuesWithStringFormat(HttpRequest request, public static <R extends HttpRequest> R indexStringArrayToFormValuesWithStringFormat(R request, String format,
String format, Object input) { Object input) {
checkArgument(checkNotNull(input, "input") instanceof String[], checkArgument(checkNotNull(input, "input") instanceof String[], "this binder is only valid for String[] : "
"this binder is only valid for String[] : " + input.getClass()); + input.getClass());
String[] values = (String[]) input; String[] values = (String[]) input;
Builder<String, String> builder = ImmutableMultimap.<String, String> builder();
for (int i = 0; i < values.length; i++) { for (int i = 0; i < values.length; i++) {
addFormParamTo(request, String.format(format, (i + 1)), checkNotNull(values[i], format builder.put(String.format(format, (i + 1)), checkNotNull(values[i], format.toLowerCase() + "s[" + i + "]"));
.toLowerCase()
+ "s[" + i + "]"));
} }
ImmutableMultimap<String, String> forms = builder.build();
return forms.size() == 0 ? request : ModifyRequest.putFormParams(request, forms);
} }
private static final Pattern ELB_PATTERN = Pattern private static final Pattern ELB_PATTERN = Pattern.compile("([^.]+)-[^.]+\\.([^.]+)\\.elb\\.amazonaws\\.com");
.compile("([^.]+)-[^.]+\\.([^.]+)\\.elb\\.amazonaws\\.com");
public static Map<String, String> getLoadBalancerNameAndRegionFromDnsName(String dnsName) { public static Map<String, String> getLoadBalancerNameAndRegionFromDnsName(String dnsName) {
Matcher matcher = ELB_PATTERN.matcher(checkNotNull(dnsName, "dnsName")); Matcher matcher = ELB_PATTERN.matcher(checkNotNull(dnsName, "dnsName"));
checkArgument(matcher.find(), "dnsName syntax is " + ELB_PATTERN + " didn't match: " checkArgument(matcher.find(), "dnsName syntax is " + ELB_PATTERN + " didn't match: " + dnsName);
+ dnsName);
String loadBalancerName = matcher.group(1); String loadBalancerName = matcher.group(1);
String regionName = matcher.group(2); String regionName = matcher.group(2);
checkArgument((isRegion(regionName)), String.format( checkArgument((isRegion(regionName)),
"Region (%s) parsed from (%s) is not a valid region", regionName, dnsName)); String.format("Region (%s) parsed from (%s) is not a valid region", regionName, dnsName));
return ImmutableMap.<String, String> of(regionName, loadBalancerName); return ImmutableMap.<String, String> of(regionName, loadBalancerName);
} }
} }

View File

@ -33,9 +33,9 @@ import org.jclouds.rest.Binder;
*/ */
@Singleton @Singleton
public class BindAvailabilityZonesToIndexedFormParams implements Binder { public class BindAvailabilityZonesToIndexedFormParams implements Binder {
@Override
public void bindToRequest(HttpRequest request, Object input) { public <R extends HttpRequest> R bindToRequest(R request, Object input) {
indexStringArrayToFormValuesWithStringFormat(request, "AvailabilityZones.member.%s", input); return indexStringArrayToFormValuesWithStringFormat(request, "AvailabilityZones.member.%s", input);
} }
} }

View File

@ -33,9 +33,9 @@ import org.jclouds.rest.Binder;
*/ */
@Singleton @Singleton
public class BindELBInstanceIdsToIndexedFormParams implements Binder { public class BindELBInstanceIdsToIndexedFormParams implements Binder {
@Override
public void bindToRequest(HttpRequest request, Object input) { public <R extends HttpRequest> R bindToRequest(R request, Object input) {
indexStringArrayToFormValuesWithStringFormat(request, "Instances.member.%s.InstanceId", input); return indexStringArrayToFormValuesWithStringFormat(request, "Instances.member.%s.InstanceId", input);
} }
} }

View File

@ -34,7 +34,6 @@ import org.jclouds.date.DateService;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;

View File

@ -28,8 +28,6 @@ import static org.jclouds.aws.ec2.reference.EC2Parameters.SIGNATURE_METHOD;
import static org.jclouds.aws.ec2.reference.EC2Parameters.SIGNATURE_VERSION; import static org.jclouds.aws.ec2.reference.EC2Parameters.SIGNATURE_VERSION;
import static org.jclouds.aws.ec2.reference.EC2Parameters.TIMESTAMP; import static org.jclouds.aws.ec2.reference.EC2Parameters.TIMESTAMP;
import static org.jclouds.aws.ec2.reference.EC2Parameters.VERSION; import static org.jclouds.aws.ec2.reference.EC2Parameters.VERSION;
import static org.jclouds.http.HttpUtils.makeQueryLine;
import static org.jclouds.http.HttpUtils.parseQueryToMap;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
@ -52,10 +50,11 @@ import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpRequestFilter; import org.jclouds.http.HttpRequestFilter;
import org.jclouds.http.HttpUtils; import org.jclouds.http.HttpUtils;
import org.jclouds.http.internal.SignatureWire; import org.jclouds.http.internal.SignatureWire;
import org.jclouds.http.utils.ModifyRequest;
import org.jclouds.io.InputSuppliers; import org.jclouds.io.InputSuppliers;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rest.RequestSigner; import org.jclouds.rest.RequestSigner;
import org.jclouds.util.Utils; import org.jclouds.util.Strings2;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@ -97,16 +96,18 @@ public class FormSigner implements HttpRequestFilter, RequestSigner {
this.utils = utils; this.utils = utils;
} }
public void filter(HttpRequest request) throws HttpException { public HttpRequest filter(HttpRequest request) throws HttpException {
checkNotNull(request.getFirstHeaderOrNull(HttpHeaders.HOST), "request is not ready to sign; host not present"); checkNotNull(request.getFirstHeaderOrNull(HttpHeaders.HOST), "request is not ready to sign; host not present");
Multimap<String, String> decodedParams = parseQueryToMap(request.getPayload().getRawContent().toString()); Multimap<String, String> decodedParams = ModifyRequest.parseQueryToMap(request.getPayload().getRawContent()
.toString());
addSigningParams(decodedParams); addSigningParams(decodedParams);
validateParams(decodedParams); validateParams(decodedParams);
String stringToSign = createStringToSign(request, decodedParams); String stringToSign = createStringToSign(request, decodedParams);
String signature = sign(stringToSign); String signature = sign(stringToSign);
addSignature(decodedParams, signature); addSignature(decodedParams, signature);
setPayload(request, decodedParams); request = setPayload(request, decodedParams);
utils.logRequest(signatureLog, request, "<<"); utils.logRequest(signatureLog, request, "<<");
return request;
} }
String[] sortForSigning(String queryLine) { String[] sortForSigning(String queryLine) {
@ -124,8 +125,8 @@ public class FormSigner implements HttpRequestFilter, RequestSigner {
return parts; return parts;
} }
void setPayload(HttpRequest request, Multimap<String, String> decodedParams) { HttpRequest setPayload(HttpRequest request, Multimap<String, String> decodedParams) {
request.setPayload(makeQueryLine(decodedParams, new Comparator<Map.Entry<String, String>>() { request.setPayload(ModifyRequest.makeQueryLine(decodedParams, new Comparator<Map.Entry<String, String>>() {
public int compare(Entry<String, String> o1, Entry<String, String> o2) { public int compare(Entry<String, String> o1, Entry<String, String> o2) {
if (o1.getKey().startsWith("Action") || o2.getKey().startsWith("AWSAccessKeyId")) if (o1.getKey().startsWith("Action") || o2.getKey().startsWith("AWSAccessKeyId"))
return -1; return -1;
@ -135,6 +136,7 @@ public class FormSigner implements HttpRequestFilter, RequestSigner {
} }
})); }));
request.getPayload().getContentMetadata().setContentType("application/x-www-form-urlencoded"); request.getPayload().getContentMetadata().setContentType("application/x-www-form-urlencoded");
return request;
} }
@VisibleForTesting @VisibleForTesting
@ -153,10 +155,10 @@ public class FormSigner implements HttpRequestFilter, RequestSigner {
public String sign(String stringToSign) { public String sign(String stringToSign) {
String signature; String signature;
try { try {
signature = CryptoStreams.base64(CryptoStreams.mac(InputSuppliers.of(stringToSign), crypto signature = CryptoStreams.base64(CryptoStreams.mac(InputSuppliers.of(stringToSign),
.hmacSHA256(secretKey.getBytes()))); crypto.hmacSHA256(secretKey.getBytes())));
if (signatureWire.enabled()) if (signatureWire.enabled())
signatureWire.input(Utils.toInputStream(signature)); signatureWire.input(Strings2.toInputStream(signature));
} catch (Exception e) { } catch (Exception e) {
throw new HttpException("error signing request", e); throw new HttpException("error signing request", e);
} }
@ -182,7 +184,7 @@ public class FormSigner implements HttpRequestFilter, RequestSigner {
@VisibleForTesting @VisibleForTesting
String buildCanonicalizedString(Multimap<String, String> decodedParams) { String buildCanonicalizedString(Multimap<String, String> decodedParams) {
return makeQueryLine(decodedParams, new Comparator<Map.Entry<String, String>>() { return ModifyRequest.makeQueryLine(decodedParams, new Comparator<Map.Entry<String, String>>() {
public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) { public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) {
if (o1.getKey().startsWith("AWSAccessKeyId")) if (o1.getKey().startsWith("AWSAccessKeyId"))
return -1; return -1;
@ -201,7 +203,7 @@ public class FormSigner implements HttpRequestFilter, RequestSigner {
} }
public String createStringToSign(HttpRequest input) { public String createStringToSign(HttpRequest input) {
return createStringToSign(input, parseQueryToMap(input.getPayload().getRawContent().toString())); return createStringToSign(input, ModifyRequest.parseQueryToMap(input.getPayload().getRawContent().toString()));
} }
} }

View File

@ -64,7 +64,7 @@ public class AWSClientErrorRetryHandler implements HttpRetryHandler {
// Content can be null in the case of HEAD requests // Content can be null in the case of HEAD requests
if (response.getPayload() != null) { if (response.getPayload() != null) {
closeClientButKeepContentStream(response); closeClientButKeepContentStream(response);
AWSError error = utils.parseAWSErrorFromContent(command.getRequest(), response); AWSError error = utils.parseAWSErrorFromContent(command.getCurrentRequest(), response);
if (error != null if (error != null
&& ("RequestTimeout".equals(error.getCode()) && ("RequestTimeout".equals(error.getCode())
|| "OperationAborted".equals(error.getCode()) || "SignatureDoesNotMatch" || "OperationAborted".equals(error.getCode()) || "SignatureDoesNotMatch"

View File

@ -19,8 +19,6 @@
package org.jclouds.aws.handlers; package org.jclouds.aws.handlers;
import static org.jclouds.http.HttpUtils.changeSchemeHostAndPortTo;
import static org.jclouds.http.HttpUtils.changeToGETRequest;
import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream; import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream;
import javax.inject.Inject; import javax.inject.Inject;
@ -57,23 +55,23 @@ public class AWSRedirectionRetryHandler extends RedirectionRetryHandler {
public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) { public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) {
if (response.getFirstHeaderOrNull(HttpHeaders.LOCATION) == null if (response.getFirstHeaderOrNull(HttpHeaders.LOCATION) == null
&& (response.getStatusCode() == 301 || response.getStatusCode() == 307)) { && (response.getStatusCode() == 301 || response.getStatusCode() == 307)) {
if (command.getRequest().getMethod() == HttpMethod.HEAD) { if (command.getCurrentRequest().getMethod() == HttpMethod.HEAD) {
changeToGETRequest(command.getRequest()); command.setCurrentRequest(command.getCurrentRequest().toBuilder().method("GET").build());
return true; return true;
} else { } else {
command.incrementRedirectCount(); command.incrementRedirectCount();
closeClientButKeepContentStream(response); closeClientButKeepContentStream(response);
AWSError error = utils.parseAWSErrorFromContent(command.getRequest(), response); AWSError error = utils.parseAWSErrorFromContent(command.getCurrentRequest(), response);
String host = error.getDetails().get("Endpoint"); String host = error.getDetails().get("Endpoint");
if (host != null) { if (host != null) {
if (host.equals(command.getRequest().getEndpoint().getHost())) { if (host.equals(command.getCurrentRequest().getEndpoint().getHost())) {
// must be an amazon error related to // must be an amazon error related to
// http://developer.amazonwebservices.com/connect/thread.jspa?messageID=72287&#72287 // http://developer.amazonwebservices.com/connect/thread.jspa?messageID=72287&#72287
return backoffHandler.shouldRetryRequest(command, response); return backoffHandler.shouldRetryRequest(command, response);
} else { } else {
changeSchemeHostAndPortTo(command.getRequest(), command.getRequest() UriBuilder builder = uriBuilderProvider.get().uri(command.getCurrentRequest().getEndpoint());
.getEndpoint().getScheme(), host, command.getRequest().getEndpoint() builder.host(host);
.getPort(), uriBuilderProvider.get()); command.setCurrentRequest(command.getCurrentRequest().toBuilder().endpoint(builder.build()).build());
} }
return true; return true;
} else { } else {

View File

@ -27,7 +27,6 @@ import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.aws.AWSResponseException;
import org.jclouds.aws.domain.AWSError; import org.jclouds.aws.domain.AWSError;
import org.jclouds.aws.util.AWSUtils; import org.jclouds.aws.util.AWSUtils;
import org.jclouds.blobstore.ContainerNotFoundException; import org.jclouds.blobstore.ContainerNotFoundException;
@ -40,7 +39,7 @@ import org.jclouds.http.HttpResponseException;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.ResourceNotFoundException; import org.jclouds.rest.ResourceNotFoundException;
import org.jclouds.util.Utils; import org.jclouds.util.Strings2;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
@ -65,7 +64,7 @@ public class ParseAWSErrorFromXmlContent implements HttpErrorHandler {
} }
public void handleError(HttpCommand command, HttpResponse response) { public void handleError(HttpCommand command, HttpResponse response) {
HttpRequest request = command.getRequest(); HttpRequest request = command.getCurrentRequest();
Exception exception = new HttpResponseException(command, response); Exception exception = new HttpResponseException(command, response);
try { try {
AWSError error = null; AWSError error = null;
@ -80,7 +79,7 @@ public class ParseAWSErrorFromXmlContent implements HttpErrorHandler {
} }
} else { } else {
try { try {
message = Utils.toStringAndClose(response.getPayload().getInput()); message = Strings2.toStringAndClose(response.getPayload().getInput());
exception = new HttpResponseException(command, response, message); exception = new HttpResponseException(command, response, message);
} catch (IOException e) { } catch (IOException e) {
} }
@ -109,7 +108,7 @@ public class ParseAWSErrorFromXmlContent implements HttpErrorHandler {
exception = new AuthorizationException(exception.getMessage(), exception); exception = new AuthorizationException(exception.getMessage(), exception);
break; break;
case 404: case 404:
if (!command.getRequest().getMethod().equals("DELETE")) { if (!command.getCurrentRequest().getMethod().equals("DELETE")) {
String container = request.getEndpoint().getHost(); String container = request.getEndpoint().getHost();
String key = request.getEndpoint().getPath(); String key = request.getEndpoint().getPath();
if (key == null || key.equals("/")) if (key == null || key.equals("/"))

View File

@ -39,7 +39,7 @@ import org.jclouds.aws.s3.binders.BindAsHostPrefixIfConfigured;
import org.jclouds.aws.s3.binders.BindBucketLoggingToXmlPayload; import org.jclouds.aws.s3.binders.BindBucketLoggingToXmlPayload;
import org.jclouds.aws.s3.binders.BindNoBucketLoggingToXmlPayload; import org.jclouds.aws.s3.binders.BindNoBucketLoggingToXmlPayload;
import org.jclouds.aws.s3.binders.BindPayerToXmlPayload; import org.jclouds.aws.s3.binders.BindPayerToXmlPayload;
import org.jclouds.aws.s3.binders.BindS3ObjectToPayload; import org.jclouds.aws.s3.binders.BindS3ObjectMetadataToRequest;
import org.jclouds.aws.s3.domain.AccessControlList; import org.jclouds.aws.s3.domain.AccessControlList;
import org.jclouds.aws.s3.domain.BucketLogging; import org.jclouds.aws.s3.domain.BucketLogging;
import org.jclouds.aws.s3.domain.BucketMetadata; import org.jclouds.aws.s3.domain.BucketMetadata;
@ -162,7 +162,7 @@ public interface S3AsyncClient {
@ResponseParser(ParseETagHeader.class) @ResponseParser(ParseETagHeader.class)
ListenableFuture<String> putObject( ListenableFuture<String> putObject(
@Bucket @BinderParam(BindAsHostPrefixIfConfigured.class) @ParamValidators( { BucketNameValidator.class }) String bucketName, @Bucket @BinderParam(BindAsHostPrefixIfConfigured.class) @ParamValidators( { BucketNameValidator.class }) String bucketName,
@PathParam("key") @ParamParser(ObjectKey.class) @BinderParam(BindS3ObjectToPayload.class) S3Object object, @PathParam("key") @ParamParser(ObjectKey.class) @BinderParam(BindS3ObjectMetadataToRequest.class) S3Object object,
PutObjectOptions... options); PutObjectOptions... options);
/** /**

View File

@ -44,8 +44,8 @@ import com.jamesmurty.utils.XMLBuilder;
*/ */
@Singleton @Singleton
public class BindACLToXMLPayload implements Binder { public class BindACLToXMLPayload implements Binder {
@Override
public void bindToRequest(HttpRequest request, Object payload) { public <R extends HttpRequest> R bindToRequest(R request, Object payload) {
AccessControlList from = (AccessControlList) payload; AccessControlList from = (AccessControlList) payload;
Properties outputProperties = new Properties(); Properties outputProperties = new Properties();
outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes"); outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
@ -57,6 +57,7 @@ public class BindACLToXMLPayload implements Binder {
Throwables.propagateIfPossible(e); Throwables.propagateIfPossible(e);
throw new RuntimeException("error transforming acl: " + from, e); throw new RuntimeException("error transforming acl: " + from, e);
} }
return request;
} }
protected XMLBuilder generateBuilder(AccessControlList acl) throws ParserConfigurationException, protected XMLBuilder generateBuilder(AccessControlList acl) throws ParserConfigurationException,
@ -77,18 +78,16 @@ public class BindACLToXMLPayload implements Binder {
"http://www.w3.org/2001/XMLSchema-instance"); "http://www.w3.org/2001/XMLSchema-instance");
if (grant.getGrantee() instanceof GroupGrantee) { if (grant.getGrantee() instanceof GroupGrantee) {
granteeBuilder.attr("xsi:type", "Group").elem("URI").text( granteeBuilder.attr("xsi:type", "Group").elem("URI").text(grant.getGrantee().getIdentifier());
grant.getGrantee().getIdentifier());
} else if (grant.getGrantee() instanceof CanonicalUserGrantee) { } else if (grant.getGrantee() instanceof CanonicalUserGrantee) {
CanonicalUserGrantee grantee = (CanonicalUserGrantee) grant.getGrantee(); CanonicalUserGrantee grantee = (CanonicalUserGrantee) grant.getGrantee();
granteeBuilder.attr("xsi:type", "CanonicalUser").elem("ID").text( granteeBuilder.attr("xsi:type", "CanonicalUser").elem("ID").text(grantee.getIdentifier()).up();
grantee.getIdentifier()).up();
if (grantee.getDisplayName() != null) { if (grantee.getDisplayName() != null) {
granteeBuilder.elem("DisplayName").text(grantee.getDisplayName()); granteeBuilder.elem("DisplayName").text(grantee.getDisplayName());
} }
} else if (grant.getGrantee() instanceof EmailAddressGrantee) { } else if (grant.getGrantee() instanceof EmailAddressGrantee) {
granteeBuilder.attr("xsi:type", "AmazonCustomerByEmail").elem("EmailAddress").text( granteeBuilder.attr("xsi:type", "AmazonCustomerByEmail").elem("EmailAddress")
grant.getGrantee().getIdentifier()); .text(grant.getGrantee().getIdentifier());
} }
grantBuilder.elem("Permission").text(grant.getPermission().toString()); grantBuilder.elem("Permission").text(grant.getPermission().toString());
} }

View File

@ -21,7 +21,6 @@ package org.jclouds.aws.s3.binders;
import static org.jclouds.aws.s3.reference.S3Constants.PROPERTY_S3_SERVICE_PATH; import static org.jclouds.aws.s3.reference.S3Constants.PROPERTY_S3_SERVICE_PATH;
import static org.jclouds.aws.s3.reference.S3Constants.PROPERTY_S3_VIRTUAL_HOST_BUCKETS; import static org.jclouds.aws.s3.reference.S3Constants.PROPERTY_S3_VIRTUAL_HOST_BUCKETS;
import static org.jclouds.http.HttpUtils.urlEncode;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
@ -32,11 +31,12 @@ import javax.ws.rs.core.UriBuilder;
import org.jclouds.aws.s3.S3AsyncClient; import org.jclouds.aws.s3.S3AsyncClient;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.utils.ModifyRequest;
import org.jclouds.rest.Binder; import org.jclouds.rest.Binder;
import org.jclouds.rest.annotations.SkipEncoding; import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.binders.BindAsHostPrefix; import org.jclouds.rest.binders.BindAsHostPrefix;
import org.jclouds.util.Strings2;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
/** /**
@ -54,29 +54,30 @@ public class BindAsHostPrefixIfConfigured implements Binder {
@Inject @Inject
public BindAsHostPrefixIfConfigured(BindAsHostPrefix bindAsHostPrefix, public BindAsHostPrefixIfConfigured(BindAsHostPrefix bindAsHostPrefix,
@Named(PROPERTY_S3_VIRTUAL_HOST_BUCKETS) boolean isVhostStyle, @Named(PROPERTY_S3_VIRTUAL_HOST_BUCKETS) boolean isVhostStyle,
@Named(PROPERTY_S3_SERVICE_PATH) String servicePath, @Named(PROPERTY_S3_SERVICE_PATH) String servicePath, Provider<UriBuilder> uriBuilderProvider) {
Provider<UriBuilder> uriBuilderProvider) {
this.bindAsHostPrefix = bindAsHostPrefix; this.bindAsHostPrefix = bindAsHostPrefix;
this.isVhostStyle = isVhostStyle; this.isVhostStyle = isVhostStyle;
this.servicePath = servicePath; this.servicePath = servicePath;
this.uriBuilderProvider = uriBuilderProvider; this.uriBuilderProvider = uriBuilderProvider;
} }
public void bindToRequest(HttpRequest request, Object payload) { @SuppressWarnings("unchecked")
@Override
public <R extends HttpRequest> R bindToRequest(R request, Object payload) {
if (isVhostStyle) { if (isVhostStyle) {
bindAsHostPrefix.bindToRequest(request, payload); request = bindAsHostPrefix.bindToRequest(request, payload);
request.getHeaders().replaceValues(HttpHeaders.HOST, return ModifyRequest.replaceHeader(request, HttpHeaders.HOST, request.getEndpoint().getHost());
ImmutableSet.of(request.getEndpoint().getHost()));
} else { } else {
UriBuilder builder = uriBuilderProvider.get().uri(request.getEndpoint()); UriBuilder builder = uriBuilderProvider.get().uri(request.getEndpoint());
StringBuilder path = new StringBuilder(urlEncode(request.getEndpoint().getPath(), StringBuilder path = new StringBuilder(Strings2.urlEncode(request.getEndpoint().getPath(), S3AsyncClient.class
S3AsyncClient.class.getAnnotation(SkipEncoding.class).value())); .getAnnotation(SkipEncoding.class).value()));
int indexToInsert = path.indexOf(servicePath); int indexToInsert = path.indexOf(servicePath);
indexToInsert = indexToInsert == -1 ? 0 : indexToInsert; indexToInsert = indexToInsert == -1 ? 0 : indexToInsert;
indexToInsert += servicePath.length(); indexToInsert += servicePath.length();
path.insert(indexToInsert, "/" + payload.toString()); path.insert(indexToInsert, "/" + payload.toString());
builder.replacePath(path.toString()); builder.replacePath(path.toString());
request.setEndpoint(builder.buildFromEncodedMap(Maps.<String, Object> newHashMap())); return (R) request.toBuilder().endpoint(builder.buildFromEncodedMap(Maps.<String, Object> newLinkedHashMap()))
.build();
} }
} }
} }

View File

@ -44,8 +44,8 @@ import com.jamesmurty.utils.XMLBuilder;
*/ */
@Singleton @Singleton
public class BindBucketLoggingToXmlPayload implements Binder { public class BindBucketLoggingToXmlPayload implements Binder {
@Override
public void bindToRequest(HttpRequest request, Object payload) { public <R extends HttpRequest> R bindToRequest(R request, Object payload) {
BucketLogging from = (BucketLogging) payload; BucketLogging from = (BucketLogging) payload;
Properties outputProperties = new Properties(); Properties outputProperties = new Properties();
outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes"); outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
@ -57,12 +57,13 @@ public class BindBucketLoggingToXmlPayload implements Binder {
Throwables.propagateIfPossible(e); Throwables.propagateIfPossible(e);
throw new RuntimeException("error transforming bucketLogging: " + from, e); throw new RuntimeException("error transforming bucketLogging: " + from, e);
} }
return request;
} }
protected XMLBuilder generateBuilder(BucketLogging bucketLogging) protected XMLBuilder generateBuilder(BucketLogging bucketLogging) throws ParserConfigurationException,
throws ParserConfigurationException, FactoryConfigurationError { FactoryConfigurationError {
XMLBuilder rootBuilder = XMLBuilder.create("BucketLoggingStatus").attr("xmlns", XMLBuilder rootBuilder = XMLBuilder.create("BucketLoggingStatus")
S3Constants.S3_REST_API_XML_NAMESPACE).e("LoggingEnabled"); .attr("xmlns", S3Constants.S3_REST_API_XML_NAMESPACE).e("LoggingEnabled");
rootBuilder.e("TargetBucket").t(bucketLogging.getTargetBucket()); rootBuilder.e("TargetBucket").t(bucketLogging.getTargetBucket());
rootBuilder.e("TargetPrefix").t(bucketLogging.getTargetPrefix()); rootBuilder.e("TargetPrefix").t(bucketLogging.getTargetPrefix());
XMLBuilder grantsBuilder = rootBuilder.elem("TargetGrants"); XMLBuilder grantsBuilder = rootBuilder.elem("TargetGrants");
@ -72,18 +73,16 @@ public class BindBucketLoggingToXmlPayload implements Binder {
"http://www.w3.org/2001/XMLSchema-instance"); "http://www.w3.org/2001/XMLSchema-instance");
if (grant.getGrantee() instanceof GroupGrantee) { if (grant.getGrantee() instanceof GroupGrantee) {
granteeBuilder.attr("xsi:type", "Group").elem("URI").text( granteeBuilder.attr("xsi:type", "Group").elem("URI").text(grant.getGrantee().getIdentifier());
grant.getGrantee().getIdentifier());
} else if (grant.getGrantee() instanceof CanonicalUserGrantee) { } else if (grant.getGrantee() instanceof CanonicalUserGrantee) {
CanonicalUserGrantee grantee = (CanonicalUserGrantee) grant.getGrantee(); CanonicalUserGrantee grantee = (CanonicalUserGrantee) grant.getGrantee();
granteeBuilder.attr("xsi:type", "CanonicalUser").elem("ID").text( granteeBuilder.attr("xsi:type", "CanonicalUser").elem("ID").text(grantee.getIdentifier()).up();
grantee.getIdentifier()).up();
if (grantee.getDisplayName() != null) { if (grantee.getDisplayName() != null) {
granteeBuilder.elem("DisplayName").text(grantee.getDisplayName()); granteeBuilder.elem("DisplayName").text(grantee.getDisplayName());
} }
} else if (grant.getGrantee() instanceof EmailAddressGrantee) { } else if (grant.getGrantee() instanceof EmailAddressGrantee) {
granteeBuilder.attr("xsi:type", "AmazonCustomerByEmail").elem("EmailAddress").text( granteeBuilder.attr("xsi:type", "AmazonCustomerByEmail").elem("EmailAddress")
grant.getGrantee().getIdentifier()); .text(grant.getGrantee().getIdentifier());
} }
grantBuilder.elem("Permission").text(grant.getPermission().toString()); grantBuilder.elem("Permission").text(grant.getPermission().toString());
} }

View File

@ -38,10 +38,12 @@ public class BindNoBucketLoggingToXmlPayload implements Binder {
this.bindAsHostPrefixIfConfigured = bindAsHostPrefixIfConfigured; this.bindAsHostPrefixIfConfigured = bindAsHostPrefixIfConfigured;
} }
public void bindToRequest(HttpRequest request, Object payload) { @Override
bindAsHostPrefixIfConfigured.bindToRequest(request, payload); public <R extends HttpRequest> R bindToRequest(R request, Object payload) {
request = bindAsHostPrefixIfConfigured.bindToRequest(request, payload);
String stringPayload = "<BucketLoggingStatus xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"/>"; String stringPayload = "<BucketLoggingStatus xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"/>";
request.setPayload(stringPayload); request.setPayload(stringPayload);
return request;
} }
} }

View File

@ -36,15 +36,15 @@ import org.jclouds.rest.Binder;
*/ */
@Singleton @Singleton
public class BindPayerToXmlPayload implements Binder { public class BindPayerToXmlPayload implements Binder {
@Override
public void bindToRequest(HttpRequest request, Object toBind) { public <R extends HttpRequest> R bindToRequest(R request, Object toBind) {
checkArgument(checkNotNull(toBind, "toBind") instanceof Payer, checkArgument(checkNotNull(toBind, "toBind") instanceof Payer, "this binder is only valid for Payer!");
"this binder is only valid for Payer!");
String text = String String text = String
.format( .format(
"<RequestPaymentConfiguration xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"><Payer>%s</Payer></RequestPaymentConfiguration>", "<RequestPaymentConfiguration xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"><Payer>%s</Payer></RequestPaymentConfiguration>",
((Payer) toBind).value()); ((Payer) toBind).value());
request.setPayload(text); request.setPayload(text);
request.getPayload().getContentMetadata().setContentType(MediaType.TEXT_XML); request.getPayload().getContentMetadata().setContentType(MediaType.TEXT_XML);
return request;
} }
} }

View File

@ -20,6 +20,7 @@
package org.jclouds.aws.s3.binders; package org.jclouds.aws.s3.binders;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
@ -29,6 +30,7 @@ import org.jclouds.aws.s3.blobstore.functions.ObjectToBlob;
import org.jclouds.aws.s3.domain.S3Object; import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.blobstore.binders.BindUserMetadataToHeadersWithPrefix; import org.jclouds.blobstore.binders.BindUserMetadataToHeadersWithPrefix;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.utils.ModifyRequest;
import org.jclouds.rest.Binder; import org.jclouds.rest.Binder;
/** /**
@ -36,27 +38,33 @@ import org.jclouds.rest.Binder;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Singleton @Singleton
public class BindS3ObjectToPayload implements Binder { public class BindS3ObjectMetadataToRequest implements Binder {
private final BindUserMetadataToHeadersWithPrefix blobBinder; private final BindUserMetadataToHeadersWithPrefix blobBinder;
private final ObjectToBlob object2Blob; private final ObjectToBlob object2Blob;
@Inject @Inject
public BindS3ObjectToPayload(ObjectToBlob object2Blob, BindUserMetadataToHeadersWithPrefix blobBinder) { public BindS3ObjectMetadataToRequest(ObjectToBlob object2Blob, BindUserMetadataToHeadersWithPrefix blobBinder) {
this.blobBinder = blobBinder; this.blobBinder = checkNotNull(blobBinder, "blobBinder");
this.object2Blob = object2Blob; this.object2Blob = checkNotNull(object2Blob, "object2Blob");
} }
public void bindToRequest(HttpRequest request, Object payload) { @Override
S3Object s3Object = (S3Object) payload; public <R extends HttpRequest> R bindToRequest(R request, Object input) {
checkArgument(checkNotNull(input, "input") instanceof S3Object, "this binder is only valid for S3Object!");
checkNotNull(request, "request");
S3Object s3Object = S3Object.class.cast(input);
checkArgument(s3Object.getMetadata().getKey() != null, "s3Object.getMetadata().getKey() must be set!");
checkArgument(s3Object.getPayload().getContentMetadata().getContentLength() != null, checkArgument(s3Object.getPayload().getContentMetadata().getContentLength() != null,
"contentLength must be set, streaming not supported"); "contentLength must be set, streaming not supported");
checkArgument(s3Object.getPayload().getContentMetadata().getContentLength() <= 5l * 1024 * 1024 * 1024, checkArgument(s3Object.getPayload().getContentMetadata().getContentLength() <= 5l * 1024 * 1024 * 1024,
"maximum size for put object is 5GB"); "maximum size for put object is 5GB");
blobBinder.bindToRequest(request, object2Blob.apply(s3Object)); request = blobBinder.bindToRequest(request, object2Blob.apply(s3Object));
if (s3Object.getMetadata().getCacheControl() != null) { if (s3Object.getMetadata().getCacheControl() != null) {
request.getHeaders().put(HttpHeaders.CACHE_CONTROL, s3Object.getMetadata().getCacheControl()); request = ModifyRequest.replaceHeader(request, HttpHeaders.CACHE_CONTROL, s3Object.getMetadata()
.getCacheControl());
} }
return request;
} }
} }

View File

@ -52,7 +52,7 @@ import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.collect.Memoized; import org.jclouds.collect.Memoized;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.http.options.GetOptions; import org.jclouds.http.options.GetOptions;
import org.jclouds.util.Utils; import org.jclouds.util.Assertions;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
@ -160,7 +160,7 @@ public class S3BlobStore extends BaseBlobStore {
*/ */
public void clearAndDeleteContainer(final String container) { public void clearAndDeleteContainer(final String container) {
try { try {
if (!Utils.eventuallyTrue(new Supplier<Boolean>() { if (!Assertions.eventuallyTrue(new Supplier<Boolean>() {
public Boolean get() { public Boolean get() {
clearContainer(container); clearContainer(container);
return sync.deleteBucketIfEmpty(container); return sync.deleteBucketIfEmpty(container);

View File

@ -32,7 +32,7 @@ import com.google.inject.TypeLiteral;
*/ */
public class ScaleUpCloudBlobStoreContextModule extends S3BlobStoreContextModule { public class ScaleUpCloudBlobStoreContextModule extends S3BlobStoreContextModule {
@SuppressWarnings("rawtypes") @SuppressWarnings({ "rawtypes", "unchecked" })
@Override @Override
protected void bindBucketLocationStrategy() { protected void bindBucketLocationStrategy() {
bind(new TypeLiteral<Function<BucketMetadata, Location>>() { bind(new TypeLiteral<Function<BucketMetadata, Location>>() {

View File

@ -31,7 +31,6 @@ import static org.jclouds.util.Patterns.NEWLINE_PATTERN;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
@ -52,16 +51,20 @@ import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpRequestFilter; import org.jclouds.http.HttpRequestFilter;
import org.jclouds.http.HttpUtils; import org.jclouds.http.HttpUtils;
import org.jclouds.http.internal.SignatureWire; import org.jclouds.http.internal.SignatureWire;
import org.jclouds.http.utils.ModifyRequest;
import org.jclouds.io.InputSuppliers; import org.jclouds.io.InputSuppliers;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rest.RequestSigner; import org.jclouds.rest.RequestSigner;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.util.Utils; import org.jclouds.util.Strings2;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Multimaps;
/** /**
* Signs the S3 request. * Signs the S3 request.
@ -110,11 +113,26 @@ public class RequestAuthorizeSignature implements HttpRequestFilter, RequestSign
this.utils = utils; this.utils = utils;
} }
public void filter(HttpRequest request) throws HttpException { public HttpRequest filter(HttpRequest request) throws HttpException {
replaceDateHeader(request); request = replaceDateHeader(request);
String toSign = createStringToSign(request); String signature = calculateSignature(createStringToSign(request));
calculateAndReplaceAuthHeader(request, toSign); request = replaceAuthorizationHeader(request, signature);
utils.logRequest(signatureLog, request, "<<"); utils.logRequest(signatureLog, request, "<<");
return request;
}
HttpRequest replaceAuthorizationHeader(HttpRequest request, String signature) {
request = ModifyRequest.replaceHeader(request, HttpHeaders.AUTHORIZATION, authTag + " " + accessKey + ":"
+ signature);
return request;
}
HttpRequest replaceDateHeader(HttpRequest request) {
Builder<String, String> builder = ImmutableMap.builder();
String date = timeStampProvider.get();
builder.put(HttpHeaders.DATE, date);
request = ModifyRequest.replaceHeaders(request, Multimaps.forMap(builder.build()));
return request;
} }
public String createStringToSign(HttpRequest request) { public String createStringToSign(HttpRequest request) {
@ -133,19 +151,18 @@ public class RequestAuthorizeSignature implements HttpRequestFilter, RequestSign
return buffer.toString(); return buffer.toString();
} }
void calculateAndReplaceAuthHeader(HttpRequest request, String toSign) throws HttpException { String calculateSignature(String toSign) throws HttpException {
String signature = sign(toSign); String signature = sign(toSign);
if (signatureWire.enabled()) if (signatureWire.enabled())
signatureWire.input(Utils.toInputStream(signature)); signatureWire.input(Strings2.toInputStream(signature));
request.getHeaders().replaceValues(HttpHeaders.AUTHORIZATION, return signature;
Collections.singletonList(authTag + " " + accessKey + ":" + signature));
} }
public String sign(String toSign) { public String sign(String toSign) {
String signature; String signature;
try { try {
signature = CryptoStreams.base64(CryptoStreams.mac(InputSuppliers.of(toSign), crypto.hmacSHA1(secretKey signature = CryptoStreams.base64(CryptoStreams.mac(InputSuppliers.of(toSign),
.getBytes()))); crypto.hmacSHA1(secretKey.getBytes())));
} catch (Exception e) { } catch (Exception e) {
throw new HttpException("error signing request", e); throw new HttpException("error signing request", e);
} }
@ -156,17 +173,13 @@ public class RequestAuthorizeSignature implements HttpRequestFilter, RequestSign
toSign.append(request.getMethod()).append("\n"); toSign.append(request.getMethod()).append("\n");
} }
void replaceDateHeader(HttpRequest request) {
request.getHeaders().replaceValues(HttpHeaders.DATE, Collections.singletonList(timeStampProvider.get()));
}
void appendAmzHeaders(HttpRequest request, StringBuilder toSign) { void appendAmzHeaders(HttpRequest request, StringBuilder toSign) {
Set<String> headers = new TreeSet<String>(request.getHeaders().keySet()); Set<String> headers = new TreeSet<String>(request.getHeaders().keySet());
for (String header : headers) { for (String header : headers) {
if (header.startsWith("x-" + headerTag + "-")) { if (header.startsWith("x-" + headerTag + "-")) {
toSign.append(header.toLowerCase()).append(":"); toSign.append(header.toLowerCase()).append(":");
for (String value : request.getHeaders().get(header)) { for (String value : request.getHeaders().get(header)) {
toSign.append(Utils.replaceAll(value, NEWLINE_PATTERN, "")).append(","); toSign.append(Strings2.replaceAll(value, NEWLINE_PATTERN, "")).append(",");
} }
toSign.deleteCharAt(toSign.lastIndexOf(",")); toSign.deleteCharAt(toSign.lastIndexOf(","));
toSign.append("\n"); toSign.append("\n");
@ -202,7 +215,7 @@ public class RequestAuthorizeSignature implements HttpRequestFilter, RequestSign
return input.annotationType().equals(Bucket.class); return input.annotationType().equals(Bucket.class);
} }
})) { })) {
bucketName = (String) request.getArgs()[i]; bucketName = (String) request.getArgs().get(i);
break; break;
} }
} }

View File

@ -61,14 +61,14 @@ public class BindRegionToXmlPayload extends BindToStringPayload {
} }
@Override @Override
public void bindToRequest(HttpRequest request, Object input) { public <R extends HttpRequest> R bindToRequest(R request, Object input) {
input = input == null ? Iterables.get(defaultRegions, 0) : input; input = input == null ? Iterables.get(defaultRegions, 0) : input;
checkArgument(input instanceof String, "this binder is only valid for Region!"); checkArgument(input instanceof String, "this binder is only valid for Region!");
String constraint = (String) input; String constraint = (String) input;
String value = null; String value = null;
if (Iterables.contains(defaultRegions, constraint)) { if (Iterables.contains(defaultRegions, constraint)) {
// nothing to bind as this is default. // nothing to bind as this is default.
return; return request;
} else if (Iterables.contains(regions, constraint)) { } else if (Iterables.contains(regions, constraint)) {
value = constraint; value = constraint;
} else { } else {
@ -79,10 +79,12 @@ public class BindRegionToXmlPayload extends BindToStringPayload {
value = constraint; value = constraint;
} }
} }
String payload = String.format( String payload = String
.format(
"<CreateBucketConfiguration><LocationConstraint>%s</LocationConstraint></CreateBucketConfiguration>", "<CreateBucketConfiguration><LocationConstraint>%s</LocationConstraint></CreateBucketConfiguration>",
value); value);
super.bindToRequest(request, payload); request = super.bindToRequest(request, payload);
request.getPayload().getContentMetadata().setContentType(MediaType.TEXT_XML); request.getPayload().getContentMetadata().setContentType(MediaType.TEXT_XML);
return request;
} }
} }

View File

@ -35,7 +35,8 @@ import com.google.common.base.Function;
* @see ParseMetadataFromHeaders * @see ParseMetadataFromHeaders
* @author Adrian Cole * @author Adrian Cole
*/ */
public class ParseObjectFromHeadersAndHttpContent implements Function<HttpResponse, S3Object>, InvocationContext { public class ParseObjectFromHeadersAndHttpContent implements Function<HttpResponse, S3Object>,
InvocationContext<ParseObjectFromHeadersAndHttpContent> {
private final ParseObjectMetadataFromHeaders metadataParser; private final ParseObjectMetadataFromHeaders metadataParser;
private final S3Object.Factory objectProvider; private final S3Object.Factory objectProvider;

View File

@ -44,7 +44,8 @@ import com.google.common.base.Function;
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/latest/RESTObjectGET.html" /> * @see <a href="http://docs.amazonwebservices.com/AmazonS3/latest/RESTObjectGET.html" />
* @author Adrian Cole * @author Adrian Cole
*/ */
public class ParseObjectMetadataFromHeaders implements Function<HttpResponse, MutableObjectMetadata>, InvocationContext { public class ParseObjectMetadataFromHeaders implements Function<HttpResponse, MutableObjectMetadata>,
InvocationContext<ParseObjectMetadataFromHeaders> {
private final ParseSystemAndUserMetadataFromHeaders blobMetadataParser; private final ParseSystemAndUserMetadataFromHeaders blobMetadataParser;
private final BlobToObjectMetadata blobToObjectMetadata; private final BlobToObjectMetadata blobToObjectMetadata;
private final String userMdPrefix; private final String userMdPrefix;

View File

@ -23,7 +23,7 @@ import static com.google.common.base.Throwables.getCausalChain;
import static com.google.common.collect.Iterables.filter; import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.get; import static com.google.common.collect.Iterables.get;
import static com.google.common.collect.Iterables.size; import static com.google.common.collect.Iterables.size;
import static org.jclouds.util.Utils.propagateOrNull; import static org.jclouds.util.Throwables2.propagateOrNull;
import java.util.List; import java.util.List;

View File

@ -25,7 +25,7 @@ import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.get; import static com.google.common.collect.Iterables.get;
import static com.google.common.collect.Iterables.size; import static com.google.common.collect.Iterables.size;
import static org.jclouds.http.HttpUtils.returnValueOnCodeOrNull; import static org.jclouds.http.HttpUtils.returnValueOnCodeOrNull;
import static org.jclouds.util.Utils.propagateOrNull; import static org.jclouds.util.Throwables2.propagateOrNull;
import java.util.List; import java.util.List;

View File

@ -33,7 +33,7 @@ import org.jclouds.aws.s3.domain.internal.ListBucketResponseImpl;
import org.jclouds.crypto.CryptoStreams; import org.jclouds.crypto.CryptoStreams;
import org.jclouds.date.DateService; import org.jclouds.date.DateService;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.util.Utils; import org.jclouds.util.Strings2;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
@ -101,7 +101,7 @@ public class ListBucketHandler extends ParseSax.HandlerWithResult<ListBucketResp
currentLastModified = dateParser.iso8601DateParse(currentText.toString().trim()); currentLastModified = dateParser.iso8601DateParse(currentText.toString().trim());
} else if (qName.equals("ETag")) { } else if (qName.equals("ETag")) {
currentETag = currentText.toString().trim(); currentETag = currentText.toString().trim();
currentMD5 = CryptoStreams.hex(Utils.replaceAll(currentETag, '"', "")); currentMD5 = CryptoStreams.hex(Strings2.replaceAll(currentETag, '"', ""));
} else if (qName.equals("Size")) { } else if (qName.equals("Size")) {
currentSize = new Long(currentText.toString().trim()); currentSize = new Long(currentText.toString().trim());
} else if (qName.equals("Owner")) { } else if (qName.equals("Owner")) {

View File

@ -47,7 +47,7 @@ import org.testng.annotations.Test;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "live", testName = "jclouds.ComputeAndBlobStoreTogetherHappilyLiveTest") @Test(groups = "live")
public class ComputeAndBlobStoreTogetherHappilyLiveTest extends BlobStoreAndComputeServiceLiveTest { public class ComputeAndBlobStoreTogetherHappilyLiveTest extends BlobStoreAndComputeServiceLiveTest {
@BeforeClass @BeforeClass
protected void setupCredentials() { protected void setupCredentials() {

View File

@ -36,7 +36,7 @@ import org.jclouds.compute.RunNodesException;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.rest.config.CredentialStoreModule; import org.jclouds.rest.config.CredentialStoreModule;
import org.jclouds.util.Utils; import org.jclouds.util.Strings2;
import org.testng.annotations.BeforeTest; import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -95,7 +95,7 @@ public class CredentialsStoredInBlobStoreTest {
assertEquals(credentialsMap.size(), 10); assertEquals(credentialsMap.size(), 10);
for (Entry<String, InputStream> entry : credentialsMap.entrySet()) { for (Entry<String, InputStream> entry : credentialsMap.entrySet()) {
Credentials credentials = computeContext.credentialStore().get(entry.getKey()); Credentials credentials = computeContext.credentialStore().get(entry.getKey());
assertEquals(Utils.toStringAndClose(entry.getValue()), String.format( assertEquals(Strings2.toStringAndClose(entry.getValue()), String.format(
"{\"identity\":\"%s\",\"credential\":\"%s\"}", credentials.identity, credentials.credential)); "{\"identity\":\"%s\",\"credential\":\"%s\"}", credentials.identity, credentials.credential));
} }
} }

View File

@ -21,7 +21,7 @@ package org.jclouds.aws;
import org.jclouds.blobstore.util.BlobStoreUtils; import org.jclouds.blobstore.util.BlobStoreUtils;
import org.jclouds.compute.util.ComputeServiceUtils; import org.jclouds.compute.util.ComputeServiceUtils;
import org.jclouds.util.Utils; import org.jclouds.rest.Providers;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
@ -49,7 +49,7 @@ public class ProvidersInPropertiesTest {
@Test @Test
public void testSupportedProviders() { public void testSupportedProviders() {
Iterable<String> providers = Utils.getSupportedProviders(); Iterable<String> providers = Providers.getSupportedProviders();
assert Iterables.contains(providers, "sqs") : providers; assert Iterables.contains(providers, "sqs") : providers;
assert Iterables.contains(providers, "elb") : providers; assert Iterables.contains(providers, "elb") : providers;
assert Iterables.contains(providers, "s3") : providers; assert Iterables.contains(providers, "s3") : providers;

View File

@ -51,7 +51,8 @@ import com.google.inject.TypeLiteral;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit", testName = "cloudwatch.MonitoringAsyncClientTest") // NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
@Test(groups = "unit", testName = "CloudWatchAsyncClientTest")
public class CloudWatchAsyncClientTest extends RestClientTest<CloudWatchAsyncClient> { public class CloudWatchAsyncClientTest extends RestClientTest<CloudWatchAsyncClient> {
public void testRegisterInstancesWithMeasure() throws SecurityException, NoSuchMethodException, IOException { public void testRegisterInstancesWithMeasure() throws SecurityException, NoSuchMethodException, IOException {

View File

@ -43,7 +43,7 @@ import com.google.inject.Module;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "live", sequential = true, testName = "cloudwatch.CloudWatchClientLiveTest") @Test(groups = "live", sequential = true)
public class CloudWatchClientLiveTest { public class CloudWatchClientLiveTest {
private CloudWatchClient client; private CloudWatchClient client;

Some files were not shown because too many files have changed in this diff Show More