Forráskód Böngészése

new filesystem-aware WebDAV LocatorFactory

Sebastian Stenzel 9 éve
szülő
commit
a9744167c1
13 módosított fájl, 396 hozzáadás és 266 törlés
  1. 8 1
      main/jackrabbit-filesystem-adapter/pom.xml
  2. 60 0
      main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/filesystem/jackrabbit/FileLocator.java
  3. 23 0
      main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/filesystem/jackrabbit/FileSystemLocator.java
  4. 61 0
      main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/filesystem/jackrabbit/FileSystemResourceLocator.java
  5. 55 0
      main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/filesystem/jackrabbit/FileSystemResourceLocatorFactory.java
  6. 71 0
      main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/filesystem/jackrabbit/FolderLocator.java
  7. 4 5
      main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/webdav/jackrabbitservlet/DavFile.java
  8. 10 11
      main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/webdav/jackrabbitservlet/DavFolder.java
  9. 9 11
      main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/webdav/jackrabbitservlet/DavNode.java
  10. 0 180
      main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/webdav/jackrabbitservlet/DavPathFactory.java
  11. 13 56
      main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/webdav/jackrabbitservlet/FilesystemResourceFactory.java
  12. 3 2
      main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/webdav/jackrabbitservlet/WebDavServlet.java
  13. 79 0
      main/jackrabbit-filesystem-adapter/src/test/java/org/cryptomator/filesystem/jackrabbit/FileSystemResourceLocatorFactoryTest.java

+ 8 - 1
main/jackrabbit-filesystem-adapter/pom.xml

@@ -23,11 +23,14 @@
 	</properties>
 
 	<dependencies>
-		<!-- Filesystem -->
 		<dependency>
 			<groupId>org.cryptomator</groupId>
 			<artifactId>filesystem-api</artifactId>
 		</dependency>
+		<dependency>
+			<groupId>org.cryptomator</groupId>
+			<artifactId>commons</artifactId>
+		</dependency>
 
 		<!-- Jackrabbit -->
 		<dependency>
@@ -48,6 +51,10 @@
 		</dependency>
 		
 		<!-- Test -->
+		<dependency>
+			<groupId>org.cryptomator</groupId>
+			<artifactId>commons-test</artifactId>
+		</dependency>
 		<dependency>
 			<groupId>org.eclipse.jetty</groupId>
 			<artifactId>jetty-server</artifactId>

+ 60 - 0
main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/filesystem/jackrabbit/FileLocator.java

@@ -0,0 +1,60 @@
+package org.cryptomator.filesystem.jackrabbit;
+
+import java.io.UncheckedIOException;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.jackrabbit.webdav.DavLocatorFactory;
+import org.cryptomator.filesystem.File;
+import org.cryptomator.filesystem.delegating.DelegatingFile;
+import org.cryptomator.filesystem.delegating.DelegatingReadableFile;
+import org.cryptomator.filesystem.delegating.DelegatingWritableFile;
+
+public class FileLocator extends DelegatingFile<DelegatingReadableFile, DelegatingWritableFile, FolderLocator>implements FileSystemResourceLocator {
+
+	private final DavLocatorFactory factory;
+	private final String prefix;
+	private final AtomicReference<String> resourcePath = new AtomicReference<>();
+
+	public FileLocator(DavLocatorFactory factory, String prefix, FolderLocator parent, File delegate) {
+		super(parent, delegate);
+		this.factory = factory;
+		this.prefix = prefix;
+	}
+
+	@Override
+	public DelegatingReadableFile openReadable() throws UncheckedIOException {
+		return new DelegatingReadableFile(delegate.openReadable());
+	}
+
+	@Override
+	public DelegatingWritableFile openWritable() throws UncheckedIOException {
+		return new DelegatingWritableFile(delegate.openWritable());
+	}
+
+	@Override
+	public String getPrefix() {
+		return prefix;
+	}
+
+	@Override
+	public boolean isRootLocation() {
+		return false;
+	}
+
+	@Override
+	public DavLocatorFactory getFactory() {
+		return factory;
+	}
+
+	@Override
+	public AtomicReference<String> getResourcePathRef() {
+		return resourcePath;
+	}
+
+	@Override
+	public String computeResourcePath() {
+		assert parent().isPresent();
+		return parent().get().getResourcePath() + name();
+	}
+
+}

+ 23 - 0
main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/filesystem/jackrabbit/FileSystemLocator.java

@@ -0,0 +1,23 @@
+package org.cryptomator.filesystem.jackrabbit;
+
+import org.apache.jackrabbit.webdav.DavLocatorFactory;
+import org.cryptomator.filesystem.FileSystem;
+import org.cryptomator.filesystem.Folder;
+
+class FileSystemLocator extends FolderLocator implements FileSystem {
+
+	public FileSystemLocator(DavLocatorFactory factory, String prefix, Folder delegate) {
+		super(factory, prefix, null, delegate);
+	}
+
+	@Override
+	public boolean isRootLocation() {
+		return true;
+	}
+
+	@Override
+	public String getResourcePath() {
+		return "/";
+	}
+
+}

+ 61 - 0
main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/filesystem/jackrabbit/FileSystemResourceLocator.java

@@ -0,0 +1,61 @@
+package org.cryptomator.filesystem.jackrabbit;
+
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.jackrabbit.webdav.DavResourceLocator;
+import org.apache.jackrabbit.webdav.util.EncodeUtil;
+import org.cryptomator.common.LazyInitializer;
+import org.cryptomator.filesystem.Node;
+
+public interface FileSystemResourceLocator extends DavResourceLocator, Node {
+
+	@Override
+	default String getResourcePath() {
+		return LazyInitializer.initializeLazily(getResourcePathRef(), this::computeResourcePath);
+	}
+
+	AtomicReference<String> getResourcePathRef();
+
+	String computeResourcePath();
+
+	@Override
+	Optional<FolderLocator> parent();
+
+	@Override
+	default String getWorkspacePath() {
+		return null;
+	}
+
+	@Override
+	default String getWorkspaceName() {
+		return null;
+	}
+
+	@Override
+	default boolean isSameWorkspace(DavResourceLocator locator) {
+		return false;
+	}
+
+	@Override
+	default boolean isSameWorkspace(String workspaceName) {
+		return false;
+	}
+
+	default String getHref() {
+		final boolean isCollection = getResourcePath().endsWith("/");
+		return getHref(isCollection);
+	}
+
+	@Override
+	default String getHref(boolean isCollection) {
+		final String encodedResourcePath = EncodeUtil.escapePath(getResourcePath());
+		return getPrefix() + encodedResourcePath;
+	}
+
+	@Override
+	default String getRepositoryPath() {
+		return getResourcePath();
+	}
+
+}

+ 55 - 0
main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/filesystem/jackrabbit/FileSystemResourceLocatorFactory.java

@@ -0,0 +1,55 @@
+package org.cryptomator.filesystem.jackrabbit;
+
+import java.net.URI;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.jackrabbit.webdav.DavLocatorFactory;
+import org.apache.jackrabbit.webdav.util.EncodeUtil;
+import org.cryptomator.filesystem.Folder;
+
+public class FileSystemResourceLocatorFactory implements DavLocatorFactory {
+
+	private final FileSystemLocator fs;
+
+	public FileSystemResourceLocatorFactory(URI contextRootUri, Folder root) {
+		String pathPrefix = StringUtils.removeEnd(contextRootUri.toString(), "/");
+		this.fs = new FileSystemLocator(this, pathPrefix, root);
+	}
+
+	@Override
+	public FileSystemResourceLocator createResourceLocator(String prefix, String href) {
+		final String fullPrefix = StringUtils.removeEnd(prefix, "/");
+		final String remainingHref = StringUtils.removeStart(href, fullPrefix);
+		final String unencodedRemaingingHref = EncodeUtil.unescape(remainingHref);
+		return createResourceLocator(unencodedRemaingingHref);
+	}
+
+	@Override
+	public FileSystemResourceLocator createResourceLocator(String prefix, String workspacePath, String resourcePath) {
+		return createResourceLocator(resourcePath);
+	}
+
+	@Override
+	public FileSystemResourceLocator createResourceLocator(String prefix, String workspacePath, String path, boolean isResourcePath) {
+		return createResourceLocator(path);
+	}
+
+	private FileSystemResourceLocator createResourceLocator(String path) {
+		if (StringUtils.isEmpty(path) || "/".equals(path)) {
+			return fs;
+		}
+		final FolderLocator folder = fs.resolveFolder(path);
+		final FileLocator file = fs.resolveFile(path);
+		if (folder.exists()) {
+			return folder;
+		} else if (file.exists()) {
+			return file;
+		} else if (path.endsWith("/")) {
+			return folder;
+		} else {
+			return file;
+		}
+
+	}
+
+}

+ 71 - 0
main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/filesystem/jackrabbit/FolderLocator.java

@@ -0,0 +1,71 @@
+package org.cryptomator.filesystem.jackrabbit;
+
+import java.io.UncheckedIOException;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.jackrabbit.webdav.DavLocatorFactory;
+import org.cryptomator.filesystem.File;
+import org.cryptomator.filesystem.Folder;
+import org.cryptomator.filesystem.delegating.DelegatingFolder;
+import org.cryptomator.filesystem.delegating.DelegatingReadableFile;
+import org.cryptomator.filesystem.delegating.DelegatingWritableFile;
+
+public class FolderLocator extends DelegatingFolder<DelegatingReadableFile, DelegatingWritableFile, FolderLocator, FileLocator>implements FileSystemResourceLocator {
+
+	private final DavLocatorFactory factory;
+	private final String prefix;
+	private final AtomicReference<String> resourcePath = new AtomicReference<>();
+
+	public FolderLocator(DavLocatorFactory factory, String prefix, FolderLocator parent, Folder delegate) {
+		super(parent, delegate);
+		this.factory = factory;
+		this.prefix = prefix;
+	}
+
+	@Override
+	protected FileLocator file(File delegate) {
+		return new FileLocator(factory, prefix, this, delegate);
+	}
+
+	@Override
+	public FileLocator resolveFile(String relativePath) throws UncheckedIOException {
+		return (FileLocator) super.resolveFile(relativePath);
+	}
+
+	@Override
+	protected FolderLocator folder(Folder delegate) {
+		return new FolderLocator(factory, prefix, this, delegate);
+	}
+
+	@Override
+	public FolderLocator resolveFolder(String relativePath) throws UncheckedIOException {
+		return (FolderLocator) super.resolveFolder(relativePath);
+	}
+
+	@Override
+	public String getPrefix() {
+		return prefix;
+	}
+
+	@Override
+	public boolean isRootLocation() {
+		return false;
+	}
+
+	@Override
+	public DavLocatorFactory getFactory() {
+		return factory;
+	}
+
+	@Override
+	public AtomicReference<String> getResourcePathRef() {
+		return resourcePath;
+	}
+
+	@Override
+	public String computeResourcePath() {
+		assert parent().isPresent();
+		return parent().get().getResourcePath() + name() + "/";
+	}
+
+}

+ 4 - 5
main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/webdav/jackrabbitservlet/DavFile.java

@@ -21,15 +21,14 @@ import org.apache.jackrabbit.webdav.DavSession;
 import org.apache.jackrabbit.webdav.io.InputContext;
 import org.apache.jackrabbit.webdav.io.OutputContext;
 import org.apache.jackrabbit.webdav.lock.LockManager;
-import org.cryptomator.filesystem.File;
 import org.cryptomator.filesystem.ReadableFile;
 import org.cryptomator.filesystem.WritableFile;
-import org.cryptomator.webdav.jackrabbitservlet.DavPathFactory.DavPath;
+import org.cryptomator.filesystem.jackrabbit.FileLocator;
 
-class DavFile extends DavNode<File> {
+class DavFile extends DavNode<FileLocator> {
 
-	public DavFile(FilesystemResourceFactory factory, LockManager lockManager, DavSession session, DavPath path, File node) {
-		super(factory, lockManager, session, path, node);
+	public DavFile(FilesystemResourceFactory factory, LockManager lockManager, DavSession session, FileLocator node) {
+		super(factory, lockManager, session, node);
 	}
 
 	@Override

+ 10 - 11
main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/webdav/jackrabbitservlet/DavFolder.java

@@ -34,12 +34,13 @@ import org.cryptomator.filesystem.File;
 import org.cryptomator.filesystem.Folder;
 import org.cryptomator.filesystem.Node;
 import org.cryptomator.filesystem.WritableFile;
-import org.cryptomator.webdav.jackrabbitservlet.DavPathFactory.DavPath;
+import org.cryptomator.filesystem.jackrabbit.FileLocator;
+import org.cryptomator.filesystem.jackrabbit.FolderLocator;
 
-class DavFolder extends DavNode<Folder> {
+class DavFolder extends DavNode<FolderLocator> {
 
-	public DavFolder(FilesystemResourceFactory factory, LockManager lockManager, DavSession session, DavPath path, Folder folder) {
-		super(factory, lockManager, session, path, folder);
+	public DavFolder(FilesystemResourceFactory factory, LockManager lockManager, DavSession session, FolderLocator folder) {
+		super(factory, lockManager, session, folder);
 		properties.add(new ResourceType(ResourceType.COLLECTION));
 		properties.add(new DefaultDavProperty<Integer>(DavPropertyName.ISCOLLECTION, 1));
 	}
@@ -89,14 +90,12 @@ class DavFolder extends DavNode<Folder> {
 		return new DavResourceIteratorImpl(Stream.concat(folders, files).collect(Collectors.toList()));
 	}
 
-	private DavFolder folderToDavFolder(Folder memberFolder) {
-		final DavPath subFolderLocator = path.getChild(memberFolder.name() + '/');
-		return factory.createFolder(memberFolder, subFolderLocator, session);
+	private DavFolder folderToDavFolder(FolderLocator memberFolder) {
+		return factory.createFolder(memberFolder, session);
 	}
 
-	private DavFile fileToDavFile(File memberFile) {
-		final DavPath subFolderLocator = path.getChild(memberFile.name());
-		return factory.createFile(memberFile, subFolderLocator, session);
+	private DavFile fileToDavFile(FileLocator memberFile) {
+		return factory.createFile(memberFile, session);
 	}
 
 	@Override
@@ -121,7 +120,7 @@ class DavFolder extends DavNode<Folder> {
 	 */
 	private Node getMemberNode(String name) throws DavException {
 		return node.children().filter(c -> c.name().equals(name)).findAny().orElseThrow(() -> {
-			return new DavException(DavServletResponse.SC_NOT_FOUND, "No such file or directory: " + path + name);
+			return new DavException(DavServletResponse.SC_NOT_FOUND, "No such file or directory: " + node.getResourcePath() + name);
 		});
 	}
 

+ 9 - 11
main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/webdav/jackrabbitservlet/DavNode.java

@@ -29,10 +29,9 @@ import org.apache.jackrabbit.webdav.property.DavPropertyName;
 import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
 import org.apache.jackrabbit.webdav.property.DavPropertySet;
 import org.apache.jackrabbit.webdav.property.PropEntry;
-import org.cryptomator.filesystem.Node;
-import org.cryptomator.webdav.jackrabbitservlet.DavPathFactory.DavPath;
+import org.cryptomator.filesystem.jackrabbit.FileSystemResourceLocator;
 
-abstract class DavNode<T extends Node> implements DavResource {
+abstract class DavNode<T extends FileSystemResourceLocator> implements DavResource {
 
 	private static final String DAV_COMPLIANCE_CLASSES = "1, 2";
 	private static final String[] DAV_CREATIONDATE_PROPNAMES = {DavPropertyName.CREATIONDATE.getName(), "Win32CreationTime"};
@@ -41,15 +40,13 @@ abstract class DavNode<T extends Node> implements DavResource {
 	protected final FilesystemResourceFactory factory;
 	protected final LockManager lockManager;
 	protected final DavSession session;
-	protected final DavPath path;
 	protected final T node;
 	protected final DavPropertySet properties;
 
-	public DavNode(FilesystemResourceFactory factory, LockManager lockManager, DavSession session, DavPath path, T node) {
+	public DavNode(FilesystemResourceFactory factory, LockManager lockManager, DavSession session, T node) {
 		this.factory = factory;
 		this.lockManager = lockManager;
 		this.session = session;
-		this.path = path;
 		this.node = node;
 		this.properties = new DavPropertySet();
 	}
@@ -76,17 +73,17 @@ abstract class DavNode<T extends Node> implements DavResource {
 
 	@Override
 	public DavResourceLocator getLocator() {
-		return path;
+		return node;
 	}
 
 	@Override
 	public String getResourcePath() {
-		return path.getResourcePath();
+		return node.getResourcePath();
 	}
 
 	@Override
 	public String getHref() {
-		return path.getHref();
+		return node.getHref();
 	}
 
 	@Override
@@ -157,11 +154,12 @@ abstract class DavNode<T extends Node> implements DavResource {
 
 	@Override
 	public DavResource getCollection() {
-		if (path.isRootLocation()) {
+		if (node.isRootLocation()) {
 			return null;
 		}
 
-		final DavPath parentPath = path.getParent();
+		assert node.parent().isPresent() : "as my mom always sais: if it's not root, it has a parent";
+		final FileSystemResourceLocator parentPath = node.parent().get();
 		try {
 			return factory.createResource(parentPath, session);
 		} catch (DavException e) {

+ 0 - 180
main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/webdav/jackrabbitservlet/DavPathFactory.java

@@ -1,180 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Sebastian Stenzel and others.
- * This file is licensed under the terms of the MIT license.
- * See the LICENSE.txt file for more info.
- *
- * Contributors:
- *     Sebastian Stenzel - initial API and implementation
- *******************************************************************************/
-package org.cryptomator.webdav.jackrabbitservlet;
-
-import java.net.URI;
-
-import org.apache.commons.io.FilenameUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.jackrabbit.webdav.DavLocatorFactory;
-import org.apache.jackrabbit.webdav.DavResourceLocator;
-import org.apache.jackrabbit.webdav.util.EncodeUtil;
-
-/**
- * A LocatorFactory constructing Locators, whose {@link DavResourceLocator#getResourcePath() resourcePath} and {@link DavResourceLocator#getRepositoryPath() repositoryPath} are equal.
- * These paths will be plain, case-sensitive, absolute, unencoded Strings with Unix-style path separators.
- * 
- * Paths ending on "/" are treated as directory paths and all others as file paths.
- */
-class DavPathFactory implements DavLocatorFactory {
-
-	private final String pathPrefix;
-
-	public DavPathFactory(URI contextRootUri) {
-		this.pathPrefix = StringUtils.removeEnd(contextRootUri.toString(), "/");
-	}
-
-	@Override
-	public DavPath createResourceLocator(String prefix, String href) {
-		final String fullPrefix = StringUtils.removeEnd(prefix, "/");
-		final String remainingHref = StringUtils.removeStart(href, fullPrefix);
-		final String unencodedRemaingingHref = EncodeUtil.unescape(remainingHref);
-		return new DavPath(unencodedRemaingingHref);
-	}
-
-	@Override
-	public DavPath createResourceLocator(String prefix, String workspacePath, String resourcePath) {
-		return createResourceLocator(prefix, workspacePath, resourcePath, true);
-	}
-
-	@Override
-	public DavPath createResourceLocator(String prefix, String workspacePath, String path, boolean isResourcePath) {
-		return new DavPath(path);
-	}
-
-	public class DavPath implements DavResourceLocator {
-
-		private final String absPath;
-
-		private DavPath(String absPath) {
-			assert absPath.startsWith("/");
-			this.absPath = FilenameUtils.normalize(absPath, true);
-		}
-
-		/**
-		 * @return <code>true</code> if the path ends on "/".
-		 */
-		public boolean isDirectory() {
-			return absPath.endsWith("/");
-		}
-
-		/**
-		 * @return Parent DavPath or <code>null</code> if this is the root node.
-		 */
-		public DavPath getParent() {
-			if (isRootLocation()) {
-				return null;
-			} else {
-				final String parentPath = FilenameUtils.getFullPath(FilenameUtils.normalizeNoEndSeparator(absPath, true));
-				return createResourceLocator(getPrefix(), getWorkspacePath(), parentPath);
-			}
-		}
-
-		/**
-		 * Get the path of a child resource, consisting of curren path + child path.
-		 * If the child path ends on "/", the returned DavPath will be a directory path.
-		 * 
-		 * @return Child path
-		 */
-		public DavPath getChild(String relativeChildPath) {
-			if (isDirectory()) {
-				final String absChildPath = absPath + StringUtils.removeStart(relativeChildPath, "/");
-				return createResourceLocator(getPrefix(), getWorkspacePath(), absChildPath);
-			} else {
-				throw new UnsupportedOperationException("Can only resolve subpaths of a path representing a directory");
-			}
-		}
-
-		@Override
-		public String getPrefix() {
-			return pathPrefix;
-		}
-
-		@Override
-		public String getResourcePath() {
-			return absPath;
-		}
-
-		@Override
-		public String getWorkspacePath() {
-			return null;
-		}
-
-		@Override
-		public String getWorkspaceName() {
-			return null;
-		}
-
-		@Override
-		public boolean isSameWorkspace(DavResourceLocator locator) {
-			return false;
-		}
-
-		@Override
-		public boolean isSameWorkspace(String workspaceName) {
-			return false;
-		}
-
-		/**
-		 * @see #getHref(boolean)
-		 */
-		public String getHref() {
-			return getHref(isDirectory());
-		}
-
-		@Override
-		public String getHref(boolean isCollection) {
-			final String encodedResourcePath = EncodeUtil.escapePath(absPath);
-			if (isRootLocation()) {
-				return pathPrefix + "/";
-			} else {
-				assert isCollection ? isDirectory() : true;
-				return pathPrefix + encodedResourcePath;
-			}
-		}
-
-		@Override
-		public boolean isRootLocation() {
-			return "/".equals(absPath);
-		}
-
-		@Override
-		public DavPathFactory getFactory() {
-			return DavPathFactory.this;
-		}
-
-		@Override
-		public String getRepositoryPath() {
-			return absPath;
-		}
-
-		@Override
-		public String toString() {
-			return "[" + pathPrefix + "]" + absPath;
-		}
-
-		@Override
-		public int hashCode() {
-			return absPath.hashCode();
-		}
-
-		@Override
-		public boolean equals(Object obj) {
-			if (obj instanceof DavPath) {
-				final DavPath other = (DavPath) obj;
-				final boolean samePrefix = this.getPrefix() == null && other.getPrefix() == null || this.getPrefix().equals(other.getPrefix());
-				final boolean sameRelativeCleartextPath = this.absPath == null && other.absPath == null || this.absPath.equals(other.absPath);
-				return samePrefix && sameRelativeCleartextPath;
-			} else {
-				return false;
-			}
-		}
-	}
-
-}

+ 13 - 56
main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/webdav/jackrabbitservlet/FilesystemResourceFactory.java

@@ -8,11 +8,6 @@
  *******************************************************************************/
 package org.cryptomator.webdav.jackrabbitservlet;
 
-import java.util.Arrays;
-import java.util.Iterator;
-
-import org.apache.commons.lang3.ArrayUtils;
-import org.apache.commons.lang3.StringUtils;
 import org.apache.jackrabbit.webdav.DavException;
 import org.apache.jackrabbit.webdav.DavResource;
 import org.apache.jackrabbit.webdav.DavResourceFactory;
@@ -22,22 +17,14 @@ import org.apache.jackrabbit.webdav.DavServletResponse;
 import org.apache.jackrabbit.webdav.DavSession;
 import org.apache.jackrabbit.webdav.lock.LockManager;
 import org.apache.jackrabbit.webdav.lock.SimpleLockManager;
-import org.cryptomator.filesystem.File;
-import org.cryptomator.filesystem.FileSystem;
-import org.cryptomator.filesystem.Folder;
-import org.cryptomator.filesystem.Node;
-import org.cryptomator.webdav.jackrabbitservlet.DavPathFactory.DavPath;
+import org.cryptomator.filesystem.jackrabbit.FileLocator;
+import org.cryptomator.filesystem.jackrabbit.FolderLocator;
 
 class FilesystemResourceFactory implements DavResourceFactory {
 
-	private static final Class<Folder> FOLDER = Folder.class;
-	private static final Class<File> FILE = File.class;
-
-	private final FileSystem filesystem;
 	private final LockManager lockManager;
 
-	public FilesystemResourceFactory(FileSystem filesystem) {
-		this.filesystem = filesystem;
+	public FilesystemResourceFactory() {
 		this.lockManager = new SimpleLockManager();
 	}
 
@@ -48,53 +35,23 @@ class FilesystemResourceFactory implements DavResourceFactory {
 
 	@Override
 	public DavResource createResource(DavResourceLocator locator, DavSession session) throws DavException {
-		if (locator instanceof DavPath) {
-			return createResource((DavPath) locator, session);
+		if (locator instanceof FolderLocator) {
+			FolderLocator folder = (FolderLocator) locator;
+			return createFolder(folder, session);
+		} else if (locator instanceof FileLocator) {
+			FileLocator file = (FileLocator) locator;
+			return createFile(file, session);
 		} else {
 			throw new IllegalArgumentException("Unsupported locator type " + locator.getClass().getName());
 		}
 	}
 
-	private DavResource createResource(DavPath path, DavSession session) throws DavException {
-		if (path.isDirectory()) {
-			Folder folder = this.resolve(path.getResourcePath(), FOLDER);
-			return createFolder(folder, path, session);
-		} else {
-			File file = this.resolve(path.getResourcePath(), FILE);
-			return createFile(file, path, session);
-		}
-	}
-
-	DavFolder createFolder(Folder folder, DavPath path, DavSession session) {
-		return new DavFolder(this, lockManager, session, path, folder);
-	}
-
-	DavFile createFile(File file, DavPath path, DavSession session) {
-		return new DavFile(this, lockManager, session, path, file);
+	DavFolder createFolder(FolderLocator folder, DavSession session) {
+		return new DavFolder(this, lockManager, session, folder);
 	}
 
-	private <T extends Node> T resolve(String path, Class<T> expectedNodeType) {
-		final String[] pathFragments = StringUtils.split(path, '/');
-		if (ArrayUtils.isEmpty(pathFragments)) {
-			assert expectedNodeType.isAssignableFrom(Folder.class);
-			return expectedNodeType.cast(filesystem);
-		} else {
-			return resolve(filesystem, Arrays.stream(pathFragments).iterator(), expectedNodeType);
-		}
-	}
-
-	private <T extends Node> T resolve(Folder parent, Iterator<String> pathIterator, Class<T> expectedNodeType) {
-		assert pathIterator.hasNext();
-		final String childName = pathIterator.next();
-		if (pathIterator.hasNext()) {
-			return resolve(parent.folder(childName), pathIterator, expectedNodeType);
-		} else if (expectedNodeType.isAssignableFrom(Folder.class)) {
-			return expectedNodeType.cast(parent.folder(childName));
-		} else if (expectedNodeType.isAssignableFrom(File.class)) {
-			return expectedNodeType.cast(parent.file(childName));
-		} else {
-			throw new IllegalArgumentException("Supported expectedNodeTypes are File or Folder.");
-		}
+	DavFile createFile(FileLocator file, DavSession session) {
+		return new DavFile(this, lockManager, session, file);
 	}
 
 }

+ 3 - 2
main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/webdav/jackrabbitservlet/WebDavServlet.java

@@ -17,6 +17,7 @@ import org.apache.jackrabbit.webdav.DavSessionProvider;
 import org.apache.jackrabbit.webdav.WebdavRequest;
 import org.apache.jackrabbit.webdav.server.AbstractWebdavServlet;
 import org.cryptomator.filesystem.FileSystem;
+import org.cryptomator.filesystem.jackrabbit.FileSystemResourceLocatorFactory;
 
 public class WebDavServlet extends AbstractWebdavServlet {
 
@@ -28,8 +29,8 @@ public class WebDavServlet extends AbstractWebdavServlet {
 
 	public WebDavServlet(URI contextRootUri, FileSystem filesystem) {
 		davSessionProvider = new DavSessionProviderImpl();
-		davLocatorFactory = new DavPathFactory(contextRootUri);
-		davResourceFactory = new FilesystemResourceFactory(filesystem);
+		davLocatorFactory = new FileSystemResourceLocatorFactory(contextRootUri, filesystem);
+		davResourceFactory = new FilesystemResourceFactory();
 	}
 
 	@Override

+ 79 - 0
main/jackrabbit-filesystem-adapter/src/test/java/org/cryptomator/filesystem/jackrabbit/FileSystemResourceLocatorFactoryTest.java

@@ -0,0 +1,79 @@
+package org.cryptomator.filesystem.jackrabbit;
+
+import java.net.URI;
+import java.nio.ByteBuffer;
+
+import org.cryptomator.filesystem.FileSystem;
+import org.cryptomator.filesystem.WritableFile;
+import org.cryptomator.filesystem.inmem.InMemoryFileSystem;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class FileSystemResourceLocatorFactoryTest {
+
+	private FileSystemResourceLocatorFactory factory;
+
+	@Before
+	public void setupLocatorFactory() {
+		final FileSystem fs = new InMemoryFileSystem();
+		fs.folder("existingFolder").create();
+		try (WritableFile writable = fs.file("existingFile").openWritable()) {
+			writable.write(ByteBuffer.allocate(0));
+		}
+		factory = new FileSystemResourceLocatorFactory(URI.create("http://localhost/contextroot"), fs);
+	}
+
+	@Test
+	public void testCreateFoldersEvenWhenRequestingFiles() {
+		FileSystemResourceLocator locator = factory.createResourceLocator(null, null, "/existingFolder");
+		Assert.assertTrue(locator instanceof FolderLocator);
+
+		locator = factory.createResourceLocator("http://localhost/contextroot", "http://localhost/contextroot/existingFolder");
+		Assert.assertTrue(locator instanceof FolderLocator);
+	}
+
+	@Test
+	public void testCreateFilesEvenWhenRequestingFolders() {
+		FileSystemResourceLocator locator = factory.createResourceLocator(null, null, "/existingFile/");
+		Assert.assertTrue(locator instanceof FileLocator);
+
+		locator = factory.createResourceLocator("http://localhost/contextroot", "http://localhost/contextroot/existingFile/");
+		Assert.assertTrue(locator instanceof FileLocator);
+	}
+
+	@Test
+	public void testCreateFolders() {
+		FileSystemResourceLocator locator = factory.createResourceLocator(null, null, "/foo/bar/");
+		Assert.assertTrue(locator instanceof FolderLocator);
+		Assert.assertEquals("bar", locator.name());
+		Assert.assertEquals("foo", locator.parent().get().name());
+		Assert.assertEquals("", locator.parent().get().parent().get().name());
+		Assert.assertFalse(locator.parent().get().parent().get().parent().isPresent());
+
+		locator = factory.createResourceLocator("http://localhost/contextroot", "http://localhost/contextroot/foo/bar/");
+		Assert.assertTrue(locator instanceof FolderLocator);
+		Assert.assertEquals("bar", locator.name());
+		Assert.assertEquals("foo", locator.parent().get().name());
+		Assert.assertEquals("", locator.parent().get().parent().get().name());
+		Assert.assertFalse(locator.parent().get().parent().get().parent().isPresent());
+	}
+
+	@Test
+	public void testCreateFiles() {
+		FileSystemResourceLocator locator = factory.createResourceLocator(null, null, "/foo/bar");
+		Assert.assertTrue(locator instanceof FileLocator);
+		Assert.assertEquals("bar", locator.name());
+		Assert.assertEquals("foo", locator.parent().get().name());
+		Assert.assertEquals("", locator.parent().get().parent().get().name());
+		Assert.assertFalse(locator.parent().get().parent().get().parent().isPresent());
+
+		locator = factory.createResourceLocator("http://localhost/contextroot", "http://localhost/contextroot/foo/bar");
+		Assert.assertTrue(locator instanceof FileLocator);
+		Assert.assertEquals("bar", locator.name());
+		Assert.assertEquals("foo", locator.parent().get().name());
+		Assert.assertEquals("", locator.parent().get().parent().get().name());
+		Assert.assertFalse(locator.parent().get().parent().get().parent().isPresent());
+	}
+
+}