mirror of https://github.com/apache/jclouds.git
JCLOUDS-929: Implement delimiter support in Swift.
The patch adds the delimiter support in the openstack-swift API. As part of the change, the subdirectory support in results is introduced. This occurs when a prefix and delimiter options are set and there are subdirectories present in the listing (i.e. multiple objects under the same prefix/delimiter). In this case, Swift will return a list of "subdir" objects (similar to CommonPrefixes in S3), which need to be treated differently.
This commit is contained in:
parent
a29d75a5d1
commit
6ec11fd6ec
|
@ -25,6 +25,7 @@ import org.jclouds.blobstore.strategy.IfDirectoryReturnNameStrategy;
|
||||||
import org.jclouds.blobstore.strategy.internal.MarkersIfDirectoryReturnNameStrategy;
|
import org.jclouds.blobstore.strategy.internal.MarkersIfDirectoryReturnNameStrategy;
|
||||||
import org.jclouds.openstack.swift.v1.domain.Container;
|
import org.jclouds.openstack.swift.v1.domain.Container;
|
||||||
import org.jclouds.openstack.swift.v1.domain.SwiftObject;
|
import org.jclouds.openstack.swift.v1.domain.SwiftObject;
|
||||||
|
import org.jclouds.openstack.swift.v1.functions.ParseObjectListFromResponse;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
|
|
||||||
|
@ -54,9 +55,7 @@ public class ToBlobMetadata implements Function<SwiftObject, MutableBlobMetadata
|
||||||
to.getContentMetadata().setContentMD5(from.getPayload().getContentMetadata().getContentMD5AsHashCode());
|
to.getContentMetadata().setContentMD5(from.getPayload().getContentMetadata().getContentMD5AsHashCode());
|
||||||
to.getContentMetadata().setExpires(from.getPayload().getContentMetadata().getExpires());
|
to.getContentMetadata().setExpires(from.getPayload().getContentMetadata().getExpires());
|
||||||
to.setUserMetadata(from.getMetadata());
|
to.setUserMetadata(from.getMetadata());
|
||||||
String directoryName = ifDirectoryReturnName.execute(to);
|
if (from.getETag().equals(ParseObjectListFromResponse.SUBDIR_ETAG)) {
|
||||||
if (directoryName != null) {
|
|
||||||
to.setName(directoryName);
|
|
||||||
to.setType(StorageType.RELATIVE_PATH);
|
to.setType(StorageType.RELATIVE_PATH);
|
||||||
} else {
|
} else {
|
||||||
to.setType(StorageType.BLOB);
|
to.setType(StorageType.BLOB);
|
||||||
|
|
|
@ -31,15 +31,25 @@ public class ToListContainerOptions implements
|
||||||
if (from.getDir() != null && from.getPrefix() != null) {
|
if (from.getDir() != null && from.getPrefix() != null) {
|
||||||
throw new IllegalArgumentException("Cannot set both directory and prefix");
|
throw new IllegalArgumentException("Cannot set both directory and prefix");
|
||||||
}
|
}
|
||||||
|
if ((from.getDir() != null || from.isRecursive()) && (from.getDelimiter() != null)) {
|
||||||
|
throw new IllegalArgumentException("Cannot set both delimiter and recursive or directory");
|
||||||
|
}
|
||||||
org.jclouds.openstack.swift.v1.options.ListContainerOptions options = new org.jclouds.openstack.swift.v1.options.ListContainerOptions();
|
org.jclouds.openstack.swift.v1.options.ListContainerOptions options = new org.jclouds.openstack.swift.v1.options.ListContainerOptions();
|
||||||
if (from.getDir() == null && !from.isRecursive()) {
|
|
||||||
|
if (from.getDir() != null) {
|
||||||
|
if (from.isRecursive()) {
|
||||||
|
options.prefix(from.getDir().endsWith("/") ? from.getDir() : from.getDir() + "/");
|
||||||
|
} else {
|
||||||
|
options.path(from.getDir());
|
||||||
|
}
|
||||||
|
} else if (!from.isRecursive()) {
|
||||||
options.delimiter('/');
|
options.delimiter('/');
|
||||||
}
|
}
|
||||||
if ((from.getDir() != null) && (from.isRecursive())) {
|
if (from.getDelimiter() != null) {
|
||||||
options.prefix(from.getDir().endsWith("/") ? from.getDir() : from.getDir() + "/");
|
if (from.getDelimiter().length() != 1) {
|
||||||
}
|
throw new IllegalArgumentException("Delimiter must be a single character");
|
||||||
if ((from.getDir() != null) && (!from.isRecursive())) {
|
}
|
||||||
options.path(from.getDir());
|
options.delimiter(from.getDelimiter().charAt(0));
|
||||||
}
|
}
|
||||||
if (from.getPrefix() != null) {
|
if (from.getPrefix() != null) {
|
||||||
options.prefix(from.getPrefix());
|
options.prefix(from.getPrefix());
|
||||||
|
|
|
@ -43,6 +43,8 @@ import com.google.common.io.ByteSource;
|
||||||
public class ParseObjectListFromResponse implements Function<HttpResponse, ObjectList>,
|
public class ParseObjectListFromResponse implements Function<HttpResponse, ObjectList>,
|
||||||
InvocationContext<ParseObjectListFromResponse> {
|
InvocationContext<ParseObjectListFromResponse> {
|
||||||
|
|
||||||
|
public static final String SUBDIR_ETAG = "deadbeef";
|
||||||
|
|
||||||
private static final class InternalObject {
|
private static final class InternalObject {
|
||||||
String name;
|
String name;
|
||||||
String hash;
|
String hash;
|
||||||
|
@ -73,8 +75,6 @@ public class ParseObjectListFromResponse implements Function<HttpResponse, Objec
|
||||||
}
|
}
|
||||||
|
|
||||||
static class ToSwiftObject implements Function<InternalObject, SwiftObject> {
|
static class ToSwiftObject implements Function<InternalObject, SwiftObject> {
|
||||||
private static final String SUBDIR_ETAG = "deadbeef";
|
|
||||||
|
|
||||||
private final String containerUri;
|
private final String containerUri;
|
||||||
|
|
||||||
ToSwiftObject(String containerUri) {
|
ToSwiftObject(String containerUri) {
|
||||||
|
|
|
@ -54,7 +54,16 @@ public class SwiftContainerIntegrationLiveTest extends BaseContainerIntegrationT
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void testDelimiter() throws Exception {
|
public void testDelimiter() {
|
||||||
throw new SkipException("openstack-swift does not implement pseudo-directories");
|
// Swift does not return the last marker when listing, which breaks the testDelimiter test. One more query would
|
||||||
|
// need to be made for Swift (using the latest object and getting no results back).
|
||||||
|
throw new SkipException("The test fails for Swift, as it requires one more request");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void testDirectory() {
|
||||||
|
// The test fails with swift, where the marker blob for the directory is removed, as part of the call to
|
||||||
|
// clearContainer
|
||||||
|
throw new SkipException("Swift marker blob is removed when clearing a directory");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@ import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CRED
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import org.jclouds.blobstore.integration.internal.BaseContainerLiveTest;
|
import org.jclouds.blobstore.integration.internal.BaseContainerLiveTest;
|
||||||
import org.testng.SkipException;
|
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
@Test(groups = "live", testName = "SwiftContainerLiveTest")
|
@Test(groups = "live", testName = "SwiftContainerLiveTest")
|
||||||
|
@ -37,10 +36,4 @@ public class SwiftContainerLiveTest extends BaseContainerLiveTest {
|
||||||
setIfTestSystemPropertyPresent(props, CREDENTIAL_TYPE);
|
setIfTestSystemPropertyPresent(props, CREDENTIAL_TYPE);
|
||||||
return props;
|
return props;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Test
|
|
||||||
public void testDelimiterList() {
|
|
||||||
throw new SkipException("Delimiter support is not yet implemented");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue