mirror of https://github.com/apache/jclouds.git
Issue 264: fixed blob stuff in rackspace
This commit is contained in:
parent
237afa4ddc
commit
0684dc2344
|
@ -28,6 +28,7 @@ import java.util.regex.Pattern;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import org.jclouds.blobstore.AsyncBlobStore;
|
||||||
import org.jclouds.blobstore.BlobStore;
|
import org.jclouds.blobstore.BlobStore;
|
||||||
import org.jclouds.blobstore.domain.Blob;
|
import org.jclouds.blobstore.domain.Blob;
|
||||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||||
|
@ -135,6 +136,10 @@ public class BlobStoreUtilsImpl implements BlobStoreUtils {
|
||||||
return "".equals(prefix) ? null : prefix;
|
return "".equals(prefix) ? null : prefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String parseDirectoryFromPath(String path) {
|
||||||
|
return path.substring(0, path.lastIndexOf('/'));
|
||||||
|
}
|
||||||
|
|
||||||
private static Pattern keyFromContainer = Pattern.compile("/?[^/]+/(.*)");
|
private static Pattern keyFromContainer = Pattern.compile("/?[^/]+/(.*)");
|
||||||
|
|
||||||
public static String getKeyFor(GeneratedHttpRequest<?> request, HttpResponse from) {
|
public static String getKeyFor(GeneratedHttpRequest<?> request, HttpResponse from) {
|
||||||
|
@ -168,4 +173,12 @@ public class BlobStoreUtilsImpl implements BlobStoreUtils {
|
||||||
throw new IllegalArgumentException("Object type not supported: " + o.getClass().getName());
|
throw new IllegalArgumentException("Object type not supported: " + o.getClass().getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void createParentIfNeededAsync(AsyncBlobStore asyncBlobStore, String container,
|
||||||
|
Blob blob) {
|
||||||
|
String name = blob.getMetadata().getName();
|
||||||
|
if (name.indexOf('/') > 0) {
|
||||||
|
asyncBlobStore.createDirectory(container, parseDirectoryFromPath(name));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -36,7 +36,6 @@ import java.io.InputStream;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.zip.GZIPInputStream;
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
|
@ -46,6 +45,7 @@ import org.jclouds.blobstore.domain.Blob;
|
||||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||||
import org.jclouds.blobstore.domain.PageSet;
|
import org.jclouds.blobstore.domain.PageSet;
|
||||||
import org.jclouds.blobstore.domain.StorageMetadata;
|
import org.jclouds.blobstore.domain.StorageMetadata;
|
||||||
|
import org.jclouds.blobstore.domain.StorageType;
|
||||||
import org.jclouds.blobstore.util.internal.BlobStoreUtilsImpl;
|
import org.jclouds.blobstore.util.internal.BlobStoreUtilsImpl;
|
||||||
import org.jclouds.encryption.EncryptionService;
|
import org.jclouds.encryption.EncryptionService;
|
||||||
import org.jclouds.encryption.EncryptionService.MD5InputStreamResult;
|
import org.jclouds.encryption.EncryptionService.MD5InputStreamResult;
|
||||||
|
@ -61,6 +61,8 @@ import org.testng.annotations.DataProvider;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.base.Predicate;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.io.ByteStreams;
|
import com.google.common.io.ByteStreams;
|
||||||
import com.google.common.io.InputSupplier;
|
import com.google.common.io.InputSupplier;
|
||||||
|
@ -371,10 +373,18 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertContainerEmptyDeleting(String containerName, String key) {
|
private void assertContainerEmptyDeleting(String containerName, String key) {
|
||||||
Set<? extends StorageMetadata> listing = context.getBlobStore().list(containerName);
|
Iterable<? extends StorageMetadata> listing = Iterables.filter(context.getBlobStore().list(
|
||||||
assertEquals(listing.size(), 0, String.format(
|
containerName), new Predicate<StorageMetadata>() {
|
||||||
"deleting %s, we still have %s left in container %s, using encoding %s", key,
|
|
||||||
listing.size(), containerName, LOCAL_ENCODING));
|
@Override
|
||||||
|
public boolean apply(StorageMetadata input) {
|
||||||
|
return input.getType() == StorageType.BLOB;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
assertEquals(Iterables.size(listing), 0, String.format(
|
||||||
|
"deleting %s, we still have %s blobs left in container %s, using encoding %s", key,
|
||||||
|
Iterables.size(listing), containerName, LOCAL_ENCODING));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(groups = { "integration", "live" })
|
@Test(groups = { "integration", "live" })
|
||||||
|
|
|
@ -69,7 +69,6 @@ public class BaseContainerIntegrationTest extends BaseBlobStoreIntegrationTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test(groups = { "integration", "live" })
|
@Test(groups = { "integration", "live" })
|
||||||
public void testWithDetails() throws InterruptedException {
|
public void testWithDetails() throws InterruptedException {
|
||||||
String key = "hello";
|
String key = "hello";
|
||||||
|
@ -202,6 +201,12 @@ public class BaseContainerIntegrationTest extends BaseBlobStoreIntegrationTest {
|
||||||
assert container.getNextMarker() == null;
|
assert container.getNextMarker() == null;
|
||||||
assert container.size() == 1 : container;
|
assert container.size() == 1 : container;
|
||||||
|
|
||||||
|
context.getBlobStore().createDirectory(containerName, directory + "/" + directory);
|
||||||
|
|
||||||
|
container = context.getBlobStore().list(containerName, inDirectory(directory).recursive());
|
||||||
|
assert container.getNextMarker() == null;
|
||||||
|
assert container.size() == 1 : container;
|
||||||
|
|
||||||
context.getBlobStore().clearContainer(containerName, inDirectory(directory).recursive());
|
context.getBlobStore().clearContainer(containerName, inDirectory(directory).recursive());
|
||||||
|
|
||||||
// should no longer have the 2 level-deep directory above
|
// should no longer have the 2 level-deep directory above
|
||||||
|
|
|
@ -21,10 +21,14 @@ package org.jclouds.blobstore.util;
|
||||||
import static org.easymock.EasyMock.expect;
|
import static org.easymock.EasyMock.expect;
|
||||||
import static org.easymock.classextension.EasyMock.createMock;
|
import static org.easymock.classextension.EasyMock.createMock;
|
||||||
import static org.easymock.classextension.EasyMock.replay;
|
import static org.easymock.classextension.EasyMock.replay;
|
||||||
|
import static org.easymock.classextension.EasyMock.verify;
|
||||||
import static org.testng.Assert.assertEquals;
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
|
||||||
|
import org.jclouds.blobstore.AsyncBlobStore;
|
||||||
|
import org.jclouds.blobstore.domain.Blob;
|
||||||
|
import org.jclouds.blobstore.domain.MutableBlobMetadata;
|
||||||
import org.jclouds.blobstore.util.internal.BlobStoreUtilsImpl;
|
import org.jclouds.blobstore.util.internal.BlobStoreUtilsImpl;
|
||||||
import org.jclouds.http.HttpResponse;
|
import org.jclouds.http.HttpResponse;
|
||||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
||||||
|
@ -38,6 +42,68 @@ import org.testng.annotations.Test;
|
||||||
@Test(groups = "unit", testName = "blobstore.BlobStoreUtilsTest")
|
@Test(groups = "unit", testName = "blobstore.BlobStoreUtilsTest")
|
||||||
public class BlobStoreUtilsTest {
|
public class BlobStoreUtilsTest {
|
||||||
|
|
||||||
|
public void testCreateParentIfNeededAsyncNoPath() {
|
||||||
|
AsyncBlobStore asyncBlobStore = createMock(AsyncBlobStore.class);
|
||||||
|
String container = "container";
|
||||||
|
Blob blob = createMock(Blob.class);
|
||||||
|
MutableBlobMetadata md = createMock(MutableBlobMetadata.class);
|
||||||
|
|
||||||
|
expect(blob.getMetadata()).andReturn(md).atLeastOnce();
|
||||||
|
expect(md.getName()).andReturn("hello").atLeastOnce();
|
||||||
|
|
||||||
|
replay(asyncBlobStore);
|
||||||
|
replay(blob);
|
||||||
|
replay(md);
|
||||||
|
|
||||||
|
BlobStoreUtilsImpl.createParentIfNeededAsync(asyncBlobStore, container, blob);
|
||||||
|
|
||||||
|
verify(asyncBlobStore);
|
||||||
|
verify(blob);
|
||||||
|
verify(md);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCreateParentIfNeededAsyncSinglePath() {
|
||||||
|
AsyncBlobStore asyncBlobStore = createMock(AsyncBlobStore.class);
|
||||||
|
String container = "container";
|
||||||
|
Blob blob = createMock(Blob.class);
|
||||||
|
MutableBlobMetadata md = createMock(MutableBlobMetadata.class);
|
||||||
|
|
||||||
|
expect(blob.getMetadata()).andReturn(md).atLeastOnce();
|
||||||
|
expect(md.getName()).andReturn("rootpath/hello").atLeastOnce();
|
||||||
|
expect(asyncBlobStore.createDirectory("container", "rootpath")).andReturn(null);
|
||||||
|
|
||||||
|
replay(asyncBlobStore);
|
||||||
|
replay(blob);
|
||||||
|
replay(md);
|
||||||
|
|
||||||
|
BlobStoreUtilsImpl.createParentIfNeededAsync(asyncBlobStore, container, blob);
|
||||||
|
|
||||||
|
verify(asyncBlobStore);
|
||||||
|
verify(blob);
|
||||||
|
verify(md);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCreateParentIfNeededAsyncNestedPath() {
|
||||||
|
AsyncBlobStore asyncBlobStore = createMock(AsyncBlobStore.class);
|
||||||
|
String container = "container";
|
||||||
|
Blob blob = createMock(Blob.class);
|
||||||
|
MutableBlobMetadata md = createMock(MutableBlobMetadata.class);
|
||||||
|
|
||||||
|
expect(blob.getMetadata()).andReturn(md).atLeastOnce();
|
||||||
|
expect(md.getName()).andReturn("rootpath/subpath/hello").atLeastOnce();
|
||||||
|
expect(asyncBlobStore.createDirectory("container", "rootpath/subpath")).andReturn(null);
|
||||||
|
|
||||||
|
replay(asyncBlobStore);
|
||||||
|
replay(blob);
|
||||||
|
replay(md);
|
||||||
|
|
||||||
|
BlobStoreUtilsImpl.createParentIfNeededAsync(asyncBlobStore, container, blob);
|
||||||
|
|
||||||
|
verify(asyncBlobStore);
|
||||||
|
verify(blob);
|
||||||
|
verify(md);
|
||||||
|
}
|
||||||
|
|
||||||
public void testGetKeyForAzureS3AndRackspace() {
|
public void testGetKeyForAzureS3AndRackspace() {
|
||||||
|
|
||||||
GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class);
|
GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class);
|
||||||
|
@ -45,7 +111,8 @@ public class BlobStoreUtilsTest {
|
||||||
HttpResponse from = createMock(HttpResponse.class);
|
HttpResponse from = createMock(HttpResponse.class);
|
||||||
expect(request.getEndpoint()).andReturn(
|
expect(request.getEndpoint()).andReturn(
|
||||||
URI.create("https://jclouds.blob.core.windows.net/adriancole-blobstore0/five"));
|
URI.create("https://jclouds.blob.core.windows.net/adriancole-blobstore0/five"));
|
||||||
expect(request.getArgs()).andReturn(new Object[] { "adriancole-blobstore0", "five" }).atLeastOnce();
|
expect(request.getArgs()).andReturn(new Object[] { "adriancole-blobstore0", "five" })
|
||||||
|
.atLeastOnce();
|
||||||
|
|
||||||
replay(request);
|
replay(request);
|
||||||
replay(from);
|
replay(from);
|
||||||
|
@ -58,15 +125,19 @@ public class BlobStoreUtilsTest {
|
||||||
GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class);
|
GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class);
|
||||||
|
|
||||||
HttpResponse from = createMock(HttpResponse.class);
|
HttpResponse from = createMock(HttpResponse.class);
|
||||||
expect(request.getEndpoint()).andReturn(
|
expect(request.getEndpoint())
|
||||||
URI.create("https://storage4.clouddrive.com/v1/MossoCloudFS_dc1f419c-5059-4c87-a389-3f2e33a77b22/adriancole-blobstore0/four"));
|
.andReturn(
|
||||||
expect(request.getArgs()).andReturn(new Object[] { "adriancole-blobstore0/four" }).atLeastOnce();
|
URI
|
||||||
|
.create("https://storage4.clouddrive.com/v1/MossoCloudFS_dc1f419c-5059-4c87-a389-3f2e33a77b22/adriancole-blobstore0/four"));
|
||||||
|
expect(request.getArgs()).andReturn(new Object[] { "adriancole-blobstore0/four" })
|
||||||
|
.atLeastOnce();
|
||||||
|
|
||||||
replay(request);
|
replay(request);
|
||||||
replay(from);
|
replay(from);
|
||||||
|
|
||||||
assertEquals(BlobStoreUtilsImpl.getKeyFor(request, from), "four");
|
assertEquals(BlobStoreUtilsImpl.getKeyFor(request, from), "four");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGetContainer() {
|
public void testGetContainer() {
|
||||||
String container = BlobStoreUtilsImpl.parseContainerFromPath("foo");
|
String container = BlobStoreUtilsImpl.parseContainerFromPath("foo");
|
||||||
assertEquals(container, "foo");
|
assertEquals(container, "foo");
|
||||||
|
|
|
@ -20,6 +20,7 @@ package org.jclouds.rackspace.cloudfiles.blobstore;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static com.google.common.util.concurrent.Futures.compose;
|
import static com.google.common.util.concurrent.Futures.compose;
|
||||||
|
import static org.jclouds.blobstore.util.internal.BlobStoreUtilsImpl.createParentIfNeededAsync;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
@ -80,9 +81,8 @@ public class CloudFilesAsyncBlobStore extends BaseAsyncBlobStore {
|
||||||
@Inject
|
@Inject
|
||||||
CloudFilesAsyncBlobStore(BlobStoreContext context, BlobStoreUtils blobUtils,
|
CloudFilesAsyncBlobStore(BlobStoreContext context, BlobStoreUtils blobUtils,
|
||||||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService service,
|
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService service,
|
||||||
Location defaultLocation, Set<? extends Location> locations,
|
Location defaultLocation, Set<? extends Location> locations, CloudFilesClient sync,
|
||||||
CloudFilesClient sync, CloudFilesAsyncClient async,
|
CloudFilesAsyncClient async, ContainerToResourceMetadata container2ResourceMd,
|
||||||
ContainerToResourceMetadata container2ResourceMd,
|
|
||||||
BlobStoreListContainerOptionsToListContainerOptions container2ContainerListOptions,
|
BlobStoreListContainerOptionsToListContainerOptions container2ContainerListOptions,
|
||||||
ContainerToResourceList container2ResourceList, ObjectToBlob object2Blob,
|
ContainerToResourceList container2ResourceList, ObjectToBlob object2Blob,
|
||||||
BlobToObject blob2Object, ObjectToBlobMetadata object2BlobMd,
|
BlobToObject blob2Object, ObjectToBlobMetadata object2BlobMd,
|
||||||
|
@ -216,6 +216,7 @@ public class CloudFilesAsyncBlobStore extends BaseAsyncBlobStore {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<String> putBlob(String container, Blob blob) {
|
public ListenableFuture<String> putBlob(String container, Blob blob) {
|
||||||
|
createParentIfNeededAsync(this, container, blob);
|
||||||
return async.putObject(container, blob2Object.apply(blob));
|
return async.putObject(container, blob2Object.apply(blob));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
package org.jclouds.rackspace.cloudfiles.blobstore;
|
package org.jclouds.rackspace.cloudfiles.blobstore;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
import static org.jclouds.blobstore.util.internal.BlobStoreUtilsImpl.createParentIfNeededAsync;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -69,8 +70,8 @@ public class CloudFilesBlobStore extends BaseBlobStore {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
CloudFilesBlobStore(BlobStoreContext context, BlobStoreUtils blobUtils,
|
CloudFilesBlobStore(BlobStoreContext context, BlobStoreUtils blobUtils,
|
||||||
Location defaultLocation, Set<? extends Location> locations,
|
Location defaultLocation, Set<? extends Location> locations, CloudFilesClient sync,
|
||||||
CloudFilesClient sync, ContainerToResourceMetadata container2ResourceMd,
|
ContainerToResourceMetadata container2ResourceMd,
|
||||||
BlobStoreListContainerOptionsToListContainerOptions container2ContainerListOptions,
|
BlobStoreListContainerOptionsToListContainerOptions container2ContainerListOptions,
|
||||||
ContainerToResourceList container2ResourceList, ObjectToBlob object2Blob,
|
ContainerToResourceList container2ResourceList, ObjectToBlob object2Blob,
|
||||||
BlobToObject blob2Object, ObjectToBlobMetadata object2BlobMd,
|
BlobToObject blob2Object, ObjectToBlobMetadata object2BlobMd,
|
||||||
|
@ -194,6 +195,7 @@ public class CloudFilesBlobStore extends BaseBlobStore {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String putBlob(String container, Blob blob) {
|
public String putBlob(String container, Blob blob) {
|
||||||
|
createParentIfNeededAsync(context.getAsyncBlobStore(), container, blob);
|
||||||
return sync.putObject(container, blob2Object.apply(blob));
|
return sync.putObject(container, blob2Object.apply(blob));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ public class BlobStoreListContainerOptionsToListContainerOptions
|
||||||
options.underPath("");
|
options.underPath("");
|
||||||
}
|
}
|
||||||
if ((from.getDir() != null) && (from.isRecursive())) {
|
if ((from.getDir() != null) && (from.isRecursive())) {
|
||||||
options.withPrefix(from.getDir());
|
options.withPrefix(from.getDir().endsWith("/") ? from.getDir() : from.getDir() + "/");
|
||||||
}
|
}
|
||||||
if ((from.getDir() != null) && (!from.isRecursive())) {
|
if ((from.getDir() != null) && (!from.isRecursive())) {
|
||||||
options.underPath(from.getDir());
|
options.underPath(from.getDir());
|
||||||
|
|
Loading…
Reference in New Issue