commit - 1939c62d29abc7a7d42c831f096b5cc27f4c1182
commit + c4610f866124bd70c2c5eee691a35ecd94ab2487
blob - /dev/null
blob + a115da635abf2030cd9f127207a5e930c7c9e970 (mode 644)
--- /dev/null
+++ modules/vfs.s3/src/main/java/com/thinkberg/vfs/s3/S3FileName.java
+/*
+ * Copyright 2007 Matthias L. Jugel.
+ *
+ * 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 com.thinkberg.vfs.s3;
+
+import org.apache.commons.vfs.FileType;
+import org.apache.commons.vfs.provider.local.LocalFileName;
+
+/**
+ * @author Matthias L. Jugel
+ */
+public class S3FileName extends LocalFileName {
+ protected S3FileName(final String scheme, final String rootFile, final String path, final FileType type) {
+ super(scheme, rootFile, path, type);
+ }
+}
blob - /dev/null
blob + 98a261c899effacd3c1f562cd3db06c5357b9f43 (mode 644)
--- /dev/null
+++ modules/vfs.s3/src/main/java/com/thinkberg/vfs/s3/S3FileNameParser.java
+/*
+ * Copyright 2007 Matthias L. Jugel.
+ *
+ * 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 com.thinkberg.vfs.s3;
+
+import org.apache.commons.vfs.FileName;
+import org.apache.commons.vfs.FileSystemException;
+import org.apache.commons.vfs.FileType;
+import org.apache.commons.vfs.provider.AbstractFileNameParser;
+import org.apache.commons.vfs.provider.UriParser;
+import org.apache.commons.vfs.provider.VfsComponentContext;
+
+/**
+ * @author Matthias L. Jugel
+ */
+public class S3FileNameParser extends AbstractFileNameParser {
+ private static final S3FileNameParser instance = new S3FileNameParser();
+
+ public static S3FileNameParser getInstance() {
+ return instance;
+ }
+
+ private S3FileNameParser() {
+
+ }
+
+ public FileName parseUri(final VfsComponentContext context, final FileName base, final String filename) throws FileSystemException {
+ StringBuffer name = new StringBuffer();
+
+ String scheme = UriParser.extractScheme(filename, name);
+ UriParser.canonicalizePath(name, 0, name.length(), this);
+
+ UriParser.fixSeparators(name);
+
+ // Normalise the path
+ FileType fileType = UriParser.normalisePath(name);
+
+ // Extract the root prefix
+ final String bucketName = UriParser.extractFirstElement(name);
+
+
+ return new S3FileName(scheme, bucketName, name.toString(), fileType);
+ }
+
+}
blob - /dev/null
blob + 9c9ec0692b4d9c3723a8db92f77b2e782ff4747f (mode 644)
--- /dev/null
+++ modules/vfs.s3/src/main/java/com/thinkberg/vfs/s3/S3FileProvider.java
+/*
+ * Copyright 2007 Matthias L. Jugel.
+ *
+ * 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 com.thinkberg.vfs.s3;
+
+import com.thinkberg.vfs.s3.jets3t.Jets3tFileSystem;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.vfs.*;
+import org.apache.commons.vfs.provider.AbstractOriginatingFileProvider;
+import org.apache.commons.vfs.util.UserAuthenticatorUtils;
+import org.jets3t.service.S3Service;
+import org.jets3t.service.S3ServiceException;
+import org.jets3t.service.impl.rest.httpclient.RestS3Service;
+import org.jets3t.service.security.AWSCredentials;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * An S3 file provider. Create an S3 file system out of an S3 file name.
+ * Also defines the capabilities of the file system.
+ *
+ * @author Matthias L. Jugel
+ */
+public class S3FileProvider extends AbstractOriginatingFileProvider {
+ public final static Collection<Capability> capabilities = Collections.unmodifiableCollection(Arrays.asList(
+ Capability.CREATE,
+ Capability.DELETE,
+ Capability.RENAME,
+ Capability.GET_TYPE,
+ Capability.GET_LAST_MODIFIED,
+ Capability.SET_LAST_MODIFIED_FILE,
+ Capability.SET_LAST_MODIFIED_FOLDER,
+ Capability.LIST_CHILDREN,
+ Capability.READ_CONTENT,
+ Capability.URI,
+ Capability.WRITE_CONTENT,
+ Capability.APPEND_CONTENT/*,
+ Capability.RANDOM_ACCESS_READ,
+ Capability.RANDOM_ACCESS_WRITE*/
+
+ ));
+
+ private static final UserAuthenticationData.Type[] AUTHENTICATOR_TYPES = new UserAuthenticationData.Type[]{
+ UserAuthenticationData.USERNAME,
+ UserAuthenticationData.PASSWORD
+ };
+
+ private S3Service service;
+ private static final Log LOG = LogFactory.getLog(S3FileProvider.class);
+
+ public S3FileProvider() {
+ super();
+ setFileNameParser(S3FileNameParser.getInstance());
+ }
+
+ /**
+ * Create a file system with the S3 root provided.
+ *
+ * @param fileName the S3 file name that defines the root (bucket)
+ * @param fileSystemOptions file system options
+ * @return an S3 file system
+ * @throws FileSystemException if te file system cannot be created
+ */
+ protected FileSystem doCreateFileSystem(FileName fileName, FileSystemOptions fileSystemOptions) throws FileSystemException {
+ LOG.debug(String.format("creating new file system '%s'", fileName));
+ if (null == service) {
+ LOG.debug("creating new S3 service");
+ UserAuthenticationData authenticationInfo = UserAuthenticatorUtils.authenticate(fileSystemOptions, AUTHENTICATOR_TYPES);
+ String accessKey = UserAuthenticatorUtils.toString(UserAuthenticatorUtils.getData(authenticationInfo, UserAuthenticationData.USERNAME, null));
+ String secretKey = UserAuthenticatorUtils.toString(UserAuthenticatorUtils.getData(authenticationInfo, UserAuthenticationData.PASSWORD, null));
+
+ try {
+ service = new RestS3Service(new AWSCredentials(accessKey, secretKey));
+ } catch (S3ServiceException e) {
+ throw new FileSystemException("Amazon S3 service initialization failed", e);
+ } finally {
+ authenticationInfo.cleanup();
+ }
+ }
+
+ return new Jets3tFileSystem(service, (S3FileName) fileName, fileSystemOptions);
+ }
+
+ /**
+ * Get the capabilities of the file system provider.
+ *
+ * @return the file system capabilities
+ */
+ public Collection getCapabilities() {
+ return capabilities;
+ }
+}
blob - /dev/null
blob + f63cf8f032a072313edd39e344a09e9259c6f63b (mode 644)
--- /dev/null
+++ modules/vfs.s3/src/main/resources/META-INF/vfs-providers.xml
+<!--
+ ~ Copyright 2007 Matthias L. Jugel.
+ ~
+ ~ 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.
+ -->
+
+<providers>
+
+ <provider class-name="com.thinkberg.vfs.s3.S3FileProvider">
+ <scheme name="s3"/>
+ <if-available class-name="org.jets3t.service.S3Service"/>
+ </provider>
+
+</providers>
blob - /dev/null
blob + 675245da96c776ed242485906769d4017f22d830 (mode 644)
--- /dev/null
+++ modules/vfs.s3/src/test/java/com/thinkberg/vfs/s3/S3TestCase.java
+/*
+ * Copyright 2007 Matthias L. Jugel.
+ *
+ * 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 com.thinkberg.vfs.s3;
+
+import com.thinkberg.vfs.s3.tests.S3FileProviderTest;
+import junit.framework.TestCase;
+import org.apache.commons.vfs.FileObject;
+import org.apache.commons.vfs.FileSystemOptions;
+import org.apache.commons.vfs.VFS;
+import org.apache.commons.vfs.auth.StaticUserAuthenticator;
+import org.apache.commons.vfs.impl.DefaultFileSystemConfigBuilder;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+import java.util.Random;
+
+/**
+ * @author Matthias L. Jugel
+ */
+public class S3TestCase extends TestCase {
+ protected final static String BUCKETID;
+ protected static String FSURI;
+ protected static FileObject ROOT;
+ protected static FileSystemOptions OPTIONS;
+
+
+ static {
+ BUCKETID = "MOXOTEST" + String.format("%X", new Random(System.currentTimeMillis()).nextLong());
+ Properties userConfig = new Properties();
+
+ InputStream propertyResource = S3FileProviderTest.class.getResourceAsStream("/s3.auth.properties");
+ assertNotNull(propertyResource);
+
+ try {
+ userConfig.load(propertyResource);
+ StaticUserAuthenticator userAuthenticator =
+ new StaticUserAuthenticator("",
+ userConfig.getProperty("s3.access.key", ""),
+ userConfig.getProperty("s3.secret.key", ""));
+ OPTIONS = new FileSystemOptions();
+ FSURI = String.format("s3://%s/", BUCKETID);
+
+ DefaultFileSystemConfigBuilder.getInstance().setUserAuthenticator(OPTIONS, userAuthenticator);
+ ROOT = VFS.getManager().resolveFile(FSURI, OPTIONS);
+ } catch (IOException e) {
+ assertTrue("initialization failed", false);
+ }
+ }
+}
blob - /dev/null
blob + 2f17587d2386da0b3978c7478970da3626c00ca6 (mode 644)
--- /dev/null
+++ modules/vfs.s3/src/test/java/com/thinkberg/vfs/s3/tests/S3FileNameTest.java
+/*
+ * Copyright 2007 Matthias L. Jugel.
+ *
+ * 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 com.thinkberg.vfs.s3.tests;
+
+import com.thinkberg.vfs.s3.S3FileName;
+import com.thinkberg.vfs.s3.S3FileNameParser;
+import com.thinkberg.vfs.s3.S3TestCase;
+import junit.framework.Assert;
+import org.apache.commons.vfs.FileName;
+import org.apache.commons.vfs.FileSystemException;
+
+import java.net.URI;
+
+/**
+ * @author Matthias L. Jugel
+ */
+public class S3FileNameTest extends S3TestCase {
+ public void testGetBucketFromUri() throws FileSystemException {
+ String uriString = ROOT + "/junk.txt";
+ String bucketId = URI.create(uriString).getHost();
+ FileName fileName = S3FileNameParser.getInstance().parseUri(null, null, uriString);
+ Assert.assertEquals(bucketId, ((S3FileName) fileName).getRootFile());
+ }
+
+ public void testGetRootFolderFromUri() throws FileSystemException {
+ String path = "/myfolder";
+ String uri = ROOT + path;
+ FileName fileName = S3FileNameParser.getInstance().parseUri(null, null, uri);
+ assertEquals(path, fileName.getPath());
+ }
+}
blob - /dev/null
blob + 4ab104f040636ab7b267aed201ad98af0049f444 (mode 644)
--- /dev/null
+++ modules/vfs.s3/src/test/java/com/thinkberg/vfs/s3/tests/S3FileProviderTest.java
+/*
+ * Copyright 2007 Matthias L. Jugel.
+ *
+ * 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 com.thinkberg.vfs.s3.tests;
+
+import com.thinkberg.vfs.s3.S3FileName;
+import com.thinkberg.vfs.s3.S3TestCase;
+import com.thinkberg.vfs.s3.jets3t.Jets3tFileSystem;
+import junit.framework.Assert;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.vfs.*;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * @author Matthias L. Jugel
+ */
+public class S3FileProviderTest extends S3TestCase {
+ private static final FileSelector ALL_FILE_SELECTOR = new FileSelector() {
+
+ public boolean includeFile(FileSelectInfo fileInfo) throws Exception {
+ return true;
+ }
+
+ public boolean traverseDescendents(FileSelectInfo fileInfo) throws Exception {
+ return true;
+ }
+ };
+ private static final String FOLDER = "/directory";
+ private static final String FILE = FOLDER + "/newfile.txt";
+
+ static {
+ LogFactory.getLog(S3FileProviderTest.class).debug("initializing ...");
+ try {
+ ROOT.delete(ALL_FILE_SELECTOR);
+ } catch (FileSystemException e) {
+ // just delete, ignore the rest
+ }
+ }
+
+ public void testDoCreateFileSystem() throws FileSystemException {
+ FileObject object = ROOT.resolveFile("/");
+ Assert.assertEquals(BUCKETID, ((S3FileName) object.getName()).getRootFile());
+ }
+
+ public void testFileSystemIsEmpty() throws FileSystemException {
+ FileObject object = ROOT.resolveFile("/");
+ assertEquals(1, object.findFiles(ALL_FILE_SELECTOR).length);
+ }
+
+ public void testRootDirectoryIsFolder() throws FileSystemException {
+ FileObject object = ROOT.resolveFile("/");
+ assertEquals(FileType.FOLDER, object.getType());
+ }
+
+ public void testCreateFolder() throws FileSystemException {
+ FileObject object = ROOT.resolveFile(FOLDER);
+ assertFalse(object.exists());
+ object.createFolder();
+ assertTrue(object.exists());
+ assertEquals(FileType.FOLDER, object.getType());
+ }
+
+ public void testGetFolder() throws FileSystemException {
+ FileObject object = ROOT.resolveFile(FOLDER);
+ assertTrue(object.exists());
+ assertEquals(FileType.FOLDER, object.getType());
+ }
+
+ public void testCreateFile() throws IOException {
+ FileObject object = ROOT.resolveFile(FILE);
+ assertFalse(object.exists());
+ OutputStream os = object.getContent().getOutputStream();
+ os.write(0xfc);
+ os.close();
+ assertTrue(object.exists());
+ assertEquals(FileType.FILE, object.getType());
+ }
+
+ public void testCreateEmptyFile() throws IOException {
+ FileObject object = ROOT.resolveFile(FILE + ".empty");
+ assertFalse(object.exists());
+ object.createFile();
+ assertTrue(object.exists());
+ assertEquals(FileType.FILE, object.getType());
+ }
+
+ public void testFileHasLastModifiedTimestamp() throws FileSystemException {
+ FileObject object = ROOT.resolveFile(FILE);
+ object.getContent().getLastModifiedTime();
+ }
+
+ public void testGetFolderListing() throws FileSystemException {
+ FileObject object = ROOT.resolveFile(FOLDER);
+ FileObject[] files = object.findFiles(new DepthFileSelector(1));
+ assertEquals(3, files.length);
+ }
+
+ public void testMissingFile() throws FileSystemException {
+ FileObject object = ROOT.resolveFile("/nonexisting.txt");
+ assertFalse(object.exists());
+ }
+
+ public void testGetLastModifiedTimeFolder() throws FileSystemException {
+ FileObject object = ROOT.resolveFile(FOLDER);
+ object.getContent().getLastModifiedTime();
+ }
+
+ public void testGetLastModifiedTimeFile() throws FileSystemException {
+ FileObject object = ROOT.resolveFile(FILE);
+ object.getContent().getLastModifiedTime();
+ }
+
+ public void testDeleteFile() throws FileSystemException {
+ FileObject object = ROOT.resolveFile(FILE);
+ object.delete();
+ assertFalse(object.exists());
+ }
+
+ public void testDeleteFolder() throws FileSystemException {
+ FileObject object = ROOT.resolveFile(FOLDER);
+ object.delete(ALL_FILE_SELECTOR);
+ assertFalse(object.exists());
+ }
+
+ public void testCopyFolder() throws FileSystemException {
+ FileObject origFolder = ROOT.resolveFile(FOLDER);
+ origFolder.createFolder();
+
+ origFolder.resolveFile("file.0").createFile();
+ origFolder.resolveFile("file.1").createFile();
+ origFolder.resolveFile("file.2").createFile();
+
+ FileObject[] origFiles = origFolder.findFiles(new DepthFileSelector(1));
+ assertEquals(4, origFiles.length);
+
+ FileObject destFolder = ROOT.resolveFile(FOLDER + "_dest");
+ assertFalse(destFolder.exists());
+ destFolder.copyFrom(origFolder, new DepthFileSelector(1));
+ assertTrue(destFolder.exists());
+
+ FileObject[] destFiles = destFolder.findFiles(new DepthFileSelector(1));
+ assertEquals(4, destFiles.length);
+
+ for (int i = 0; i < origFiles.length; i++) {
+ assertEquals(origFiles[i].getName().getRelativeName(origFolder.getName()),
+ destFiles[i].getName().getRelativeName(destFolder.getName()));
+ }
+
+ origFolder.delete(ALL_FILE_SELECTOR);
+ destFolder.delete(ALL_FILE_SELECTOR);
+
+ assertFalse(origFolder.exists());
+ assertFalse(destFolder.exists());
+ }
+
+// public void testMoveFolder() throws FileSystemException {
+//
+// }
+
+ public void testCloseFileSystem() throws FileSystemException {
+ VFS.getManager().closeFileSystem(ROOT.getFileSystem());
+ }
+
+ public void testDestroyFileSystem() throws FileSystemException {
+ final FileSystem fileSystem = ROOT.getFileSystem();
+ assertTrue(fileSystem instanceof Jets3tFileSystem);
+ ((Jets3tFileSystem) fileSystem).destroyFileSystem();
+ }
+
+ private class DepthFileSelector implements FileSelector {
+ int depth = 0;
+
+ public DepthFileSelector(int depth) {
+ this.depth = depth;
+ }
+
+ public boolean includeFile(FileSelectInfo fileInfo) throws Exception {
+ return fileInfo.getDepth() <= depth;
+ }
+
+ public boolean traverseDescendents(FileSelectInfo fileInfo) throws Exception {
+ return fileInfo.getDepth() < depth;
+ }
+ }
+}