mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-17 10:11:27 +00:00
new filesystem-aware WebDAV LocatorFactory
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 "/";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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() + "/";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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(FolderLocator folder, DavSession session) {
|
||||
return new DavFolder(this, lockManager, session, folder);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user