Repository: jclouds Updated Branches: refs/heads/master 95b6064c3 -> 9009bb526
JCLOUDS-658: use xattr only on supported systems Mac OS X HFS+ does not support UserDefinedFileAttributeView: https://bugs.openjdk.java.net/browse/JDK-8030048 Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/9009bb52 Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/9009bb52 Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/9009bb52 Branch: refs/heads/master Commit: 9009bb526875aa25a60aedb1811ecdea439759b5 Parents: 95b6064 Author: Andrew Gaul <[email protected]> Authored: Mon Aug 11 15:34:41 2014 -0700 Committer: Andrew Gaul <[email protected]> Committed: Tue Aug 12 12:30:06 2014 -0700 ---------------------------------------------------------------------- .../internal/FilesystemStorageStrategyImpl.java | 115 +++++++++++-------- .../FilesystemBlobIntegrationTest.java | 38 ++++++ .../FilesystemContainerIntegrationTest.java | 15 +++ .../test/java/org/jclouds/utils/TestUtils.java | 5 + 4 files changed, 124 insertions(+), 49 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/jclouds/blob/9009bb52/apis/filesystem/src/main/java/org/jclouds/filesystem/strategy/internal/FilesystemStorageStrategyImpl.java ---------------------------------------------------------------------- diff --git a/apis/filesystem/src/main/java/org/jclouds/filesystem/strategy/internal/FilesystemStorageStrategyImpl.java b/apis/filesystem/src/main/java/org/jclouds/filesystem/strategy/internal/FilesystemStorageStrategyImpl.java index 74ebef7..ea975e8 100644 --- a/apis/filesystem/src/main/java/org/jclouds/filesystem/strategy/internal/FilesystemStorageStrategyImpl.java +++ b/apis/filesystem/src/main/java/org/jclouds/filesystem/strategy/internal/FilesystemStorageStrategyImpl.java @@ -16,6 +16,9 @@ */ package org.jclouds.filesystem.strategy.internal; +import static java.nio.file.Files.getFileAttributeView; +import static java.nio.file.Files.getFileStore; + import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Strings.isNullOrEmpty; import static com.google.common.io.BaseEncoding.base16; @@ -23,6 +26,7 @@ import static com.google.common.io.BaseEncoding.base16; import java.io.File; import java.io.IOException; import java.nio.ByteBuffer; +import java.nio.file.Path; import java.nio.file.attribute.UserDefinedFileAttributeView; import java.nio.charset.StandardCharsets; import java.util.Date; @@ -196,47 +200,58 @@ public class FilesystemStorageStrategyImpl implements LocalStorageStrategy { BlobBuilder builder = blobBuilders.get(); builder.name(key); File file = getFileForBlobKey(container, key); + Path path = file.toPath(); ByteSource byteSource = Files.asByteSource(file); try { - UserDefinedFileAttributeView view = java.nio.file.Files.getFileAttributeView( - file.toPath(), UserDefinedFileAttributeView.class); - Set<String> attributes = ImmutableSet.copyOf(view.list()); - - String contentDisposition = readStringAttributeIfPresent(view, attributes, XATTR_CONTENT_DISPOSITION); - String contentEncoding = readStringAttributeIfPresent(view, attributes, XATTR_CONTENT_ENCODING); - String contentLanguage = readStringAttributeIfPresent(view, attributes, XATTR_CONTENT_LANGUAGE); - String contentType = readStringAttributeIfPresent(view, attributes, XATTR_CONTENT_TYPE); + String contentDisposition = null; + String contentEncoding = null; + String contentLanguage = null; + String contentType = null; HashCode hashCode = null; - if (attributes.contains(XATTR_CONTENT_MD5)) { - ByteBuffer buf = ByteBuffer.allocate(view.size(XATTR_CONTENT_MD5)); - view.read(XATTR_CONTENT_MD5, buf); - hashCode = HashCode.fromBytes(buf.array()); - } Date expires = null; - if (attributes.contains(XATTR_EXPIRES)) { - ByteBuffer buf = ByteBuffer.allocate(view.size(XATTR_EXPIRES)); - view.read(XATTR_EXPIRES, buf); - buf.flip(); - expires = new Date(buf.asLongBuffer().get()); - } ImmutableMap.Builder<String, String> userMetadata = ImmutableMap.builder(); - for (String attribute : attributes) { - if (!attribute.startsWith(XATTR_USER_METADATA_PREFIX)) { - continue; + + if (getFileStore(file.toPath()).supportsFileAttributeView(UserDefinedFileAttributeView.class)) { + UserDefinedFileAttributeView view = getFileAttributeView(path, UserDefinedFileAttributeView.class); + Set<String> attributes = ImmutableSet.copyOf(view.list()); + + contentDisposition = readStringAttributeIfPresent(view, attributes, XATTR_CONTENT_DISPOSITION); + contentEncoding = readStringAttributeIfPresent(view, attributes, XATTR_CONTENT_ENCODING); + contentLanguage = readStringAttributeIfPresent(view, attributes, XATTR_CONTENT_LANGUAGE); + contentType = readStringAttributeIfPresent(view, attributes, XATTR_CONTENT_TYPE); + if (attributes.contains(XATTR_CONTENT_MD5)) { + ByteBuffer buf = ByteBuffer.allocate(view.size(XATTR_CONTENT_MD5)); + view.read(XATTR_CONTENT_MD5, buf); + hashCode = HashCode.fromBytes(buf.array()); + } + if (attributes.contains(XATTR_EXPIRES)) { + ByteBuffer buf = ByteBuffer.allocate(view.size(XATTR_EXPIRES)); + view.read(XATTR_EXPIRES, buf); + buf.flip(); + expires = new Date(buf.asLongBuffer().get()); + } + for (String attribute : attributes) { + if (!attribute.startsWith(XATTR_USER_METADATA_PREFIX)) { + continue; + } + String value = readStringAttributeIfPresent(view, attributes, attribute); + userMetadata.put(attribute.substring(XATTR_USER_METADATA_PREFIX.length()), value); } - String value = readStringAttributeIfPresent(view, attributes, attribute); - userMetadata.put(attribute.substring(XATTR_USER_METADATA_PREFIX.length()), value); - } - builder.payload(byteSource) - .contentDisposition(contentDisposition) - .contentEncoding(contentEncoding) - .contentLanguage(contentLanguage) - .contentLength(byteSource.size()) - .contentMD5(hashCode) - .contentType(contentType) - .expires(expires) - .userMetadata(userMetadata.build()); + builder.payload(byteSource) + .contentDisposition(contentDisposition) + .contentEncoding(contentEncoding) + .contentLanguage(contentLanguage) + .contentLength(byteSource.size()) + .contentMD5(hashCode) + .contentType(contentType) + .expires(expires) + .userMetadata(userMetadata.build()); + } else { + builder.payload(byteSource) + .contentLength(byteSource.size()) + .contentMD5(byteSource.hash(Hashing.md5()).asBytes()); + } } catch (IOException e) { throw Throwables.propagate(e); } @@ -256,6 +271,7 @@ public class FilesystemStorageStrategyImpl implements LocalStorageStrategy { filesystemContainerNameValidator.validate(containerName); filesystemBlobKeyValidator.validate(blobKey); File outputFile = getFileForBlobKey(containerName, blobKey); + Path outputPath = outputFile.toPath(); HashingInputStream his = null; try { Files.createParentDirs(outputFile); @@ -269,21 +285,22 @@ public class FilesystemStorageStrategyImpl implements LocalStorageStrategy { } payload.getContentMetadata().setContentMD5(actualHashCode); - UserDefinedFileAttributeView view = java.nio.file.Files.getFileAttributeView( - outputFile.toPath(), UserDefinedFileAttributeView.class); - view.write(XATTR_CONTENT_MD5, ByteBuffer.wrap(actualHashCode.asBytes())); - writeStringAttributeIfPresent(view, XATTR_CONTENT_DISPOSITION, metadata.getContentDisposition()); - writeStringAttributeIfPresent(view, XATTR_CONTENT_ENCODING, metadata.getContentEncoding()); - writeStringAttributeIfPresent(view, XATTR_CONTENT_LANGUAGE, metadata.getContentLanguage()); - writeStringAttributeIfPresent(view, XATTR_CONTENT_TYPE, metadata.getContentType()); - Date expires = metadata.getExpires(); - if (expires != null) { - ByteBuffer buf = ByteBuffer.allocate(Longs.BYTES).putLong(expires.getTime()); - buf.flip(); - view.write(XATTR_EXPIRES, buf); - } - for (Map.Entry<String, String> entry : blob.getMetadata().getUserMetadata().entrySet()) { - writeStringAttributeIfPresent(view, XATTR_USER_METADATA_PREFIX + entry.getKey(), entry.getValue()); + if (getFileStore(outputPath).supportsFileAttributeView(UserDefinedFileAttributeView.class)) { + UserDefinedFileAttributeView view = getFileAttributeView(outputPath, UserDefinedFileAttributeView.class); + view.write(XATTR_CONTENT_MD5, ByteBuffer.wrap(actualHashCode.asBytes())); + writeStringAttributeIfPresent(view, XATTR_CONTENT_DISPOSITION, metadata.getContentDisposition()); + writeStringAttributeIfPresent(view, XATTR_CONTENT_ENCODING, metadata.getContentEncoding()); + writeStringAttributeIfPresent(view, XATTR_CONTENT_LANGUAGE, metadata.getContentLanguage()); + writeStringAttributeIfPresent(view, XATTR_CONTENT_TYPE, metadata.getContentType()); + Date expires = metadata.getExpires(); + if (expires != null) { + ByteBuffer buf = ByteBuffer.allocate(Longs.BYTES).putLong(expires.getTime()); + buf.flip(); + view.write(XATTR_EXPIRES, buf); + } + for (Map.Entry<String, String> entry : blob.getMetadata().getUserMetadata().entrySet()) { + writeStringAttributeIfPresent(view, XATTR_USER_METADATA_PREFIX + entry.getKey(), entry.getValue()); + } } return base16().lowerCase().encode(actualHashCode.asBytes()); } catch (IOException ex) { http://git-wip-us.apache.org/repos/asf/jclouds/blob/9009bb52/apis/filesystem/src/test/java/org/jclouds/filesystem/integration/FilesystemBlobIntegrationTest.java ---------------------------------------------------------------------- diff --git a/apis/filesystem/src/test/java/org/jclouds/filesystem/integration/FilesystemBlobIntegrationTest.java b/apis/filesystem/src/test/java/org/jclouds/filesystem/integration/FilesystemBlobIntegrationTest.java index 3618fd4..f5ca672 100644 --- a/apis/filesystem/src/test/java/org/jclouds/filesystem/integration/FilesystemBlobIntegrationTest.java +++ b/apis/filesystem/src/test/java/org/jclouds/filesystem/integration/FilesystemBlobIntegrationTest.java @@ -16,8 +16,11 @@ */ package org.jclouds.filesystem.integration; +import java.io.IOException; import java.util.Properties; +import org.jclouds.blobstore.domain.Blob; +import org.jclouds.blobstore.domain.BlobMetadata; import org.jclouds.blobstore.integration.internal.BaseBlobIntegrationTest; import org.jclouds.blobstore.integration.internal.BaseBlobStoreIntegrationTest; import org.jclouds.filesystem.reference.FilesystemConstants; @@ -37,4 +40,39 @@ public class FilesystemBlobIntegrationTest extends BaseBlobIntegrationTest { props.setProperty(FilesystemConstants.PROPERTY_BASEDIR, TestUtils.TARGET_BASE_DIR); return props; } + + // Mac OS X HFS+ does not support UserDefinedFileAttributeView: + // https://bugs.openjdk.java.net/browse/JDK-8030048 + @Override + public void checkContentMetadata(Blob blob) { + if (!org.jclouds.utils.TestUtils.isMacOSX()) { + super.checkContentMetadata(blob); + } + } + + // Mac OS X HFS+ does not support UserDefinedFileAttributeView: + // https://bugs.openjdk.java.net/browse/JDK-8030048 + @Override + protected void checkContentDisposition(Blob blob, String contentDisposition) { + if (!org.jclouds.utils.TestUtils.isMacOSX()) { + super.checkContentDisposition(blob, contentDisposition); + } + } + + // Mac OS X HFS+ does not support UserDefinedFileAttributeView: + // https://bugs.openjdk.java.net/browse/JDK-8030048 + @Override + protected void validateMetadata(BlobMetadata metadata) throws IOException { + if (!org.jclouds.utils.TestUtils.isMacOSX()) { + super.validateMetadata(metadata); + } + } + + // Mac OS X HFS+ does not support UserDefinedFileAttributeView: + // https://bugs.openjdk.java.net/browse/JDK-8030048 + @Test(dataProvider = "ignoreOnMacOSX") + @Override + public void testCreateBlobWithExpiry() throws InterruptedException { + super.testCreateBlobWithExpiry(); + } } http://git-wip-us.apache.org/repos/asf/jclouds/blob/9009bb52/apis/filesystem/src/test/java/org/jclouds/filesystem/integration/FilesystemContainerIntegrationTest.java ---------------------------------------------------------------------- diff --git a/apis/filesystem/src/test/java/org/jclouds/filesystem/integration/FilesystemContainerIntegrationTest.java b/apis/filesystem/src/test/java/org/jclouds/filesystem/integration/FilesystemContainerIntegrationTest.java index d5a02a0..4b6cd03 100644 --- a/apis/filesystem/src/test/java/org/jclouds/filesystem/integration/FilesystemContainerIntegrationTest.java +++ b/apis/filesystem/src/test/java/org/jclouds/filesystem/integration/FilesystemContainerIntegrationTest.java @@ -19,6 +19,7 @@ package org.jclouds.filesystem.integration; import static org.jclouds.blobstore.options.ListContainerOptions.Builder.maxResults; import static org.testng.Assert.assertEquals; +import java.io.IOException; import java.util.Properties; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -80,6 +81,14 @@ public class FilesystemContainerIntegrationTest extends BaseContainerIntegration } } + // Mac OS X HFS+ does not support UserDefinedFileAttributeView: + // https://bugs.openjdk.java.net/browse/JDK-8030048 + @Test(dataProvider = "ignoreOnMacOSX") + @Override + public void testWithDetails() throws InterruptedException, IOException { + super.testWithDetails(); + } + @Override @Test(dataProvider = "ignoreOnWindows") public void containerExists() throws InterruptedException { @@ -147,6 +156,12 @@ public class FilesystemContainerIntegrationTest extends BaseContainerIntegration } @DataProvider + public Object[][] ignoreOnMacOSX() { + return org.jclouds.utils.TestUtils.isMacOSX() ? TestUtils.NO_INVOCATIONS + : TestUtils.SINGLE_NO_ARG_INVOCATION; + } + + @DataProvider public Object[][] ignoreOnWindows() { return TestUtils.isWindowsOs() ? TestUtils.NO_INVOCATIONS : TestUtils.SINGLE_NO_ARG_INVOCATION; http://git-wip-us.apache.org/repos/asf/jclouds/blob/9009bb52/core/src/test/java/org/jclouds/utils/TestUtils.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/jclouds/utils/TestUtils.java b/core/src/test/java/org/jclouds/utils/TestUtils.java index b62fefd..e276103 100644 --- a/core/src/test/java/org/jclouds/utils/TestUtils.java +++ b/core/src/test/java/org/jclouds/utils/TestUtils.java @@ -29,6 +29,11 @@ public class TestUtils { public static final Object[][] NO_INVOCATIONS = new Object[0][0]; public static final Object[][] SINGLE_NO_ARG_INVOCATION = { new Object[0] }; + public static boolean isMacOSX() { + String osName = System.getProperty("os.name"); + return osName.contains("OS X"); + } + public static ByteSource randomByteSource() { return randomByteSource(0); }
