Issue 462: corrected semantics of BlobMap when using inDirectory and added BlobBuilder

This commit is contained in:
Adrian Cole 2011-02-13 22:32:31 +01:00
parent 5df062ba47
commit 20c23e7962
39 changed files with 2498 additions and 2182 deletions

View File

@ -36,7 +36,7 @@ import com.google.common.base.Function;
*/ */
@Singleton @Singleton
public class ObjectToBlob implements Function<AtmosObject, Blob> { public class ObjectToBlob implements Function<AtmosObject, Blob> {
private final Blob.Factory blobFactory; private final Factory blobFactory;
private final ObjectToBlobMetadata object2BlobMd; private final ObjectToBlobMetadata object2BlobMd;
@Inject @Inject

View File

@ -129,10 +129,10 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
@Inject @Inject
protected FilesystemAsyncBlobStore(BlobStoreContext context, DateService dateService, Crypto crypto, protected FilesystemAsyncBlobStore(BlobStoreContext context, DateService dateService, Crypto crypto,
HttpGetOptionsListToGetOptions httpGetOptionsConverter, HttpGetOptionsListToGetOptions httpGetOptionsConverter, IfDirectoryReturnNameStrategy ifDirectoryReturnName,
IfDirectoryReturnNameStrategy ifDirectoryReturnName, Blob.Factory blobFactory, BlobUtils blobUtils, Factory blobFactory, BlobUtils blobUtils, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService service,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation, Supplier<Location> defaultLocation, @Memoized Supplier<Set<? extends Location>> locations,
@Memoized Supplier<Set<? extends Location>> locations, FilesystemStorageStrategy storageStrategy) { FilesystemStorageStrategy storageStrategy) {
super(context, blobUtils, service, defaultLocation, locations); super(context, blobUtils, service, defaultLocation, locations);
// super(context, blobUtils, service, null, null); // super(context, blobUtils, service, null, null);
this.blobFactory = blobFactory; this.blobFactory = blobFactory;
@ -164,22 +164,22 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
} }
SortedSet<StorageMetadata> contents = newTreeSet(transform(blobBelongingToContainer, SortedSet<StorageMetadata> contents = newTreeSet(transform(blobBelongingToContainer,
new Function<String, StorageMetadata>() { new Function<String, StorageMetadata>() {
public StorageMetadata apply(String key) { public StorageMetadata apply(String key) {
Blob oldBlob = loadFileBlob(container, key); Blob oldBlob = loadFileBlob(container, key);
checkState(oldBlob != null, "blob " + key + " is not present although it was in the list of " checkState(oldBlob != null, "blob " + key + " is not present although it was in the list of "
+ container); + container);
checkState(oldBlob.getMetadata() != null, "blob " + container + "/" + key + " has no metadata"); checkState(oldBlob.getMetadata() != null, "blob " + container + "/" + key + " has no metadata");
MutableBlobMetadata md = copy(oldBlob.getMetadata()); MutableBlobMetadata md = copy(oldBlob.getMetadata());
String directoryName = ifDirectoryReturnName.execute(md); String directoryName = ifDirectoryReturnName.execute(md);
if (directoryName != null) { if (directoryName != null) {
md.setName(directoryName); md.setName(directoryName);
md.setType(StorageType.RELATIVE_PATH); md.setType(StorageType.RELATIVE_PATH);
}
return md;
} }
})); return md;
}
}));
String marker = null; String marker = null;
if (options != null) { if (options != null) {
@ -219,21 +219,21 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
if (delimiter != null) { if (delimiter != null) {
SortedSet<String> commonPrefixes = null; SortedSet<String> commonPrefixes = null;
Iterable<String> iterable = transform(contents, new CommonPrefixes(prefix != null ? prefix : null, Iterable<String> iterable = transform(contents, new CommonPrefixes(prefix != null ? prefix : null,
delimiter)); delimiter));
commonPrefixes = iterable != null ? newTreeSet(iterable) : new TreeSet<String>(); commonPrefixes = iterable != null ? newTreeSet(iterable) : new TreeSet<String>();
commonPrefixes.remove(CommonPrefixes.NO_PREFIX); commonPrefixes.remove(CommonPrefixes.NO_PREFIX);
contents = newTreeSet(filter(contents, new DelimiterFilter(prefix != null ? prefix : null, delimiter))); contents = newTreeSet(filter(contents, new DelimiterFilter(prefix != null ? prefix : null, delimiter)));
Iterables.<StorageMetadata> addAll(contents, transform(commonPrefixes, Iterables.<StorageMetadata> addAll(contents,
new Function<String, StorageMetadata>() { transform(commonPrefixes, new Function<String, StorageMetadata>() {
public StorageMetadata apply(String o) { public StorageMetadata apply(String o) {
MutableStorageMetadata md = new MutableStorageMetadataImpl(); MutableStorageMetadata md = new MutableStorageMetadataImpl();
md.setType(StorageType.RELATIVE_PATH); md.setType(StorageType.RELATIVE_PATH);
md.setName(o); md.setName(o);
return md; return md;
} }
})); }));
} }
// trim metadata, if the response isn't supposed to be detailed. // trim metadata, if the response isn't supposed to be detailed.
@ -245,7 +245,7 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
} }
return Futures.<PageSet<? extends StorageMetadata>> immediateFuture(new PageSetImpl<StorageMetadata>(contents, return Futures.<PageSet<? extends StorageMetadata>> immediateFuture(new PageSetImpl<StorageMetadata>(contents,
marker)); marker));
} }
@ -310,14 +310,14 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
Iterable<String> containers = storageStrategy.getAllContainerNames(); Iterable<String> containers = storageStrategy.getAllContainerNames();
return Futures.<PageSet<? extends StorageMetadata>> immediateFuture(new PageSetImpl<StorageMetadata>(transform( return Futures.<PageSet<? extends StorageMetadata>> immediateFuture(new PageSetImpl<StorageMetadata>(transform(
containers, new Function<String, StorageMetadata>() { containers, new Function<String, StorageMetadata>() {
public StorageMetadata apply(String name) { public StorageMetadata apply(String name) {
MutableStorageMetadata cmd = create(); MutableStorageMetadata cmd = create();
cmd.setName(name); cmd.setName(name);
cmd.setType(StorageType.CONTAINER); cmd.setType(StorageType.CONTAINER);
return cmd; return cmd;
} }
}), null)); }), null));
} }
protected MutableStorageMetadata create() { protected MutableStorageMetadata create() {
@ -330,7 +330,7 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
@Path("{container}") @Path("{container}")
@Override @Override
public ListenableFuture<Boolean> createContainerInLocation(final Location location, public ListenableFuture<Boolean> createContainerInLocation(final Location location,
@PathParam("container") @ParamValidators( { FilesystemContainerNameValidator.class }) String name) { @PathParam("container") @ParamValidators({ FilesystemContainerNameValidator.class }) String name) {
boolean result = storageStrategy.createContainer(name); boolean result = storageStrategy.createContainer(name);
return immediateFuture(result); return immediateFuture(result);
} }
@ -478,7 +478,7 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
@Override @Override
public void setCurrentRequest(HttpRequest request) { public void setCurrentRequest(HttpRequest request) {
} }
}, response); }, response);
@ -500,7 +500,7 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
storageStrategy.writePayloadOnFile(containerName, blobKey, object.getPayload()); storageStrategy.writePayloadOnFile(containerName, blobKey, object.getPayload());
} catch (IOException e) { } catch (IOException e) {
logger.error(e, "An error occurred storing the new object with name [%s] to container [%s].", blobKey, logger.error(e, "An error occurred storing the new object with name [%s] to container [%s].", blobKey,
containerName); containerName);
Throwables.propagate(e); Throwables.propagate(e);
} }
return immediateFuture(eTag); return immediateFuture(eTag);
@ -547,7 +547,7 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
if (blob.getMetadata().getLastModified().before(modifiedSince)) { if (blob.getMetadata().getLastModified().before(modifiedSince)) {
HttpResponse response = new HttpResponse(304, null, null); HttpResponse response = new HttpResponse(304, null, null);
return immediateFailedFuture(new HttpResponseException(String.format("%1$s is before %2$s", blob return immediateFailedFuture(new HttpResponseException(String.format("%1$s is before %2$s", blob
.getMetadata().getLastModified(), modifiedSince), null, response)); .getMetadata().getLastModified(), modifiedSince), null, response));
} }
} }
@ -556,7 +556,7 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
if (blob.getMetadata().getLastModified().after(unmodifiedSince)) { if (blob.getMetadata().getLastModified().after(unmodifiedSince)) {
HttpResponse response = new HttpResponse(412, null, null); HttpResponse response = new HttpResponse(412, null, null);
return immediateFailedFuture(new HttpResponseException(String.format("%1$s is after %2$s", blob return immediateFailedFuture(new HttpResponseException(String.format("%1$s is after %2$s", blob
.getMetadata().getLastModified(), unmodifiedSince), null, response)); .getMetadata().getLastModified(), unmodifiedSince), null, response));
} }
} }

View File

@ -19,506 +19,507 @@
package org.jclouds.filesystem.strategy.internal; package org.jclouds.filesystem.strategy.internal;
import org.jclouds.rest.annotations.ParamValidators; import static com.google.common.base.Preconditions.checkNotNull;
import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import javax.annotation.Resource;
import javax.inject.Provider;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.DirectoryFileFilter;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobBuilder;
import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.filesystem.predicates.validators.FilesystemBlobKeyValidator; import org.jclouds.filesystem.predicates.validators.FilesystemBlobKeyValidator;
import org.jclouds.filesystem.predicates.validators.FilesystemContainerNameValidator; import org.jclouds.filesystem.predicates.validators.FilesystemContainerNameValidator;
import java.io.OutputStream; import org.jclouds.filesystem.reference.FilesystemConstants;
import java.util.Set; import org.jclouds.filesystem.strategy.FilesystemStorageStrategy;
import java.util.HashSet;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.io.Payload; import org.jclouds.io.Payload;
import java.io.InputStream; import org.jclouds.logging.Logger;
import java.io.FileOutputStream; import org.jclouds.rest.annotations.ParamValidators;
import java.io.FileFilter;
import org.apache.commons.io.filefilter.DirectoryFileFilter;
import java.util.Iterator;
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
import java.io.File;
import javax.annotation.Resource;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.name.Named; import com.google.inject.name.Named;
import org.jclouds.filesystem.reference.FilesystemConstants;
import org.jclouds.filesystem.strategy.FilesystemStorageStrategy;
import org.jclouds.logging.Logger;
import static com.google.common.base.Preconditions.checkNotNull;
/** /**
* *
* @author Alfredo "Rainbowbreeze" Morresi * @author Alfredo "Rainbowbreeze" Morresi
*/ */
public class FilesystemStorageStrategyImpl implements FilesystemStorageStrategy { public class FilesystemStorageStrategyImpl implements FilesystemStorageStrategy {
private static final String BACK_SLASH = "\\"; private static final String BACK_SLASH = "\\";
/** The buffer size used to copy an InputStream to an OutputStream */ /** The buffer size used to copy an InputStream to an OutputStream */
private static final int COPY_BUFFER_SIZE = 1024; private static final int COPY_BUFFER_SIZE = 1024;
@Resource @Resource
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
protected final Blob.Factory blobFactory; protected final Provider<BlobBuilder> blobBuilders;
protected final String baseDirectory; protected final String baseDirectory;
protected final FilesystemContainerNameValidator filesystemContainerNameValidator; protected final FilesystemContainerNameValidator filesystemContainerNameValidator;
protected final FilesystemBlobKeyValidator filesystemBlobKeyValidator; protected final FilesystemBlobKeyValidator filesystemBlobKeyValidator;
@Inject
protected FilesystemStorageStrategyImpl(Provider<BlobBuilder> blobBuilders,
@Named(FilesystemConstants.PROPERTY_BASEDIR) String baseDir,
FilesystemContainerNameValidator filesystemContainerNameValidator,
FilesystemBlobKeyValidator filesystemBlobKeyValidator) {
this.blobBuilders = checkNotNull(blobBuilders, "filesystem storage strategy blobBuilders");
this.baseDirectory = checkNotNull(baseDir, "filesystem storage strategy base directory");
this.filesystemContainerNameValidator = checkNotNull(filesystemContainerNameValidator,
"filesystem container name validator");
this.filesystemBlobKeyValidator = checkNotNull(filesystemBlobKeyValidator, "filesystem blob key validator");
}
@Inject @Override
protected FilesystemStorageStrategyImpl( public boolean containerExists(String container) {
Blob.Factory blobFactory, filesystemContainerNameValidator.validate(container);
@Named(FilesystemConstants.PROPERTY_BASEDIR) String baseDir, return directoryExists(container, null);
FilesystemContainerNameValidator filesystemContainerNameValidator, }
FilesystemBlobKeyValidator filesystemBlobKeyValidator) {
this.blobFactory = checkNotNull(blobFactory, "filesystem storage strategy blobfactory");
this.baseDirectory = checkNotNull(baseDir, "filesystem storage strategy base directory");
this.filesystemContainerNameValidator = checkNotNull(filesystemContainerNameValidator, "filesystem container name validator");
this.filesystemBlobKeyValidator = checkNotNull(filesystemBlobKeyValidator, "filesystem blob key validator");
}
@Override @Override
public boolean containerExists(String container) { public boolean blobExists(String container, String key) {
filesystemContainerNameValidator.validate(container); filesystemContainerNameValidator.validate(container);
return directoryExists(container, null); filesystemBlobKeyValidator.validate(key);
} return buildPathAndChecksIfFileExists(container, key);
}
@Override @Override
public boolean blobExists(String container, String key) { public boolean createContainer(String container) {
filesystemContainerNameValidator.validate(container); logger.debug("Creating container %s", container);
filesystemBlobKeyValidator.validate(key); filesystemContainerNameValidator.validate(container);
return buildPathAndChecksIfFileExists(container, key); return createDirectoryWithResult(container, null);
} }
@Override @Override
public boolean createContainer(String container) { public void deleteContainer(String container) {
logger.debug("Creating container %s", container); filesystemContainerNameValidator.validate(container);
filesystemContainerNameValidator.validate(container); deleteDirectory(container, null);
return createDirectoryWithResult(container, null); }
}
/**
@Override * Empty the directory of its content (files and subdirectories)
public void deleteContainer(String container) { *
filesystemContainerNameValidator.validate(container); * @param container
deleteDirectory(container, null);
}
/**
* Empty the directory of its content (files and subdirectories)
* @param container
*/
@Override
public void clearContainer(final String container) {
filesystemContainerNameValidator.validate(container);
clearContainer(container, ListContainerOptions.Builder.recursive());
}
@Override
public void clearContainer(String container, ListContainerOptions options) {
filesystemContainerNameValidator.validate(container);
//TODO
//now all is deleted, check it based on options
try {
File containerFile = openFolder(container);
File[] children = containerFile.listFiles();
if (null != children) {
for(File child:children) {
FileUtils.forceDelete(child);
}
}
} catch(IOException e) {
logger.error(e,"An error occurred while clearing container %s", container);
Throwables.propagate(e);
}
}
@Override
public Blob newBlob(@ParamValidators( { FilesystemBlobKeyValidator.class }) String name) {
filesystemBlobKeyValidator.validate(name);
Blob blob = blobFactory.create(null);
blob.getMetadata().setName(name);
return blob;
}
@Override
public void removeBlob(final String container, final String blobKey) {
filesystemContainerNameValidator.validate(container);
filesystemBlobKeyValidator.validate(blobKey);
String fileName = buildPathStartingFromBaseDir(container, blobKey);
logger.debug("Deleting blob %s", fileName);
File fileToBeDeleted = new File(fileName);
fileToBeDeleted.delete();
//now examins if the key of the blob is a complex key (with a directory structure)
//and eventually remove empty directory
removeDirectoriesTreeOfBlobKey(container, blobKey);
}
/**
* Return an iterator that reports all the containers under base path
* @return
*/
@Override
public Iterable<String> getAllContainerNames() {
Iterable<String> containers = new Iterable<String>() {
@Override
public Iterator<String> iterator() {
return new FileIterator(
buildPathStartingFromBaseDir(), DirectoryFileFilter.INSTANCE);
}
};
return containers;
}
/**
* Returns a {@link File} object that links to the blob
* @param container
* @param blobKey
* @return
*/
@Override
public File getFileForBlobKey(String container, String blobKey) {
filesystemContainerNameValidator.validate(container);
filesystemBlobKeyValidator.validate(blobKey);
String fileName = buildPathStartingFromBaseDir(container, blobKey);
File blobFile = new File(fileName);
return blobFile;
}
/**
* Write a {@link Blob} {@link Payload} into a file
* @param container
* @param blobKey
* @param payload
* @throws IOException
*/
@Override
public void writePayloadOnFile(String container, String blobKey, Payload payload) throws IOException {
filesystemContainerNameValidator.validate(container);
filesystemBlobKeyValidator.validate(blobKey);
File outputFile = null;
OutputStream output = null;
InputStream input = null;
try {
outputFile = getFileForBlobKey(container, blobKey);
File parentDirectory = outputFile.getParentFile();
if (!parentDirectory.exists()) {
if (!parentDirectory.mkdirs()) {
throw new IOException("An error occurred creating directory [" + parentDirectory.getName() + "].");
}
}
output = new FileOutputStream(outputFile);
input = payload.getInput();
copy(input, output);
} catch (IOException ex) {
if (outputFile != null) {
outputFile.delete();
}
throw ex;
} finally {
if (input != null) {
try {
input.close();
} catch (IOException ex) {
// Does nothing
}
}
if (output != null) {
try {
output.close();
} catch (IOException ex) {
// Does nothing
}
}
}
}
/**
* Returns all the blobs key inside a container
* @param container
* @return
* @throws IOException
*/
@Override
public Iterable<String> getBlobKeysInsideContainer(String container) throws IOException {
filesystemContainerNameValidator.validate(container);
//check if container exists
//TODO maybe an error is more appropriate
if (!containerExists(container)) {
return new HashSet<String>();
}
File containerFile = openFolder(container);
final int containerPathLenght = containerFile.getAbsolutePath().length() + 1;
Set<String> blobNames = new HashSet<String>() {
private static final long serialVersionUID = 3152191346558570795L;
@Override
public boolean add(String e) {
return super.add(e.substring(containerPathLenght));
}
};
populateBlobKeysInContainer(containerFile, blobNames);
return blobNames;
}
@Override
public boolean directoryExists(String container, String directory) {
return buildPathAndChecksIfDirectoryExists(container, directory);
}
@Override
public void createDirectory(String container, String directory) {
createDirectoryWithResult(container, directory);
}
@Override
public void deleteDirectory(String container, String directory) {
//create complete dir path
String fullDirPath = buildPathStartingFromBaseDir(container, directory);
try {
FileUtils.forceDelete(new File(fullDirPath));
} catch (IOException ex) {
logger.error("An error occurred removing directory %s.", fullDirPath);
Throwables.propagate(ex);
}
}
@Override
public long countBlobs(String container, ListContainerOptions options) {
//TODO
throw new UnsupportedOperationException("Not supported yet.");
}
//---------------------------------------------------------- Private methods
private boolean buildPathAndChecksIfFileExists(String...tokens) {
String path = buildPathStartingFromBaseDir(tokens);
File file = new File(path);
boolean exists = file.exists() || file.isFile();
return exists;
}
/**
* Check if the file system resource whose name is obtained applying buildPath
* on the input path tokens is a directory, otherwise a RuntimeException is thrown
*
* @param tokens the tokens that make up the name of the resource on the
* file system
*/ */
private boolean buildPathAndChecksIfDirectoryExists(String...tokens) { @Override
String path = buildPathStartingFromBaseDir(tokens); public void clearContainer(final String container) {
File file = new File(path); filesystemContainerNameValidator.validate(container);
boolean exists = file.exists() || file.isDirectory(); clearContainer(container, ListContainerOptions.Builder.recursive());
return exists; }
}
@Override
/** public void clearContainer(String container, ListContainerOptions options) {
* Facility method used to concatenate path tokens normalizing separators filesystemContainerNameValidator.validate(container);
* @param pathTokens all the string in the proper order that must be concatenated // TODO
* in order to obtain the filename // now all is deleted, check it based on options
* @return the resulting string try {
*/ File containerFile = openFolder(container);
protected String buildPathStartingFromBaseDir(String...pathTokens) { File[] children = containerFile.listFiles();
String normalizedToken = removeFileSeparatorFromBorders(normalize(baseDirectory), true); if (null != children) {
StringBuilder completePath = new StringBuilder(normalizedToken); for (File child : children) {
if(pathTokens!=null && pathTokens.length>0) { FileUtils.forceDelete(child);
for(int i=0; i<pathTokens.length; i++) {
if(pathTokens[i]!=null) {
normalizedToken = removeFileSeparatorFromBorders(normalize(pathTokens[i]), false);
completePath.append(File.separator).append(normalizedToken);
}
} }
} }
return completePath.toString(); } catch (IOException e) {
} logger.error(e, "An error occurred while clearing container %s", container);
Throwables.propagate(e);
}
}
/** @Override
* Substitutes all the file separator occurrences in the path with a file public Blob newBlob(@ParamValidators({ FilesystemBlobKeyValidator.class }) String name) {
* separator for the current operative system filesystemBlobKeyValidator.validate(name);
* @param pathToBeNormalized return blobBuilders.get().name(name).build();
* @return }
*/
private String normalize(String pathToBeNormalized) { @Override
if(null != pathToBeNormalized && pathToBeNormalized.contains(BACK_SLASH)) { public void removeBlob(final String container, final String blobKey) {
if(!BACK_SLASH.equals(File.separator)) { filesystemContainerNameValidator.validate(container);
return pathToBeNormalized.replaceAll(BACK_SLASH, File.separator); filesystemBlobKeyValidator.validate(blobKey);
String fileName = buildPathStartingFromBaseDir(container, blobKey);
logger.debug("Deleting blob %s", fileName);
File fileToBeDeleted = new File(fileName);
fileToBeDeleted.delete();
// now examins if the key of the blob is a complex key (with a directory structure)
// and eventually remove empty directory
removeDirectoriesTreeOfBlobKey(container, blobKey);
}
/**
* Return an iterator that reports all the containers under base path
*
* @return
*/
@Override
public Iterable<String> getAllContainerNames() {
Iterable<String> containers = new Iterable<String>() {
@Override
public Iterator<String> iterator() {
return new FileIterator(buildPathStartingFromBaseDir(), DirectoryFileFilter.INSTANCE);
}
};
return containers;
}
/**
* Returns a {@link File} object that links to the blob
*
* @param container
* @param blobKey
* @return
*/
@Override
public File getFileForBlobKey(String container, String blobKey) {
filesystemContainerNameValidator.validate(container);
filesystemBlobKeyValidator.validate(blobKey);
String fileName = buildPathStartingFromBaseDir(container, blobKey);
File blobFile = new File(fileName);
return blobFile;
}
/**
* Write a {@link Blob} {@link Payload} into a file
*
* @param container
* @param blobKey
* @param payload
* @throws IOException
*/
@Override
public void writePayloadOnFile(String container, String blobKey, Payload payload) throws IOException {
filesystemContainerNameValidator.validate(container);
filesystemBlobKeyValidator.validate(blobKey);
File outputFile = null;
OutputStream output = null;
InputStream input = null;
try {
outputFile = getFileForBlobKey(container, blobKey);
File parentDirectory = outputFile.getParentFile();
if (!parentDirectory.exists()) {
if (!parentDirectory.mkdirs()) {
throw new IOException("An error occurred creating directory [" + parentDirectory.getName() + "].");
} }
} }
return pathToBeNormalized; output = new FileOutputStream(outputFile);
} input = payload.getInput();
copy(input, output);
/** } catch (IOException ex) {
* Remove leading and trailing {@link File.separator} character from the if (outputFile != null) {
* string. outputFile.delete();
* @param pathToBeCleaned }
* @param remove only trailing separator char from path throw ex;
* @return } finally {
*/ if (input != null) {
private String removeFileSeparatorFromBorders(String pathToBeCleaned, boolean onlyTrailing) { try {
if (null == pathToBeCleaned || pathToBeCleaned.equals("")) return pathToBeCleaned; input.close();
} catch (IOException ex) {
int beginIndex = 0; // Does nothing
int endIndex = pathToBeCleaned.length();
//search for separator chars
if (!onlyTrailing) {
if (pathToBeCleaned.substring(0, 1).equals(File.separator)) beginIndex = 1;
}
if (pathToBeCleaned.substring(pathToBeCleaned.length() - 1).equals(File.separator)) endIndex--;
return pathToBeCleaned.substring(beginIndex, endIndex);
}
/**
* Removes recursively the directory structure of a complex blob key, only
* if the directory is empty
* @param container
* @param normalizedKey
*/
private void removeDirectoriesTreeOfBlobKey(String container, String blobKey) {
String normalizedBlobKey = normalize(blobKey);
//exists is no path is present in the blobkey
if (!normalizedBlobKey.contains(File.separator)) return;
File file = new File(normalizedBlobKey);
//TODO
//"/media/data/works/java/amazon/jclouds/master/filesystem/aa/bb/cc/dd/eef6f0c8-0206-460b-8870-352e6019893c.txt"
String parentPath = file.getParent();
//no need to manage "/" parentPath, because "/" cannot be used as start
//char of blobkey
if (null != parentPath || "".equals(parentPath)) {
//remove parent directory only it's empty
File directory = new File(buildPathStartingFromBaseDir(container, parentPath));
String[] children = directory.list();
if (null == children || children.length == 0) {
directory.delete();
//recursively call for removing other path
removeDirectoriesTreeOfBlobKey(container, parentPath);
} }
} }
} if (output != null) {
try {
output.close();
private File openFolder(String folderName) throws IOException { } catch (IOException ex) {
String baseFolderName = buildPathStartingFromBaseDir(folderName); // Does nothing
File folder = new File(baseFolderName);
if(folder.exists()) {
if(!folder.isDirectory()) {
throw new IOException("Resource " + baseFolderName + " isn't a folder.");
} }
} }
return folder; }
} }
/**
* Returns all the blobs key inside a container
*
* @param container
* @return
* @throws IOException
*/
@Override
public Iterable<String> getBlobKeysInsideContainer(String container) throws IOException {
filesystemContainerNameValidator.validate(container);
// check if container exists
// TODO maybe an error is more appropriate
if (!containerExists(container)) {
return new HashSet<String>();
}
private class FileIterator implements Iterator<String>{ File containerFile = openFolder(container);
int currentFileIndex = 0; final int containerPathLenght = containerFile.getAbsolutePath().length() + 1;
File[] children = new File[0]; Set<String> blobNames = new HashSet<String>() {
File currentFile = null;
public FileIterator(String fileName, FileFilter filter) { private static final long serialVersionUID = 3152191346558570795L;
File file = new File(fileName);
if(file.exists() && file.isDirectory()) { @Override
children = file.listFiles(filter); public boolean add(String e) {
return super.add(e.substring(containerPathLenght));
}
};
populateBlobKeysInContainer(containerFile, blobNames);
return blobNames;
}
@Override
public boolean directoryExists(String container, String directory) {
return buildPathAndChecksIfDirectoryExists(container, directory);
}
@Override
public void createDirectory(String container, String directory) {
createDirectoryWithResult(container, directory);
}
@Override
public void deleteDirectory(String container, String directory) {
// create complete dir path
String fullDirPath = buildPathStartingFromBaseDir(container, directory);
try {
FileUtils.forceDelete(new File(fullDirPath));
} catch (IOException ex) {
logger.error("An error occurred removing directory %s.", fullDirPath);
Throwables.propagate(ex);
}
}
@Override
public long countBlobs(String container, ListContainerOptions options) {
// TODO
throw new UnsupportedOperationException("Not supported yet.");
}
// ---------------------------------------------------------- Private methods
private boolean buildPathAndChecksIfFileExists(String... tokens) {
String path = buildPathStartingFromBaseDir(tokens);
File file = new File(path);
boolean exists = file.exists() || file.isFile();
return exists;
}
/**
* Check if the file system resource whose name is obtained applying buildPath on the input path
* tokens is a directory, otherwise a RuntimeException is thrown
*
* @param tokens
* the tokens that make up the name of the resource on the file system
*/
private boolean buildPathAndChecksIfDirectoryExists(String... tokens) {
String path = buildPathStartingFromBaseDir(tokens);
File file = new File(path);
boolean exists = file.exists() || file.isDirectory();
return exists;
}
/**
* Facility method used to concatenate path tokens normalizing separators
*
* @param pathTokens
* all the string in the proper order that must be concatenated in order to obtain the
* filename
* @return the resulting string
*/
protected String buildPathStartingFromBaseDir(String... pathTokens) {
String normalizedToken = removeFileSeparatorFromBorders(normalize(baseDirectory), true);
StringBuilder completePath = new StringBuilder(normalizedToken);
if (pathTokens != null && pathTokens.length > 0) {
for (int i = 0; i < pathTokens.length; i++) {
if (pathTokens[i] != null) {
normalizedToken = removeFileSeparatorFromBorders(normalize(pathTokens[i]), false);
completePath.append(File.separator).append(normalizedToken);
} }
} }
}
return completePath.toString();
}
@Override /**
public boolean hasNext() { * Substitutes all the file separator occurrences in the path with a file separator for the
return currentFileIndex<children.length; * current operative system
} *
* @param pathToBeNormalized
* @return
*/
private String normalize(String pathToBeNormalized) {
if (null != pathToBeNormalized && pathToBeNormalized.contains(BACK_SLASH)) {
if (!BACK_SLASH.equals(File.separator)) {
return pathToBeNormalized.replaceAll(BACK_SLASH, File.separator);
}
}
return pathToBeNormalized;
}
@Override /**
public String next() { * Remove leading and trailing {@link File.separator} character from the string.
currentFile = children[currentFileIndex++]; *
return currentFile.getName(); * @param pathToBeCleaned
} * @param remove
* only trailing separator char from path
* @return
*/
private String removeFileSeparatorFromBorders(String pathToBeCleaned, boolean onlyTrailing) {
if (null == pathToBeCleaned || pathToBeCleaned.equals(""))
return pathToBeCleaned;
@Override int beginIndex = 0;
public void remove() { int endIndex = pathToBeCleaned.length();
if(currentFile!=null && currentFile.exists()) {
if(!currentFile.delete()) { // search for separator chars
throw new RuntimeException("An error occurred deleting "+currentFile.getName()); if (!onlyTrailing) {
} if (pathToBeCleaned.substring(0, 1).equals(File.separator))
beginIndex = 1;
}
if (pathToBeCleaned.substring(pathToBeCleaned.length() - 1).equals(File.separator))
endIndex--;
return pathToBeCleaned.substring(beginIndex, endIndex);
}
/**
* Removes recursively the directory structure of a complex blob key, only if the directory is
* empty
*
* @param container
* @param normalizedKey
*/
private void removeDirectoriesTreeOfBlobKey(String container, String blobKey) {
String normalizedBlobKey = normalize(blobKey);
// exists is no path is present in the blobkey
if (!normalizedBlobKey.contains(File.separator))
return;
File file = new File(normalizedBlobKey);
// TODO
// "/media/data/works/java/amazon/jclouds/master/filesystem/aa/bb/cc/dd/eef6f0c8-0206-460b-8870-352e6019893c.txt"
String parentPath = file.getParent();
// no need to manage "/" parentPath, because "/" cannot be used as start
// char of blobkey
if (null != parentPath || "".equals(parentPath)) {
// remove parent directory only it's empty
File directory = new File(buildPathStartingFromBaseDir(container, parentPath));
String[] children = directory.list();
if (null == children || children.length == 0) {
directory.delete();
// recursively call for removing other path
removeDirectoriesTreeOfBlobKey(container, parentPath);
}
}
}
private File openFolder(String folderName) throws IOException {
String baseFolderName = buildPathStartingFromBaseDir(folderName);
File folder = new File(baseFolderName);
if (folder.exists()) {
if (!folder.isDirectory()) {
throw new IOException("Resource " + baseFolderName + " isn't a folder.");
}
}
return folder;
}
private class FileIterator implements Iterator<String> {
int currentFileIndex = 0;
File[] children = new File[0];
File currentFile = null;
public FileIterator(String fileName, FileFilter filter) {
File file = new File(fileName);
if (file.exists() && file.isDirectory()) {
children = file.listFiles(filter);
}
}
@Override
public boolean hasNext() {
return currentFileIndex < children.length;
}
@Override
public String next() {
currentFile = children[currentFileIndex++];
return currentFile.getName();
}
@Override
public void remove() {
if (currentFile != null && currentFile.exists()) {
if (!currentFile.delete()) {
throw new RuntimeException("An error occurred deleting " + currentFile.getName());
} }
} }
} }
}
private void populateBlobKeysInContainer(File directory, Set<String> blobNames) {
File[] children = directory.listFiles();
for (File child : children) {
if (child.isFile()) {
blobNames.add(child.getAbsolutePath());
} else if (child.isDirectory()) {
populateBlobKeysInContainer(child, blobNames);
}
}
}
private void populateBlobKeysInContainer(File directory, Set<String> blobNames) { /**
File[] children = directory.listFiles(); * Creates a directory and returns the result
for(File child:children) { *
if(child.isFile()) { * @param container
blobNames.add(child.getAbsolutePath()); * @param directory
} else if(child.isDirectory()) { * @return true if the directory was created, otherwise false
populateBlobKeysInContainer(child, blobNames); */
} protected boolean createDirectoryWithResult(String container, String directory) {
} String directoryFullName = buildPathStartingFromBaseDir(container, directory);
} logger.debug("Creating directory %s", directoryFullName);
// cannot use directoryFullName, because the following method rebuild
// another time the path starting from base directory
if (buildPathAndChecksIfDirectoryExists(container, directory)) {
logger.debug("Directory %s already exists", directoryFullName);
return false;
}
/** File directoryToCreate = new File(directoryFullName);
* Creates a directory and returns the result boolean result = directoryToCreate.mkdirs();
* @param container return result;
* @param directory }
* @return true if the directory was created, otherwise false
*/
protected boolean createDirectoryWithResult(String container, String directory) {
String directoryFullName = buildPathStartingFromBaseDir(container, directory);
logger.debug("Creating directory %s", directoryFullName);
//cannot use directoryFullName, because the following method rebuild /**
//another time the path starting from base directory * Copy from an InputStream to an OutputStream.
if (buildPathAndChecksIfDirectoryExists(container, directory)) { *
logger.debug("Directory %s already exists", directoryFullName); * @param input
return false; * The InputStream
} * @param output
* The OutputStream
File directoryToCreate = new File(directoryFullName); * @return the number of bytes copied
boolean result = directoryToCreate.mkdirs(); * @throws IOException
return result; * if an error occurs
} */
private long copy(InputStream input, OutputStream output) throws IOException {
/** byte[] buffer = new byte[COPY_BUFFER_SIZE];
* Copy from an InputStream to an OutputStream. long count = 0;
* while (true) {
* @param input The InputStream int read = input.read(buffer);
* @param output The OutputStream if (read < 0) {
* @return the number of bytes copied break;
* @throws IOException if an error occurs }
*/ count += read;
private long copy(InputStream input, OutputStream output)
throws IOException {
byte[] buffer = new byte[COPY_BUFFER_SIZE];
long count = 0;
while (true) {
int read = input.read(buffer);
if (read < 0) {
break;
}
count += read;
output.write(buffer, 0, read);
}
output.flush();
return count;
}
output.write(buffer, 0, read);
}
output.flush();
return count;
}
} }

View File

@ -19,14 +19,18 @@
package org.jclouds.filesystem.util.internal; package org.jclouds.filesystem.util.internal;
import com.google.inject.Inject; import static com.google.common.base.Preconditions.checkNotNull;
import javax.inject.Provider;
import org.jclouds.blobstore.AsyncBlobStore; import org.jclouds.blobstore.AsyncBlobStore;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobBuilder;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.util.BlobUtils; import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.filesystem.strategy.FilesystemStorageStrategy; import org.jclouds.filesystem.strategy.FilesystemStorageStrategy;
import static com.google.common.base.Preconditions.checkNotNull; import com.google.inject.Inject;
/** /**
* Implements the {@link BlobUtils} interfaced and act as a bridge to * Implements the {@link BlobUtils} interfaced and act as a bridge to
@ -36,44 +40,48 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/ */
public class FileSystemBlobUtilsImpl implements BlobUtils { public class FileSystemBlobUtilsImpl implements BlobUtils {
protected final FilesystemStorageStrategy storageStrategy; protected final FilesystemStorageStrategy storageStrategy;
protected final Provider<BlobBuilder> blobBuilders;
@Inject @Inject
public FileSystemBlobUtilsImpl( public FileSystemBlobUtilsImpl(FilesystemStorageStrategy storageStrategy, Provider<BlobBuilder> blobBuilders) {
FilesystemStorageStrategy storageStrategy) { this.storageStrategy = checkNotNull(storageStrategy, "Filesystem Storage Strategy");
this.storageStrategy = checkNotNull(storageStrategy, "Filesystem Storage Strategy"); this.blobBuilders = checkNotNull(blobBuilders, "Filesystem blobBuilders");
} }
@Override
public Blob newBlob(String name) {
return blobBuilder().name(name).build();
}
@Override
public BlobBuilder blobBuilder() {
return blobBuilders.get();
}
@Override @Override
public Blob newBlob(String name) { public boolean directoryExists(String containerName, String directory) {
return storageStrategy.newBlob(name); return storageStrategy.directoryExists(containerName, directory);
} }
@Override @Override
public boolean directoryExists(String containerName, String directory) { public void createDirectory(String containerName, String directory) {
return storageStrategy.directoryExists(containerName, directory); storageStrategy.createDirectory(containerName, directory);
} }
@Override @Override
public void createDirectory(String containerName, String directory) { public long countBlobs(String container, ListContainerOptions options) {
storageStrategy.createDirectory(containerName, directory); return storageStrategy.countBlobs(container, options);
} }
@Override @Override
public long countBlobs(String container, ListContainerOptions options) { public void clearContainer(String container, ListContainerOptions options) {
return storageStrategy.countBlobs(container, options); storageStrategy.clearContainer(container, options);
} }
@Override @Override
public void clearContainer(String container, ListContainerOptions options) { public void deleteDirectory(String container, String directory) {
storageStrategy.clearContainer(container, options); storageStrategy.deleteDirectory(container, directory);
} }
@Override
public void deleteDirectory(String container, String directory) {
storageStrategy.deleteDirectory(container, directory);
}
} }

View File

@ -31,6 +31,7 @@ import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.integration.internal.BaseContainerIntegrationTest; import org.jclouds.blobstore.integration.internal.BaseContainerIntegrationTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
/** /**
@ -45,19 +46,16 @@ public class FilesystemContainerIntegrationTest extends BaseContainerIntegration
String key = "hello"; String key = "hello";
Blob object = context.getBlobStore().newBlob(key);
object.setPayload(TEST_STRING);
object.getMetadata().getContentMetadata().setContentType(MediaType.TEXT_PLAIN);
// NOTE all metadata in jclouds comes out as lowercase, in an effort to normalize the // NOTE all metadata in jclouds comes out as lowercase, in an effort to normalize the
// providers. // providers.
object.getMetadata().getUserMetadata().put("Adrian", "powderpuff"); Blob object = context.getBlobStore().blobBuilder(key).userMetadata(ImmutableMap.of("Adrian", "powderpuff"))
.payload(TEST_STRING).contentType(MediaType.TEXT_PLAIN).build();
String containerName = getContainerName(); String containerName = getContainerName();
try { try {
addBlobToContainer(containerName, object); addBlobToContainer(containerName, object);
validateContent(containerName, key); validateContent(containerName, key);
PageSet<? extends StorageMetadata> container = context.getBlobStore().list(containerName, PageSet<? extends StorageMetadata> container = context.getBlobStore().list(containerName, maxResults(1));
maxResults(1));
BlobMetadata metadata = (BlobMetadata) Iterables.getOnlyElement(container); BlobMetadata metadata = (BlobMetadata) Iterables.getOnlyElement(container);
// transient container should be lenient and not return metadata on undetailed listing. // transient container should be lenient and not return metadata on undetailed listing.

View File

@ -35,7 +35,7 @@ import com.google.common.base.Function;
*/ */
@Singleton @Singleton
public class ObjectToBlob implements Function<S3Object, Blob> { public class ObjectToBlob implements Function<S3Object, Blob> {
private final Blob.Factory blobFactory; private final Factory blobFactory;
private final ObjectToBlobMetadata object2BlobMd; private final ObjectToBlobMetadata object2BlobMd;
@Inject @Inject

View File

@ -35,7 +35,7 @@ import com.google.common.base.Function;
*/ */
@Singleton @Singleton
public class ObjectToBlob implements Function<SwiftObject, Blob> { public class ObjectToBlob implements Function<SwiftObject, Blob> {
private final Blob.Factory blobFactory; private final Factory blobFactory;
private final ObjectToBlobMetadata object2BlobMd; private final ObjectToBlobMetadata object2BlobMd;
@Inject @Inject

View File

@ -24,6 +24,7 @@ import java.util.Set;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobBuilder;
import org.jclouds.blobstore.domain.BlobMetadata; import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.domain.PageSet; import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata; import org.jclouds.blobstore.domain.StorageMetadata;
@ -47,8 +48,14 @@ public interface AsyncBlobStore {
/** /**
* @see BlobStore#newBlob * @see BlobStore#newBlob
*/ */
@Deprecated
Blob newBlob(String name); Blob newBlob(String name);
/**
* @see BlobStore#blobBuilder
*/
BlobBuilder blobBuilder(String name);
/** /**
* @see BlobStore#listAssignableLocations * @see BlobStore#listAssignableLocations
*/ */

View File

@ -20,6 +20,7 @@
package org.jclouds.blobstore; package org.jclouds.blobstore;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobBuilder;
import org.jclouds.blobstore.internal.BlobMapImpl; import org.jclouds.blobstore.internal.BlobMapImpl;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
@ -34,9 +35,19 @@ import com.google.inject.ImplementedBy;
*/ */
@ImplementedBy(BlobMapImpl.class) @ImplementedBy(BlobMapImpl.class)
public interface BlobMap extends ListableMap<String, Blob> { public interface BlobMap extends ListableMap<String, Blob> {
/**
* @see #blobBuilder
* @param name
*/
@Deprecated
Blob newBlob(String name); Blob newBlob(String name);
/**
*
* @return builder for creating new {@link Blob}s
*/
BlobBuilder blobBuilder();
public static interface Factory { public static interface Factory {
BlobMap create(String containerName, ListContainerOptions options); BlobMap create(String containerName, ListContainerOptions options);
} }

View File

@ -24,6 +24,7 @@ import java.util.Set;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobBuilder;
import org.jclouds.blobstore.domain.BlobMetadata; import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.domain.PageSet; import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata; import org.jclouds.blobstore.domain.StorageMetadata;
@ -47,9 +48,17 @@ public interface BlobStore {
/** /**
* creates a new blob with the specified name. * creates a new blob with the specified name.
* @see #blobBuilder
*/ */
@Deprecated
Blob newBlob(String name); Blob newBlob(String name);
/**
*
* @return builder for creating new {@link Blob}s
*/
BlobBuilder blobBuilder(String name);
/** /**
* The get locations command returns all the valid locations for containers. A location has a * The get locations command returns all the valid locations for containers. A location has a
* scope, which is typically region or zone. A region is a general area, like eu-west, where a * scope, which is typically region or zone. A region is a general area, like eu-west, where a

View File

@ -19,6 +19,7 @@
package org.jclouds.blobstore; package org.jclouds.blobstore;
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 com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Throwables.getCausalChain; import static com.google.common.base.Throwables.getCausalChain;
@ -125,7 +126,7 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
protected TransientAsyncBlobStore(BlobStoreContext context, DateService dateService, Crypto crypto, protected TransientAsyncBlobStore(BlobStoreContext context, DateService dateService, Crypto crypto,
ConcurrentMap<String, ConcurrentMap<String, Blob>> containerToBlobs, ConcurrentMap<String, ConcurrentMap<String, Blob>> containerToBlobs,
ConcurrentMap<String, Location> containerToLocation, HttpGetOptionsListToGetOptions httpGetOptionsConverter, ConcurrentMap<String, Location> containerToLocation, HttpGetOptionsListToGetOptions httpGetOptionsConverter,
IfDirectoryReturnNameStrategy ifDirectoryReturnName, Blob.Factory blobFactory, BlobUtils blobUtils, IfDirectoryReturnNameStrategy ifDirectoryReturnName, Factory blobFactory, BlobUtils blobUtils,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation,
@Memoized Supplier<Set<? extends Location>> locations) { @Memoized Supplier<Set<? extends Location>> locations) {
super(context, blobUtils, service, defaultLocation, locations); super(context, blobUtils, service, defaultLocation, locations);
@ -487,6 +488,8 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
*/ */
@Override @Override
public ListenableFuture<String> putBlob(String containerName, Blob in) { public ListenableFuture<String> putBlob(String containerName, Blob in) {
checkArgument(containerName != null, "containerName must be set");
checkArgument(in != null, "blob must be set");
ConcurrentMap<String, Blob> container = getContainerToBlobs().get(containerName); ConcurrentMap<String, Blob> container = getContainerToBlobs().get(containerName);
if (container == null) { if (container == null) {
new IllegalStateException("containerName not found: " + containerName); new IllegalStateException("containerName not found: " + containerName);
@ -513,6 +516,8 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
} }
protected Blob createUpdatedCopyOfBlob(Blob in) { protected Blob createUpdatedCopyOfBlob(Blob in) {
checkNotNull(in, "blob");
checkNotNull(in.getPayload(), "blob.payload");
ByteArrayPayload payload = (in.getPayload() instanceof ByteArrayPayload) ? ByteArrayPayload.class.cast(in ByteArrayPayload payload = (in.getPayload() instanceof ByteArrayPayload) ? ByteArrayPayload.class.cast(in
.getPayload()) : null; .getPayload()) : null;
if (payload == null) if (payload == null)

View File

@ -20,11 +20,12 @@
package org.jclouds.blobstore.config; package org.jclouds.blobstore.config;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Provider;
import org.jclouds.blobstore.BlobMap; import org.jclouds.blobstore.BlobMap;
import org.jclouds.blobstore.BlobStore; import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.InputStreamMap; import org.jclouds.blobstore.InputStreamMap;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.BlobBuilder;
import org.jclouds.blobstore.internal.BlobMapImpl; import org.jclouds.blobstore.internal.BlobMapImpl;
import org.jclouds.blobstore.internal.InputStreamMapImpl; import org.jclouds.blobstore.internal.InputStreamMapImpl;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
@ -65,10 +66,12 @@ public class BlobStoreMapModule extends AbstractModule {
PutBlobsStrategy putBlobsStrategy; PutBlobsStrategy putBlobsStrategy;
@Inject @Inject
ListContainerAndRecurseThroughFolders listStrategy; ListContainerAndRecurseThroughFolders listStrategy;
@Inject
Provider<BlobBuilder> blobBuilders;
public BlobMap create(String containerName, ListContainerOptions options) { public BlobMap create(String containerName, ListContainerOptions options) {
return new BlobMapImpl(connection, getAllBlobs, containsValueStrategy, putBlobsStrategy, return new BlobMapImpl(connection, getAllBlobs, containsValueStrategy, putBlobsStrategy, listStrategy,
listStrategy, containerName, options); containerName, options, blobBuilders);
} }
} }
@ -77,7 +80,7 @@ public class BlobStoreMapModule extends AbstractModule {
@Inject @Inject
BlobStore connection; BlobStore connection;
@Inject @Inject
Blob.Factory blobFactory; Provider<BlobBuilder> blobBuilders;
@Inject @Inject
GetBlobsInListStrategy getAllBlobs; GetBlobsInListStrategy getAllBlobs;
@Inject @Inject
@ -90,9 +93,8 @@ public class BlobStoreMapModule extends AbstractModule {
ListContainerAndRecurseThroughFolders listStrategy; ListContainerAndRecurseThroughFolders listStrategy;
public InputStreamMap create(String containerName, ListContainerOptions options) { public InputStreamMap create(String containerName, ListContainerOptions options) {
return new InputStreamMapImpl(connection, blobFactory, getAllBlobs, listStrategy, return new InputStreamMapImpl(connection, blobBuilders, getAllBlobs, listStrategy, containsValueStrategy,
containsValueStrategy, putBlobsStrategy, containerName, options, putBlobsStrategy, containerName, options, crypto);
crypto);
} }
} }

View File

@ -0,0 +1,123 @@
/**
*
* 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.blobstore.domain;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import org.jclouds.blobstore.domain.internal.BlobBuilderImpl;
import org.jclouds.io.Payload;
import org.jclouds.io.Payloads;
import com.google.inject.ImplementedBy;
/**
*
* In case the name was confusing, this indeed builds a Blob.
*
* @author Adrian Cole
*/
@ImplementedBy(BlobBuilderImpl.class)
public interface BlobBuilder {
/**
* @param name
* The name of the {@link Blob}. Typically refers to an http path.
*/
BlobBuilder name(String name);
/**
* @param type
* overrides default type of {@link StorageType#BLOB}
*/
BlobBuilder type(StorageType type);
/**
* @param userMetadata
* User defined metadata associated with this {@link Blob}.
*
*/
BlobBuilder userMetadata(Map<String, String> userMetadata);
/**
*
* @param payload
* payload you wish to construct the {@link Blob} with.
*/
PayloadBlobBuilder payload(Payload payload);
/**
*
* @param payload
* payload you wish to construct the {@link Blob} with.
*/
PayloadBlobBuilder payload(InputStream payload);
/**
*
* @param payload
* payload you wish to construct the {@link Blob} with.
*/
PayloadBlobBuilder payload(byte[] payload);
/**
*
* @param payload
* payload you wish to construct the {@link Blob} with.
*/
PayloadBlobBuilder payload(String payload);
/**
*
* @param payload
* payload you wish to construct the {@link Blob} with.
*/
PayloadBlobBuilder payload(File payload);
/**
* This makes a blob from the currently configured parameters.
*
* @return a new blob from the current parameters
*/
Blob build();
public interface PayloadBlobBuilder extends BlobBuilder {
PayloadBlobBuilder contentLength(long contentLength);
PayloadBlobBuilder contentMD5(byte[] md5);
PayloadBlobBuilder contentType(String contentType);
PayloadBlobBuilder contentDisposition(String contentDisposition);
PayloadBlobBuilder contentLanguage(String contentLanguage);
PayloadBlobBuilder contentEncoding(String contentEncoding);
/**
*
* @see Payloads#calculateMD5
*/
PayloadBlobBuilder calculateMD5() throws IOException;
}
}

View File

@ -0,0 +1,229 @@
/**
*
* 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.blobstore.domain.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.io.Payloads.newPayload;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import javax.annotation.Nullable;
import javax.inject.Inject;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobBuilder;
import org.jclouds.blobstore.domain.StorageType;
import org.jclouds.crypto.Crypto;
import org.jclouds.io.Payload;
import org.jclouds.io.Payloads;
import com.google.common.base.Throwables;
import com.google.common.collect.Maps;
/**
* @author Adrian Cole
*/
public class BlobBuilderImpl implements BlobBuilder {
private Payload payload;
private String name;
private Map<String, String> userMetadata = Maps.newLinkedHashMap();
private StorageType type = StorageType.BLOB;
@Inject
private Crypto crypto;
@Override
public BlobBuilder name(String name) {
this.name = name;
return this;
}
@Override
public BlobBuilder type(StorageType type) {
this.type = type;
return this;
}
@Override
public BlobBuilder userMetadata(Map<String, String> userMetadata) {
this.userMetadata = Maps.newLinkedHashMap(checkNotNull(userMetadata, "userMetadata"));
return this;
}
@Override
public PayloadBlobBuilder payload(Payload payload) {
this.payload = payload;
return new PayloadBlobBuilderImpl(this, payload, crypto);
}
/**
* {@inheritDoc}
*/
@Override
public PayloadBlobBuilder payload(InputStream data) {
return payload(newPayload(checkNotNull(data, "data")));
}
/**
* {@inheritDoc}
*/
@Override
public PayloadBlobBuilder payload(byte[] data) {
return payload(newPayload(checkNotNull(data, "data")));
}
/**
* {@inheritDoc}
*/
@Override
public PayloadBlobBuilder payload(String data) {
return payload(newPayload(checkNotNull(data, "data")));
}
/**
* {@inheritDoc}
*/
@Override
public PayloadBlobBuilder payload(File data) {
return payload(newPayload(checkNotNull(data, "data")));
}
@Override
public Blob build() {
Blob blob = new BlobImpl(new MutableBlobMetadataImpl());
if (name != null)
blob.getMetadata().setName(name);
if (payload != null)
blob.setPayload(payload);
blob.getMetadata().setUserMetadata(userMetadata);
blob.getMetadata().setType(type);
return blob;
}
public class PayloadBlobBuilderImpl implements PayloadBlobBuilder {
private final BlobBuilder builder;
private final Payload payload;
private MessageDigest digest;
public PayloadBlobBuilderImpl(BlobBuilder builder, Payload payload, @Nullable Crypto crypto) {
this.builder = checkNotNull(builder, "builder");
this.payload = checkNotNull(payload, "payload");
try {
this.digest = crypto != null ? crypto.md5() : MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
Throwables.propagate(e);
this.digest = null;
}
}
@Override
public BlobBuilder name(String name) {
return builder.name(name);
}
@Override
public BlobBuilder type(StorageType type) {
return builder.type(type);
}
@Override
public BlobBuilder userMetadata(Map<String, String> userMetadata) {
return builder.userMetadata(userMetadata);
}
@Override
public PayloadBlobBuilder payload(Payload payload) {
return builder.payload(payload);
}
@Override
public PayloadBlobBuilder calculateMD5() throws IOException {
return builder.payload(Payloads.calculateMD5(payload, digest));
}
@Override
public PayloadBlobBuilder payload(InputStream payload) {
return builder.payload(payload);
}
@Override
public PayloadBlobBuilder payload(byte[] payload) {
return builder.payload(payload);
}
@Override
public PayloadBlobBuilder payload(String payload) {
return builder.payload(payload);
}
@Override
public PayloadBlobBuilder payload(File payload) {
return builder.payload(payload);
}
@Override
public Blob build() {
return builder.build();
}
@Override
public PayloadBlobBuilder contentLength(long contentLength) {
payload.getContentMetadata().setContentLength(contentLength);
return this;
}
@Override
public PayloadBlobBuilder contentMD5(byte[] md5) {
payload.getContentMetadata().setContentMD5(md5);
return this;
}
@Override
public PayloadBlobBuilder contentType(String contentType) {
payload.getContentMetadata().setContentType(contentType);
return this;
}
@Override
public PayloadBlobBuilder contentDisposition(String contentDisposition) {
payload.getContentMetadata().setContentDisposition(contentDisposition);
return this;
}
@Override
public PayloadBlobBuilder contentLanguage(String contentLanguage) {
payload.getContentMetadata().setContentLanguage(contentLanguage);
return this;
}
@Override
public PayloadBlobBuilder contentEncoding(String contentEncoding) {
payload.getContentMetadata().setContentEncoding(contentEncoding);
return this;
}
}
}

View File

@ -34,6 +34,7 @@ import org.jclouds.blobstore.AsyncBlobStore;
import org.jclouds.blobstore.BlobStoreContext; import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.ContainerNotFoundException; import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobBuilder;
import org.jclouds.blobstore.domain.PageSet; import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata; import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
@ -61,8 +62,8 @@ public abstract class BaseAsyncBlobStore implements AsyncBlobStore {
@Inject @Inject
protected BaseAsyncBlobStore(BlobStoreContext context, BlobUtils blobUtils, protected BaseAsyncBlobStore(BlobStoreContext context, BlobUtils blobUtils,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation,
@Memoized Supplier<Set<? extends Location>> locations) { @Memoized Supplier<Set<? extends Location>> locations) {
this.context = checkNotNull(context, "context"); this.context = checkNotNull(context, "context");
this.blobUtils = checkNotNull(blobUtils, "blobUtils"); this.blobUtils = checkNotNull(blobUtils, "blobUtils");
this.service = checkNotNull(service, "service"); this.service = checkNotNull(service, "service");
@ -83,6 +84,14 @@ public abstract class BaseAsyncBlobStore implements AsyncBlobStore {
return blobUtils.newBlob(name); return blobUtils.newBlob(name);
} }
/**
* invokes {@link BlobUtilsImpl#blobBuilder }
*/
@Override
public BlobBuilder blobBuilder(String name) {
return blobUtils.blobBuilder().name(name);
}
/** /**
* This implementation invokes * This implementation invokes
* {@link #list(String,org.jclouds.blobstore.options.ListContainerOptions)} * {@link #list(String,org.jclouds.blobstore.options.ListContainerOptions)}
@ -201,12 +210,12 @@ public abstract class BaseAsyncBlobStore implements AsyncBlobStore {
public ListenableFuture<Void> createDirectory(final String containerName, final String directory) { public ListenableFuture<Void> createDirectory(final String containerName, final String directory) {
return blobUtils.directoryExists(containerName, directory) ? Futures.immediateFuture((Void) null) return blobUtils.directoryExists(containerName, directory) ? Futures.immediateFuture((Void) null)
: org.jclouds.concurrent.Futures.makeListenable(service.submit(new Callable<Void>() { : org.jclouds.concurrent.Futures.makeListenable(service.submit(new Callable<Void>() {
public Void call() throws Exception { public Void call() throws Exception {
blobUtils.createDirectory(containerName, directory); blobUtils.createDirectory(containerName, directory);
return null; return null;
} }
}), service); }), service);
} }
/** /**

View File

@ -19,12 +19,16 @@
package org.jclouds.blobstore.internal; package org.jclouds.blobstore.internal;
import static com.google.common.base.Functions.identity;
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 com.google.common.collect.Iterables.transform;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.inject.Inject;
import org.jclouds.blobstore.BlobStore; import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.ListableMap; import org.jclouds.blobstore.ListableMap;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
@ -39,9 +43,7 @@ import org.jclouds.blobstore.strategy.PutBlobsStrategy;
import org.jclouds.blobstore.strategy.internal.ListContainerAndRecurseThroughFolders; import org.jclouds.blobstore.strategy.internal.ListContainerAndRecurseThroughFolders;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.collect.Iterables; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.inject.Inject;
/** /**
* Implements core Map functionality with a {@link BlobStore} * Implements core Map functionality with a {@link BlobStore}
@ -88,26 +90,19 @@ public abstract class BaseBlobMap<V> implements ListableMap<String, V> {
} }
} }
static class PassThrough<T> implements Function<T, T> {
public T apply(T from) {
return from;
}
}
@Inject @Inject
public BaseBlobMap(BlobStore blobstore, GetBlobsInListStrategy getAllBlobs, public BaseBlobMap(BlobStore blobstore, GetBlobsInListStrategy getAllBlobs,
ContainsValueInListStrategy containsValueStrategy, PutBlobsStrategy putBlobsStrategy, ContainsValueInListStrategy containsValueStrategy, PutBlobsStrategy putBlobsStrategy,
ListContainerAndRecurseThroughFolders listStrategy, String containerName, ListContainerAndRecurseThroughFolders listStrategy, String containerName, ListContainerOptions options) {
ListContainerOptions options) {
this.blobstore = checkNotNull(blobstore, "blobstore"); this.blobstore = checkNotNull(blobstore, "blobstore");
this.containerName = checkNotNull(containerName, "container"); this.containerName = checkNotNull(containerName, "container");
checkArgument(containerName.indexOf('/') == -1, checkArgument(containerName.indexOf('/') == -1,
"please specify directory path using the option: inDirectory, not encoded in the container name"); "please specify directory path using the option: inDirectory, not encoded in the container name");
this.options = checkNotNull(options, "options") instanceof ImmutableListContainerOptions ? options this.options = checkNotNull(options, "options") instanceof ImmutableListContainerOptions ? options
: new ImmutableListContainerOptions(options); : new ImmutableListContainerOptions(options);
String dir = options.getDir(); String dir = options.getDir();
if (dir == null) { if (dir == null) {
prefixer = new PassThrough<String>(); prefixer = identity();
pathStripper = prefixer; pathStripper = prefixer;
} else { } else {
prefixer = new PrefixKey(dir, "/"); prefixer = new PrefixKey(dir, "/");
@ -122,13 +117,12 @@ public abstract class BaseBlobMap<V> implements ListableMap<String, V> {
@Override @Override
public Set<java.util.Map.Entry<String, V>> entrySet() { public Set<java.util.Map.Entry<String, V>> entrySet() {
return Sets.newHashSet(Iterables.transform(list(), return ImmutableSet.copyOf(transform(list(), new Function<BlobMetadata, Map.Entry<String, V>>() {
new Function<BlobMetadata, Map.Entry<String, V>>() { @Override
@Override public java.util.Map.Entry<String, V> apply(BlobMetadata from) {
public java.util.Map.Entry<String, V> apply(BlobMetadata from) { return new Entry(pathStripper.apply(from.getName()));
return new Entry(pathStripper.apply(from.getName())); }
} }));
}));
} }
public class Entry implements java.util.Map.Entry<String, V> { public class Entry implements java.util.Map.Entry<String, V> {
@ -187,7 +181,7 @@ public abstract class BaseBlobMap<V> implements ListableMap<String, V> {
@Override @Override
public Set<String> keySet() { public Set<String> keySet() {
return Sets.newHashSet(Iterables.transform(list(), new Function<BlobMetadata, String>() { return ImmutableSet.copyOf(transform(list(), new Function<BlobMetadata, String>() {
@Override @Override
public String apply(BlobMetadata from) { public String apply(BlobMetadata from) {
return from.getName(); return from.getName();
@ -197,7 +191,7 @@ public abstract class BaseBlobMap<V> implements ListableMap<String, V> {
@Override @Override
public boolean containsKey(Object key) { public boolean containsKey(Object key) {
String realKey = prefixer.apply(key.toString()); String realKey = prefixer.apply(checkNotNull(key, "key").toString());
return blobstore.blobExists(containerName, realKey); return blobstore.blobExists(containerName, realKey);
} }
@ -207,21 +201,20 @@ public abstract class BaseBlobMap<V> implements ListableMap<String, V> {
} }
public Iterable<? extends BlobMetadata> list() { public Iterable<? extends BlobMetadata> list() {
return Iterables.transform(listStrategy.execute(containerName, options), return transform(listStrategy.execute(containerName, options), new Function<BlobMetadata, BlobMetadata>() {
new Function<BlobMetadata, BlobMetadata>() { public BlobMetadata apply(BlobMetadata from) {
public BlobMetadata apply(BlobMetadata from) { MutableBlobMetadata md = new MutableBlobMetadataImpl(from);
MutableBlobMetadata md = new MutableBlobMetadataImpl(from); if (options.getDir() != null)
if (options.getDir() != null) md.setName(pathStripper.apply(from.getName()));
md.setName(pathStripper.apply(from.getName())); return md;
return md; }
}
}); });
} }
@Override @Override
public String toString() { public String toString() {
return "BaseBlobMap [containerName=" + containerName + ", options=" + options + "]"; return "[containerName=" + containerName + ", options=" + options + "]";
} }
} }

View File

@ -30,6 +30,7 @@ import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.BlobStoreContext; import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.ContainerNotFoundException; import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobBuilder;
import org.jclouds.blobstore.domain.PageSet; import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata; import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
@ -54,7 +55,7 @@ public abstract class BaseBlobStore implements BlobStore {
@Inject @Inject
protected BaseBlobStore(BlobStoreContext context, BlobUtils blobUtils, Supplier<Location> defaultLocation, protected BaseBlobStore(BlobStoreContext context, BlobUtils blobUtils, Supplier<Location> defaultLocation,
@Memoized Supplier<Set<? extends Location>> locations) { @Memoized Supplier<Set<? extends Location>> locations) {
this.context = checkNotNull(context, "context"); this.context = checkNotNull(context, "context");
this.blobUtils = checkNotNull(blobUtils, "blobUtils"); this.blobUtils = checkNotNull(blobUtils, "blobUtils");
this.defaultLocation = checkNotNull(defaultLocation, "defaultLocation"); this.defaultLocation = checkNotNull(defaultLocation, "defaultLocation");
@ -74,6 +75,14 @@ public abstract class BaseBlobStore implements BlobStore {
return blobUtils.newBlob(name); return blobUtils.newBlob(name);
} }
/**
* invokes {@link BlobUtilsImpl#blobBuilder }
*/
@Override
public BlobBuilder blobBuilder(String name) {
return blobUtils.blobBuilder().name(name);
}
/** /**
* This implementation invokes * This implementation invokes
* {@link #list(String,org.jclouds.blobstore.options.ListContainerOptions)} * {@link #list(String,org.jclouds.blobstore.options.ListContainerOptions)}

View File

@ -19,22 +19,28 @@
package org.jclouds.blobstore.internal; package org.jclouds.blobstore.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.transform;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Provider;
import org.jclouds.blobstore.BlobMap; import org.jclouds.blobstore.BlobMap;
import org.jclouds.blobstore.BlobStore; import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.KeyNotFoundException; import org.jclouds.blobstore.KeyNotFoundException;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobBuilder;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.strategy.ContainsValueInListStrategy; import org.jclouds.blobstore.strategy.ContainsValueInListStrategy;
import org.jclouds.blobstore.strategy.GetBlobsInListStrategy; import org.jclouds.blobstore.strategy.GetBlobsInListStrategy;
import org.jclouds.blobstore.strategy.PutBlobsStrategy; import org.jclouds.blobstore.strategy.PutBlobsStrategy;
import org.jclouds.blobstore.strategy.internal.ListContainerAndRecurseThroughFolders; import org.jclouds.blobstore.strategy.internal.ListContainerAndRecurseThroughFolders;
import com.google.common.collect.Sets; import com.google.common.base.Function;
import com.google.common.collect.ImmutableSet;
/** /**
* Map representation of a live connection to a Blob Service. * Map representation of a live connection to a Blob Service.
@ -45,36 +51,59 @@ import com.google.common.collect.Sets;
* @author Adrian Cole * @author Adrian Cole
*/ */
public class BlobMapImpl extends BaseBlobMap<Blob> implements BlobMap { public class BlobMapImpl extends BaseBlobMap<Blob> implements BlobMap {
public static class CorrectBlobName implements Function<java.util.Map.Entry<? extends String, ? extends Blob>, Blob> {
private final Function<String, String> prefixer;
public CorrectBlobName(Function<String, String> prefixer) {
this.prefixer = checkNotNull(prefixer, "prefixer");
}
@Override
public Blob apply(java.util.Map.Entry<? extends String, ? extends Blob> arg0) {
return apply(arg0.getKey(), arg0.getValue());
}
public Blob apply(String key, Blob blob) {
blob.getMetadata().setName(prefixer.apply(key));
return blob;
}
}
private final CorrectBlobName correctBlobName;
private final Provider<BlobBuilder> blobBuilders;
@Inject @Inject
public BlobMapImpl(BlobStore blobstore, GetBlobsInListStrategy getAllBlobs, public BlobMapImpl(BlobStore blobstore, GetBlobsInListStrategy getAllBlobs,
ContainsValueInListStrategy containsValueStrategy, PutBlobsStrategy putBlobsStrategy, ContainsValueInListStrategy containsValueStrategy, PutBlobsStrategy putBlobsStrategy,
ListContainerAndRecurseThroughFolders listStrategy, String containerName, ListContainerOptions options) { ListContainerAndRecurseThroughFolders listStrategy, String containerName, ListContainerOptions options,
Provider<BlobBuilder> blobBuilders) {
super(blobstore, getAllBlobs, containsValueStrategy, putBlobsStrategy, listStrategy, containerName, options); super(blobstore, getAllBlobs, containsValueStrategy, putBlobsStrategy, listStrategy, containerName, options);
this.correctBlobName = new CorrectBlobName(prefixer);
this.blobBuilders = checkNotNull(blobBuilders, "blobBuilders");
} }
@Override @Override
public Blob get(Object key) { public Blob get(Object key) {
String realKey = prefixer.apply(key.toString()); String realKey = prefixer.apply(checkNotNull(key, "key").toString());
Blob blob = blobstore.getBlob(containerName, realKey); Blob blob = blobstore.getBlob(containerName, realKey);
return blob != null ? stripPrefix(blob) : null; return blob != null ? stripPrefix(blob) : null;
} }
@Override @Override
public Blob put(String key, Blob value) { public Blob put(String key, Blob value) {
Blob returnVal = getLastValue(key); Blob returnVal = getLastValue(checkNotNull(key, "key"));
blobstore.putBlob(containerName, value); blobstore.putBlob(containerName, correctBlobName.apply(key, value));
return returnVal; return returnVal;
} }
@Override @Override
public void putAll(Map<? extends String, ? extends Blob> map) { public void putAll(Map<? extends String, ? extends Blob> map) {
putBlobsStrategy.execute(containerName, map.values()); putBlobsStrategy.execute(containerName, transform(checkNotNull(map, "map").entrySet(), correctBlobName));
} }
@Override @Override
public Blob remove(Object key) { public Blob remove(Object key) {
Blob old = getLastValue(key); Blob old = getLastValue(checkNotNull(key, "key"));
String realKey = prefixer.apply(key.toString()); String realKey = prefixer.apply(key.toString());
blobstore.removeBlob(containerName, realKey); blobstore.removeBlob(containerName, realKey);
return old; return old;
@ -83,7 +112,7 @@ public class BlobMapImpl extends BaseBlobMap<Blob> implements BlobMap {
private Blob getLastValue(Object key) { private Blob getLastValue(Object key) {
Blob old; Blob old;
try { try {
old = get(key); old = get(checkNotNull(key, "key"));
} catch (KeyNotFoundException e) { } catch (KeyNotFoundException e) {
old = null; old = null;
} }
@ -92,12 +121,16 @@ public class BlobMapImpl extends BaseBlobMap<Blob> implements BlobMap {
@Override @Override
public Collection<Blob> values() { public Collection<Blob> values() {
return Sets.newLinkedHashSet(getAllBlobs.execute(containerName, options)); return ImmutableSet.copyOf(getAllBlobs.execute(containerName, options));
} }
@Override @Override
public Blob newBlob(String name) { public Blob newBlob(String name) {
return blobstore.newBlob(name); return blobBuilder().name(name).build();
} }
@Override
public BlobBuilder blobBuilder() {
return blobBuilders.get();
}
} }

View File

@ -30,11 +30,13 @@ import java.util.Collection;
import java.util.Map; import java.util.Map;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Provider;
import org.jclouds.blobstore.BlobMap; import org.jclouds.blobstore.BlobMap;
import org.jclouds.blobstore.BlobStore; import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.InputStreamMap; import org.jclouds.blobstore.InputStreamMap;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobBuilder;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.strategy.ContainsValueInListStrategy; import org.jclouds.blobstore.strategy.ContainsValueInListStrategy;
import org.jclouds.blobstore.strategy.GetBlobsInListStrategy; import org.jclouds.blobstore.strategy.GetBlobsInListStrategy;
@ -66,12 +68,11 @@ public class InputStreamMapImpl extends BaseBlobMap<InputStream> implements Inpu
protected final Crypto crypto; protected final Crypto crypto;
@Inject @Inject
public InputStreamMapImpl(BlobStore connection, Blob.Factory blobFactory, public InputStreamMapImpl(BlobStore connection, Provider<BlobBuilder> blobBuilders,
GetBlobsInListStrategy getAllBlobs, ListContainerAndRecurseThroughFolders listStrategy, GetBlobsInListStrategy getAllBlobs, ListContainerAndRecurseThroughFolders listStrategy,
ContainsValueInListStrategy containsValueStrategy, PutBlobsStrategy putBlobsStrategy, ContainsValueInListStrategy containsValueStrategy, PutBlobsStrategy putBlobsStrategy, String containerName,
String containerName, ListContainerOptions options, Crypto crypto) { ListContainerOptions options, Crypto crypto) {
super(connection, getAllBlobs, containsValueStrategy, putBlobsStrategy, listStrategy, super(connection, getAllBlobs, containsValueStrategy, putBlobsStrategy, listStrategy, containerName, options);
containerName, options);
this.crypto = crypto; this.crypto = crypto;
} }
@ -96,12 +97,11 @@ public class InputStreamMapImpl extends BaseBlobMap<InputStream> implements Inpu
@Override @Override
public Collection<InputStream> values() { public Collection<InputStream> values() {
return newArrayList(transform(getAllBlobs.execute(containerName, options), return newArrayList(transform(getAllBlobs.execute(containerName, options), new Function<Blob, InputStream>() {
new Function<Blob, InputStream>() { public InputStream apply(Blob from) {
public InputStream apply(Blob from) { return getInputStreamOrNull(from);
return getInputStreamOrNull(from); }
} }));
}));
} }
@Override @Override
@ -132,22 +132,21 @@ public class InputStreamMapImpl extends BaseBlobMap<InputStream> implements Inpu
*/ */
@VisibleForTesting @VisibleForTesting
void putAllInternal(Map<? extends String, ? extends Object> map) { void putAllInternal(Map<? extends String, ? extends Object> map) {
putBlobsStrategy.execute(containerName, transform(map.entrySet(), putBlobsStrategy.execute(containerName,
new Function<Map.Entry<? extends String, ? extends Object>, Blob>() { transform(map.entrySet(), new Function<Map.Entry<? extends String, ? extends Object>, Blob>() {
@Override @Override
public Blob apply(Map.Entry<? extends String, ? extends Object> from) { public Blob apply(Map.Entry<? extends String, ? extends Object> from) {
String name = from.getKey(); String name = from.getKey();
Object value = from.getValue(); Object value = from.getValue();
return newBlobWithMD5(name, value); return newBlobWithMD5(name, value);
} }
})); }));
} }
@VisibleForTesting @VisibleForTesting
Blob newBlobWithMD5(String name, Object value) { Blob newBlobWithMD5(String name, Object value) {
Blob blob = blobstore.newBlob(prefixer.apply(name)); Blob blob = blobstore.blobBuilder(prefixer.apply(name)).payload(newPayload(value)).build();
blob.setPayload(newPayload(value));
try { try {
Payloads.calculateMD5(blob, crypto.md5()); Payloads.calculateMD5(blob, crypto.md5());
} catch (IOException e) { } catch (IOException e) {

View File

@ -19,15 +19,15 @@
package org.jclouds.blobstore.strategy.internal; package org.jclouds.blobstore.strategy.internal;
import static org.jclouds.io.Payloads.newByteArrayPayload;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.blobstore.BlobStore; import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.StorageType; import org.jclouds.blobstore.domain.StorageType;
import org.jclouds.blobstore.reference.BlobStoreConstants; import org.jclouds.blobstore.reference.BlobStoreConstants;
import org.jclouds.blobstore.strategy.MkdirStrategy; import org.jclouds.blobstore.strategy.MkdirStrategy;
import org.jclouds.io.Payloads;
import com.google.inject.Inject; import com.google.inject.Inject;
@ -44,18 +44,17 @@ public class MarkerFileMkdirStrategy implements MkdirStrategy {
@Inject(optional = true) @Inject(optional = true)
@Named(BlobStoreConstants.PROPERTY_BLOBSTORE_DIRECTORY_SUFFIX) @Named(BlobStoreConstants.PROPERTY_BLOBSTORE_DIRECTORY_SUFFIX)
protected String directorySuffix = ""; protected String directorySuffix = "";
private final BlobStore connection; private final BlobStore blobStore;
@Inject @Inject
MarkerFileMkdirStrategy(BlobStore connection) { MarkerFileMkdirStrategy(BlobStore blobStore) {
this.connection = connection; this.blobStore = blobStore;
} }
public void execute(String containerName, String directory) { public void execute(String containerName, String directory) {
Blob blob = connection.newBlob(directory + directorySuffix); blobStore.putBlob(
blob.setPayload(Payloads.newByteArrayPayload(new byte[] {})); containerName,
blob.getPayload().getContentMetadata().setContentType("application/directory"); blobStore.blobBuilder(directory + directorySuffix).type(StorageType.RELATIVE_PATH)
blob.getMetadata().setType(StorageType.RELATIVE_PATH); .payload(newByteArrayPayload(new byte[] {})).contentType("application/directory").build());
connection.putBlob(containerName, blob);
} }
} }

View File

@ -68,7 +68,7 @@ public class PutBlobsStrategyImpl implements PutBlobsStrategy {
@Override @Override
public void execute(String containerName, Iterable<? extends Blob> blobs) { public void execute(String containerName, Iterable<? extends Blob> blobs) {
Map<Blob, Future<?>> responses = Maps.newHashMap(); Map<Blob, Future<?>> responses = Maps.newLinkedHashMap();
for (Blob blob : blobs) { for (Blob blob : blobs) {
responses.put(blob, ablobstore.putBlob(containerName, blob)); responses.put(blob, ablobstore.putBlob(containerName, blob));
} }

View File

@ -80,7 +80,8 @@ public class BlobStoreUtils {
} }
public static Blob newBlob(BlobStore blobStore, StorageMetadata blobMeta) { public static Blob newBlob(BlobStore blobStore, StorageMetadata blobMeta) {
Blob blob = checkNotNull(blobStore, "blobStore").newBlob(checkNotNull(blobMeta, "blobMeta").getName()); Blob blob = checkNotNull(blobStore, "blobStore").blobBuilder(checkNotNull(blobMeta, "blobMeta").getName())
.userMetadata(blobMeta.getUserMetadata()).build();
if (blobMeta instanceof BlobMetadata) { if (blobMeta instanceof BlobMetadata) {
HttpUtils.copy(((BlobMetadata) blobMeta).getContentMetadata(), blob.getMetadata().getContentMetadata()); HttpUtils.copy(((BlobMetadata) blobMeta).getContentMetadata(), blob.getMetadata().getContentMetadata());
} }
@ -89,7 +90,6 @@ public class BlobStoreUtils {
blob.getMetadata().setLastModified(blobMeta.getLastModified()); blob.getMetadata().setLastModified(blobMeta.getLastModified());
blob.getMetadata().setLocation(blobMeta.getLocation()); blob.getMetadata().setLocation(blobMeta.getLocation());
blob.getMetadata().setUri(blobMeta.getUri()); blob.getMetadata().setUri(blobMeta.getUri());
blob.getMetadata().setUserMetadata(blobMeta.getUserMetadata());
return blob; return blob;
} }

View File

@ -20,6 +20,7 @@
package org.jclouds.blobstore.util; package org.jclouds.blobstore.util;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobBuilder;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.util.internal.BlobUtilsImpl; import org.jclouds.blobstore.util.internal.BlobUtilsImpl;
@ -31,6 +32,7 @@ import com.google.inject.ImplementedBy;
*/ */
@ImplementedBy(BlobUtilsImpl.class) @ImplementedBy(BlobUtilsImpl.class)
public interface BlobUtils { public interface BlobUtils {
BlobBuilder blobBuilder();
Blob newBlob(String name); Blob newBlob(String name);

View File

@ -22,9 +22,11 @@ package org.jclouds.blobstore.util.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 javax.inject.Singleton;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobBuilder;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.strategy.ClearListStrategy; import org.jclouds.blobstore.strategy.ClearListStrategy;
import org.jclouds.blobstore.strategy.CountListStrategy; import org.jclouds.blobstore.strategy.CountListStrategy;
@ -41,7 +43,7 @@ import org.jclouds.blobstore.util.BlobUtils;
@Singleton @Singleton
public class BlobUtilsImpl implements BlobUtils { public class BlobUtilsImpl implements BlobUtils {
protected final Blob.Factory blobFactory; protected final Provider<BlobBuilder> blobBuilders;
protected final ClearListStrategy clearContainerStrategy; protected final ClearListStrategy clearContainerStrategy;
protected final GetDirectoryStrategy getDirectoryStrategy; protected final GetDirectoryStrategy getDirectoryStrategy;
protected final MkdirStrategy mkdirStrategy; protected final MkdirStrategy mkdirStrategy;
@ -49,10 +51,10 @@ public class BlobUtilsImpl implements BlobUtils {
protected final CountListStrategy countBlobsStrategy; protected final CountListStrategy countBlobsStrategy;
@Inject @Inject
protected BlobUtilsImpl(Blob.Factory blobFactory, ClearListStrategy clearContainerStrategy, protected BlobUtilsImpl(Provider<BlobBuilder> blobBuilders, ClearListStrategy clearContainerStrategy,
GetDirectoryStrategy getDirectoryStrategy, MkdirStrategy mkdirStrategy, GetDirectoryStrategy getDirectoryStrategy, MkdirStrategy mkdirStrategy, CountListStrategy countBlobsStrategy,
CountListStrategy countBlobsStrategy, DeleteDirectoryStrategy rmDirStrategy) { DeleteDirectoryStrategy rmDirStrategy) {
this.blobFactory = checkNotNull(blobFactory, "blobFactory"); this.blobBuilders = checkNotNull(blobBuilders, "blobBuilders");
this.clearContainerStrategy = checkNotNull(clearContainerStrategy, "clearContainerStrategy"); this.clearContainerStrategy = checkNotNull(clearContainerStrategy, "clearContainerStrategy");
this.getDirectoryStrategy = checkNotNull(getDirectoryStrategy, "getDirectoryStrategy"); this.getDirectoryStrategy = checkNotNull(getDirectoryStrategy, "getDirectoryStrategy");
this.mkdirStrategy = checkNotNull(mkdirStrategy, "mkdirStrategy"); this.mkdirStrategy = checkNotNull(mkdirStrategy, "mkdirStrategy");
@ -60,10 +62,14 @@ public class BlobUtilsImpl implements BlobUtils {
this.countBlobsStrategy = checkNotNull(countBlobsStrategy, "countBlobsStrategy"); this.countBlobsStrategy = checkNotNull(countBlobsStrategy, "countBlobsStrategy");
} }
@Override
public Blob newBlob(String name) { public Blob newBlob(String name) {
Blob blob = blobFactory.create(null); return blobBuilder().name(name).build();
blob.getMetadata().setName(name); }
return blob;
@Override
public BlobBuilder blobBuilder() {
return blobBuilders.get();
} }
public boolean directoryExists(String containerName, String directory) { public boolean directoryExists(String containerName, String directory) {

View File

@ -19,6 +19,7 @@
package org.jclouds.blobstore.integration; package org.jclouds.blobstore.integration;
import static com.google.common.collect.Iterables.getOnlyElement;
import static org.jclouds.blobstore.options.ListContainerOptions.Builder.maxResults; import static org.jclouds.blobstore.options.ListContainerOptions.Builder.maxResults;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
@ -31,7 +32,7 @@ import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.integration.internal.BaseContainerIntegrationTest; import org.jclouds.blobstore.integration.internal.BaseContainerIntegrationTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.Iterables; import com.google.common.collect.ImmutableMap;
/** /**
* @author James Murty * @author James Murty
@ -44,22 +45,19 @@ public class TransientContainerIntegrationTest extends BaseContainerIntegrationT
public void testNotWithDetails() throws InterruptedException { public void testNotWithDetails() throws InterruptedException {
String key = "hello"; String key = "hello";
Blob object = context.getBlobStore().newBlob(key);
object.setPayload(TEST_STRING);
object.getMetadata().getContentMetadata().setContentType(MediaType.TEXT_PLAIN);
// NOTE all metadata in jclouds comes out as lowercase, in an effort to normalize the // NOTE all metadata in jclouds comes out as lowercase, in an effort to normalize the
// providers. // providers.
object.getMetadata().getUserMetadata().put("Adrian", "powderpuff"); Blob blob = context.getBlobStore().blobBuilder("hello").userMetadata(ImmutableMap.of("Adrian", "powderpuff"))
.payload(TEST_STRING).contentType(MediaType.TEXT_PLAIN).build();
String containerName = getContainerName(); String containerName = getContainerName();
try { try {
addBlobToContainer(containerName, object); addBlobToContainer(containerName, blob);
validateContent(containerName, key); validateContent(containerName, key);
PageSet<? extends StorageMetadata> container = context.getBlobStore().list(containerName, PageSet<? extends StorageMetadata> container = context.getBlobStore().list(containerName, maxResults(1));
maxResults(1));
BlobMetadata metadata = (BlobMetadata) Iterables.getOnlyElement(container); BlobMetadata metadata = (BlobMetadata) getOnlyElement(container);
// transient container should be lenient and not return metadata on undetailed listing. // transient container should be lenient and not return metadata on undetailed listing.
assertEquals(metadata.getUserMetadata().size(), 0); assertEquals(metadata.getUserMetadata().size(), 0);

View File

@ -49,6 +49,7 @@ import javax.ws.rs.core.MediaType;
import org.jclouds.blobstore.ContainerNotFoundException; import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobBuilder.PayloadBlobBuilder;
import org.jclouds.blobstore.domain.BlobMetadata; import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.domain.PageSet; import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata; import org.jclouds.blobstore.domain.StorageMetadata;
@ -73,6 +74,7 @@ import org.testng.annotations.Test;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.io.ByteStreams; import com.google.common.io.ByteStreams;
@ -97,7 +99,7 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static InputSupplier<InputStream> getTestDataSupplier() throws IOException { public static InputSupplier<InputStream> getTestDataSupplier() throws IOException {
byte[] oneConstitution = ByteStreams.toByteArray(new GZIPInputStream(BaseJettyTest.class byte[] oneConstitution = ByteStreams.toByteArray(new GZIPInputStream(BaseJettyTest.class
.getResourceAsStream("/const.txt.gz"))); .getResourceAsStream("/const.txt.gz")));
InputSupplier<ByteArrayInputStream> constitutionSupplier = ByteStreams.newInputStreamSupplier(oneConstitution); InputSupplier<ByteArrayInputStream> constitutionSupplier = ByteStreams.newInputStreamSupplier(oneConstitution);
InputSupplier<InputStream> temp = ByteStreams.join(constitutionSupplier); InputSupplier<InputStream> temp = ByteStreams.join(constitutionSupplier);
@ -120,24 +122,24 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
Map<Integer, Future<?>> responses = Maps.newHashMap(); Map<Integer, Future<?>> responses = Maps.newHashMap();
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
responses.put(i, Futures.compose(context.getAsyncBlobStore().getBlob(containerName, key), responses.put(i,
new Function<Blob, Void>() { Futures.compose(context.getAsyncBlobStore().getBlob(containerName, key), new Function<Blob, Void>() {
@Override @Override
public Void apply(Blob from) { public Void apply(Blob from) {
try { try {
assertEquals(CryptoStreams.md5(from.getPayload()), oneHundredOneConstitutionsMD5); assertEquals(CryptoStreams.md5(from.getPayload()), oneHundredOneConstitutionsMD5);
checkContentDisposition(from, expectedContentDisposition); checkContentDisposition(from, expectedContentDisposition);
} catch (IOException e) { } catch (IOException e) {
Throwables.propagate(e); Throwables.propagate(e);
}
return null;
} }
return null;
}
}, this.exec)); }, this.exec));
} }
Map<Integer, Exception> exceptions = awaitCompletion(responses, exec, 30000l, Logger.CONSOLE, Map<Integer, Exception> exceptions = awaitCompletion(responses, exec, 30000l, Logger.CONSOLE,
"get constitution"); "get constitution");
assert exceptions.size() == 0 : exceptions; assert exceptions.size() == 0 : exceptions;
} finally { } finally {
@ -147,13 +149,11 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
} }
private void uploadConstitution(String containerName, String key, String contentDisposition) throws IOException { private void uploadConstitution(String containerName, String key, String contentDisposition) throws IOException {
Blob sourceObject = context.getBlobStore().newBlob(key); context.getBlobStore().putBlob(
sourceObject.setPayload(oneHundredOneConstitutions.getInput()); containerName,
sourceObject.getMetadata().getContentMetadata().setContentType("text/plain"); context.getBlobStore().blobBuilder(key).payload(oneHundredOneConstitutions.getInput())
sourceObject.getMetadata().getContentMetadata().setContentMD5(oneHundredOneConstitutionsMD5); .contentType("text/plain").contentMD5(oneHundredOneConstitutionsMD5)
sourceObject.getMetadata().getContentMetadata().setContentLength(oneHundredOneConstitutionsLength); .contentLength(oneHundredOneConstitutionsLength).contentDisposition(contentDisposition).build());
sourceObject.getMetadata().getContentMetadata().setContentDisposition(contentDisposition);
context.getBlobStore().putBlob(containerName, sourceObject);
} }
@Test(groups = { "integration", "live" }) @Test(groups = { "integration", "live" })
@ -364,8 +364,8 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
@DataProvider(name = "delete") @DataProvider(name = "delete")
public Object[][] createData() { public Object[][] createData() {
return new Object[][] { { "normal" }, { "sp ace" }, { "qu?stion" }, { "unic₪de" }, { "path/foo" }, { "colon:" }, return new Object[][] { { "normal" }, { "sp ace" }, { "qu?stion" }, { "unic₪de" }, { "path/foo" },
{ "asteri*k" }, { "quote\"" }, { "{great<r}" }, { "lesst>en" }, { "p|pe" } }; { "colon:" }, { "asteri*k" }, { "quote\"" }, { "{great<r}" }, { "lesst>en" }, { "p|pe" } };
} }
@Test(groups = { "integration", "live" }, dataProvider = "delete") @Test(groups = { "integration", "live" }, dataProvider = "delete")
@ -382,17 +382,19 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
private void assertContainerEmptyDeleting(String containerName, String key) { private void assertContainerEmptyDeleting(String containerName, String key) {
Iterable<? extends StorageMetadata> listing = Iterables.filter(context.getBlobStore().list(containerName), Iterable<? extends StorageMetadata> listing = Iterables.filter(context.getBlobStore().list(containerName),
new Predicate<StorageMetadata>() { new Predicate<StorageMetadata>() {
@Override @Override
public boolean apply(StorageMetadata input) { public boolean apply(StorageMetadata input) {
return input.getType() == StorageType.BLOB; return input.getType() == StorageType.BLOB;
} }
}); });
assertEquals(Iterables.size(listing), 0, String.format( assertEquals(
"deleting %s, we still have %s blobs left in container %s, using encoding %s", key, Iterables Iterables.size(listing),
.size(listing), containerName, LOCAL_ENCODING)); 0,
String.format("deleting %s, we still have %s blobs left in container %s, using encoding %s", key,
Iterables.size(listing), containerName, LOCAL_ENCODING));
} }
@Test(groups = { "integration", "live" }) @Test(groups = { "integration", "live" })
@ -412,21 +414,20 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
String realObject = Strings2.toStringAndClose(new FileInputStream("pom.xml")); String realObject = Strings2.toStringAndClose(new FileInputStream("pom.xml"));
return new Object[][] { { "file", "text/xml", new File("pom.xml"), realObject }, return new Object[][] { { "file", "text/xml", new File("pom.xml"), realObject },
{ "string", "text/xml", realObject, realObject }, { "string", "text/xml", realObject, realObject },
{ "bytes", "application/octet-stream", realObject.getBytes(), realObject } }; { "bytes", "application/octet-stream", realObject.getBytes(), realObject } };
} }
@Test(groups = { "integration", "live" }, dataProvider = "putTests") @Test(groups = { "integration", "live" }, dataProvider = "putTests")
public void testPutObject(String key, String type, Object content, Object realObject) throws InterruptedException, public void testPutObject(String key, String type, Object content, Object realObject) throws InterruptedException,
IOException { IOException {
Blob blob = context.getBlobStore().newBlob(key); PayloadBlobBuilder blobBuilder = context.getBlobStore().blobBuilder(key).payload(Payloads.newPayload(content))
blob.setPayload(Payloads.newPayload(content)); .contentType(type);
blob.getMetadata().getContentMetadata().setContentType(type); addContentMetadata(blobBuilder);
addContentMetadata(blob);
if (content instanceof InputStream) { if (content instanceof InputStream) {
Payloads.calculateMD5(blob, context.utils().crypto().md5()); blobBuilder.calculateMD5();
} }
Blob blob = blobBuilder.build();
String containerName = getContainerName(); String containerName = getContainerName();
try { try {
assertNotNull(context.getBlobStore().putBlob(containerName, blob)); assertNotNull(context.getBlobStore().putBlob(containerName, blob));
@ -444,14 +445,15 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
@Test(groups = { "integration", "live" }) @Test(groups = { "integration", "live" })
public void testPutObjectStream() throws InterruptedException, IOException, ExecutionException { public void testPutObjectStream() throws InterruptedException, IOException, ExecutionException {
Blob blob = context.getBlobStore().newBlob("streaming"); PayloadBlobBuilder blobBuilder = context.getBlobStore().blobBuilder("streaming").payload(new StreamingPayload(new WriteTo() {
blob.setPayload(new StreamingPayload(new WriteTo() {
@Override @Override
public void writeTo(OutputStream outstream) throws IOException { public void writeTo(OutputStream outstream) throws IOException {
outstream.write("foo".getBytes()); outstream.write("foo".getBytes());
} }
})); }));
addContentMetadata(blob); addContentMetadata(blobBuilder);
Blob blob = blobBuilder.build();
String containerName = getContainerName(); String containerName = getContainerName();
try { try {
@ -476,40 +478,40 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
checkContentLanguage(blob, "en"); checkContentLanguage(blob, "en");
} }
private void addContentMetadata(Blob blob) { private void addContentMetadata(PayloadBlobBuilder blobBuilder) {
blob.getMetadata().getContentMetadata().setContentType("text/csv"); blobBuilder.contentType("text/csv");
blob.getMetadata().getContentMetadata().setContentDisposition("attachment; filename=photo.jpg"); blobBuilder.contentDisposition("attachment; filename=photo.jpg");
blob.getMetadata().getContentMetadata().setContentEncoding("gzip"); blobBuilder.contentEncoding("gzip");
blob.getMetadata().getContentMetadata().setContentLanguage("en"); blobBuilder.contentLanguage("en");
} }
protected void checkContentType(Blob blob, String contentType) { protected void checkContentType(Blob blob, String contentType) {
assert blob.getPayload().getContentMetadata().getContentType().startsWith(contentType) : blob.getPayload() assert blob.getPayload().getContentMetadata().getContentType().startsWith(contentType) : blob.getPayload()
.getContentMetadata().getContentType(); .getContentMetadata().getContentType();
assert blob.getMetadata().getContentMetadata().getContentType().startsWith(contentType) : blob.getMetadata() assert blob.getMetadata().getContentMetadata().getContentType().startsWith(contentType) : blob.getMetadata()
.getContentMetadata().getContentType(); .getContentMetadata().getContentType();
} }
protected void checkContentDisposition(Blob blob, String contentDisposition) { protected void checkContentDisposition(Blob blob, String contentDisposition) {
assert blob.getPayload().getContentMetadata().getContentDisposition().startsWith(contentDisposition) : blob assert blob.getPayload().getContentMetadata().getContentDisposition().startsWith(contentDisposition) : blob
.getPayload().getContentMetadata().getContentDisposition(); .getPayload().getContentMetadata().getContentDisposition();
assert blob.getMetadata().getContentMetadata().getContentDisposition().startsWith(contentDisposition) : blob assert blob.getMetadata().getContentMetadata().getContentDisposition().startsWith(contentDisposition) : blob
.getMetadata().getContentMetadata().getContentDisposition(); .getMetadata().getContentMetadata().getContentDisposition();
} }
protected void checkContentEncoding(Blob blob, String contentEncoding) { protected void checkContentEncoding(Blob blob, String contentEncoding) {
assert (blob.getPayload().getContentMetadata().getContentEncoding().indexOf(contentEncoding) != -1) : blob assert (blob.getPayload().getContentMetadata().getContentEncoding().indexOf(contentEncoding) != -1) : blob
.getPayload().getContentMetadata().getContentEncoding(); .getPayload().getContentMetadata().getContentEncoding();
assert (blob.getMetadata().getContentMetadata().getContentEncoding().indexOf(contentEncoding) != -1) : blob assert (blob.getMetadata().getContentMetadata().getContentEncoding().indexOf(contentEncoding) != -1) : blob
.getMetadata().getContentMetadata().getContentEncoding(); .getMetadata().getContentMetadata().getContentEncoding();
} }
protected void checkContentLanguage(Blob blob, String contentLanguage) { protected void checkContentLanguage(Blob blob, String contentLanguage) {
assert blob.getPayload().getContentMetadata().getContentLanguage().startsWith(contentLanguage) : blob assert blob.getPayload().getContentMetadata().getContentLanguage().startsWith(contentLanguage) : blob
.getPayload().getContentMetadata().getContentLanguage(); .getPayload().getContentMetadata().getContentLanguage();
assert blob.getMetadata().getContentMetadata().getContentLanguage().startsWith(contentLanguage) : blob assert blob.getMetadata().getContentMetadata().getContentLanguage().startsWith(contentLanguage) : blob
.getMetadata().getContentMetadata().getContentLanguage(); .getMetadata().getContentMetadata().getContentLanguage();
} }
protected volatile static Crypto crypto; protected volatile static Crypto crypto;
@ -526,15 +528,11 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
@Test(groups = { "integration", "live" }) @Test(groups = { "integration", "live" })
public void testMetadata() throws InterruptedException, IOException { public void testMetadata() throws InterruptedException, IOException {
String key = "hello"; String key = "hello";
Blob blob = context.getBlobStore().newBlob(key);
blob.setPayload(TEST_STRING);
blob.getMetadata().getContentMetadata().setContentType(MediaType.TEXT_PLAIN);
// NOTE all metadata in jclouds comes out as lowercase, in an effort to // NOTE all metadata in jclouds comes out as lowercase, in an effort to
// normalize the // normalize the
// providers. // providers.
blob.getMetadata().getUserMetadata().put("Adrian", "powderpuff"); Blob blob = context.getBlobStore().blobBuilder(key).userMetadata(ImmutableMap.of("Adrian", "powderpuff"))
Payloads.calculateMD5(blob, context.utils().crypto().md5()); .payload(TEST_STRING).contentType(MediaType.TEXT_PLAIN).calculateMD5().build();
String containerName = getContainerName(); String containerName = getContainerName();
try { try {
assertNull(context.getBlobStore().blobMetadata(containerName, "powderpuff")); assertNull(context.getBlobStore().blobMetadata(containerName, "powderpuff"));
@ -562,7 +560,7 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
protected void validateMetadata(BlobMetadata metadata) throws IOException { protected void validateMetadata(BlobMetadata metadata) throws IOException {
assert metadata.getContentMetadata().getContentType().startsWith("text/plain") : metadata.getContentMetadata() assert metadata.getContentMetadata().getContentType().startsWith("text/plain") : metadata.getContentMetadata()
.getContentType(); .getContentType();
assertEquals(metadata.getContentMetadata().getContentLength(), new Long(TEST_STRING.length())); assertEquals(metadata.getContentMetadata().getContentLength(), new Long(TEST_STRING.length()));
assertEquals(metadata.getUserMetadata().get("adrian"), "powderpuff"); assertEquals(metadata.getUserMetadata().get("adrian"), "powderpuff");
checkMD5(metadata); checkMD5(metadata);

View File

@ -46,7 +46,7 @@ public class BaseBlobLiveTest extends BaseBlobStoreIntegrationTest {
private static final String sysHttpStreamETag = System.getProperty("jclouds.blobstore.httpstream.md5"); private static final String sysHttpStreamETag = System.getProperty("jclouds.blobstore.httpstream.md5");
@Test @Test
@Parameters( { "jclouds.blobstore.httpstream.url", "jclouds.blobstore.httpstream.md5" }) @Parameters({ "jclouds.blobstore.httpstream.url", "jclouds.blobstore.httpstream.md5" })
public void testCopyUrl(@Optional String httpStreamUrl, @Optional String httpStreamETag) throws Exception { public void testCopyUrl(@Optional String httpStreamUrl, @Optional String httpStreamETag) throws Exception {
httpStreamUrl = checkNotNull(httpStreamUrl != null ? httpStreamUrl : sysHttpStreamUrl, "httpStreamUrl"); httpStreamUrl = checkNotNull(httpStreamUrl != null ? httpStreamUrl : sysHttpStreamUrl, "httpStreamUrl");
@ -61,10 +61,7 @@ public class BaseBlobLiveTest extends BaseBlobStoreIntegrationTest {
long length = connection.getContentLength(); long length = connection.getContentLength();
InputStream input = connection.getInputStream(); InputStream input = connection.getInputStream();
Blob blob = context.getBlobStore().newBlob(name); Blob blob = context.getBlobStore().blobBuilder(name).payload(input).contentLength(length).contentMD5(md5).build();
blob.setPayload(input);
blob.getPayload().getContentMetadata().setContentLength(length);
blob.getPayload().getContentMetadata().setContentMD5(md5);
String container = getContainerName(); String container = getContainerName();
try { try {
context.getBlobStore().putBlob(container, blob); context.getBlobStore().putBlob(container, blob);

View File

@ -20,17 +20,16 @@
package org.jclouds.blobstore.integration.internal; package org.jclouds.blobstore.integration.internal;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.blobstore.options.ListContainerOptions.Builder.inDirectory;
import static org.jclouds.blobstore.options.ListContainerOptions.Builder.maxResults; import static org.jclouds.blobstore.options.ListContainerOptions.Builder.maxResults;
import static org.jclouds.blobstore.util.BlobStoreUtils.getContentAsStringOrNullAndClose; import static org.jclouds.blobstore.util.BlobStoreUtils.getContentAsStringOrNullAndClose;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.IOException; import java.io.IOException;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
@ -42,7 +41,12 @@ import org.jclouds.io.Payloads;
import org.jclouds.util.Strings2; import org.jclouds.util.Strings2;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Function;
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
/** /**
@ -52,19 +56,32 @@ import com.google.common.collect.Sets;
*/ */
public abstract class BaseBlobMapIntegrationTest extends BaseMapIntegrationTest<Blob> { public abstract class BaseBlobMapIntegrationTest extends BaseMapIntegrationTest<Blob> {
private static class StringToBlob implements Function<String, Blob> {
private final BlobMap map;
private StringToBlob(BlobMap map) {
this.map = map;
}
@Override
public Blob apply(String arg0) {
return map.blobBuilder().payload(arg0).build();
}
}
@Override @Override
@Test(groups = { "integration", "live" }) @Test(groups = { "integration", "live" })
public void testValues() throws IOException, InterruptedException { public void testValues() throws IOException, InterruptedException {
String bucketName = getContainerName(); String bucketName = getContainerName();
try { try {
Map<String, Blob> map = createMap(context, bucketName); BlobMap map = createMap(context, bucketName);
putFiveStrings(map); putFiveStrings(map);
putFiveStringsUnderPath(map); putFiveStringsUnderPath(map);
Collection<Blob> blobs = map.values(); Collection<Blob> blobs = map.values();
assertConsistencyAwareMapSize(map, 5); assertConsistencyAwareMapSize(map, 5);
Set<String> blobsAsString = new HashSet<String>(); Set<String> blobsAsString = Sets.newLinkedHashSet();
for (Blob blob : blobs) { for (Blob blob : blobs) {
blobsAsString.add(getContentAsStringOrNullAndClose(blob)); blobsAsString.add(getContentAsStringOrNullAndClose(blob));
} }
@ -92,7 +109,7 @@ public abstract class BaseBlobMapIntegrationTest extends BaseMapIntegrationTest<
} }
private void assertConsistencyAwareContentEquals(final Map<String, Blob> map, final String key, final String blob) private void assertConsistencyAwareContentEquals(final Map<String, Blob> map, final String key, final String blob)
throws InterruptedException { throws InterruptedException {
assertConsistencyAware(new Runnable() { assertConsistencyAware(new Runnable() {
public void run() { public void run() {
Blob old = map.remove(key); Blob old = map.remove(key);
@ -110,7 +127,7 @@ public abstract class BaseBlobMapIntegrationTest extends BaseMapIntegrationTest<
public void testEntrySet() throws IOException, InterruptedException { public void testEntrySet() throws IOException, InterruptedException {
String bucketName = getContainerName(); String bucketName = getContainerName();
try { try {
final Map<String, Blob> map = createMap(context, bucketName); final BlobMap map = createMap(context, bucketName);
putFiveStrings(map); putFiveStrings(map);
assertConsistencyAwareMapSize(map, 5); assertConsistencyAwareMapSize(map, 5);
Set<Entry<String, Blob>> entries = map.entrySet(); Set<Entry<String, Blob>> entries = map.entrySet();
@ -145,9 +162,7 @@ public abstract class BaseBlobMapIntegrationTest extends BaseMapIntegrationTest<
try { try {
Map<String, Blob> map = createMap(context, bucketName); Map<String, Blob> map = createMap(context, bucketName);
putStringWithMD5(map, "one", "apple"); putStringWithMD5(map, "one", "apple");
Blob blob = context.getBlobStore().newBlob("one"); Blob blob = context.getBlobStore().blobBuilder("one").payload("apple").calculateMD5().build();
blob.setPayload("apple");
Payloads.calculateMD5(blob);
assertConsistencyAwareContainsValue(map, blob); assertConsistencyAwareContainsValue(map, blob);
} finally { } finally {
returnContainer(bucketName); returnContainer(bucketName);
@ -161,7 +176,7 @@ public abstract class BaseBlobMapIntegrationTest extends BaseMapIntegrationTest<
} }
void getOneReturnsBearAndOldValueIsApple(Map<String, Blob> map, Blob oldValue) throws IOException, void getOneReturnsBearAndOldValueIsApple(Map<String, Blob> map, Blob oldValue) throws IOException,
InterruptedException { InterruptedException {
assertEquals(getContentAsStringOrNullAndClose(checkNotNull(map.get("one"), "one")), "bear"); assertEquals(getContentAsStringOrNullAndClose(checkNotNull(map.get("one"), "one")), "bear");
assertEquals(getContentAsStringOrNullAndClose(oldValue), "apple"); assertEquals(getContentAsStringOrNullAndClose(oldValue), "apple");
assertConsistencyAwareMapSize(map, 1); assertConsistencyAwareMapSize(map, 1);
@ -172,9 +187,8 @@ public abstract class BaseBlobMapIntegrationTest extends BaseMapIntegrationTest<
String bucketName = getContainerName(); String bucketName = getContainerName();
try { try {
Map<String, Blob> map = createMap(context, bucketName); Map<String, Blob> map = createMap(context, bucketName);
Blob blob = context.getBlobStore().newBlob("one"); Blob blob = context.getBlobStore().blobBuilder("one").payload(Strings2.toInputStream("apple")).calculateMD5()
blob.setPayload(Strings2.toInputStream("apple")); .build();
Payloads.calculateMD5(blob);
Blob old = map.put(blob.getMetadata().getName(), blob); Blob old = map.put(blob.getMetadata().getName(), blob);
getOneReturnsAppleAndOldValueIsNull(map, old); getOneReturnsAppleAndOldValueIsNull(map, old);
blob.setPayload(Strings2.toInputStream("bear")); blob.setPayload(Strings2.toInputStream("bear"));
@ -191,16 +205,16 @@ public abstract class BaseBlobMapIntegrationTest extends BaseMapIntegrationTest<
String bucketName = getContainerName(); String bucketName = getContainerName();
try { try {
Map<String, Blob> map = createMap(context, bucketName); Map<String, Blob> map = createMap(context, bucketName);
Map<String, Blob> newMap = new HashMap<String, Blob>(); ImmutableMap.Builder<String, Blob> newMap = ImmutableMap.<String, Blob> builder();
for (String key : fiveInputs.keySet()) { for (String key : fiveInputs.keySet()) {
Blob blob = context.getBlobStore().newBlob(key); newMap.put(
blob.setPayload(fiveInputs.get(key)); key,
blob.getPayload().getContentMetadata().setContentLength((long) fiveBytes.get(key).length); context.getBlobStore().blobBuilder(key).payload(fiveInputs.get(key))
newMap.put(key, blob); .contentLength((long) fiveBytes.get(key).length).build());
} }
map.putAll(newMap); map.putAll(newMap.build());
assertConsistencyAwareMapSize(map, 5); assertConsistencyAwareMapSize(map, 5);
assertConsistencyAwareKeySetEquals(map, new HashSet<String>(fiveInputs.keySet())); assertConsistencyAwareKeySetEquals(map, ImmutableSet.copyOf(fiveInputs.keySet()));
fourLeftRemovingOne(map); fourLeftRemovingOne(map);
} finally { } finally {
returnContainer(bucketName); returnContainer(bucketName);
@ -213,23 +227,21 @@ public abstract class BaseBlobMapIntegrationTest extends BaseMapIntegrationTest<
return; return;
String bucketName = getContainerName(); String bucketName = getContainerName();
try { try {
Map<String, Blob> map = createMap(context, bucketName); BlobMap map = createMap(context, bucketName);
Set<String> keySet = Sets.newHashSet(); Builder<String> keySet = ImmutableSet.<String> builder();
for (int i = 0; i < maxResultsForTestListings() + 1; i++) { for (int i = 0; i < maxResultsForTestListings() + 1; i++) {
keySet.add(i + ""); keySet.add(i + "");
} }
Map<String, Blob> newMap = new HashMap<String, Blob>(); Map<String, Blob> newMap = Maps.newLinkedHashMap();
for (String key : keySet) { for (String key : keySet.build()) {
Blob blob = context.getBlobStore().newBlob(key); newMap.put(key, map.blobBuilder().payload(key).build());
blob.setPayload(key);
newMap.put(key, blob);
} }
map.putAll(newMap); map.putAll(newMap);
newMap.clear(); newMap.clear();
assertConsistencyAwareMapSize(map, maxResultsForTestListings() + 1); assertConsistencyAwareMapSize(map, maxResultsForTestListings() + 1);
assertConsistencyAwareKeySetEquals(map, keySet); assertConsistencyAwareKeySetEquals(map, keySet.build());
map.clear(); map.clear();
assertConsistencyAwareMapSize(map, 0); assertConsistencyAwareMapSize(map, 0);
} finally { } finally {
@ -239,30 +251,15 @@ public abstract class BaseBlobMapIntegrationTest extends BaseMapIntegrationTest<
@Override @Override
protected void putStringWithMD5(Map<String, Blob> map, String key, String text) throws IOException { protected void putStringWithMD5(Map<String, Blob> map, String key, String text) throws IOException {
Blob blob = context.getBlobStore().newBlob(key); map.put(key, context.getBlobStore().blobBuilder(key).payload(text).calculateMD5().build());
blob.setPayload(text);
Payloads.calculateMD5(blob);
map.put(key, blob);
} }
protected void putFiveStrings(Map<String, Blob> map) { protected void putFiveStrings(BlobMap map) {
Map<String, Blob> newMap = new HashMap<String, Blob>(); map.putAll(Maps.transformValues(fiveStrings, new StringToBlob(map)));
for (Map.Entry<String, String> entry : fiveStrings.entrySet()) {
Blob blob = context.getBlobStore().newBlob(entry.getKey());
blob.setPayload(entry.getValue());
newMap.put(entry.getKey(), blob);
}
map.putAll(newMap);
} }
protected void putFiveStringsUnderPath(Map<String, Blob> map) { protected void putFiveStringsUnderPath(BlobMap map) {
Map<String, Blob> newMap = new HashMap<String, Blob>(); map.putAll(Maps.transformValues(fiveStringsUnderPath, new StringToBlob(map)));
for (Map.Entry<String, String> entry : fiveStringsUnderPath.entrySet()) {
Blob blob = context.getBlobStore().newBlob(entry.getKey());
blob.setPayload(entry.getValue());
newMap.put(entry.getKey(), blob);
}
map.putAll(newMap);
} }
protected int maxResultsForTestListings() { protected int maxResultsForTestListings() {
@ -276,4 +273,20 @@ public abstract class BaseBlobMapIntegrationTest extends BaseMapIntegrationTest<
protected BlobMap createMap(BlobStoreContext context, String bucket, ListContainerOptions options) { protected BlobMap createMap(BlobStoreContext context, String bucket, ListContainerOptions options) {
return context.createBlobMap(bucket, options); return context.createBlobMap(bucket, options);
} }
@Override
protected void addTenObjectsUnderPrefix(String containerName, String prefix) throws InterruptedException {
BlobMap blobMap = createMap(context, containerName, inDirectory(prefix));
for (int i = 0; i < 10; i++) {
blobMap.put(i + "", blobMap.blobBuilder().payload(i + "content").build());
}
}
@Override
protected void addTenObjectsUnderRoot(String containerName) throws InterruptedException {
BlobMap blobMap = createMap(context, containerName, ListContainerOptions.NONE);
for (int i = 0; i < 10; i++) {
blobMap.put(i + "", blobMap.blobBuilder().payload(i + "content").build());
}
}
} }

View File

@ -41,9 +41,7 @@ public class BaseBlobSignerLiveTest extends BaseBlobStoreIntegrationTest {
String name = "hello"; String name = "hello";
String text = "fooooooooooooooooooooooo"; String text = "fooooooooooooooooooooooo";
Blob blob = context.getBlobStore().newBlob(name); Blob blob = context.getBlobStore().blobBuilder(name).payload(text).contentType("text/plain").build();
blob.setPayload(text);
blob.getPayload().getContentMetadata().setContentType("text/plain");
String container = getContainerName(); String container = getContainerName();
try { try {
context.getBlobStore().putBlob(container, blob); context.getBlobStore().putBlob(container, blob);
@ -62,9 +60,7 @@ public class BaseBlobSignerLiveTest extends BaseBlobStoreIntegrationTest {
String name = "hello"; String name = "hello";
String text = "fooooooooooooooooooooooo"; String text = "fooooooooooooooooooooooo";
Blob blob = context.getBlobStore().newBlob(name); Blob blob = context.getBlobStore().blobBuilder(name).payload(text).contentType("text/plain").build();
blob.setPayload(text);
blob.getPayload().getContentMetadata().setContentType("text/plain");
String container = getContainerName(); String container = getContainerName();
try { try {
context.getBlobStore().putBlob(container, blob); context.getBlobStore().putBlob(container, blob);
@ -82,9 +78,7 @@ public class BaseBlobSignerLiveTest extends BaseBlobStoreIntegrationTest {
String name = "hello"; String name = "hello";
String text = "fooooooooooooooooooooooo"; String text = "fooooooooooooooooooooooo";
Blob blob = context.getBlobStore().newBlob(name); Blob blob = context.getBlobStore().blobBuilder(name).payload(text).contentType("text/plain").build();
blob.setPayload(text);
blob.getPayload().getContentMetadata().setContentType("text/plain");
String container = getContainerName(); String container = getContainerName();
try { try {
HttpRequest request = context.getSigner().signPutBlob(container, blob); HttpRequest request = context.getSigner().signPutBlob(container, blob);

View File

@ -244,17 +244,14 @@ public class BaseBlobStoreIntegrationTest {
} }
protected String addBlobToContainer(String sourceContainer, String key, String payload, String contentType) { protected String addBlobToContainer(String sourceContainer, String key, String payload, String contentType) {
Blob sourceObject = context.getBlobStore().newBlob(key); Blob sourceObject = context.getBlobStore().blobBuilder(key).payload(payload).contentType(contentType).build();
sourceObject.setPayload(payload);
sourceObject.getMetadata().getContentMetadata().setContentType(contentType);
return addBlobToContainer(sourceContainer, sourceObject); return addBlobToContainer(sourceContainer, sourceObject);
} }
protected void add5BlobsUnderPathAnd5UnderRootToContainer(String sourceContainer) { protected void add5BlobsUnderPathAnd5UnderRootToContainer(String sourceContainer) {
for (Entry<String, String> entry : Iterables.concat(fiveStrings.entrySet(), fiveStringsUnderPath.entrySet())) { for (Entry<String, String> entry : Iterables.concat(fiveStrings.entrySet(), fiveStringsUnderPath.entrySet())) {
Blob sourceObject = context.getBlobStore().newBlob(entry.getKey()); Blob sourceObject = context.getBlobStore().blobBuilder(entry.getKey()).payload(entry.getValue())
sourceObject.setPayload(entry.getValue()); .contentType("text/xml").build();
sourceObject.getMetadata().getContentMetadata().setContentType("text/xml");
addBlobToContainer(sourceContainer, sourceObject); addBlobToContainer(sourceContainer, sourceObject);
} }
} }

View File

@ -40,9 +40,10 @@ import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata; import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.crypto.CryptoStreams; import org.jclouds.crypto.CryptoStreams;
import org.jclouds.io.InputSuppliers; import org.jclouds.io.InputSuppliers;
import org.jclouds.io.Payloads;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
/** /**
* @author Adrian Cole * @author Adrian Cole
*/ */
@ -60,8 +61,7 @@ public class BaseContainerIntegrationTest extends BaseBlobStoreIntegrationTest {
try { try {
context.getBlobStore().createContainerInLocation(null, containerName); context.getBlobStore().createContainerInLocation(null, containerName);
Blob blob = context.getBlobStore().newBlob("hello"); Blob blob = context.getBlobStore().blobBuilder("hello").payload(TEST_STRING).build();
blob.setPayload(TEST_STRING);
context.getBlobStore().putBlob(containerName, blob); context.getBlobStore().putBlob(containerName, blob);
context.getBlobStore().createContainerInLocation(null, containerName); context.getBlobStore().createContainerInLocation(null, containerName);
@ -74,27 +74,22 @@ public class BaseContainerIntegrationTest extends BaseBlobStoreIntegrationTest {
@Test(groups = { "integration", "live" }) @Test(groups = { "integration", "live" })
public void testWithDetails() throws InterruptedException, IOException { public void testWithDetails() throws InterruptedException, IOException {
String key = "hello"; String key = "hello";
Blob object = context.getBlobStore().newBlob(key);
object.setPayload(TEST_STRING);
object.getMetadata().getContentMetadata().setContentType(MediaType.TEXT_PLAIN);
// NOTE all metadata in jclouds comes out as lowercase, in an effort to
// normalize the
// providers.
object.getMetadata().getUserMetadata().put("Adrian", "powderpuff");
Payloads.calculateMD5(object, context.utils().crypto().md5());
String containerName = getContainerName(); String containerName = getContainerName();
try { try {
addBlobToContainer(containerName, object); addBlobToContainer(containerName,
// NOTE all metadata in jclouds comes out as lowercase, in an effort to
// normalize the providers.
context.getBlobStore().blobBuilder(key).userMetadata(ImmutableMap.of("Adrian", "powderpuff"))
.payload(TEST_STRING).contentType(MediaType.TEXT_PLAIN).calculateMD5().build());
validateContent(containerName, key); validateContent(containerName, key);
PageSet<? extends StorageMetadata> container = context.getBlobStore().list(containerName, PageSet<? extends StorageMetadata> container = context.getBlobStore().list(containerName,
maxResults(1).withDetails()); maxResults(1).withDetails());
BlobMetadata metadata = BlobMetadata.class.cast(get(container, 0)); BlobMetadata metadata = BlobMetadata.class.cast(get(container, 0));
assert metadata.getContentMetadata().getContentType().startsWith("text/plain") : metadata.getContentMetadata() assert metadata.getContentMetadata().getContentType().startsWith("text/plain") : metadata.getContentMetadata()
.getContentType(); .getContentType();
assertEquals(metadata.getContentMetadata().getContentLength(), new Long(TEST_STRING.length())); assertEquals(metadata.getContentMetadata().getContentLength(), new Long(TEST_STRING.length()));
assertEquals(metadata.getUserMetadata().get("adrian"), "powderpuff"); assertEquals(metadata.getUserMetadata().get("adrian"), "powderpuff");
checkMD5(metadata); checkMD5(metadata);
@ -134,7 +129,7 @@ public class BaseContainerIntegrationTest extends BaseBlobStoreIntegrationTest {
container = context.getBlobStore().list(containerName, afterMarker(marker)); container = context.getBlobStore().list(containerName, afterMarker(marker));
assertEquals(container.getNextMarker(), null); assertEquals(container.getNextMarker(), null);
assert container.size() == 25 : String.format("size should have been 25, but was %d: %s", container.size(), assert container.size() == 25 : String.format("size should have been 25, but was %d: %s", container.size(),
container); container);
assert container.getNextMarker() == null; assert container.getNextMarker() == null;
} finally { } finally {
@ -305,7 +300,7 @@ public class BaseContainerIntegrationTest extends BaseBlobStoreIntegrationTest {
public void run() { public void run() {
try { try {
assert !context.getBlobStore().containerExists(containerName) : "container " + containerName assert !context.getBlobStore().containerExists(containerName) : "container " + containerName
+ " still exists"; + " still exists";
} catch (Exception e) { } catch (Exception e) {
propagateIfPossible(e); propagateIfPossible(e);
} }
@ -315,7 +310,7 @@ public class BaseContainerIntegrationTest extends BaseBlobStoreIntegrationTest {
@Test(groups = { "integration", "live" }) @Test(groups = { "integration", "live" })
public void testListContainer() throws InterruptedException, ExecutionException, TimeoutException, public void testListContainer() throws InterruptedException, ExecutionException, TimeoutException,
UnsupportedEncodingException { UnsupportedEncodingException {
String containerName = getContainerName(); String containerName = getContainerName();
try { try {
add15UnderRoot(containerName); add15UnderRoot(containerName);
@ -329,9 +324,8 @@ public class BaseContainerIntegrationTest extends BaseBlobStoreIntegrationTest {
protected void addAlphabetUnderRoot(String containerName) throws InterruptedException { protected void addAlphabetUnderRoot(String containerName) throws InterruptedException {
for (char letter = 'a'; letter <= 'z'; letter++) { for (char letter = 'a'; letter <= 'z'; letter++) {
Blob blob = context.getBlobStore().newBlob(letter + ""); context.getBlobStore().putBlob(containerName,
blob.setPayload(letter + "content"); context.getBlobStore().blobBuilder(letter + "").payload(letter + "content").build());
context.getBlobStore().putBlob(containerName, blob);
} }
assertContainerSize(containerName, 26); assertContainerSize(containerName, 26);
@ -351,17 +345,15 @@ public class BaseContainerIntegrationTest extends BaseBlobStoreIntegrationTest {
protected void add15UnderRoot(String containerName) throws InterruptedException { protected void add15UnderRoot(String containerName) throws InterruptedException {
for (int i = 0; i < 15; i++) { for (int i = 0; i < 15; i++) {
Blob blob = context.getBlobStore().newBlob(i + ""); context.getBlobStore().putBlob(containerName,
blob.setPayload(i + "content"); context.getBlobStore().blobBuilder(i + "").payload(i + "content").build());
context.getBlobStore().putBlob(containerName, blob);
} }
} }
protected void addTenObjectsUnderPrefix(String containerName, String prefix) throws InterruptedException { protected void addTenObjectsUnderPrefix(String containerName, String prefix) throws InterruptedException {
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
Blob blob = context.getBlobStore().newBlob(prefix + "/" + i); context.getBlobStore().putBlob(containerName,
blob.setPayload(i + "content"); context.getBlobStore().blobBuilder(prefix + "/" + i).payload(i + "content").build());
context.getBlobStore().putBlob(containerName, blob);
} }
} }
} }

View File

@ -27,11 +27,10 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.Map.Entry;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
@ -61,7 +60,7 @@ public abstract class BaseInputStreamMapIntegrationTest extends BaseMapIntegrati
assertConsistencyAwareMapSize(map, 5); assertConsistencyAwareMapSize(map, 5);
Collection<InputStream> values = map.values(); Collection<InputStream> values = map.values();
assertEquals(values.size(), 5); assertEquals(values.size(), 5);
Set<String> valuesAsString = new HashSet<String>(); Set<String> valuesAsString = Sets.newLinkedHashSet();
for (InputStream stream : values) { for (InputStream stream : values) {
valuesAsString.add(Strings2.toStringAndClose(stream)); valuesAsString.add(Strings2.toStringAndClose(stream));
} }
@ -77,7 +76,7 @@ public abstract class BaseInputStreamMapIntegrationTest extends BaseMapIntegrati
String containerName = getContainerName(); String containerName = getContainerName();
try { try {
InputStreamMap map = createMap(context, containerName); InputStreamMap map = createMap(context, containerName);
Set<String> keySet = Sets.newHashSet(); Set<String> keySet = Sets.newLinkedHashSet();
for (int i = 0; i < maxResultsForTestListings() + 1; i++) { for (int i = 0; i < maxResultsForTestListings() + 1; i++) {
keySet.add(i + ""); keySet.add(i + "");
} }

View File

@ -30,15 +30,14 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.Map.Entry;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import org.jclouds.blobstore.BlobStoreContext; import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.ListableMap; import org.jclouds.blobstore.ListableMap;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.util.Strings2; import org.jclouds.util.Strings2;
import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeClass;
@ -50,6 +49,7 @@ import org.testng.annotations.Test;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
@ -82,14 +82,14 @@ public abstract class BaseMapIntegrationTest<V> extends BaseBlobStoreIntegration
} }
@BeforeClass(groups = { "integration", "live" }) @BeforeClass(groups = { "integration", "live" })
@Parameters( { "basedir" }) @Parameters({ "basedir" })
protected void setUpTempDir(@Optional String basedir) throws InterruptedException, ExecutionException, protected void setUpTempDir(@Optional String basedir) throws InterruptedException, ExecutionException,
FileNotFoundException, IOException, TimeoutException { FileNotFoundException, IOException, TimeoutException {
if (basedir == null) { if (basedir == null) {
basedir = System.getProperty("java.io.tmpdir"); basedir = System.getProperty("java.io.tmpdir");
} }
tmpDirectory = basedir + File.separator + "target" + File.separator + "testFiles" + File.separator tmpDirectory = basedir + File.separator + "target" + File.separator + "testFiles" + File.separator
+ getClass().getSimpleName(); + getClass().getSimpleName();
new File(tmpDirectory).mkdirs(); new File(tmpDirectory).mkdirs();
fiveFiles = Maps.newHashMap(); fiveFiles = Maps.newHashMap();
for (Entry<String, String> entry : fiveStrings.entrySet()) { for (Entry<String, String> entry : fiveStrings.entrySet()) {
@ -102,7 +102,7 @@ public abstract class BaseMapIntegrationTest<V> extends BaseBlobStoreIntegration
protected abstract Map<String, V> createMap(BlobStoreContext context, String containerName); protected abstract Map<String, V> createMap(BlobStoreContext context, String containerName);
protected abstract Map<String, V> createMap(BlobStoreContext context, String containerName, protected abstract Map<String, V> createMap(BlobStoreContext context, String containerName,
ListContainerOptions options); ListContainerOptions options);
@Test(groups = { "integration", "live" }) @Test(groups = { "integration", "live" })
public void testClear() throws InterruptedException, ExecutionException, TimeoutException, IOException { public void testClear() throws InterruptedException, ExecutionException, TimeoutException, IOException {
@ -138,17 +138,15 @@ public abstract class BaseMapIntegrationTest<V> extends BaseBlobStoreIntegration
protected void addTenObjectsUnderPrefix(String containerName, String prefix) throws InterruptedException { protected void addTenObjectsUnderPrefix(String containerName, String prefix) throws InterruptedException {
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
Blob blob = context.getBlobStore().newBlob(prefix + "/" + i); context.getBlobStore().putBlob(containerName,
blob.setPayload(i + "content"); context.getBlobStore().blobBuilder(prefix + "/" + i).payload(i + "content").build());
context.getBlobStore().putBlob(containerName, blob);
} }
} }
protected void addTenObjectsUnderRoot(String containerName) throws InterruptedException { protected void addTenObjectsUnderRoot(String containerName) throws InterruptedException {
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
Blob blob = context.getBlobStore().newBlob(i + ""); context.getBlobStore().putBlob(containerName,
blob.setPayload(i + "content"); context.getBlobStore().blobBuilder(i + "").payload(i + "content").build());
context.getBlobStore().putBlob(containerName, blob);
} }
} }
@ -165,15 +163,28 @@ public abstract class BaseMapIntegrationTest<V> extends BaseBlobStoreIntegration
context.getBlobStore().createDirectory(containerName, directory); context.getBlobStore().createDirectory(containerName, directory);
addTenObjectsUnderRoot(containerName); addTenObjectsUnderRoot(containerName);
assertEquals(rootMap.size(), 10); assertEquals(rootMap.size(), 10);
assertEquals(ImmutableSortedSet.copyOf(rootMap.keySet()),
ImmutableSortedSet.of("0", "1", "2", "3", "4", "5", "6", "7", "8", "9"));
assertEquals(rootRecursiveMap.size(), 10); assertEquals(rootRecursiveMap.size(), 10);
assertEquals(ImmutableSortedSet.copyOf(rootRecursiveMap.keySet()),
ImmutableSortedSet.of("0", "1", "2", "3", "4", "5", "6", "7", "8", "9"));
assertEquals(inDirectoryMap.size(), 0); assertEquals(inDirectoryMap.size(), 0);
assertEquals(inDirectoryRecursiveMap.size(), 0); assertEquals(inDirectoryRecursiveMap.size(), 0);
addTenObjectsUnderPrefix(containerName, directory); addTenObjectsUnderPrefix(containerName, directory);
assertEquals(rootMap.size(), 10); assertEquals(rootMap.size(), 10);
assertEquals(ImmutableSortedSet.copyOf(rootMap.keySet()),
ImmutableSortedSet.of("0", "1", "2", "3", "4", "5", "6", "7", "8", "9"));
assertEquals(rootRecursiveMap.size(), 20); assertEquals(rootRecursiveMap.size(), 20);
assertEquals(ImmutableSortedSet.copyOf(rootRecursiveMap.keySet()), ImmutableSet.of("0", "1", "2", "3", "4",
"5", "6", "7", "8", "9", "apps/0", "apps/1", "apps/2", "apps/3", "apps/4", "apps/5", "apps/6", "apps/7",
"apps/8", "apps/9"));
assertEquals(inDirectoryMap.size(), 10); assertEquals(inDirectoryMap.size(), 10);
assertEquals(ImmutableSortedSet.copyOf(inDirectoryMap.keySet()),
ImmutableSortedSet.of("0", "1", "2", "3", "4", "5", "6", "7", "8", "9"));
assertEquals(inDirectoryRecursiveMap.size(), 10); assertEquals(inDirectoryRecursiveMap.size(), 10);
assertEquals(ImmutableSortedSet.copyOf(inDirectoryRecursiveMap.keySet()),
ImmutableSortedSet.of("0", "1", "2", "3", "4", "5", "6", "7", "8", "9"));
context.getBlobStore().createDirectory(containerName, directory + "/" + directory); context.getBlobStore().createDirectory(containerName, directory + "/" + directory);
assertEquals(rootMap.size(), 10); assertEquals(rootMap.size(), 10);
@ -200,7 +211,7 @@ public abstract class BaseMapIntegrationTest<V> extends BaseBlobStoreIntegration
} }
protected void assertConsistencyAwareKeySetEquals(final Map<String, V> map, final Set<String> expected) protected void assertConsistencyAwareKeySetEquals(final Map<String, V> map, final Set<String> expected)
throws InterruptedException { throws InterruptedException {
assertConsistencyAware(new Runnable() { assertConsistencyAware(new Runnable() {
public void run() { public void run() {
Set<String> toMatch = map.keySet(); Set<String> toMatch = map.keySet();
@ -214,7 +225,7 @@ public abstract class BaseMapIntegrationTest<V> extends BaseBlobStoreIntegration
} }
protected void assertConsistencyAwareRemoveEquals(final Map<String, V> map, final String key, final Object equals) protected void assertConsistencyAwareRemoveEquals(final Map<String, V> map, final String key, final Object equals)
throws InterruptedException { throws InterruptedException {
assertConsistencyAware(new Runnable() { assertConsistencyAware(new Runnable() {
public void run() { public void run() {
assertEquals(map.remove(key), equals); assertEquals(map.remove(key), equals);
@ -223,7 +234,7 @@ public abstract class BaseMapIntegrationTest<V> extends BaseBlobStoreIntegration
} }
protected void assertConsistencyAwareGetEquals(final Map<String, V> map, final String key, final Object equals) protected void assertConsistencyAwareGetEquals(final Map<String, V> map, final String key, final Object equals)
throws InterruptedException { throws InterruptedException {
assertConsistencyAware(new Runnable() { assertConsistencyAware(new Runnable() {
public void run() { public void run() {
assertEquals(map.get(key), equals); assertEquals(map.get(key), equals);
@ -257,7 +268,7 @@ public abstract class BaseMapIntegrationTest<V> extends BaseBlobStoreIntegration
* eventual consistency problems. * eventual consistency problems.
*/ */
protected void assertConsistencyAwareContainsValue(final Map<String, V> map, final Object value) protected void assertConsistencyAwareContainsValue(final Map<String, V> map, final Object value)
throws InterruptedException { throws InterruptedException {
assertConsistencyAware(new Runnable() { assertConsistencyAware(new Runnable() {
public void run() { public void run() {
assert map.containsValue(value); assert map.containsValue(value);
@ -311,7 +322,7 @@ public abstract class BaseMapIntegrationTest<V> extends BaseBlobStoreIntegration
} }
abstract protected void putStringWithMD5(Map<String, V> map, String key, String value) throws InterruptedException, abstract protected void putStringWithMD5(Map<String, V> map, String key, String value) throws InterruptedException,
ExecutionException, TimeoutException, IOException; ExecutionException, TimeoutException, IOException;
protected void fourLeftRemovingOne(Map<String, V> map) throws InterruptedException { protected void fourLeftRemovingOne(Map<String, V> map) throws InterruptedException {
map.remove("one"); map.remove("one");
@ -342,7 +353,7 @@ public abstract class BaseMapIntegrationTest<V> extends BaseBlobStoreIntegration
} }
protected void assertConsistencyAwareListContainer(final ListableMap<?, ?> map, final String containerNameName) protected void assertConsistencyAwareListContainer(final ListableMap<?, ?> map, final String containerNameName)
throws InterruptedException { throws InterruptedException {
assertConsistencyAware(new Runnable() { assertConsistencyAware(new Runnable() {
public void run() { public void run() {
assertTrue(Iterables.size(map.list()) >= 0); assertTrue(Iterables.size(map.list()) >= 0);

View File

@ -25,10 +25,7 @@ import java.io.IOException;
import org.jclouds.blobstore.BlobStore; import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.BlobStoreContextFactory; import org.jclouds.blobstore.BlobStoreContextFactory;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.strategy.internal.ConcatenateContainerLists;
import org.jclouds.blobstore.strategy.internal.ListContainerAndRecurseThroughFolders;
import org.testng.annotations.BeforeTest; import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -48,9 +45,7 @@ public class BiggerThanPageSizeTest {
public void test() throws IOException { public void test() throws IOException {
blobstore.createContainerInLocation(null, "goodies"); blobstore.createContainerInLocation(null, "goodies");
for (int i = 0; i < 1001; i++) { for (int i = 0; i < 1001; i++) {
Blob blob = blobstore.newBlob(i + ""); blobstore.putBlob("goodies", blobstore.blobBuilder(i + "").payload(i + "").build());
blob.setPayload(i + "");
blobstore.putBlob("goodies", blob);
} }
assertEquals(blobstore.countBlobs("goodies"), 1001); assertEquals(blobstore.countBlobs("goodies"), 1001);
blobstore.clearContainer("goodies"); blobstore.clearContainer("goodies");
@ -60,9 +55,7 @@ public class BiggerThanPageSizeTest {
public void testStrategies() throws IOException { public void testStrategies() throws IOException {
blobstore.createContainerInLocation(null, "poo"); blobstore.createContainerInLocation(null, "poo");
for (int i = 0; i < 1001; i++) { for (int i = 0; i < 1001; i++) {
Blob blob = blobstore.newBlob(i + ""); blobstore.putBlob("poo", blobstore.blobBuilder(i + "").payload(i + "").build());
blob.setPayload(i + "");
blobstore.putBlob("poo", blob);
} }
ListContainerAndRecurseThroughFolders lister = new ListContainerAndRecurseThroughFolders( ListContainerAndRecurseThroughFolders lister = new ListContainerAndRecurseThroughFolders(

View File

@ -48,7 +48,7 @@ public class MutableResourceMetadataImpl<T extends Enum<T>> implements MutableRe
private Map<String, String> userMetadata; private Map<String, String> userMetadata;
public MutableResourceMetadataImpl() { public MutableResourceMetadataImpl() {
userMetadata = Maps.newHashMap(); userMetadata = Maps.newLinkedHashMap();
} }
public MutableResourceMetadataImpl(ResourceMetadata<T> from) { public MutableResourceMetadataImpl(ResourceMetadata<T> from) {

View File

@ -89,7 +89,7 @@ public class Payloads {
} }
public static UrlEncodedFormPayload newUrlEncodedFormPayload(Multimap<String, String> formParams, public static UrlEncodedFormPayload newUrlEncodedFormPayload(Multimap<String, String> formParams,
@Nullable Comparator<Map.Entry<String, String>> sorter, char... skips) { @Nullable Comparator<Map.Entry<String, String>> sorter, char... skips) {
return new UrlEncodedFormPayload(formParams, sorter, skips); return new UrlEncodedFormPayload(formParams, sorter, skips);
} }
@ -109,14 +109,16 @@ public class Payloads {
public static Payload calculateMD5(Payload payload, MessageDigest md5) throws IOException { public static Payload calculateMD5(Payload payload, MessageDigest md5) throws IOException {
checkNotNull(payload, "payload"); checkNotNull(payload, "payload");
if (!payload.isRepeatable()) { if (!payload.isRepeatable()) {
String oldContentType = payload.getContentMetadata().getContentType(); MutableContentMetadata oldContentMetadata = payload.getContentMetadata();
Payload oldPayload = payload; Payload oldPayload = payload;
try { try {
payload = newByteArrayPayload(toByteArray(payload)); payload = newByteArrayPayload(toByteArray(payload));
} finally { } finally {
oldPayload.release(); oldPayload.release();
} }
payload.getContentMetadata().setContentType(oldContentType); oldContentMetadata.setContentLength(payload.getContentMetadata().getContentLength());
oldContentMetadata.setContentMD5(payload.getContentMetadata().getContentMD5());
payload.setContentMetadata(oldContentMetadata);
} }
payload.getContentMetadata().setContentMD5(CryptoStreams.digest(payload, md5)); payload.getContentMetadata().setContentMD5(CryptoStreams.digest(payload, md5));
return payload; return payload;

View File

@ -35,7 +35,7 @@ import com.google.common.base.Function;
*/ */
@Singleton @Singleton
public class AzureBlobToBlob implements Function<AzureBlob, Blob> { public class AzureBlobToBlob implements Function<AzureBlob, Blob> {
private final Blob.Factory blobFactory; private final Factory blobFactory;
private final BlobPropertiesToBlobMetadata blobPr2BlobMd; private final BlobPropertiesToBlobMetadata blobPr2BlobMd;
@Inject @Inject