mirror of https://github.com/apache/jclouds.git
added filesystem provider
This commit is contained in:
parent
0e5823afad
commit
9cc80ca7aa
|
@ -49,5 +49,10 @@
|
||||||
<artifactId>jclouds-rackspace</artifactId>
|
<artifactId>jclouds-rackspace</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.groupId}</groupId>
|
||||||
|
<artifactId>jclouds-filesystem</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -116,3 +116,7 @@ googlestorage.propertiesbuilder=org.jclouds.aws.s3.GoogleStoragePropertiesBuilde
|
||||||
|
|
||||||
transient.contextbuilder=org.jclouds.blobstore.TransientBlobStoreContextBuilder
|
transient.contextbuilder=org.jclouds.blobstore.TransientBlobStoreContextBuilder
|
||||||
transient.propertiesbuilder=org.jclouds.blobstore.TransientBlobStorePropertiesBuilder
|
transient.propertiesbuilder=org.jclouds.blobstore.TransientBlobStorePropertiesBuilder
|
||||||
|
|
||||||
|
filesystem.contextbuilder=org.jclouds.filesystem.FilesystemBlobStoreContextBuilder
|
||||||
|
filesystem.propertiesbuilder=org.jclouds.filesystem.FilesystemBlobStorePropertiesBuilder
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
|
||||||
|
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.
|
||||||
|
====================================================================
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4.0.0.xsd" >
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.jclouds</groupId>
|
||||||
|
<artifactId>jclouds-project</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<relativePath>../project/pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
<artifactId>jclouds-filesystem</artifactId>
|
||||||
|
<name>jcloud filesystem core</name>
|
||||||
|
<description>jclouds components to access filesystem</description>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.groupId}</groupId>
|
||||||
|
<artifactId>jclouds-blobstore</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<type>jar</type>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.groupId}</groupId>
|
||||||
|
<artifactId>jclouds-core</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<type>test-jar</type>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-io</groupId>
|
||||||
|
<artifactId>commons-io</artifactId>
|
||||||
|
<version>1.4</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.groupId}</groupId>
|
||||||
|
<artifactId>jclouds-blobstore</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<type>test-jar</type>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.groupId}</groupId>
|
||||||
|
<artifactId>jclouds-log4j</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<jclouds.test.initializer>org.jclouds.filesystem.integration.FilesystemTestInitializer</jclouds.test.initializer>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
</project>
|
||||||
|
|
|
@ -0,0 +1,666 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.filesystem;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
|
import static com.google.common.base.Throwables.getCausalChain;
|
||||||
|
import static com.google.common.base.Throwables.propagate;
|
||||||
|
import static com.google.common.collect.Iterables.filter;
|
||||||
|
import static com.google.common.collect.Iterables.find;
|
||||||
|
import static com.google.common.collect.Iterables.size;
|
||||||
|
import static com.google.common.collect.Iterables.transform;
|
||||||
|
import static com.google.common.collect.Lists.newArrayList;
|
||||||
|
import static com.google.common.collect.Lists.partition;
|
||||||
|
import static com.google.common.collect.Maps.newHashMap;
|
||||||
|
import static com.google.common.collect.Sets.filter;
|
||||||
|
import static com.google.common.collect.Sets.newTreeSet;
|
||||||
|
import static com.google.common.io.ByteStreams.toByteArray;
|
||||||
|
import static com.google.common.util.concurrent.Futures.immediateFailedFuture;
|
||||||
|
import static com.google.common.util.concurrent.Futures.immediateFuture;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInput;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutput;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.SortedSet;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Named;
|
||||||
|
|
||||||
|
import org.jclouds.Constants;
|
||||||
|
import org.jclouds.blobstore.domain.Blob;
|
||||||
|
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||||
|
import org.jclouds.blobstore.domain.MutableBlobMetadata;
|
||||||
|
import org.jclouds.blobstore.domain.MutableStorageMetadata;
|
||||||
|
import org.jclouds.blobstore.domain.PageSet;
|
||||||
|
import org.jclouds.blobstore.domain.StorageMetadata;
|
||||||
|
import org.jclouds.blobstore.domain.StorageType;
|
||||||
|
import org.jclouds.blobstore.domain.Blob.Factory;
|
||||||
|
import org.jclouds.blobstore.domain.internal.MutableStorageMetadataImpl;
|
||||||
|
import org.jclouds.blobstore.domain.internal.PageSetImpl;
|
||||||
|
import org.jclouds.blobstore.functions.HttpGetOptionsListToGetOptions;
|
||||||
|
import org.jclouds.blobstore.internal.BaseAsyncBlobStore;
|
||||||
|
import org.jclouds.blobstore.options.GetOptions;
|
||||||
|
import org.jclouds.blobstore.options.ListContainerOptions;
|
||||||
|
import org.jclouds.blobstore.strategy.IfDirectoryReturnNameStrategy;
|
||||||
|
import org.jclouds.blobstore.util.BlobUtils;
|
||||||
|
import org.jclouds.crypto.Crypto;
|
||||||
|
import org.jclouds.crypto.CryptoStreams;
|
||||||
|
import org.jclouds.date.DateService;
|
||||||
|
import org.jclouds.domain.Location;
|
||||||
|
import org.jclouds.filesystem.strategy.FilesystemStorageStrategy;
|
||||||
|
import org.jclouds.http.HttpCommand;
|
||||||
|
import org.jclouds.http.HttpRequest;
|
||||||
|
import org.jclouds.http.HttpResponse;
|
||||||
|
import org.jclouds.http.HttpResponseException;
|
||||||
|
import org.jclouds.http.options.HttpRequestOptions;
|
||||||
|
import org.jclouds.io.Payloads;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.base.Predicate;
|
||||||
|
import com.google.common.base.Supplier;
|
||||||
|
import com.google.common.base.Throwables;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
import com.google.common.util.concurrent.Futures;
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
import com.google.inject.internal.Nullable;
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.PathParam;
|
||||||
|
import org.jclouds.blobstore.BlobStoreContext;
|
||||||
|
import org.jclouds.blobstore.ContainerNotFoundException;
|
||||||
|
import org.jclouds.blobstore.KeyNotFoundException;
|
||||||
|
import org.jclouds.blobstore.domain.internal.MutableBlobMetadataImpl;
|
||||||
|
import org.jclouds.filesystem.predicates.validators.FilesystemContainerNameValidator;
|
||||||
|
import org.jclouds.io.Payload;
|
||||||
|
import org.jclouds.io.payloads.FilePayload;
|
||||||
|
import org.jclouds.logging.Logger;
|
||||||
|
import org.jclouds.rest.annotations.ParamValidators;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Preconditions:
|
||||||
|
* Blob name cannot start with / char (or \ under windows)
|
||||||
|
*
|
||||||
|
* @author Alfredo "Rainbowbreeze" Morresi
|
||||||
|
*/
|
||||||
|
public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
protected Logger logger = Logger.NULL;
|
||||||
|
|
||||||
|
protected final DateService dateService;
|
||||||
|
protected final Crypto crypto;
|
||||||
|
protected final HttpGetOptionsListToGetOptions httpGetOptionsConverter;
|
||||||
|
protected final IfDirectoryReturnNameStrategy ifDirectoryReturnName;
|
||||||
|
protected final Factory blobFactory;
|
||||||
|
protected final FilesystemStorageStrategy storageStrategy;
|
||||||
|
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected FilesystemAsyncBlobStore(BlobStoreContext context, DateService dateService, Crypto crypto,
|
||||||
|
HttpGetOptionsListToGetOptions httpGetOptionsConverter,
|
||||||
|
IfDirectoryReturnNameStrategy ifDirectoryReturnName, Blob.Factory blobFactory, BlobUtils blobUtils,
|
||||||
|
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService service,
|
||||||
|
Supplier<Location> defaultLocation,
|
||||||
|
Supplier<Set<? extends Location>> locations,
|
||||||
|
FilesystemStorageStrategy storageStrategy) {
|
||||||
|
super(context, blobUtils, service, defaultLocation, locations);
|
||||||
|
//super(context, blobUtils, service, null, null);
|
||||||
|
this.blobFactory = blobFactory;
|
||||||
|
this.dateService = dateService;
|
||||||
|
this.crypto = crypto;
|
||||||
|
this.httpGetOptionsConverter = httpGetOptionsConverter;
|
||||||
|
this.ifDirectoryReturnName = ifDirectoryReturnName;
|
||||||
|
this.storageStrategy = checkNotNull(storageStrategy, "Storage strategy");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* default maxResults is 1000
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<PageSet<? extends StorageMetadata>> list(final String container, ListContainerOptions options) {
|
||||||
|
|
||||||
|
// Check if the container exists
|
||||||
|
if (!containerExistsSyncImpl(container)) {
|
||||||
|
return immediateFailedFuture(cnfe(container));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loading blobs from container
|
||||||
|
Iterable<String> blobBelongingToContainer = null;
|
||||||
|
try {
|
||||||
|
blobBelongingToContainer = storageStrategy.getBlobKeysInsideContainer(container);
|
||||||
|
} catch(IOException e) {
|
||||||
|
logger.error(e,
|
||||||
|
"An error occurred loading blobs contained into container %s",
|
||||||
|
container);
|
||||||
|
Throwables.propagate(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SortedSet<StorageMetadata> contents = newTreeSet(transform(blobBelongingToContainer,
|
||||||
|
new Function<String, StorageMetadata>() {
|
||||||
|
public StorageMetadata apply(String key) {
|
||||||
|
Blob oldBlob = loadFileBlob(container, key);
|
||||||
|
|
||||||
|
checkState(oldBlob != null, "blob " + key + " is not present although it was in the list of "
|
||||||
|
+ container);
|
||||||
|
checkState(oldBlob.getMetadata() != null, "blob " + container + "/" + key + " has no metadata");
|
||||||
|
MutableBlobMetadata md = copy(oldBlob.getMetadata());
|
||||||
|
String directoryName = ifDirectoryReturnName.execute(md);
|
||||||
|
if (directoryName != null) {
|
||||||
|
md.setName(directoryName);
|
||||||
|
md.setType(StorageType.RELATIVE_PATH);
|
||||||
|
}
|
||||||
|
return md;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
String marker = null;
|
||||||
|
if(options!=null) {
|
||||||
|
if (options.getMarker() != null) {
|
||||||
|
final String finalMarker = options.getMarker();
|
||||||
|
StorageMetadata lastMarkerMetadata = find(contents, new Predicate<StorageMetadata>() {
|
||||||
|
public boolean apply(StorageMetadata metadata) {
|
||||||
|
return metadata.getName().equals(finalMarker);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
contents = contents.tailSet(lastMarkerMetadata);
|
||||||
|
contents.remove(lastMarkerMetadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String prefix = options.getDir();
|
||||||
|
if (prefix != null) {
|
||||||
|
contents = newTreeSet(filter(contents, new Predicate<StorageMetadata>() {
|
||||||
|
public boolean apply(StorageMetadata o) {
|
||||||
|
return (o != null && o.getName().startsWith(prefix) && !o.getName().equals(prefix));
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer maxResults = options.getMaxResults() != null ? options.getMaxResults() : 1000;
|
||||||
|
if (contents.size() > 0) {
|
||||||
|
SortedSet<StorageMetadata> contentsSlice = firstSliceOfSize(contents, maxResults);
|
||||||
|
if (!contentsSlice.contains(contents.last())) {
|
||||||
|
// Partial listing
|
||||||
|
marker = contentsSlice.last().getName();
|
||||||
|
} else {
|
||||||
|
marker = null;
|
||||||
|
}
|
||||||
|
contents = contentsSlice;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String delimiter = options.isRecursive() ? null : File.separator;
|
||||||
|
if (delimiter != null) {
|
||||||
|
SortedSet<String> commonPrefixes = null;
|
||||||
|
Iterable<String> iterable = transform(contents, new CommonPrefixes(prefix != null ? prefix : null, delimiter));
|
||||||
|
commonPrefixes = iterable != null ? newTreeSet(iterable) : new TreeSet<String>();
|
||||||
|
commonPrefixes.remove(CommonPrefixes.NO_PREFIX);
|
||||||
|
|
||||||
|
contents = newTreeSet(filter(contents, new DelimiterFilter(prefix != null ? prefix : null, delimiter)));
|
||||||
|
|
||||||
|
Iterables.<StorageMetadata> addAll(contents, transform(commonPrefixes,
|
||||||
|
new Function<String, StorageMetadata>() {
|
||||||
|
public StorageMetadata apply(String o) {
|
||||||
|
MutableStorageMetadata md = new MutableStorageMetadataImpl();
|
||||||
|
md.setType(StorageType.RELATIVE_PATH);
|
||||||
|
md.setName(o);
|
||||||
|
return md;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim metadata, if the response isn't supposed to be detailed.
|
||||||
|
if (!options.isDetailed()) {
|
||||||
|
for (StorageMetadata md : contents) {
|
||||||
|
md.getUserMetadata().clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Futures.<PageSet<? extends StorageMetadata>> immediateFuture(new PageSetImpl<StorageMetadata>(contents,
|
||||||
|
marker));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private ContainerNotFoundException cnfe(final String name) {
|
||||||
|
return new ContainerNotFoundException(name, String.format("container %s not in filesystem", name));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MutableBlobMetadata copy(MutableBlobMetadata in) {
|
||||||
|
ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
||||||
|
ObjectOutput os;
|
||||||
|
try {
|
||||||
|
os = new ObjectOutputStream(bout);
|
||||||
|
os.writeObject(in);
|
||||||
|
ObjectInput is = new ObjectInputStream(new ByteArrayInputStream(bout.toByteArray()));
|
||||||
|
MutableBlobMetadata metadata = (MutableBlobMetadata) is.readObject();
|
||||||
|
convertUserMetadataKeysToLowercase(metadata);
|
||||||
|
return metadata;
|
||||||
|
} catch (Exception e) {
|
||||||
|
propagate(e);
|
||||||
|
assert false : "exception should have propagated: " + e;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void convertUserMetadataKeysToLowercase(MutableBlobMetadata metadata) {
|
||||||
|
Map<String, String> lowerCaseUserMetadata = newHashMap();
|
||||||
|
for (Entry<String, String> entry : metadata.getUserMetadata().entrySet()) {
|
||||||
|
lowerCaseUserMetadata.put(entry.getKey().toLowerCase(), entry.getValue());
|
||||||
|
}
|
||||||
|
metadata.setUserMetadata(lowerCaseUserMetadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MutableBlobMetadata copy(MutableBlobMetadata in, String newKey) {
|
||||||
|
MutableBlobMetadata newMd = copy(in);
|
||||||
|
newMd.setName(newKey);
|
||||||
|
return newMd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<Void> removeBlob(final String container, final String key) {
|
||||||
|
storageStrategy.removeBlob(container, key);
|
||||||
|
return immediateFuture(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<Boolean> containerExists(final String containerName) {
|
||||||
|
boolean exists = containerExistsSyncImpl(containerName);
|
||||||
|
return immediateFuture(exists);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<PageSet<? extends StorageMetadata>> list() {
|
||||||
|
Iterable<String> containers = storageStrategy.getAllContainerNames();
|
||||||
|
|
||||||
|
return Futures.<PageSet<? extends StorageMetadata>> immediateFuture(new PageSetImpl<StorageMetadata>(transform(
|
||||||
|
containers, new Function<String, StorageMetadata>() {
|
||||||
|
public StorageMetadata apply(String name) {
|
||||||
|
MutableStorageMetadata cmd = create();
|
||||||
|
cmd.setName(name);
|
||||||
|
cmd.setType(StorageType.CONTAINER);
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
}), null));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected MutableStorageMetadata create() {
|
||||||
|
return new MutableStorageMetadataImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Path("{container}")
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<Boolean> createContainerInLocation(
|
||||||
|
final Location location,
|
||||||
|
@PathParam("container") @ParamValidators( { FilesystemContainerNameValidator.class }) String name) {
|
||||||
|
boolean result = storageStrategy.createContainer(name);
|
||||||
|
return immediateFuture(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFirstQueryOrNull(String string, @Nullable HttpRequestOptions options) {
|
||||||
|
if (options == null)
|
||||||
|
return null;
|
||||||
|
Collection<String> values = options.buildQueryParameters().get(string);
|
||||||
|
return (values != null && values.size() >= 1) ? values.iterator().next() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the blob with the given key belonging to the container with the given
|
||||||
|
* name. There must exist a resource on the file system whose complete name
|
||||||
|
* is given concatenating the container name and the key
|
||||||
|
*
|
||||||
|
* @param container it's the name of the container the blob belongs to
|
||||||
|
* @param key it's the key of the blob
|
||||||
|
*
|
||||||
|
* @return the blob belonging to the given container with the given key
|
||||||
|
*/
|
||||||
|
private Blob loadFileBlob(final String container, final String key) {
|
||||||
|
logger.debug("Opening blob in container: %s - %s", container, key);
|
||||||
|
File blobPayload = storageStrategy.getFileForBlobKey(container, key);
|
||||||
|
|
||||||
|
Payload payload = new FilePayload(blobPayload);
|
||||||
|
// Loading object metadata
|
||||||
|
MutableBlobMetadata metadata = new MutableBlobMetadataImpl();
|
||||||
|
metadata.setName(key);
|
||||||
|
metadata.setLastModified(new Date(blobPayload.lastModified()));
|
||||||
|
metadata.setSize(blobPayload.length());
|
||||||
|
// TODO What about the MD5? are we supposed to calculate it each time we load
|
||||||
|
//the file?
|
||||||
|
try {
|
||||||
|
payload = Payloads.calculateMD5(payload);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("An error occurred calculating MD5 for blob %s from container ", key, container);
|
||||||
|
Throwables.propagateIfPossible(e);
|
||||||
|
}
|
||||||
|
metadata.setContentType("");
|
||||||
|
String eTag = CryptoStreams.hex(payload.getContentMD5());
|
||||||
|
metadata.setETag(eTag);
|
||||||
|
// Creating new blob object
|
||||||
|
Blob blob = blobFactory.create(metadata);
|
||||||
|
blob.setPayload(blobPayload);
|
||||||
|
return blob;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
protected static class DelimiterFilter implements Predicate<StorageMetadata> {
|
||||||
|
private final String prefix;
|
||||||
|
private final String delimiter;
|
||||||
|
|
||||||
|
public DelimiterFilter(String prefix, String delimiter) {
|
||||||
|
this.prefix = prefix;
|
||||||
|
this.delimiter = delimiter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean apply(StorageMetadata metadata) {
|
||||||
|
if (prefix == null)
|
||||||
|
return metadata.getName().indexOf(delimiter) == -1;
|
||||||
|
// ensure we don't accidentally append twice
|
||||||
|
String toMatch = prefix.endsWith("/") ? prefix : prefix + delimiter;
|
||||||
|
if (metadata.getName().startsWith(toMatch)) {
|
||||||
|
String unprefixedName = metadata.getName().replaceFirst(toMatch, "");
|
||||||
|
if (unprefixedName.equals("")) {
|
||||||
|
// we are the prefix in this case, return false
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return unprefixedName.indexOf(delimiter) == -1;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static class CommonPrefixes implements Function<StorageMetadata, String> {
|
||||||
|
private final String prefix;
|
||||||
|
private final String delimiter;
|
||||||
|
public static final String NO_PREFIX = "NO_PREFIX";
|
||||||
|
|
||||||
|
public CommonPrefixes(String prefix, String delimiter) {
|
||||||
|
this.prefix = prefix;
|
||||||
|
this.delimiter = delimiter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String apply(StorageMetadata metadata) {
|
||||||
|
String working = metadata.getName();
|
||||||
|
if (prefix != null) {
|
||||||
|
// ensure we don't accidentally append twice
|
||||||
|
String toMatch = prefix.endsWith("/") ? prefix : prefix + delimiter;
|
||||||
|
if (working.startsWith(toMatch)) {
|
||||||
|
working = working.replaceFirst(toMatch, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (working.contains(delimiter)) {
|
||||||
|
return working.substring(0, working.indexOf(delimiter));
|
||||||
|
}
|
||||||
|
return NO_PREFIX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T extends Comparable<?>> SortedSet<T> firstSliceOfSize(Iterable<T> elements, int size) {
|
||||||
|
List<List<T>> slices = partition(newArrayList(elements), size);
|
||||||
|
return newTreeSet(slices.get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpResponseException returnResponseException(int code) {
|
||||||
|
HttpResponse response = null;
|
||||||
|
response = new HttpResponse(code, null, null);
|
||||||
|
return new HttpResponseException(new HttpCommand() {
|
||||||
|
|
||||||
|
public int getRedirectCount() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int incrementRedirectCount() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isReplayable() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Exception getException() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFailureCount() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpRequest getRequest() {
|
||||||
|
return new HttpRequest("GET", URI.create("http://stub"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int incrementFailureCount() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setException(Exception exception) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<String> putBlob(String containerName, Blob object) {
|
||||||
|
String blobKey = object.getMetadata().getName();
|
||||||
|
|
||||||
|
logger.debug("Put object with key [%s] to container [%s]", blobKey, containerName);
|
||||||
|
String eTag = getEtag(object);
|
||||||
|
try {
|
||||||
|
//TODO
|
||||||
|
//must override existing file?
|
||||||
|
|
||||||
|
storageStrategy.writePayloadOnFile(containerName, blobKey, object.getPayload());
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error(e, "An error occurred storing the new object with name [%s] to container [%s].",
|
||||||
|
blobKey,
|
||||||
|
containerName);
|
||||||
|
Throwables.propagate(e);
|
||||||
|
}
|
||||||
|
return immediateFuture(eTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<Boolean> blobExists(final String containerName, final String key) {
|
||||||
|
return immediateFuture(storageStrategy.blobExists(containerName, key));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<Blob> getBlob(final String containerName, final String key, GetOptions options) {
|
||||||
|
logger.debug("Retrieving blob with key %s from container %s", key,containerName);
|
||||||
|
// If the container doesn't exist, an exception is thrown
|
||||||
|
if(!containerExistsSyncImpl(containerName)) {
|
||||||
|
logger.debug("Container %s does not exist", containerName);
|
||||||
|
return immediateFailedFuture(cnfe(containerName));
|
||||||
|
}
|
||||||
|
// If the blob doesn't exist, a null object is returned
|
||||||
|
if (!storageStrategy.blobExists(containerName, key)) {
|
||||||
|
logger.debug("Item %s does not exist in container %s", key, containerName);
|
||||||
|
return immediateFuture(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
Blob blob = loadFileBlob(containerName, key);
|
||||||
|
|
||||||
|
if(options!=null) {
|
||||||
|
if (options.getIfMatch() != null) {
|
||||||
|
if (!blob.getMetadata().getETag().equals(options.getIfMatch()))
|
||||||
|
return immediateFailedFuture(returnResponseException(412));
|
||||||
|
}
|
||||||
|
if (options.getIfNoneMatch() != null) {
|
||||||
|
if (blob.getMetadata().getETag().equals(options.getIfNoneMatch()))
|
||||||
|
return immediateFailedFuture(returnResponseException(304));
|
||||||
|
}
|
||||||
|
if (options.getIfModifiedSince() != null) {
|
||||||
|
Date modifiedSince = options.getIfModifiedSince();
|
||||||
|
if (blob.getMetadata().getLastModified().before(modifiedSince)) {
|
||||||
|
HttpResponse response = new HttpResponse(304, null, null);
|
||||||
|
return immediateFailedFuture(new HttpResponseException(String.format("%1$s is before %2$s", blob
|
||||||
|
.getMetadata().getLastModified(), modifiedSince), null, response));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (options.getIfUnmodifiedSince() != null) {
|
||||||
|
Date unmodifiedSince = options.getIfUnmodifiedSince();
|
||||||
|
if (blob.getMetadata().getLastModified().after(unmodifiedSince)) {
|
||||||
|
HttpResponse response = new HttpResponse(412, null, null);
|
||||||
|
return immediateFailedFuture(new HttpResponseException(String.format("%1$s is after %2$s", blob
|
||||||
|
.getMetadata().getLastModified(), unmodifiedSince), null, response));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.getRanges() != null && options.getRanges().size() > 0) {
|
||||||
|
byte[] data;
|
||||||
|
try {
|
||||||
|
data = toByteArray(blob.getPayload().getInput());
|
||||||
|
} catch (IOException e) {
|
||||||
|
return immediateFailedFuture(new RuntimeException(e));
|
||||||
|
}
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
for (String s : options.getRanges()) {
|
||||||
|
if (s.startsWith("-")) {
|
||||||
|
int length = Integer.parseInt(s.substring(1));
|
||||||
|
out.write(data, data.length - length, length);
|
||||||
|
} else if (s.endsWith("-")) {
|
||||||
|
int offset = Integer.parseInt(s.substring(0, s.length() - 1));
|
||||||
|
out.write(data, offset, data.length - offset);
|
||||||
|
} else if (s.contains("-")) {
|
||||||
|
String[] firstLast = s.split("\\-");
|
||||||
|
int offset = Integer.parseInt(firstLast[0]);
|
||||||
|
int last = Integer.parseInt(firstLast[1]);
|
||||||
|
int length = (last < data.length) ? last + 1 : data.length - offset;
|
||||||
|
out.write(data, offset, length);
|
||||||
|
} else {
|
||||||
|
return immediateFailedFuture(new IllegalArgumentException("first and last were null!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
blob.setPayload(out.toByteArray());
|
||||||
|
blob.getMetadata().setSize(new Long(data.length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkNotNull(blob.getPayload(), "payload " + blob);
|
||||||
|
return immediateFuture(blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<BlobMetadata> blobMetadata(final String container, final String key) {
|
||||||
|
try {
|
||||||
|
Blob blob = getBlob(container, key).get();
|
||||||
|
return immediateFuture(blob != null ? (BlobMetadata) copy(blob.getMetadata()) : null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (size(filter(getCausalChain(e), KeyNotFoundException.class)) >= 1)
|
||||||
|
return immediateFuture(null);
|
||||||
|
return immediateFailedFuture(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean deleteAndVerifyContainerGone(String container) {
|
||||||
|
storageStrategy.deleteContainer(container);
|
||||||
|
return containerExistsSyncImpl(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override parent method because it uses strange futures and listenables
|
||||||
|
* that creates problem in the test if more than one test that deletes the
|
||||||
|
* container is executed
|
||||||
|
* @param container
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<Void> deleteContainer(String container) {
|
||||||
|
deleteAndVerifyContainerGone(container);
|
||||||
|
return immediateFuture(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Each container is a directory, so in order to check if a container exists
|
||||||
|
* the corresponding directory must exists. Synchronous implementation
|
||||||
|
* @param containerName
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private boolean containerExistsSyncImpl(String containerName) {
|
||||||
|
return storageStrategy.containerExists(containerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Calculates the object MD5 and returns it as eTag
|
||||||
|
* @param object
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private String getEtag(Blob object) {
|
||||||
|
try {
|
||||||
|
Payloads.calculateMD5(object, crypto.md5());
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.error(ex, "An error occurred calculating MD5 for object with name %s.",
|
||||||
|
object.getMetadata().getName());
|
||||||
|
Throwables.propagate(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
String eTag = CryptoStreams.hex(object.getPayload().getContentMD5());
|
||||||
|
return eTag;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.filesystem;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.jclouds.blobstore.BlobStore;
|
||||||
|
import org.jclouds.concurrent.Timeout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alfredo "Rainbowbreeze" Morresi
|
||||||
|
*/
|
||||||
|
@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS) public interface FilesystemBlobStore extends BlobStore {
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.filesystem;
|
||||||
|
|
||||||
|
import com.google.inject.Module;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
|
import org.jclouds.blobstore.AsyncBlobStore;
|
||||||
|
import org.jclouds.blobstore.BlobStore;
|
||||||
|
import org.jclouds.blobstore.BlobStoreContextBuilder;
|
||||||
|
import org.jclouds.filesystem.config.FilesystemBlobStoreContextModule;
|
||||||
|
import org.jclouds.filesystem.config.FilesystemBlobStoreModule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alfredo "Rainbowbreeze" Morresi
|
||||||
|
*/
|
||||||
|
public class FilesystemBlobStoreContextBuilder extends
|
||||||
|
BlobStoreContextBuilder<BlobStore, AsyncBlobStore> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is only to have the same syntax.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public FilesystemBlobStoreContextBuilder() {
|
||||||
|
this(new Properties());
|
||||||
|
}
|
||||||
|
|
||||||
|
public FilesystemBlobStoreContextBuilder(Properties props) {
|
||||||
|
super(BlobStore.class, AsyncBlobStore.class, props);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addContextModule(List<Module> modules) {
|
||||||
|
modules.add(new FilesystemBlobStoreContextModule());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addClientModule(List<Module> modules) {
|
||||||
|
modules.add(new FilesystemBlobStoreModule());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
* ====================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To change this template, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jclouds.filesystem;
|
||||||
|
|
||||||
|
import static org.jclouds.Constants.PROPERTY_API_VERSION;
|
||||||
|
import static org.jclouds.Constants.PROPERTY_ENDPOINT;
|
||||||
|
import static org.jclouds.Constants.PROPERTY_IO_WORKER_THREADS;
|
||||||
|
import static org.jclouds.Constants.PROPERTY_IDENTITY;
|
||||||
|
import static org.jclouds.Constants.PROPERTY_USER_THREADS;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
import org.jclouds.PropertiesBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author rainbowbreeze
|
||||||
|
*/
|
||||||
|
public class FilesystemBlobStorePropertiesBuilder extends PropertiesBuilder {
|
||||||
|
@Override
|
||||||
|
protected Properties defaultProperties() {
|
||||||
|
Properties properties = super.defaultProperties();
|
||||||
|
properties.setProperty(PROPERTY_ENDPOINT, "http://localhost/transient");
|
||||||
|
properties.setProperty(PROPERTY_API_VERSION, "1");
|
||||||
|
properties.setProperty(PROPERTY_IDENTITY, System.getProperty("user.name"));
|
||||||
|
properties.setProperty(PROPERTY_USER_THREADS, "0");
|
||||||
|
properties.setProperty(PROPERTY_IO_WORKER_THREADS, "0");
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FilesystemBlobStorePropertiesBuilder(Properties properties) {
|
||||||
|
super(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.filesystem.config;
|
||||||
|
|
||||||
|
import com.google.common.base.Supplier;
|
||||||
|
import com.google.common.base.Suppliers;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.inject.AbstractModule;
|
||||||
|
import com.google.inject.Provides;
|
||||||
|
import com.google.inject.Scopes;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
|
import com.google.inject.TypeLiteral;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.jclouds.blobstore.AsyncBlobStore;
|
||||||
|
import org.jclouds.blobstore.BlobStore;
|
||||||
|
import org.jclouds.blobstore.BlobStoreContext;
|
||||||
|
import org.jclouds.blobstore.attr.ConsistencyModel;
|
||||||
|
import org.jclouds.blobstore.config.BlobStoreMapModule;
|
||||||
|
import org.jclouds.blobstore.config.BlobStoreObjectModule;
|
||||||
|
import org.jclouds.blobstore.internal.BlobStoreContextImpl;
|
||||||
|
import org.jclouds.blobstore.util.BlobUtils;
|
||||||
|
import org.jclouds.domain.Location;
|
||||||
|
import org.jclouds.domain.LocationScope;
|
||||||
|
import org.jclouds.domain.internal.LocationImpl;
|
||||||
|
import org.jclouds.filesystem.FilesystemBlobStore;
|
||||||
|
import org.jclouds.filesystem.predicates.validators.FilesystemBlobKeyValidator;
|
||||||
|
import org.jclouds.filesystem.predicates.validators.FilesystemContainerNameValidator;
|
||||||
|
import org.jclouds.filesystem.predicates.validators.internal.FilesystemBlobKeyValidatorImpl;
|
||||||
|
import org.jclouds.filesystem.predicates.validators.internal.FilesystemContainerNameValidatorImpl;
|
||||||
|
import org.jclouds.filesystem.strategy.FilesystemStorageStrategy;
|
||||||
|
import org.jclouds.filesystem.strategy.internal.FilesystemStorageStrategyImpl;
|
||||||
|
import org.jclouds.filesystem.util.internal.FileSystemBlobUtilsImpl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alfredo "Rainbowbreeze" Morresi
|
||||||
|
*/
|
||||||
|
public class FilesystemBlobStoreContextModule extends AbstractModule {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
bind(new TypeLiteral<BlobStoreContext>() {
|
||||||
|
}).to(new TypeLiteral<BlobStoreContextImpl<FilesystemBlobStore, AsyncBlobStore>>() {
|
||||||
|
}).in(Scopes.SINGLETON);
|
||||||
|
install(new BlobStoreObjectModule());
|
||||||
|
install(new BlobStoreMapModule());
|
||||||
|
bind(ConsistencyModel.class).toInstance(ConsistencyModel.STRICT);
|
||||||
|
bind(FilesystemStorageStrategy.class).to(FilesystemStorageStrategyImpl.class);
|
||||||
|
bind(BlobUtils.class).to(FileSystemBlobUtilsImpl.class);
|
||||||
|
bind(FilesystemBlobKeyValidator.class).to(FilesystemBlobKeyValidatorImpl.class);
|
||||||
|
bind(FilesystemContainerNameValidator.class).to(FilesystemContainerNameValidatorImpl.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
BlobStore provide(FilesystemBlobStore in) {
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
Supplier<Set<? extends Location>> provideLocations(Supplier<Location> defaultLocation) {
|
||||||
|
return Suppliers.<Set<? extends Location>> ofInstance(ImmutableSet.of(defaultLocation.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
Supplier<Location> provideDefaultLocation() {
|
||||||
|
return Suppliers
|
||||||
|
.<Location> ofInstance(new LocationImpl(LocationScope.PROVIDER, "filesystem", "filesystem", null));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ====================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jclouds.filesystem.config;
|
||||||
|
|
||||||
|
import org.jclouds.blobstore.AsyncBlobStore;
|
||||||
|
import org.jclouds.filesystem.FilesystemAsyncBlobStore;
|
||||||
|
import org.jclouds.filesystem.FilesystemBlobStore;
|
||||||
|
import org.jclouds.rest.config.RestClientModule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alfredo "Rainbowbreeze" Morresi
|
||||||
|
*/
|
||||||
|
public class FilesystemBlobStoreModule extends RestClientModule<FilesystemBlobStore, AsyncBlobStore> {
|
||||||
|
|
||||||
|
public FilesystemBlobStoreModule() {
|
||||||
|
super(FilesystemBlobStore.class, AsyncBlobStore.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
super.configure();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void bindAsyncClient() {
|
||||||
|
bind(AsyncBlobStore.class).to(FilesystemAsyncBlobStore.class).asEagerSingleton();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.filesystem.predicates.validators;
|
||||||
|
|
||||||
|
import org.jclouds.predicates.Validator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates name for filesystem container blob keys
|
||||||
|
*
|
||||||
|
* @see org.jclouds.rest.InputParamValidator
|
||||||
|
* @see org.jclouds.predicates.Validator
|
||||||
|
*
|
||||||
|
* @author Alfredo "Rainbowbreeze" Morresi
|
||||||
|
*/
|
||||||
|
public abstract class FilesystemBlobKeyValidator extends Validator<String> {
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.filesystem.predicates.validators;
|
||||||
|
|
||||||
|
import org.jclouds.predicates.Validator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates container name for filesystem provider
|
||||||
|
*
|
||||||
|
* @see org.jclouds.rest.InputParamValidator
|
||||||
|
* @see org.jclouds.predicates.Validator
|
||||||
|
*
|
||||||
|
* @author Alfredo "Rainbowbreeze" Morresi
|
||||||
|
*/
|
||||||
|
public abstract class FilesystemContainerNameValidator extends Validator<String> {
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.filesystem.predicates.validators.internal;
|
||||||
|
|
||||||
|
import com.google.inject.Singleton;
|
||||||
|
import java.io.File;
|
||||||
|
import org.jclouds.filesystem.predicates.validators.FilesystemBlobKeyValidator;
|
||||||
|
import org.jclouds.predicates.Validator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates name for filesystem container blob keys implementation
|
||||||
|
*
|
||||||
|
* @see org.jclouds.rest.InputParamValidator
|
||||||
|
* @see org.jclouds.predicates.Validator
|
||||||
|
*
|
||||||
|
* @author Alfredo "Rainbowbreeze" Morresi
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class FilesystemBlobKeyValidatorImpl extends FilesystemBlobKeyValidator {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validate(String name) throws IllegalArgumentException {
|
||||||
|
//blob key cannot be null or empty
|
||||||
|
if (name == null || name.length() < 1)
|
||||||
|
throw new IllegalArgumentException("Blob key can't be null or empty");
|
||||||
|
|
||||||
|
//blobkey cannot start with / (or \ in Windows) character
|
||||||
|
if (name.startsWith(File.separator))
|
||||||
|
throw new IllegalArgumentException(String.format(
|
||||||
|
"Blob key '%s' cannot start with character %s", name, File.separator));
|
||||||
|
|
||||||
|
//blobkey cannot end with / (or \ in Windows) character
|
||||||
|
if (name.endsWith(File.separator))
|
||||||
|
throw new IllegalArgumentException(String.format(
|
||||||
|
"Blob key '%s' cannot end with character %s", name, File.separator));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.filesystem.predicates.validators.internal;
|
||||||
|
|
||||||
|
import com.google.inject.Singleton;
|
||||||
|
import java.io.File;
|
||||||
|
import org.jclouds.filesystem.predicates.validators.FilesystemContainerNameValidator;
|
||||||
|
import org.jclouds.predicates.Validator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates container name for filesystem provider implementation
|
||||||
|
*
|
||||||
|
* @see org.jclouds.rest.InputParamValidator
|
||||||
|
* @see org.jclouds.predicates.Validator
|
||||||
|
*
|
||||||
|
* @author Alfredo "Rainbowbreeze" Morresi
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class FilesystemContainerNameValidatorImpl extends FilesystemContainerNameValidator {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validate(String name) throws IllegalArgumentException {
|
||||||
|
//container name cannot be null or empty
|
||||||
|
if (name == null || name.length() < 1)
|
||||||
|
throw new IllegalArgumentException("Container name can't be null or empty");
|
||||||
|
|
||||||
|
//container name cannot contains / (or \ in Windows) character
|
||||||
|
if (name.contains(File.separator))
|
||||||
|
throw new IllegalArgumentException(String.format(
|
||||||
|
"Container name '%s' cannot contain character %s", name, File.separator));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.filesystem.reference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common constants used in filesystem provider
|
||||||
|
*
|
||||||
|
* @author Alfredo "Rainbowbreeze" Morresi
|
||||||
|
*/
|
||||||
|
public class FilesystemConstants {
|
||||||
|
|
||||||
|
/** Specify the base directory where provider starts its file operations - must exists */
|
||||||
|
public static final String PROPERTY_BASEDIR = "FileSystemAsyncBlobStore-basedir";
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,167 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.filesystem.strategy;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import org.jclouds.blobstore.domain.Blob;
|
||||||
|
import org.jclouds.blobstore.options.ListContainerOptions;
|
||||||
|
import org.jclouds.filesystem.predicates.validators.FilesystemContainerNameValidator;
|
||||||
|
import org.jclouds.io.Payload;
|
||||||
|
import org.jclouds.rest.annotations.ParamValidators;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strategy for filesystem operations related to container and blob
|
||||||
|
*
|
||||||
|
* @author Alfredo "Rainbowbreeze" Morresi
|
||||||
|
*/
|
||||||
|
public interface FilesystemStorageStrategy {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new container
|
||||||
|
*
|
||||||
|
* @param container
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
boolean createContainer(String container);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a container and all its content
|
||||||
|
* @param container
|
||||||
|
*/
|
||||||
|
void deleteContainer(String container);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a container exists
|
||||||
|
* @param container
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
boolean containerExists(String container);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Empty the container of its content (files and subdirectories), but doesn't
|
||||||
|
* delete the container itself
|
||||||
|
* @param container
|
||||||
|
*/
|
||||||
|
void clearContainer(final String container);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like {@link #clearContainer(String)} except you can use options to do things like recursive
|
||||||
|
* deletes, or clear at a different path than root.
|
||||||
|
*
|
||||||
|
* @param container
|
||||||
|
* what to clear
|
||||||
|
* @param options
|
||||||
|
* recursion and path to clear
|
||||||
|
*/
|
||||||
|
void clearContainer(String container, ListContainerOptions options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an iterator that reports all the containers under base path
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Iterable<String> getAllContainerNames();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if a directory exists
|
||||||
|
*
|
||||||
|
* @param container
|
||||||
|
* container where the directory resides
|
||||||
|
* @param directory
|
||||||
|
* full path to the directory
|
||||||
|
*/
|
||||||
|
boolean directoryExists(String container, String directory);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a folder or a directory marker depending on the service
|
||||||
|
*
|
||||||
|
* @param container
|
||||||
|
* container to create the directory in
|
||||||
|
* @param directory
|
||||||
|
* full path to the directory
|
||||||
|
*/
|
||||||
|
void createDirectory(String container, String directory);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a folder or a directory marker depending on the service
|
||||||
|
*
|
||||||
|
* @param container
|
||||||
|
* container to delete the directory from
|
||||||
|
* @param directory
|
||||||
|
* full path to the directory to delete
|
||||||
|
*/
|
||||||
|
void deleteDirectory(String container, String directory);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new blob
|
||||||
|
* @param name
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Blob newBlob(String name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param container
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
boolean blobExists(String container, String key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all the blobs key inside a container
|
||||||
|
* @param container
|
||||||
|
* @return
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
Iterable<String> getBlobKeysInsideContainer(String container) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Counts number of blobs inside a container
|
||||||
|
* @param container
|
||||||
|
* @param options
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
long countBlobs(String container, ListContainerOptions options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a {@link File} object that links to the blob
|
||||||
|
* @param container
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
File getFileForBlobKey(String container, String key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param container
|
||||||
|
* @param key
|
||||||
|
*/
|
||||||
|
void removeBlob(final String container, final String key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a {@link Blob} {@link Payload} into a file
|
||||||
|
* @param fileName
|
||||||
|
* @param payload
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
void writePayloadOnFile(String container, String blobKey, Payload payload) throws IOException;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,521 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.filesystem.strategy.internal;
|
||||||
|
|
||||||
|
import org.jclouds.rest.annotations.ParamValidators;
|
||||||
|
import org.jclouds.filesystem.predicates.validators.FilesystemBlobKeyValidator;
|
||||||
|
import org.jclouds.filesystem.predicates.validators.FilesystemContainerNameValidator;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import org.jclouds.blobstore.domain.Blob;
|
||||||
|
import org.jclouds.blobstore.options.ListContainerOptions;
|
||||||
|
import org.jclouds.io.Payload;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import org.apache.commons.io.filefilter.DirectoryFileFilter;
|
||||||
|
import java.util.Iterator;
|
||||||
|
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.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
|
||||||
|
*/
|
||||||
|
public class FilesystemStorageStrategyImpl implements FilesystemStorageStrategy {
|
||||||
|
|
||||||
|
private static final String BACK_SLASH = "\\";
|
||||||
|
/** The buffer size used to copy an InputStream to an OutputStream */
|
||||||
|
private static final int COPY_BUFFER_SIZE = 1024;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
protected Logger logger = Logger.NULL;
|
||||||
|
|
||||||
|
protected final Blob.Factory blobFactory;
|
||||||
|
protected final String baseDirectory;
|
||||||
|
protected final FilesystemContainerNameValidator filesystemContainerNameValidator;
|
||||||
|
protected final FilesystemBlobKeyValidator filesystemBlobKeyValidator;
|
||||||
|
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected FilesystemStorageStrategyImpl(
|
||||||
|
Blob.Factory blobFactory,
|
||||||
|
@Named(FilesystemConstants.PROPERTY_BASEDIR) String baseDir,
|
||||||
|
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
|
||||||
|
public boolean containerExists(String container) {
|
||||||
|
filesystemContainerNameValidator.validate(container);
|
||||||
|
return directoryExists(container, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean blobExists(String container, String key) {
|
||||||
|
filesystemContainerNameValidator.validate(container);
|
||||||
|
filesystemBlobKeyValidator.validate(key);
|
||||||
|
return buildPathAndChecksIfFileExists(container, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean createContainer(String container) {
|
||||||
|
logger.debug("Creating container %s", container);
|
||||||
|
filesystemContainerNameValidator.validate(container);
|
||||||
|
return createDirectoryWithResult(container, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteContainer(String container) {
|
||||||
|
filesystemContainerNameValidator.validate(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) {
|
||||||
|
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));
|
||||||
|
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]));
|
||||||
|
completePath.append(File.separator).append(normalizedToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return completePath.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Substitutes all the file separator occurrences in the path with a file
|
||||||
|
* separator for the 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove leading and trailing {@link File.separator} character from the
|
||||||
|
* string.
|
||||||
|
* @param pathToBeCleaned
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private String removeFileSeparatorFromBorders(String pathToBeCleaned) {
|
||||||
|
if (null == pathToBeCleaned || pathToBeCleaned.equals("")) return pathToBeCleaned;
|
||||||
|
|
||||||
|
int beginIndex = 0;
|
||||||
|
int endIndex = pathToBeCleaned.length();
|
||||||
|
|
||||||
|
//search for separator chars
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a directory and returns the result
|
||||||
|
* @param container
|
||||||
|
* @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
|
||||||
|
if (buildPathAndChecksIfDirectoryExists(container, directory)) {
|
||||||
|
logger.debug("Directory %s already exists", directoryFullName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
File directoryToCreate = new File(directoryFullName);
|
||||||
|
boolean result = directoryToCreate.mkdirs();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy from an InputStream to an OutputStream.
|
||||||
|
*
|
||||||
|
* @param input The InputStream
|
||||||
|
* @param output The OutputStream
|
||||||
|
* @return the number of bytes copied
|
||||||
|
* @throws IOException if an error occurs
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ====================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jclouds.filesystem.util.internal;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import org.jclouds.blobstore.AsyncBlobStore;
|
||||||
|
import org.jclouds.blobstore.domain.Blob;
|
||||||
|
import org.jclouds.blobstore.options.ListContainerOptions;
|
||||||
|
import org.jclouds.blobstore.util.BlobUtils;
|
||||||
|
import org.jclouds.filesystem.strategy.FilesystemStorageStrategy;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the {@link BlobUtils} interfaced and act as a bridge to
|
||||||
|
* {@link FilesystemStorageStrategy} when used inside {@link AsyncBlobStore}
|
||||||
|
*
|
||||||
|
* @author Alfredo "Rainbowbreeze" Morresi
|
||||||
|
*/
|
||||||
|
public class FileSystemBlobUtilsImpl implements BlobUtils {
|
||||||
|
|
||||||
|
protected final FilesystemStorageStrategy storageStrategy;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public FileSystemBlobUtilsImpl(
|
||||||
|
FilesystemStorageStrategy storageStrategy) {
|
||||||
|
this.storageStrategy = checkNotNull(storageStrategy, "Filesystem Storage Strategy");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Blob newBlob(String name) {
|
||||||
|
return storageStrategy.newBlob(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean directoryExists(String containerName, String directory) {
|
||||||
|
return storageStrategy.directoryExists(containerName, directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createDirectory(String containerName, String directory) {
|
||||||
|
storageStrategy.createDirectory(containerName, directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long countBlobs(String container, ListContainerOptions options) {
|
||||||
|
return storageStrategy.countBlobs(container, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearContainer(String container, ListContainerOptions options) {
|
||||||
|
storageStrategy.clearContainer(container, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteDirectory(String container, String directory) {
|
||||||
|
storageStrategy.deleteDirectory(container, directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,846 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.filesystem;
|
||||||
|
|
||||||
|
import org.jclouds.filesystem.reference.FilesystemConstants;
|
||||||
|
import org.jclouds.filesystem.utils.TestUtils;
|
||||||
|
import com.google.inject.CreationException;
|
||||||
|
import org.jclouds.blobstore.options.GetOptions;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Properties;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.jclouds.blobstore.BlobStore;
|
||||||
|
import org.jclouds.blobstore.BlobStoreContext;
|
||||||
|
import org.jclouds.blobstore.BlobStoreContextFactory;
|
||||||
|
import org.jclouds.blobstore.ContainerNotFoundException;
|
||||||
|
import org.jclouds.blobstore.domain.Blob;
|
||||||
|
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||||
|
import org.jclouds.blobstore.domain.MutableBlobMetadata;
|
||||||
|
import org.jclouds.blobstore.domain.PageSet;
|
||||||
|
import org.jclouds.blobstore.domain.StorageMetadata;
|
||||||
|
import org.jclouds.blobstore.domain.StorageType;
|
||||||
|
import org.jclouds.blobstore.domain.internal.BlobImpl;
|
||||||
|
import org.jclouds.blobstore.options.ListContainerOptions;
|
||||||
|
import org.testng.annotations.*;
|
||||||
|
|
||||||
|
import static org.testng.Assert.*;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test class for {@link FilesystemAsyncBlobStore} class
|
||||||
|
*
|
||||||
|
* @author Alfredo "Rainbowbreeze" Morresi
|
||||||
|
*/
|
||||||
|
@Test(groups = "unit", testName = "filesystem.FilesystemAsyncBlobStoreTest", sequential = true)
|
||||||
|
public class FilesystemAsyncBlobStoreTest {
|
||||||
|
|
||||||
|
private static final String CONTAINER_NAME = "fun-blobstore-test";
|
||||||
|
private static final String TARGET_CONTAINER_NAME = TestUtils.TARGET_BASE_DIR + CONTAINER_NAME;
|
||||||
|
private static final String LOGGING_CONFIG_KEY
|
||||||
|
= "java.util.logging.config.file";
|
||||||
|
private static final String LOGGING_CONFIG_VALUE
|
||||||
|
= "src/main/resources/logging.properties";
|
||||||
|
|
||||||
|
private static final String PROVIDER = "filesystem";
|
||||||
|
|
||||||
|
|
||||||
|
static {
|
||||||
|
System.setProperty(LOGGING_CONFIG_KEY,
|
||||||
|
LOGGING_CONFIG_VALUE);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private BlobStoreContext context = null;
|
||||||
|
private BlobStore blobStore = null;
|
||||||
|
private Set<File> resourcesToBeDeleted = new HashSet<File>();
|
||||||
|
|
||||||
|
@BeforeMethod
|
||||||
|
protected void setUp() throws Exception {
|
||||||
|
//create context for filesystem container
|
||||||
|
Properties prop = new Properties();
|
||||||
|
prop.setProperty(FilesystemConstants.PROPERTY_BASEDIR, TestUtils.TARGET_BASE_DIR);
|
||||||
|
context = (BlobStoreContext) new BlobStoreContextFactory().createContext(
|
||||||
|
PROVIDER, prop);
|
||||||
|
//create a container in the default location
|
||||||
|
blobStore = context.getBlobStore();
|
||||||
|
|
||||||
|
resourcesToBeDeleted.add(new File(TestUtils.TARGET_BASE_DIR));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@AfterMethod
|
||||||
|
protected void tearDown() {
|
||||||
|
context.close();
|
||||||
|
context = null;
|
||||||
|
// freeing filesystem resources used for tests
|
||||||
|
Iterator<File> resourceToDelete = resourcesToBeDeleted.iterator();
|
||||||
|
while(resourceToDelete.hasNext()) {
|
||||||
|
File fileToDelete = resourceToDelete.next();
|
||||||
|
try {
|
||||||
|
FileUtils.forceDelete(fileToDelete);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
System.err.println("Error deleting folder ["+fileToDelete.getName()+"].");
|
||||||
|
}
|
||||||
|
resourceToDelete.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if context parameters are managed in the correct way
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void testParameters() {
|
||||||
|
//no base directory declared in properties
|
||||||
|
try {
|
||||||
|
Properties props = new Properties();
|
||||||
|
new BlobStoreContextFactory().createContext(
|
||||||
|
PROVIDER, props);
|
||||||
|
fail("No error if base directory is not specified");
|
||||||
|
} catch (CreationException e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
//no base directory declared in properties
|
||||||
|
try {
|
||||||
|
Properties props = new Properties();
|
||||||
|
props.setProperty(FilesystemConstants.PROPERTY_BASEDIR, null);
|
||||||
|
new BlobStoreContextFactory().createContext(
|
||||||
|
PROVIDER, props);
|
||||||
|
fail("No error if base directory is null in the option");
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of list method of the root context
|
||||||
|
*/
|
||||||
|
public void testList_Root() throws IOException {
|
||||||
|
PageSet<? extends StorageMetadata> containersRetrieved;
|
||||||
|
Set<String> containersCreated = new HashSet<String>();
|
||||||
|
|
||||||
|
// Testing list with no containers
|
||||||
|
containersRetrieved = blobStore.list();
|
||||||
|
assertTrue(containersRetrieved.isEmpty(), "List operation returns a not empty set of container");
|
||||||
|
|
||||||
|
// Testing list with some containers
|
||||||
|
String[] containerNames = new String[]{"34343", "aaaa", "bbbbb"};
|
||||||
|
containersCreated = new HashSet<String>();
|
||||||
|
for(String containerName:containerNames) {
|
||||||
|
blobStore.createContainerInLocation(null, containerName);
|
||||||
|
containersCreated.add(containerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
containersRetrieved = blobStore.list();
|
||||||
|
assertEquals(containersCreated.size(), containersRetrieved.size(), "Different numbers of container");
|
||||||
|
|
||||||
|
for(StorageMetadata data:containersRetrieved) {
|
||||||
|
String containerName = data.getName();
|
||||||
|
if(!containersCreated.remove(containerName)) {
|
||||||
|
fail("Container list contains unexpected value ["+containerName+"]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertTrue(containersCreated.isEmpty(), "List operation doesn't return all values.");
|
||||||
|
|
||||||
|
for(String containerName:containerNames) {
|
||||||
|
//delete all creaded containers
|
||||||
|
blobStore.deleteContainer(containerName);
|
||||||
|
}
|
||||||
|
containersRetrieved = blobStore.list();
|
||||||
|
assertTrue(containersRetrieved.isEmpty(), "List operation returns a not empty set of container");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of list method, of class FilesystemAsyncBlobStore.
|
||||||
|
*/
|
||||||
|
public void testList_NoOptionSingleContainer() throws IOException {
|
||||||
|
|
||||||
|
// Testing list for a not existing container
|
||||||
|
try {
|
||||||
|
blobStore.list(CONTAINER_NAME);
|
||||||
|
fail("Found a not existing container");
|
||||||
|
} catch(ContainerNotFoundException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
blobStore.createContainerInLocation(null, CONTAINER_NAME);
|
||||||
|
// Testing list for an empty container
|
||||||
|
checkForContainerContent(CONTAINER_NAME, null);
|
||||||
|
|
||||||
|
//creates blobs in first container
|
||||||
|
Set<String> blobsExpected = TestUtils.createBlobsInContainer(
|
||||||
|
CONTAINER_NAME,
|
||||||
|
new String[] {
|
||||||
|
"bbb" + File.separator + "ccc" + File.separator + "ddd" + File.separator + "1234.jpg",
|
||||||
|
"4rrr.jpg",
|
||||||
|
"rrr" + File.separator + "sss" + File.separator + "788.jpg",
|
||||||
|
"xdc" + File.separator + "wert.kpg" }
|
||||||
|
);
|
||||||
|
|
||||||
|
checkForContainerContent(CONTAINER_NAME, blobsExpected);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testList_NotExistingContainer() {
|
||||||
|
// Testing list for a not existing container
|
||||||
|
try {
|
||||||
|
blobStore.list(CONTAINER_NAME);
|
||||||
|
fail("Found a not existing container");
|
||||||
|
} catch(ContainerNotFoundException e) {
|
||||||
|
//ok if arriver here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of list method, of class FilesystemAsyncBlobStore.
|
||||||
|
*/
|
||||||
|
public void testList_NoOptionDoubleContainer() throws IOException {
|
||||||
|
final String CONTAINER_NAME2 = "container2";
|
||||||
|
|
||||||
|
//create first container
|
||||||
|
blobStore.createContainerInLocation(null, CONTAINER_NAME);
|
||||||
|
//checks for empty container
|
||||||
|
checkForContainerContent(CONTAINER_NAME, null);
|
||||||
|
|
||||||
|
//create second container
|
||||||
|
blobStore.createContainerInLocation(null, CONTAINER_NAME2);
|
||||||
|
//checks for empty
|
||||||
|
checkForContainerContent(CONTAINER_NAME2, null);
|
||||||
|
|
||||||
|
//creates blobs in first container
|
||||||
|
|
||||||
|
Set<String> blobNamesCreatedInContainer1 = TestUtils.createBlobsInContainer(
|
||||||
|
CONTAINER_NAME,
|
||||||
|
new String[] {
|
||||||
|
"bbb" + File.separator + "ccc" + File.separator + "ddd" + File.separator + "1234.jpg",
|
||||||
|
TestUtils.createRandomBlobKey(),
|
||||||
|
"rrr" + File.separator + "sss" + File.separator + "788.jpg",
|
||||||
|
"xdc" + File.separator + "wert.kpg"}
|
||||||
|
);
|
||||||
|
|
||||||
|
//creates blobs in second container
|
||||||
|
blobStore.createContainerInLocation(null, CONTAINER_NAME2);
|
||||||
|
Set<String> blobNamesCreatedInContainer2 = TestUtils.createBlobsInContainer(
|
||||||
|
CONTAINER_NAME2,
|
||||||
|
new String[] {
|
||||||
|
"asd" + File.separator + "bbb" + File.separator + "ccc" + File.separator + "ddd" + File.separator + "1234.jpg",
|
||||||
|
TestUtils.createRandomBlobKey(),
|
||||||
|
"rrr" + File.separator + "sss" + File.separator + "788.jpg",
|
||||||
|
"xdc" + File.separator + "wert.kpg" }
|
||||||
|
);
|
||||||
|
|
||||||
|
//test blobs in first container
|
||||||
|
checkForContainerContent(CONTAINER_NAME, blobNamesCreatedInContainer1);
|
||||||
|
//test blobs in second container
|
||||||
|
checkForContainerContent(CONTAINER_NAME2, blobNamesCreatedInContainer2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
* Should throws an exception?
|
||||||
|
*/
|
||||||
|
public void testClearContainer_NotExistingContainer(){
|
||||||
|
blobStore.clearContainer(CONTAINER_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integration test, because clearContainer is not redefined in
|
||||||
|
* {@link FilesystemAsyncBlobStore} class
|
||||||
|
*/
|
||||||
|
public void testClearContainer_NoOptions() throws IOException {
|
||||||
|
final String CONTAINER_NAME2 = "containerToClear";
|
||||||
|
|
||||||
|
//create containers
|
||||||
|
blobStore.createContainerInLocation(null, CONTAINER_NAME);
|
||||||
|
blobStore.createContainerInLocation(null, CONTAINER_NAME2);
|
||||||
|
|
||||||
|
//creates blobs in first container
|
||||||
|
Set<String> blobNamesCreatedInContainer1 = TestUtils.createBlobsInContainer(
|
||||||
|
CONTAINER_NAME,
|
||||||
|
new String[] {
|
||||||
|
"bbb" + File.separator + "ccc" + File.separator + "ddd" + File.separator + "1234.jpg",
|
||||||
|
TestUtils.createRandomBlobKey(),
|
||||||
|
"rrr" + File.separator + "sss" + File.separator + "788.jpg",
|
||||||
|
"xdc" + File.separator + "wert.kpg"}
|
||||||
|
);
|
||||||
|
|
||||||
|
//creates blobs in second container
|
||||||
|
blobStore.createContainerInLocation(null, CONTAINER_NAME2);
|
||||||
|
Set<String> blobNamesCreatedInContainer2 = TestUtils.createBlobsInContainer(
|
||||||
|
CONTAINER_NAME2,
|
||||||
|
new String[] {
|
||||||
|
"asd" + File.separator + "bbb" + File.separator + "ccc" + File.separator + "ddd" + File.separator + "1234.jpg",
|
||||||
|
TestUtils.createRandomBlobKey(),
|
||||||
|
"rrr" + File.separator + "sss" + File.separator + "788.jpg",
|
||||||
|
"xdc" + File.separator + "wert.kpg" }
|
||||||
|
);
|
||||||
|
|
||||||
|
//test blobs in containers
|
||||||
|
checkForContainerContent(CONTAINER_NAME, blobNamesCreatedInContainer1);
|
||||||
|
checkForContainerContent(CONTAINER_NAME2, blobNamesCreatedInContainer2);
|
||||||
|
|
||||||
|
//delete blobs in first container
|
||||||
|
blobStore.clearContainer(CONTAINER_NAME);
|
||||||
|
checkForContainerContent(CONTAINER_NAME, null);
|
||||||
|
checkForContainerContent(CONTAINER_NAME2, blobNamesCreatedInContainer2);
|
||||||
|
//delete blobs in second container
|
||||||
|
blobStore.clearContainer(CONTAINER_NAME2);
|
||||||
|
checkForContainerContent(CONTAINER_NAME2, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integration test, because countBlobs is not redefined in
|
||||||
|
* {@link FilesystemAsyncBlobStore} class
|
||||||
|
*/
|
||||||
|
public void testCountBlobs_NotExistingContainer() {
|
||||||
|
try {
|
||||||
|
blobStore.countBlobs(PROVIDER);
|
||||||
|
fail("Magically the method was implemented... Wow!");
|
||||||
|
} catch (UnsupportedOperationException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integration test, because countBlobs is not redefined in
|
||||||
|
* {@link FilesystemAsyncBlobStore} class
|
||||||
|
*/
|
||||||
|
public void testCountBlobs_NoOptionsEmptyContainer() {
|
||||||
|
blobStore.createContainerInLocation(null, CONTAINER_NAME);
|
||||||
|
try {
|
||||||
|
blobStore.countBlobs(PROVIDER);
|
||||||
|
fail("Magically the method was implemented... Wow!");
|
||||||
|
} catch (UnsupportedOperationException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integration test, because countBlobs is not redefined in
|
||||||
|
* {@link FilesystemAsyncBlobStore} class
|
||||||
|
*/
|
||||||
|
public void testCountBlobs_NoOptions() {
|
||||||
|
blobStore.createContainerInLocation(null, CONTAINER_NAME);
|
||||||
|
try {
|
||||||
|
blobStore.countBlobs(PROVIDER);
|
||||||
|
fail("Magically the method was implemented... Wow!");
|
||||||
|
} catch (UnsupportedOperationException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testRemoveBlob_SimpleBlobKey() throws IOException {
|
||||||
|
final String BLOB_KEY = TestUtils.createRandomBlobKey(null, ".txt");
|
||||||
|
boolean result;
|
||||||
|
|
||||||
|
blobStore.createContainerInLocation(null, CONTAINER_NAME);
|
||||||
|
|
||||||
|
//checks that blob doesn't exists
|
||||||
|
result = blobStore.blobExists(CONTAINER_NAME, BLOB_KEY);
|
||||||
|
assertFalse(result, "Blob exists");
|
||||||
|
|
||||||
|
//create the blob
|
||||||
|
TestUtils.createBlobsInContainer(
|
||||||
|
CONTAINER_NAME,
|
||||||
|
new String[] { BLOB_KEY }
|
||||||
|
);
|
||||||
|
result = blobStore.blobExists(CONTAINER_NAME, BLOB_KEY);
|
||||||
|
assertTrue(result, "Blob exists");
|
||||||
|
|
||||||
|
//remove it
|
||||||
|
blobStore.removeBlob(CONTAINER_NAME, BLOB_KEY);
|
||||||
|
result = blobStore.blobExists(CONTAINER_NAME, BLOB_KEY);
|
||||||
|
assertFalse(result, "Blob still exists");
|
||||||
|
TestUtils.fileExists(TARGET_CONTAINER_NAME + File.separator + BLOB_KEY, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testRemoveBlob_TwoSimpleBlobKeys() throws IOException {
|
||||||
|
final String BLOB_KEY1 = TestUtils.createRandomBlobKey(null, null);
|
||||||
|
final String BLOB_KEY2 = TestUtils.createRandomBlobKey(null, null);
|
||||||
|
boolean result;
|
||||||
|
|
||||||
|
//create the container and checks that blob doesn't exists
|
||||||
|
blobStore.createContainerInLocation(null, CONTAINER_NAME);
|
||||||
|
result = blobStore.blobExists(CONTAINER_NAME, BLOB_KEY1);
|
||||||
|
assertFalse(result, "Blob1 exists");
|
||||||
|
result = blobStore.blobExists(CONTAINER_NAME, BLOB_KEY2);
|
||||||
|
assertFalse(result, "Blob2 exists");
|
||||||
|
|
||||||
|
//create the blob
|
||||||
|
TestUtils.createBlobsInContainer(
|
||||||
|
CONTAINER_NAME,
|
||||||
|
new String[] { BLOB_KEY1, BLOB_KEY2 }
|
||||||
|
);
|
||||||
|
result = blobStore.blobExists(CONTAINER_NAME, BLOB_KEY1);
|
||||||
|
assertTrue(result, "Blob " + BLOB_KEY1 + " doesn't exist");
|
||||||
|
result = blobStore.blobExists(CONTAINER_NAME, BLOB_KEY2);
|
||||||
|
assertTrue(result, "Blob " + BLOB_KEY2 + " doesn't exist");
|
||||||
|
|
||||||
|
//remove first blob
|
||||||
|
blobStore.removeBlob(CONTAINER_NAME, BLOB_KEY1);
|
||||||
|
result = blobStore.blobExists(CONTAINER_NAME, BLOB_KEY1);
|
||||||
|
assertFalse(result, "Blob1 still exists");
|
||||||
|
result = blobStore.blobExists(CONTAINER_NAME, BLOB_KEY2);
|
||||||
|
assertTrue(result, "Blob2 doesn't exist");
|
||||||
|
TestUtils.fileExists(TARGET_CONTAINER_NAME + File.separator + BLOB_KEY1, false);
|
||||||
|
TestUtils.fileExists(TARGET_CONTAINER_NAME + File.separator + BLOB_KEY2, true);
|
||||||
|
//remove second blob
|
||||||
|
blobStore.removeBlob(CONTAINER_NAME, BLOB_KEY2);
|
||||||
|
result = blobStore.blobExists(CONTAINER_NAME, BLOB_KEY2);
|
||||||
|
assertFalse(result, "Blob2 still exists");
|
||||||
|
TestUtils.fileExists(TARGET_CONTAINER_NAME + File.separator + BLOB_KEY2, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of removeBlob method, with only one blob with a complex path as key
|
||||||
|
*/
|
||||||
|
public void testRemoveBlob_ComplexBlobKey() throws IOException {
|
||||||
|
final String BLOB_KEY = TestUtils.createRandomBlobKey("aa/bb/cc/dd/", null);
|
||||||
|
boolean result;
|
||||||
|
|
||||||
|
//checks that blob doesn't exists
|
||||||
|
blobStore.createContainerInLocation(null, CONTAINER_NAME);
|
||||||
|
result = blobStore.blobExists(CONTAINER_NAME, BLOB_KEY);
|
||||||
|
assertFalse(result, "Blob exists");
|
||||||
|
TestUtils.fileExists(TARGET_CONTAINER_NAME + File.separator + BLOB_KEY, false);
|
||||||
|
|
||||||
|
//create the blob
|
||||||
|
TestUtils.createBlobsInContainer(
|
||||||
|
CONTAINER_NAME,
|
||||||
|
new String[] { BLOB_KEY }
|
||||||
|
);
|
||||||
|
result = blobStore.blobExists(CONTAINER_NAME, BLOB_KEY);
|
||||||
|
assertTrue(result, "Blob doesn't exist");
|
||||||
|
|
||||||
|
//remove it
|
||||||
|
blobStore.removeBlob(CONTAINER_NAME, BLOB_KEY);
|
||||||
|
result = blobStore.blobExists(CONTAINER_NAME, BLOB_KEY);
|
||||||
|
assertFalse(result, "Blob still exists");
|
||||||
|
//file removed
|
||||||
|
TestUtils.fileExists(TARGET_CONTAINER_NAME + File.separator + BLOB_KEY, false);
|
||||||
|
//also the entire directory structure was removed
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME + "/aa", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of removeBlob method, with two blobs with a complex path as key and
|
||||||
|
* when first blob is removed, not all of its key's path is removed, because
|
||||||
|
* it is shared with the second blob's key
|
||||||
|
*/
|
||||||
|
public void testRemoveBlob_TwoComplexBlobKeys() throws IOException {
|
||||||
|
final String BLOB_KEY1 = TestUtils.createRandomBlobKey("aa/bb/cc/dd/", null);
|
||||||
|
final String BLOB_KEY2 = TestUtils.createRandomBlobKey("aa/bb/ee/ff/", null);
|
||||||
|
boolean result;
|
||||||
|
|
||||||
|
blobStore.createContainerInLocation(null, CONTAINER_NAME);
|
||||||
|
|
||||||
|
//checks that blob doesn't exist
|
||||||
|
result = blobStore.blobExists(CONTAINER_NAME, BLOB_KEY1);
|
||||||
|
assertFalse(result, "Blob1 exists");
|
||||||
|
result = blobStore.blobExists(CONTAINER_NAME, BLOB_KEY2);
|
||||||
|
assertFalse(result, "Blob2 exists");
|
||||||
|
|
||||||
|
//create the blobs
|
||||||
|
TestUtils.createBlobsInContainer(
|
||||||
|
CONTAINER_NAME,
|
||||||
|
new String[] { BLOB_KEY1, BLOB_KEY2 }
|
||||||
|
);
|
||||||
|
result = blobStore.blobExists(CONTAINER_NAME, BLOB_KEY1);
|
||||||
|
assertTrue(result, "Blob " + BLOB_KEY1 + " doesn't exist");
|
||||||
|
result = blobStore.blobExists(CONTAINER_NAME, BLOB_KEY2);
|
||||||
|
assertTrue(result, "Blob " + BLOB_KEY2 + " doesn't exist");
|
||||||
|
|
||||||
|
//remove first blob
|
||||||
|
blobStore.removeBlob(CONTAINER_NAME, BLOB_KEY1);
|
||||||
|
result = blobStore.blobExists(CONTAINER_NAME, BLOB_KEY1);
|
||||||
|
assertFalse(result, "Blob still exists");
|
||||||
|
//first file deleted, not the second
|
||||||
|
TestUtils.fileExists(TARGET_CONTAINER_NAME + File.separator + BLOB_KEY1, false);
|
||||||
|
TestUtils.fileExists(TARGET_CONTAINER_NAME + File.separator + BLOB_KEY2, true);
|
||||||
|
//only partial directory structure was removed, because it shares a path
|
||||||
|
//with the second blob created
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME + "/aa/bb/cc/dd", false);
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME + "/aa/bb", true);
|
||||||
|
//remove second blob
|
||||||
|
blobStore.removeBlob(CONTAINER_NAME, BLOB_KEY2);
|
||||||
|
result = blobStore.blobExists(CONTAINER_NAME, BLOB_KEY2);
|
||||||
|
assertFalse(result, "Blob still exists");
|
||||||
|
TestUtils.fileExists(TARGET_CONTAINER_NAME + File.separator + BLOB_KEY2, false);
|
||||||
|
//now all the directory structure is empty
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME + "/aa", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of containerExists method, of class FilesystemAsyncBlobStore.
|
||||||
|
*/
|
||||||
|
public void testContainerExists() throws IOException {
|
||||||
|
boolean result;
|
||||||
|
|
||||||
|
result = blobStore.containerExists(CONTAINER_NAME);
|
||||||
|
assertFalse(result, "Container exists");
|
||||||
|
|
||||||
|
//create container
|
||||||
|
TestUtils.createContainerAsDirectory(CONTAINER_NAME);
|
||||||
|
|
||||||
|
result = blobStore.containerExists(CONTAINER_NAME);
|
||||||
|
assertTrue(result, "Container doesn't exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of createContainerInLocation method, of class FilesystemAsyncBlobStore.
|
||||||
|
*/
|
||||||
|
public void testCreateContainerInLocation() throws IOException {
|
||||||
|
final String CONTAINER_NAME2 = "funambol-test-2";
|
||||||
|
final String TARGET_CONTAINER_NAME2 = TestUtils.TARGET_BASE_DIR + CONTAINER_NAME2;
|
||||||
|
|
||||||
|
boolean result;
|
||||||
|
|
||||||
|
result = blobStore.containerExists(CONTAINER_NAME);
|
||||||
|
assertFalse(result, "Container exists");
|
||||||
|
result = blobStore.createContainerInLocation(null, CONTAINER_NAME);
|
||||||
|
assertTrue(result, "Container not created");
|
||||||
|
result = blobStore.containerExists(CONTAINER_NAME);
|
||||||
|
assertTrue(result, "Container doesn't exist");
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME, true);
|
||||||
|
|
||||||
|
result = blobStore.containerExists(CONTAINER_NAME2);
|
||||||
|
assertFalse(result, "Container exists");
|
||||||
|
result = blobStore.createContainerInLocation(null, CONTAINER_NAME2);
|
||||||
|
assertTrue(result, "Container not created");
|
||||||
|
result = blobStore.containerExists(CONTAINER_NAME2);
|
||||||
|
assertTrue(result, "Container doesn't exist");
|
||||||
|
TestUtils.directoryExists(TestUtils.TARGET_BASE_DIR + CONTAINER_NAME2, true);
|
||||||
|
|
||||||
|
//clean the environment
|
||||||
|
FileUtils.forceDelete(new File(TARGET_CONTAINER_NAME2));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of putBlob method, of class FilesystemAsyncBlobStore.
|
||||||
|
* with a simple filename - no path in the filename, eg
|
||||||
|
* filename.jpg
|
||||||
|
*/
|
||||||
|
public void testPutBlobSimpleName() {
|
||||||
|
blobStore.createContainerInLocation(null, CONTAINER_NAME);
|
||||||
|
putBlobAndCheckIt(TestUtils.createRandomBlobKey("putBlob-", ".jpg"));
|
||||||
|
putBlobAndCheckIt(TestUtils.createRandomBlobKey("putBlob-", ".jpg"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of putBlob method with a complex key, with path in the filename, eg
|
||||||
|
* picture/filename.jpg
|
||||||
|
*/
|
||||||
|
public void testPutBlobComplexName1() {
|
||||||
|
blobStore.createContainerInLocation(null, CONTAINER_NAME);
|
||||||
|
putBlobAndCheckIt(TestUtils.createRandomBlobKey("picture/putBlob-", ".jpg"));
|
||||||
|
putBlobAndCheckIt(TestUtils.createRandomBlobKey("video/putBlob-", ".jpg"));
|
||||||
|
putBlobAndCheckIt(TestUtils.createRandomBlobKey("putBlob-", ".jpg"));
|
||||||
|
putBlobAndCheckIt(TestUtils.createRandomBlobKey("video/putBlob-", ".jpg"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of putBlob method with a complex key, with path in the filename, eg
|
||||||
|
* picture/filename.jpg
|
||||||
|
*/
|
||||||
|
public void testPutBlobComplexName2() {
|
||||||
|
blobStore.createContainerInLocation(null, CONTAINER_NAME);
|
||||||
|
putBlobAndCheckIt(TestUtils.createRandomBlobKey("aa/bb/cc/dd/ee/putBlob-", ".jpg"));
|
||||||
|
putBlobAndCheckIt(TestUtils.createRandomBlobKey("aa/bb/cc/dd/ee/putBlob-", ".jpg"));
|
||||||
|
putBlobAndCheckIt(TestUtils.createRandomBlobKey("putBlob-", ".jpg"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of blobExists method, of class FilesystemAsyncBlobStore.
|
||||||
|
*/
|
||||||
|
public void testBlobExists() throws IOException {
|
||||||
|
boolean result;
|
||||||
|
String blobKey;
|
||||||
|
|
||||||
|
//when location doesn't exists
|
||||||
|
blobKey = TestUtils.createRandomBlobKey();
|
||||||
|
result = blobStore.blobExists(CONTAINER_NAME, blobKey);
|
||||||
|
assertFalse(result, "Blob exists");
|
||||||
|
|
||||||
|
//when location exists
|
||||||
|
blobStore.createContainerInLocation(null, CONTAINER_NAME);
|
||||||
|
result = blobStore.blobExists(CONTAINER_NAME, blobKey);
|
||||||
|
assertFalse(result, "Blob exists");
|
||||||
|
|
||||||
|
//create blob
|
||||||
|
TestUtils.createBlobAsFile(CONTAINER_NAME, blobKey, TestUtils.getImageForBlobPayload());
|
||||||
|
result = blobStore.blobExists(CONTAINER_NAME, blobKey);
|
||||||
|
assertTrue(result, "Blob doesn't exist");
|
||||||
|
|
||||||
|
//complex path test
|
||||||
|
blobKey = TestUtils.createRandomBlobKey("ss/asdas/", "");
|
||||||
|
result = blobStore.blobExists(CONTAINER_NAME, blobKey);
|
||||||
|
assertFalse(result, "Blob exists");
|
||||||
|
TestUtils.createBlobAsFile(CONTAINER_NAME, blobKey, TestUtils.getImageForBlobPayload());
|
||||||
|
result = blobStore.blobExists(CONTAINER_NAME, blobKey);
|
||||||
|
assertTrue(result, "Blob doesn't exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testGetBlob_NotExistingContainer() {
|
||||||
|
try {
|
||||||
|
blobStore.getBlob(CONTAINER_NAME, TestUtils.createRandomBlobKey(), null);
|
||||||
|
fail("Retrieve must fail, container does not exist.");
|
||||||
|
} catch(ContainerNotFoundException e) {
|
||||||
|
//correct if arrive here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of getBlob method, of class FilesystemAsyncBlobStore.
|
||||||
|
*/
|
||||||
|
public void testGetBlob() throws IOException {
|
||||||
|
String blobKey = TestUtils.createRandomBlobKey();
|
||||||
|
GetOptions options = null;
|
||||||
|
Blob resultBlob;
|
||||||
|
|
||||||
|
blobStore.createContainerInLocation(null, CONTAINER_NAME);
|
||||||
|
|
||||||
|
resultBlob = blobStore.getBlob(CONTAINER_NAME, blobKey, options);
|
||||||
|
assertNull(resultBlob, "Blob exists");
|
||||||
|
|
||||||
|
//create blob
|
||||||
|
TestUtils.createBlobsInContainer(
|
||||||
|
CONTAINER_NAME,
|
||||||
|
new String[]{blobKey});
|
||||||
|
|
||||||
|
resultBlob = blobStore.getBlob(CONTAINER_NAME, blobKey, options);
|
||||||
|
|
||||||
|
assertNotNull(resultBlob, "Blob exists");
|
||||||
|
//checks file content
|
||||||
|
InputStream expectedFile = new FileInputStream(TARGET_CONTAINER_NAME + File.separator + blobKey);
|
||||||
|
InputStream currentFile = resultBlob.getPayload().getInput();
|
||||||
|
assertTrue(TestUtils.isSame(expectedFile, currentFile), "Blob payload differs from file content");
|
||||||
|
//metadata are verified in the test for blobMetadata, so no need to
|
||||||
|
//perform a complete test here
|
||||||
|
assertNotNull(resultBlob.getMetadata(), "Metadata null");
|
||||||
|
MutableBlobMetadata metadata = resultBlob.getMetadata();
|
||||||
|
assertEquals(blobKey, metadata.getName(), "Wrong blob metadata");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testBlobMetadata_withDefaultMetadata() throws IOException {
|
||||||
|
String BLOB_KEY = TestUtils.createRandomBlobKey(null, null);
|
||||||
|
//create the blob
|
||||||
|
TestUtils.createBlobsInContainer(
|
||||||
|
CONTAINER_NAME,
|
||||||
|
new String[]{ BLOB_KEY }
|
||||||
|
);
|
||||||
|
|
||||||
|
BlobMetadata metadata = blobStore.blobMetadata(CONTAINER_NAME, BLOB_KEY);
|
||||||
|
assertNotNull(metadata, "Metadata null");
|
||||||
|
|
||||||
|
assertEquals(metadata.getName(), BLOB_KEY, "Wrong blob name");
|
||||||
|
assertEquals(metadata.getType(), StorageType.BLOB, "Wrong blob type");
|
||||||
|
assertEquals(metadata.getContentType(), "", "Wrong blob content-type");
|
||||||
|
assertEquals(metadata.getContentMD5(), null, "Wrong blob MD5");
|
||||||
|
assertEquals(metadata.getLocation(), null, "Wrong blob location");
|
||||||
|
assertEquals(metadata.getProviderId(), null, "Wrong blob provider id");
|
||||||
|
assertEquals(metadata.getUri(), null, "Wrong blob URI");
|
||||||
|
assertNotNull(metadata.getUserMetadata(), "No blob UserMetadata");
|
||||||
|
assertEquals(metadata.getUserMetadata().size(), 0, "Wrong blob UserMetadata");
|
||||||
|
//metadata.getLastModified()
|
||||||
|
File file = new File(TARGET_CONTAINER_NAME + File.separator + BLOB_KEY);
|
||||||
|
assertEquals(metadata.getSize(), new Long(file.length()), "Wrong blob size");
|
||||||
|
//don't know how to calculate ETAG
|
||||||
|
//assertEquals(metadata.getETag(), "105cf4e6c052d65352dabd20028ff102", "Wrong blob ETag");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testDeleteContainer_NotExistingContainer(){
|
||||||
|
try {
|
||||||
|
blobStore.deleteContainer(CONTAINER_NAME);
|
||||||
|
fail("No error when container doesn't exist");
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDeleteContainer_EmptyContanier(){
|
||||||
|
boolean result;
|
||||||
|
blobStore.createContainerInLocation(null, CONTAINER_NAME);
|
||||||
|
|
||||||
|
result = blobStore.containerExists(CONTAINER_NAME);
|
||||||
|
assertTrue(result, "Container doesn't exists");
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME, true);
|
||||||
|
|
||||||
|
//delete container
|
||||||
|
blobStore.deleteContainer(CONTAINER_NAME);
|
||||||
|
result = blobStore.containerExists(CONTAINER_NAME);
|
||||||
|
assertFalse(result, "Container still exists");
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testDeleteContainer() throws IOException{
|
||||||
|
boolean result;
|
||||||
|
String CONTAINER_NAME2 = "container-to-delete";
|
||||||
|
String TARGET_CONTAINER_NAME2 = TestUtils.TARGET_BASE_DIR + CONTAINER_NAME2;
|
||||||
|
blobStore.createContainerInLocation(null, CONTAINER_NAME);
|
||||||
|
blobStore.createContainerInLocation(null, CONTAINER_NAME2);
|
||||||
|
|
||||||
|
result = blobStore.containerExists(CONTAINER_NAME);
|
||||||
|
assertTrue(result, "Container [" + CONTAINER_NAME + "] doesn't exists");
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME, true);
|
||||||
|
result = blobStore.containerExists(CONTAINER_NAME2);
|
||||||
|
assertTrue(result, "Container [" + CONTAINER_NAME2 + "] doesn't exists");
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME2, true);
|
||||||
|
|
||||||
|
//create blobs inside container
|
||||||
|
TestUtils.createBlobsInContainer(
|
||||||
|
CONTAINER_NAME,
|
||||||
|
new String[]{
|
||||||
|
TestUtils.createRandomBlobKey("testutils-", null),
|
||||||
|
TestUtils.createRandomBlobKey("testutils-", null),
|
||||||
|
TestUtils.createRandomBlobKey("ab123s" + File.separator + "testutils-", null),
|
||||||
|
});
|
||||||
|
TestUtils.createBlobsInContainer(
|
||||||
|
CONTAINER_NAME,
|
||||||
|
new String[]{
|
||||||
|
TestUtils.createRandomBlobKey("testutils-", null),
|
||||||
|
TestUtils.createRandomBlobKey("testutils-", null),
|
||||||
|
TestUtils.createRandomBlobKey("asda123s" + File.separator + "testutils-", null),
|
||||||
|
TestUtils.createRandomBlobKey("123-_3s" + File.separator + "testutils-", null),
|
||||||
|
});
|
||||||
|
|
||||||
|
//delete first container
|
||||||
|
blobStore.deleteContainer(CONTAINER_NAME);
|
||||||
|
result = blobStore.containerExists(CONTAINER_NAME);
|
||||||
|
assertFalse(result, "Container [" + CONTAINER_NAME + "] still exists");
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME, false);
|
||||||
|
result = blobStore.containerExists(CONTAINER_NAME2);
|
||||||
|
assertTrue(result, "Container [" + CONTAINER_NAME2 + "] still exists");
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME2, true);
|
||||||
|
//delete second container
|
||||||
|
blobStore.deleteContainer(CONTAINER_NAME2);
|
||||||
|
result = blobStore.containerExists(CONTAINER_NAME2);
|
||||||
|
assertFalse(result, "Container [" + CONTAINER_NAME2 + "] still exists");
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME2, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testInvalidContainerName() {
|
||||||
|
try {
|
||||||
|
blobStore.createContainerInLocation(null, "file/system");
|
||||||
|
fail("Wrong container name not recognized");
|
||||||
|
} catch (IllegalArgumentException e) {}
|
||||||
|
try {
|
||||||
|
blobStore.containerExists("file/system");
|
||||||
|
fail("Wrong container name not recognized");
|
||||||
|
} catch (IllegalArgumentException e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// public void testInvalidBlobKey() {
|
||||||
|
// try {
|
||||||
|
// blobStore.newBlob(File.separator + "testwrongblobkey");
|
||||||
|
// fail("Wrong blob key not recognized");
|
||||||
|
// } catch (IllegalArgumentException e) {}
|
||||||
|
//
|
||||||
|
// try {
|
||||||
|
// blobStore.newBlob("testwrongblobkey" + File.separator);
|
||||||
|
// fail("Wrong blob key not recognized");
|
||||||
|
// } catch (IllegalArgumentException e) {}
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------- Private Methods
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@link Blob} object filled with data from a file
|
||||||
|
* @param keyName
|
||||||
|
* @param fileContent
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private Blob createBlob(String keyName, File filePayload) {
|
||||||
|
Blob blob = blobStore.newBlob(keyName);
|
||||||
|
blob.setPayload(filePayload);
|
||||||
|
return blob;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests if container contains only the expected blobs
|
||||||
|
* @param containerName
|
||||||
|
* @param expectedBlobKeys
|
||||||
|
*/
|
||||||
|
private void checkForContainerContent(final String containerName, Set<String> expectedBlobKeys) {
|
||||||
|
ListContainerOptions options = ListContainerOptions.Builder.recursive();
|
||||||
|
|
||||||
|
PageSet<? extends StorageMetadata> blobsRetrieved = blobStore.list(containerName, options);
|
||||||
|
|
||||||
|
//nothing expected
|
||||||
|
if (null == expectedBlobKeys) {
|
||||||
|
assertTrue(blobsRetrieved.isEmpty(), "Wrong blob number retrieved in the containter [" + containerName + "]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//copies values
|
||||||
|
Set<String> expectedBlobKeysCopy = new HashSet<String>();
|
||||||
|
for (String value:expectedBlobKeys){
|
||||||
|
expectedBlobKeysCopy.add(value);
|
||||||
|
}
|
||||||
|
assertEquals(blobsRetrieved.size(), expectedBlobKeysCopy.size(), "Wrong blob number retrieved in the containter [" + containerName + "]");
|
||||||
|
for (StorageMetadata data : blobsRetrieved) {
|
||||||
|
String blobName = data.getName();
|
||||||
|
if (!expectedBlobKeysCopy.remove(blobName)) {
|
||||||
|
fail("List for container [" + containerName + "] contains unexpected value [" + blobName + "]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertTrue(expectedBlobKeysCopy.isEmpty(), "List operation for container [" + containerName + "] doesn't return all values.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a blob with putBlob method
|
||||||
|
*/
|
||||||
|
private void putBlobAndCheckIt(String blobKey) {
|
||||||
|
Blob blob;
|
||||||
|
|
||||||
|
TestUtils.fileExists(TARGET_CONTAINER_NAME + File.separator + blobKey, false);
|
||||||
|
|
||||||
|
//create the blob
|
||||||
|
blob = createBlob(blobKey, TestUtils.getImageForBlobPayload());
|
||||||
|
String eTag = blobStore.putBlob(CONTAINER_NAME, blob);
|
||||||
|
assertNotNull(eTag, "putBlob result null");
|
||||||
|
assertNotSame(eTag, "", "putBlob result empty");
|
||||||
|
|
||||||
|
//checks if the blob exists
|
||||||
|
TestUtils.fileExists(TARGET_CONTAINER_NAME + File.separator + blobKey, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.filesystem.integration;
|
||||||
|
|
||||||
|
import org.jclouds.blobstore.integration.internal.BaseBlobIntegrationTest;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author James Murty
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Test(groups = { "integration" }, testName = "blobstore.FilesystemBlobIntegrationTest")
|
||||||
|
public class FilesystemBlobIntegrationTest extends BaseBlobIntegrationTest {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.filesystem.integration;
|
||||||
|
|
||||||
|
import org.jclouds.blobstore.integration.internal.BaseBlobMapIntegrationTest;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Test(groups = { "integration", "live" }, testName = "blobstore.FilesystemBlobMapIntegrationTest")
|
||||||
|
public class FilesystemBlobMapIntegrationTest extends BaseBlobMapIntegrationTest {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.filesystem.integration;
|
||||||
|
|
||||||
|
import static org.jclouds.blobstore.options.ListContainerOptions.Builder.maxResults;
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
|
import org.jclouds.blobstore.domain.Blob;
|
||||||
|
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||||
|
import org.jclouds.blobstore.domain.PageSet;
|
||||||
|
import org.jclouds.blobstore.domain.StorageMetadata;
|
||||||
|
import org.jclouds.blobstore.integration.internal.BaseContainerIntegrationTest;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author James Murty
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Test(groups = { "integration", "live" }, testName = "blobstore.FilesystemContainerIntegrationTest")
|
||||||
|
public class FilesystemContainerIntegrationTest extends BaseContainerIntegrationTest {
|
||||||
|
|
||||||
|
@Test(groups = { "integration", "live" })
|
||||||
|
public void testNotWithDetails() throws InterruptedException {
|
||||||
|
|
||||||
|
String key = "hello";
|
||||||
|
|
||||||
|
Blob object = context.getBlobStore().newBlob(key);
|
||||||
|
object.setPayload(TEST_STRING);
|
||||||
|
object.getMetadata().setContentType(MediaType.TEXT_PLAIN);
|
||||||
|
object.getMetadata().setSize(new Long(TEST_STRING.length()));
|
||||||
|
// NOTE all metadata in jclouds comes out as lowercase, in an effort to normalize the
|
||||||
|
// providers.
|
||||||
|
object.getMetadata().getUserMetadata().put("Adrian", "powderpuff");
|
||||||
|
String containerName = getContainerName();
|
||||||
|
try {
|
||||||
|
addBlobToContainer(containerName, object);
|
||||||
|
validateContent(containerName, key);
|
||||||
|
|
||||||
|
PageSet<? extends StorageMetadata> container = context.getBlobStore().list(containerName,
|
||||||
|
maxResults(1));
|
||||||
|
|
||||||
|
BlobMetadata metadata = (BlobMetadata) Iterables.getOnlyElement(container);
|
||||||
|
// transient container should be lenient and not return metadata on undetailed listing.
|
||||||
|
|
||||||
|
assertEquals(metadata.getUserMetadata().size(), 0);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
returnContainer(containerName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.filesystem.integration;
|
||||||
|
|
||||||
|
import org.jclouds.blobstore.integration.internal.BaseInputStreamMapIntegrationTest;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Test(groups = { "integration", "live" }, testName = "blobstore.FilesystemInputStreamMapIntegrationTest")
|
||||||
|
public class FilesystemInputStreamMapIntegrationTest extends BaseInputStreamMapIntegrationTest {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.filesystem.integration;
|
||||||
|
|
||||||
|
import org.jclouds.blobstore.integration.internal.BaseServiceIntegrationTest;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Test(groups = { "integration", "live" }, testName = "blobstore.FilesystemServiceIntegrationTest")
|
||||||
|
public class FilesystemServiceIntegrationTest extends BaseServiceIntegrationTest {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.filesystem.integration;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.jclouds.blobstore.BlobStoreContext;
|
||||||
|
import org.jclouds.blobstore.BlobStoreContextFactory;
|
||||||
|
import org.jclouds.blobstore.integration.TransientBlobStoreTestInitializer;
|
||||||
|
import org.jclouds.blobstore.integration.internal.BaseBlobStoreIntegrationTest;
|
||||||
|
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.inject.Module;
|
||||||
|
|
||||||
|
import org.jclouds.filesystem.reference.FilesystemConstants;
|
||||||
|
import org.jclouds.filesystem.utils.TestUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
public class FilesystemTestInitializer extends TransientBlobStoreTestInitializer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BlobStoreContext createLiveContext(Module configurationModule, String url, String app,
|
||||||
|
String identity, String key) throws IOException {
|
||||||
|
BaseBlobStoreIntegrationTest.SANITY_CHECK_RETURNED_BUCKET_NAME = true;
|
||||||
|
|
||||||
|
Properties prop = new Properties();
|
||||||
|
prop.setProperty(FilesystemConstants.PROPERTY_BASEDIR, TestUtils.TARGET_BASE_DIR);
|
||||||
|
return new BlobStoreContextFactory().createContext(
|
||||||
|
"filesystem",
|
||||||
|
ImmutableSet.of(configurationModule, new Log4JLoggingModule()),
|
||||||
|
prop);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.filesystem.predicates.validators.internal;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import org.jclouds.filesystem.predicates.validators.FilesystemBlobKeyValidator;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import static org.testng.Assert.*;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test class for {@link FilesystemBlobKeyValidator } class
|
||||||
|
*
|
||||||
|
* @author Alfredo "Rainbowbreeze" Morresi
|
||||||
|
*/
|
||||||
|
@Test(groups = "unit", testName = "filesystem.FilesystemBlobKeyValidatorTest")
|
||||||
|
public class FilesystemBlobKeyValidatorTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNamesValidity() {
|
||||||
|
FilesystemBlobKeyValidator validator = new FilesystemBlobKeyValidatorImpl();
|
||||||
|
|
||||||
|
validator.validate("all.img");
|
||||||
|
validator.validate("all" + File.separator + "is" + File.separator + "" + "ok");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvalidNames() {
|
||||||
|
FilesystemBlobKeyValidator validator = new FilesystemBlobKeyValidatorImpl();
|
||||||
|
|
||||||
|
try {
|
||||||
|
validator.validate("");
|
||||||
|
fail("Blob key value incorrect, but was not recognized");
|
||||||
|
} catch(IllegalArgumentException e) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
validator.validate(File.separator + "is" + File.separator + "" + "ok");
|
||||||
|
fail("Blob key value incorrect, but was not recognized");
|
||||||
|
} catch(IllegalArgumentException e) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
validator.validate("all" + File.separator + "is" + File.separator);
|
||||||
|
fail("Blob key value incorrect, but was not recognized");
|
||||||
|
} catch(IllegalArgumentException e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------- Private methods
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.filesystem.predicates.validators.internal;
|
||||||
|
|
||||||
|
import org.jclouds.filesystem.predicates.validators.internal.FilesystemBlobKeyValidatorImpl;
|
||||||
|
import java.io.File;
|
||||||
|
import org.jclouds.filesystem.predicates.validators.FilesystemBlobKeyValidator;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import static org.testng.Assert.*;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test class for {@link FilesystemContainerNameValidator } class
|
||||||
|
*
|
||||||
|
* @author Alfredo "Rainbowbreeze" Morresi
|
||||||
|
*/
|
||||||
|
@Test(groups = "unit", testName = "filesystem.FilesystemContainerNameValidatorTest")
|
||||||
|
public class FilesystemContainerNameValidatorTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNamesValidity() {
|
||||||
|
FilesystemBlobKeyValidator validator = new FilesystemBlobKeyValidatorImpl();
|
||||||
|
|
||||||
|
validator.validate("all.img");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvalidNames() {
|
||||||
|
FilesystemBlobKeyValidator validator = new FilesystemBlobKeyValidatorImpl();
|
||||||
|
|
||||||
|
try {
|
||||||
|
validator.validate("");
|
||||||
|
fail("Container name value incorrect, but was not recognized");
|
||||||
|
} catch(IllegalArgumentException e) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
validator.validate(null);
|
||||||
|
fail("Container name value incorrect, but was not recognized");
|
||||||
|
} catch(IllegalArgumentException e) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
validator.validate(File.separator + "is" + File.separator + "" + "ok");
|
||||||
|
fail("Container name value incorrect, but was not recognized");
|
||||||
|
} catch(IllegalArgumentException e) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
validator.validate("all" + File.separator + "is" + File.separator);
|
||||||
|
fail("Container name value incorrect, but was not recognized");
|
||||||
|
} catch(IllegalArgumentException e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------- Private methods
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,532 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.filesystem.strategy.internal;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.jclouds.blobstore.domain.internal.MutableBlobMetadataImpl;
|
||||||
|
import org.jclouds.blobstore.domain.internal.BlobImpl;
|
||||||
|
import org.jclouds.blobstore.domain.MutableBlobMetadata;
|
||||||
|
import org.jclouds.blobstore.domain.Blob;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import org.jclouds.blobstore.options.ListContainerOptions;
|
||||||
|
import org.jclouds.filesystem.predicates.validators.internal.FilesystemContainerNameValidatorImpl;
|
||||||
|
import org.jclouds.filesystem.predicates.validators.internal.FilesystemBlobKeyValidatorImpl;
|
||||||
|
import org.jclouds.filesystem.strategy.FilesystemStorageStrategy;
|
||||||
|
import org.jclouds.filesystem.utils.TestUtils;
|
||||||
|
import org.jclouds.io.payloads.FilePayload;
|
||||||
|
import org.testng.annotations.*;
|
||||||
|
|
||||||
|
import static org.testng.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test class for {@link FilesystemStorageStrategyImpl } class
|
||||||
|
*
|
||||||
|
* @author Alfredo "Rainbowbreeze" Morresi
|
||||||
|
*/
|
||||||
|
@Test(groups = "unit", testName = "filesystem.FilesystemBlobUtilsTest", sequential = true)
|
||||||
|
public class FilesystemStorageStrategyImplTest {
|
||||||
|
private static final String CONTAINER_NAME = "funambol-test";
|
||||||
|
private static final String TARGET_CONTAINER_NAME = TestUtils.TARGET_BASE_DIR + CONTAINER_NAME;
|
||||||
|
|
||||||
|
private static final String LOGGING_CONFIG_KEY = "java.util.logging.config.file";
|
||||||
|
private static final String LOGGING_CONFIG_VALUE = "src/main/resources/logging.properties";
|
||||||
|
|
||||||
|
static {
|
||||||
|
System.setProperty(LOGGING_CONFIG_KEY,
|
||||||
|
LOGGING_CONFIG_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private FilesystemStorageStrategy storageStrategy;
|
||||||
|
|
||||||
|
@BeforeMethod
|
||||||
|
protected void setUp() throws Exception {
|
||||||
|
storageStrategy = new FilesystemStorageStrategyImpl(
|
||||||
|
new Blob.Factory() {
|
||||||
|
@Override
|
||||||
|
public Blob create(MutableBlobMetadata metadata) {
|
||||||
|
return new BlobImpl(metadata != null ? metadata : new MutableBlobMetadataImpl());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
TestUtils.TARGET_BASE_DIR,
|
||||||
|
new FilesystemContainerNameValidatorImpl(),
|
||||||
|
new FilesystemBlobKeyValidatorImpl());
|
||||||
|
TestUtils.cleanDirectoryContent(TestUtils.TARGET_BASE_DIR);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@AfterMethod
|
||||||
|
protected void tearDown() throws IOException {
|
||||||
|
TestUtils.cleanDirectoryContent(TestUtils.TARGET_BASE_DIR);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testCreateDirectory() {
|
||||||
|
storageStrategy.createDirectory(CONTAINER_NAME, null);
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME, true);
|
||||||
|
|
||||||
|
storageStrategy.createDirectory(CONTAINER_NAME, "subdir");
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME + File.separator + "subdir", true);
|
||||||
|
|
||||||
|
storageStrategy.createDirectory(CONTAINER_NAME, "subdir1" + File.separator);
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME + File.separator + "subdir1", true);
|
||||||
|
|
||||||
|
storageStrategy.createDirectory(CONTAINER_NAME, File.separator + "subdir2");
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME + File.separator + "subdir2", true);
|
||||||
|
|
||||||
|
storageStrategy.createDirectory(CONTAINER_NAME, "subdir3" + File.separator + "subdir4");
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME + File.separator + "subdir2", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCreateDirectory_DirectoryAlreadyExists() {
|
||||||
|
storageStrategy.createDirectory(CONTAINER_NAME, null);
|
||||||
|
storageStrategy.createDirectory(CONTAINER_NAME, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCreateDirectory_WrongDirectoryName() {
|
||||||
|
try {
|
||||||
|
storageStrategy.createDirectory(CONTAINER_NAME, "$%&!'`\\");
|
||||||
|
fail("No exception throwed");
|
||||||
|
} catch(Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testCreateContainer() {
|
||||||
|
boolean result;
|
||||||
|
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME, false);
|
||||||
|
result = storageStrategy.createContainer(CONTAINER_NAME);
|
||||||
|
assertTrue(result, "Container not created");
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCreateContainer_ContainerAlreadyExists() {
|
||||||
|
boolean result;
|
||||||
|
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME, false);
|
||||||
|
result = storageStrategy.createContainer(CONTAINER_NAME);
|
||||||
|
assertTrue(result, "Container not created");
|
||||||
|
result = storageStrategy.createContainer(CONTAINER_NAME);
|
||||||
|
assertFalse(result, "Container not created");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testDeleteDirectory() throws IOException {
|
||||||
|
TestUtils.createContainerAsDirectory(CONTAINER_NAME);
|
||||||
|
TestUtils.createBlobsInContainer(
|
||||||
|
CONTAINER_NAME,
|
||||||
|
new String[]{
|
||||||
|
TestUtils.createRandomBlobKey("lev1/lev2/lev3/", ".txt"),
|
||||||
|
TestUtils.createRandomBlobKey("lev1/lev2/lev4/", ".jpg")
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
//delete directory in different ways
|
||||||
|
storageStrategy.deleteDirectory(CONTAINER_NAME, "lev1/lev2/lev4");
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME + File.separator + "lev1/lev2/lev4", false);
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME + File.separator + "lev1/lev2", true);
|
||||||
|
|
||||||
|
storageStrategy.deleteDirectory(CONTAINER_NAME, "lev1/lev2/lev3/");
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME + File.separator + "lev1/lev2/lev3", false);
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME + File.separator + "lev1/lev2", true);
|
||||||
|
|
||||||
|
storageStrategy.deleteDirectory(CONTAINER_NAME, "/lev1");
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME + File.separator + "lev1", false);
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME, true);
|
||||||
|
|
||||||
|
//delete the directory and all the files inside
|
||||||
|
TestUtils.createBlobsInContainer(
|
||||||
|
CONTAINER_NAME,
|
||||||
|
new String[]{
|
||||||
|
TestUtils.createRandomBlobKey("lev1/lev2/lev3/", ".txt"),
|
||||||
|
TestUtils.createRandomBlobKey("lev1/lev2/lev4/", ".jpg")
|
||||||
|
}
|
||||||
|
);
|
||||||
|
storageStrategy.deleteDirectory(CONTAINER_NAME, null);
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDeleteDirectory_ErrorWhenNotExists(){
|
||||||
|
try {
|
||||||
|
storageStrategy.deleteDirectory(CONTAINER_NAME, null);
|
||||||
|
fail("No exception throwed");
|
||||||
|
} catch(Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testDirectoryExists() throws IOException {
|
||||||
|
final String SUBDIRECTORY_NAME = "ad" + File.separator + "sda" + File.separator + "asd";
|
||||||
|
boolean result;
|
||||||
|
|
||||||
|
result = storageStrategy.directoryExists(CONTAINER_NAME, null);
|
||||||
|
assertFalse(result, "Directory exist");
|
||||||
|
|
||||||
|
//create the container
|
||||||
|
TestUtils.createContainerAsDirectory(CONTAINER_NAME);
|
||||||
|
//check if exists
|
||||||
|
result = storageStrategy.directoryExists(CONTAINER_NAME, null);
|
||||||
|
assertTrue(result, "Directory doesn't exist");
|
||||||
|
result = storageStrategy.directoryExists(CONTAINER_NAME + File.separator, null);
|
||||||
|
assertTrue(result, "Directory doesn't exist");
|
||||||
|
|
||||||
|
|
||||||
|
result = storageStrategy.directoryExists(CONTAINER_NAME, SUBDIRECTORY_NAME);
|
||||||
|
assertFalse(result, "Directory exist");
|
||||||
|
|
||||||
|
//create subdirs inside the container
|
||||||
|
TestUtils.createContainerAsDirectory(CONTAINER_NAME + File.separator + SUBDIRECTORY_NAME);
|
||||||
|
//check if exists
|
||||||
|
result = storageStrategy.directoryExists(CONTAINER_NAME, SUBDIRECTORY_NAME);
|
||||||
|
assertTrue(result, "Directory doesn't exist");
|
||||||
|
result = storageStrategy.directoryExists(CONTAINER_NAME, File.separator + SUBDIRECTORY_NAME);
|
||||||
|
assertTrue(result, "Directory doesn't exist");
|
||||||
|
result = storageStrategy.directoryExists(CONTAINER_NAME, SUBDIRECTORY_NAME + File.separator);
|
||||||
|
assertTrue(result, "Directory doesn't exist");
|
||||||
|
result = storageStrategy.directoryExists(CONTAINER_NAME + File.separator, File.separator + SUBDIRECTORY_NAME);
|
||||||
|
assertTrue(result, "Directory doesn't exist");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testClearContainer() throws IOException{
|
||||||
|
storageStrategy.createContainer(CONTAINER_NAME);
|
||||||
|
Set<String> blobs = TestUtils.createBlobsInContainer(
|
||||||
|
CONTAINER_NAME,
|
||||||
|
new String[]{
|
||||||
|
TestUtils.createRandomBlobKey("clean_container-", ".jpg"),
|
||||||
|
TestUtils.createRandomBlobKey("bf/sd/as/clean_container-", ".jpg")}
|
||||||
|
);
|
||||||
|
//test if file exits
|
||||||
|
for(String blob:blobs) {
|
||||||
|
TestUtils.fileExists(TARGET_CONTAINER_NAME + File.separator + blob, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
//clear the container
|
||||||
|
storageStrategy.clearContainer(CONTAINER_NAME);
|
||||||
|
//test if container still exits
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME, true);
|
||||||
|
//test if file was cleared
|
||||||
|
for(String blob:blobs) {
|
||||||
|
TestUtils.fileExists(TARGET_CONTAINER_NAME + File.separator + blob, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testClearContainer_NotExistingContainer() throws IOException{
|
||||||
|
//test if container still exits
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME, false);
|
||||||
|
//clear the container
|
||||||
|
storageStrategy.clearContainer(CONTAINER_NAME);
|
||||||
|
//test if container still exits
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testClearContainerAndThenDeleteContainer() throws IOException{
|
||||||
|
storageStrategy.createContainer(CONTAINER_NAME);
|
||||||
|
Set<String> blobs = TestUtils.createBlobsInContainer(
|
||||||
|
CONTAINER_NAME,
|
||||||
|
new String[]{
|
||||||
|
TestUtils.createRandomBlobKey("clean_container-", ".jpg"),
|
||||||
|
TestUtils.createRandomBlobKey("bf/sd/as/clean_container-", ".jpg")}
|
||||||
|
);
|
||||||
|
//test if file exits
|
||||||
|
for(String blob:blobs) {
|
||||||
|
TestUtils.fileExists(TARGET_CONTAINER_NAME + File.separator + blob, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
//clear the container
|
||||||
|
storageStrategy.clearContainer(CONTAINER_NAME);
|
||||||
|
//test if container still exits
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME, true);
|
||||||
|
//test if file was cleared
|
||||||
|
for(String blob:blobs) {
|
||||||
|
TestUtils.fileExists(TARGET_CONTAINER_NAME + File.separator + blob, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
//delete the container
|
||||||
|
storageStrategy.deleteContainer(CONTAINER_NAME);
|
||||||
|
//test if container still exits
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME, false);
|
||||||
|
assertFalse(storageStrategy.containerExists(CONTAINER_NAME), "Container still exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testDeleteContainer() throws IOException {
|
||||||
|
final String BLOB_KEY1 = "blobName.jpg";
|
||||||
|
final String BLOB_KEY2 = "aa/bb/cc/dd/ee/ff/23/blobName.jpg";
|
||||||
|
boolean result;
|
||||||
|
|
||||||
|
result = storageStrategy.createContainer(CONTAINER_NAME);
|
||||||
|
|
||||||
|
//put data inside the container
|
||||||
|
TestUtils.createBlobsInContainer(
|
||||||
|
CONTAINER_NAME,
|
||||||
|
new String[] {BLOB_KEY1, BLOB_KEY2}
|
||||||
|
);
|
||||||
|
|
||||||
|
storageStrategy.deleteContainer(CONTAINER_NAME);
|
||||||
|
assertTrue(result, "Cannot delete container");
|
||||||
|
TestUtils.directoryExists(CONTAINER_NAME, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDeleteContainer_EmptyContainer() {
|
||||||
|
boolean result;
|
||||||
|
|
||||||
|
result = storageStrategy.createContainer(CONTAINER_NAME);
|
||||||
|
assertTrue(result, "Cannot create container");
|
||||||
|
|
||||||
|
storageStrategy.deleteContainer(CONTAINER_NAME);
|
||||||
|
TestUtils.directoryExists(CONTAINER_NAME, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDeleteContainer_ErrorWhenNotExists() {
|
||||||
|
try {
|
||||||
|
storageStrategy.deleteContainer(CONTAINER_NAME);
|
||||||
|
fail("Exception not throwed");
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testGetAllContainerNames() {
|
||||||
|
Iterable<String> resultList;
|
||||||
|
|
||||||
|
//no container
|
||||||
|
resultList = storageStrategy.getAllContainerNames();
|
||||||
|
assertNotNull(resultList, "Result is null");
|
||||||
|
assertFalse(resultList.iterator().hasNext(), "Containers detected");
|
||||||
|
|
||||||
|
//create containers
|
||||||
|
storageStrategy.createContainer(CONTAINER_NAME + "1");
|
||||||
|
storageStrategy.createContainer(CONTAINER_NAME + "2");
|
||||||
|
storageStrategy.createContainer(CONTAINER_NAME + "3");
|
||||||
|
|
||||||
|
List<String> containers = new ArrayList<String>();
|
||||||
|
resultList = storageStrategy.getAllContainerNames();
|
||||||
|
Iterator<String> containersIterator = resultList.iterator();
|
||||||
|
while(containersIterator.hasNext()){
|
||||||
|
containers.add(containersIterator.next());
|
||||||
|
}
|
||||||
|
assertEquals(containers.size(), 3, "Different containers number");
|
||||||
|
assertTrue(containers.contains(CONTAINER_NAME + "1"), "Containers doesn't exist");
|
||||||
|
assertTrue(containers.contains(CONTAINER_NAME + "2"), "Containers doesn't exist");
|
||||||
|
assertTrue(containers.contains(CONTAINER_NAME + "3"), "Containers doesn't exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testContainerExists(){
|
||||||
|
boolean result;
|
||||||
|
|
||||||
|
TestUtils.directoryExists(TARGET_CONTAINER_NAME, false);
|
||||||
|
result = storageStrategy.containerExists(CONTAINER_NAME);
|
||||||
|
assertFalse(result, "Container exists");
|
||||||
|
storageStrategy.createContainer(CONTAINER_NAME);
|
||||||
|
result = storageStrategy.containerExists(CONTAINER_NAME);
|
||||||
|
assertTrue(result, "Container exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testNewBlob() {
|
||||||
|
String blobKey;
|
||||||
|
Blob newBlob;
|
||||||
|
|
||||||
|
blobKey = TestUtils.createRandomBlobKey("blobtest-", ".txt");
|
||||||
|
newBlob = storageStrategy.newBlob(blobKey);
|
||||||
|
assertNotNull(newBlob, "Created blob was null");
|
||||||
|
assertNotNull(newBlob.getMetadata(), "Created blob metadata were null");
|
||||||
|
assertEquals(newBlob.getMetadata().getName(), blobKey, "Created blob name is different");
|
||||||
|
|
||||||
|
blobKey = TestUtils.createRandomBlobKey("blobtest-", "");
|
||||||
|
newBlob = storageStrategy.newBlob(blobKey);
|
||||||
|
assertEquals(newBlob.getMetadata().getName(), blobKey, "Created blob name is different");
|
||||||
|
|
||||||
|
blobKey = TestUtils.createRandomBlobKey("asd/asd/asdasd/afadsf-", "");
|
||||||
|
newBlob = storageStrategy.newBlob(blobKey);
|
||||||
|
assertEquals(newBlob.getMetadata().getName(), blobKey, "Created blob name is different");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testWritePayloadOnFile() throws IOException {
|
||||||
|
String blobKey;
|
||||||
|
File sourceFile;
|
||||||
|
FilePayload filePayload;
|
||||||
|
|
||||||
|
blobKey = TestUtils.createRandomBlobKey("writePayload-", ".img");
|
||||||
|
sourceFile = TestUtils.getImageForBlobPayload();
|
||||||
|
filePayload = new FilePayload(sourceFile);
|
||||||
|
//write files
|
||||||
|
storageStrategy.writePayloadOnFile(CONTAINER_NAME, blobKey, filePayload);
|
||||||
|
//verify that the files is equal
|
||||||
|
String blobFullPath = TARGET_CONTAINER_NAME + File.separator + blobKey;
|
||||||
|
InputStream expectedInput = new FileInputStream(sourceFile);
|
||||||
|
InputStream currentInput = new FileInputStream(blobFullPath);
|
||||||
|
assertTrue(TestUtils.isSame(expectedInput, currentInput), "Files aren't equals");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWritePayloadOnFile_SourceFileDoesntExist() {
|
||||||
|
File sourceFile = new File("asdfkjsadkfjasdlfasdflk.asdfasdfas");
|
||||||
|
try {
|
||||||
|
new FilePayload(sourceFile);
|
||||||
|
fail("Exception not throwed");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testGetFileForBlobKey() {
|
||||||
|
String blobKey;
|
||||||
|
File fileForPayload;
|
||||||
|
String fullPath = (new File(TARGET_CONTAINER_NAME).getAbsolutePath()) + File.separator;
|
||||||
|
|
||||||
|
blobKey = TestUtils.createRandomBlobKey("getFileForBlobKey-", ".img");
|
||||||
|
fileForPayload = storageStrategy.getFileForBlobKey(CONTAINER_NAME, blobKey);
|
||||||
|
assertNotNull(fileForPayload, "Result File object is null");
|
||||||
|
assertEquals(fileForPayload.getAbsolutePath(), fullPath + blobKey, "Wrong file path");
|
||||||
|
|
||||||
|
blobKey = TestUtils.createRandomBlobKey("asd/vmad/andsnf/getFileForBlobKey-", ".img");
|
||||||
|
fileForPayload = storageStrategy.getFileForBlobKey(CONTAINER_NAME, blobKey);
|
||||||
|
assertEquals(fileForPayload.getAbsolutePath(), fullPath + blobKey, "Wrong file path");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testBlobExists() throws IOException {
|
||||||
|
String[] sourceBlobKeys = new String[]{
|
||||||
|
TestUtils.createRandomBlobKey("blobExists-", ".jpg"),
|
||||||
|
TestUtils.createRandomBlobKey("blobExists-", ".jpg"),
|
||||||
|
TestUtils.createRandomBlobKey("afasd" + File.separator + "asdma" + File.separator + "blobExists-", ".jpg")
|
||||||
|
};
|
||||||
|
|
||||||
|
for(String blobKey:sourceBlobKeys) {
|
||||||
|
assertFalse(storageStrategy.blobExists(CONTAINER_NAME, blobKey), "Blob " + blobKey + " exists");
|
||||||
|
}
|
||||||
|
TestUtils.createBlobsInContainer(CONTAINER_NAME, sourceBlobKeys);
|
||||||
|
for(String blobKey:sourceBlobKeys) {
|
||||||
|
assertTrue(storageStrategy.blobExists(CONTAINER_NAME, blobKey), "Blob " + blobKey + " doesn't exist");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testRemoveBlob() throws IOException {
|
||||||
|
storageStrategy.createContainer(CONTAINER_NAME);
|
||||||
|
Set<String> blobKeys = TestUtils.createBlobsInContainer(
|
||||||
|
CONTAINER_NAME,
|
||||||
|
new String[]{
|
||||||
|
TestUtils.createRandomBlobKey("removeBlob-", ".jpg"),
|
||||||
|
TestUtils.createRandomBlobKey("removeBlob-", ".jpg"),
|
||||||
|
TestUtils.createRandomBlobKey("346" + File.separator + "g3sx2" + File.separator + "removeBlob-", ".jpg"),
|
||||||
|
TestUtils.createRandomBlobKey("346" + File.separator + "g3sx2" + File.separator + "removeBlob-", ".jpg")
|
||||||
|
});
|
||||||
|
|
||||||
|
Set<String> remainingBlobKeys = new HashSet<String>();
|
||||||
|
for(String key:blobKeys) {
|
||||||
|
remainingBlobKeys.add(key);
|
||||||
|
}
|
||||||
|
for (String blobKeyToRemove:blobKeys) {
|
||||||
|
storageStrategy.removeBlob(CONTAINER_NAME, blobKeyToRemove);
|
||||||
|
//checks if the blob was removed
|
||||||
|
TestUtils.fileExists(blobKeyToRemove, false);
|
||||||
|
remainingBlobKeys.remove(blobKeyToRemove);
|
||||||
|
//checks if all other blobs still exists
|
||||||
|
for(String remainingBlobKey:remainingBlobKeys) {
|
||||||
|
TestUtils.fileExists(TARGET_CONTAINER_NAME + File.separator + remainingBlobKey, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testRemoveBlob_ContainerNotExists() {
|
||||||
|
storageStrategy.removeBlob("asdasdasd", "sdfsdfsdfasd");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testRemoveBlob_BlobNotExists() {
|
||||||
|
storageStrategy.createContainer(CONTAINER_NAME);
|
||||||
|
storageStrategy.removeBlob(CONTAINER_NAME, "sdfsdfsdfasd");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testGetBlobKeysInsideContainer() throws IOException {
|
||||||
|
Iterable<String> resultList;
|
||||||
|
|
||||||
|
//no container
|
||||||
|
resultList = storageStrategy.getBlobKeysInsideContainer(CONTAINER_NAME);
|
||||||
|
assertNotNull(resultList, "Result is null");
|
||||||
|
assertFalse(resultList.iterator().hasNext(), "Blobs detected");
|
||||||
|
|
||||||
|
//create blobs
|
||||||
|
storageStrategy.createContainer(CONTAINER_NAME);
|
||||||
|
Set<String> createBlobKeys = TestUtils.createBlobsInContainer(
|
||||||
|
CONTAINER_NAME,
|
||||||
|
new String[]{
|
||||||
|
TestUtils.createRandomBlobKey("GetBlobKeys-", ".jpg"),
|
||||||
|
TestUtils.createRandomBlobKey("GetBlobKeys-", ".jpg"),
|
||||||
|
TestUtils.createRandomBlobKey("563" + File.separator + "g3sx2" + File.separator + "removeBlob-", ".jpg"),
|
||||||
|
TestUtils.createRandomBlobKey("563" + File.separator + "g3sx2" + File.separator + "removeBlob-", ".jpg")
|
||||||
|
});
|
||||||
|
storageStrategy.getBlobKeysInsideContainer(CONTAINER_NAME);
|
||||||
|
|
||||||
|
List<String> retrievedBlobKeys = new ArrayList<String>();
|
||||||
|
resultList = storageStrategy.getBlobKeysInsideContainer(CONTAINER_NAME);
|
||||||
|
Iterator<String> containersIterator = resultList.iterator();
|
||||||
|
while(containersIterator.hasNext()){
|
||||||
|
retrievedBlobKeys.add(containersIterator.next());
|
||||||
|
}
|
||||||
|
assertEquals(retrievedBlobKeys.size(), createBlobKeys.size(), "Different blobs number");
|
||||||
|
for(String createdBlobKey:createBlobKeys) {
|
||||||
|
assertTrue(retrievedBlobKeys.contains(createdBlobKey), "Blob " + createdBlobKey + " not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testCountsBlob() {
|
||||||
|
try {
|
||||||
|
storageStrategy.countBlobs(CONTAINER_NAME, ListContainerOptions.NONE);
|
||||||
|
fail("Magically the method was implemented... Wow!");
|
||||||
|
} catch (UnsupportedOperationException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testInvalidBlobKey() {
|
||||||
|
try {
|
||||||
|
storageStrategy.newBlob("/test.jpg");
|
||||||
|
fail("Wrong blob key not recognized");
|
||||||
|
} catch (IllegalArgumentException e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testInvalidContainerName() {
|
||||||
|
try {
|
||||||
|
storageStrategy.createContainer("file/system");
|
||||||
|
fail("Wrong container name not recognized");
|
||||||
|
} catch (IllegalArgumentException e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------- Private methods
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,245 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.filesystem.utils;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
|
||||||
|
import static org.testng.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class for test
|
||||||
|
*
|
||||||
|
* @author Alfredo "Rainbowbreeze" Morresi
|
||||||
|
*/
|
||||||
|
public class TestUtils {
|
||||||
|
|
||||||
|
private static final String TARGET_RESOURCE_DIR = "." + File.separator + "src" + File.separator + "test" + File.separator + "resources" + File.separator;
|
||||||
|
/** All the files available for the tests */
|
||||||
|
private static String[] imageResource = new String[]{
|
||||||
|
TARGET_RESOURCE_DIR + "image1.jpg",
|
||||||
|
TARGET_RESOURCE_DIR + "image2.jpg",
|
||||||
|
TARGET_RESOURCE_DIR + "image3.jpg",
|
||||||
|
TARGET_RESOURCE_DIR + "image4.jpg"
|
||||||
|
};
|
||||||
|
private static int imageResourceIndex = 0;
|
||||||
|
|
||||||
|
public static final String TARGET_BASE_DIR = "." + File.separator + "target" + File.separator + "basedir" + File.separator;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a random blob key simple name (with no path in the key)
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static String createRandomBlobKey() {
|
||||||
|
return createRandomBlobKey("", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a random blob key simple name (with no path in the key)
|
||||||
|
* @param prefix a prefix to the id, default "testkey-"
|
||||||
|
* @param extension a extension for the blob key, default ".jpg"
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static String createRandomBlobKey(String prefix, String extension) {
|
||||||
|
String okPrefix = (null != prefix && !"".equals(prefix)) ? prefix : "testkey-";
|
||||||
|
String okExtension = (null != extension && !"".equals(extension)) ? extension : ".jpg";
|
||||||
|
return okPrefix + UUID.randomUUID().toString() + okExtension;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates blobs in container
|
||||||
|
* @param containerName
|
||||||
|
* @param blobNames
|
||||||
|
* @return a Set with all blobs created
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static Set<String> createBlobsInContainer(String containerName, String[] blobNames) throws IOException {
|
||||||
|
Set<String> blobNamesCreatedInContainer = new HashSet<String>();
|
||||||
|
for (String blobName : blobNames) {
|
||||||
|
createBlobAsFile(containerName, blobName, getImageForBlobPayload());
|
||||||
|
blobNamesCreatedInContainer.add(blobName);
|
||||||
|
}
|
||||||
|
return blobNamesCreatedInContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a container object creating a directory
|
||||||
|
* @param containerName
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static void createContainerAsDirectory(String containerName) throws IOException {
|
||||||
|
FileUtils.forceMkdir(new File(TARGET_BASE_DIR + containerName));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param directoryFullPath the directory path
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static boolean directoryExists(String directoryFullPath) {
|
||||||
|
File file = new File(directoryFullPath);
|
||||||
|
boolean exists = file.exists() || file.isDirectory();
|
||||||
|
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param directoryFullPath
|
||||||
|
* @param checkResult
|
||||||
|
* @param expectedResult
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static boolean directoryExists(String directoryFullPath, boolean expectedResult) {
|
||||||
|
boolean exists = directoryExists(directoryFullPath);
|
||||||
|
|
||||||
|
if (expectedResult) {
|
||||||
|
assertTrue(exists, "Directory " + directoryFullPath + " doens't exists");
|
||||||
|
} else {
|
||||||
|
assertFalse(exists, "Directory " + directoryFullPath + " still exists");
|
||||||
|
}
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean fileExists(String fileFullName) {
|
||||||
|
File file = new File(fileFullName);
|
||||||
|
boolean exists = file.exists() || file.isFile();
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param fileFullName
|
||||||
|
* @param checkResult
|
||||||
|
* @param expectedResult
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static boolean fileExists(String fileFullName, boolean expectedResult) {
|
||||||
|
boolean exists = fileExists(fileFullName);
|
||||||
|
|
||||||
|
if (expectedResult) {
|
||||||
|
assertTrue(exists, "File " + fileFullName + " doens't exists");
|
||||||
|
} else {
|
||||||
|
assertFalse(exists, "File " + fileFullName + " still exists");
|
||||||
|
}
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Empty a directory
|
||||||
|
*
|
||||||
|
* @param directoryName
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static void cleanDirectoryContent(String directoryName) throws IOException {
|
||||||
|
File parentDirectory = new File(directoryName);
|
||||||
|
File[] children = parentDirectory.listFiles();
|
||||||
|
if (null != children) {
|
||||||
|
for(File child:children) {
|
||||||
|
FileUtils.forceDelete(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a blob object from a given file
|
||||||
|
* @param source
|
||||||
|
* @param containerName
|
||||||
|
* @param blobKey
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static void createBlobAsFile(String containerName, String blobKey, File source) throws IOException {
|
||||||
|
String filePath;
|
||||||
|
if (blobKey.startsWith("\\"))
|
||||||
|
filePath = containerName + blobKey;
|
||||||
|
else
|
||||||
|
filePath = containerName + File.separator + blobKey;
|
||||||
|
FileUtils.copyFile(source, new File(TARGET_BASE_DIR + filePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a pointer to an image, cycling between the ones that are available
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static File getImageForBlobPayload() {
|
||||||
|
String fileName = imageResource[imageResourceIndex++];
|
||||||
|
if (imageResourceIndex >= imageResource.length) imageResourceIndex = 0;
|
||||||
|
return new File(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare two input stream
|
||||||
|
*
|
||||||
|
* @param input1 the first stream
|
||||||
|
* @param input2 the second stream
|
||||||
|
* @return true if the streams contain the same content, or false otherwise
|
||||||
|
* @throws IOException
|
||||||
|
* @throws IllegalArgumentException if the stream is null
|
||||||
|
*/
|
||||||
|
public static boolean isSame(InputStream input1, InputStream input2 ) throws IOException {
|
||||||
|
boolean error = false;
|
||||||
|
try {
|
||||||
|
byte[] buffer1 = new byte[1024];
|
||||||
|
byte[] buffer2 = new byte[1024];
|
||||||
|
try {
|
||||||
|
int numRead1 = 0;
|
||||||
|
int numRead2 = 0;
|
||||||
|
while (true) {
|
||||||
|
numRead1 = input1.read(buffer1);
|
||||||
|
numRead2 = input2.read(buffer2);
|
||||||
|
if (numRead1 > -1) {
|
||||||
|
if (numRead2 != numRead1) return false;
|
||||||
|
// Otherwise same number of bytes read
|
||||||
|
if (!Arrays.equals(buffer1, buffer2)) return false;
|
||||||
|
// Otherwise same bytes read, so continue ...
|
||||||
|
} else {
|
||||||
|
// Nothing more in stream 1 ...
|
||||||
|
return numRead2 < 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
input1.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
error = true; // this error should be thrown, even if there is an error closing stream 2
|
||||||
|
throw e;
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
error = true; // this error should be thrown, even if there is an error closing stream 2
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
input2.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (!error) throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 339 KiB |
Binary file not shown.
After Width: | Height: | Size: 844 KiB |
Binary file not shown.
After Width: | Height: | Size: 641 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.8 MiB |
|
@ -0,0 +1,27 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
# ====================================================================
|
||||||
|
#
|
||||||
|
|
||||||
|
# Set the default logging level for all loggers to WARNING
|
||||||
|
.level = INFO
|
||||||
|
|
||||||
|
handlers = java.util.logging.ConsoleHandler
|
||||||
|
java.util.logging.ConsoleHandler.level = ALL
|
||||||
|
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
|
||||||
|
org.jclouds.filesystem.FilesystemAsyncBlobStore.level=ALL
|
||||||
|
org.jclouds.filesystem.FilesystemAsyncBlobStore.handler=java.util.logging.ConsoleHandler
|
Loading…
Reference in New Issue