Skip to content

Instantly share code, notes, and snippets.

@ag88
Last active March 2, 2023 20:19
Show Gist options
  • Save ag88/5d8c5246bf200f25159348d315109552 to your computer and use it in GitHub Desktop.
Save ag88/5d8c5246bf200f25159348d315109552 to your computer and use it in GitHub Desktop.
webdav-nio-filesystem-provider
/*
Copyright 2012-2013 University of Stavanger, Norway
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.
note: codes has been edited by ag88 and is not original
*/
package no.maddin.niofs.webdav;
import java.io.IOException;
import java.net.URI;
import java.net.ProxySelector;
import java.nio.file.FileStore;
import java.nio.file.FileSystem;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.WatchService;
import java.nio.file.attribute.UserPrincipalLookupService;
import java.nio.file.spi.FileSystemProvider;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.sardine.Sardine;
import com.github.sardine.SardineFactory;
/**
* WebDAV implementation of a FileSystem.
*/
public class WebdavFileSystem extends FileSystem {
private final FileSystemProvider provider;
private final int port;
private final String host;
private final String password;
private final String username;
private String rootpath;
Cache<Path, WebdavFileAttributes> attcache;
/**
*
* @param provider an instance of a WebdavFileSystemProvided. This can be a shared instance.
* @param serverUri URI for the WEBDAV server, the scheme is ignored.
*/
public WebdavFileSystem(WebdavFileSystemProvider provider, URI serverUri) {
this.provider = provider;
this.host = serverUri.getHost();
this.port = serverUri.getPort();
if (serverUri.getUserInfo() != null) {
String[] ui = serverUri.getUserInfo().split(":");
this.username = ui[0];
if(ui.length > 1)
this.password = ui[1];
else
this.password = null;
} else {
this.username = null;
this.password = null;
}
this.rootpath = getSeparator();
if( serverUri.getPath() != null && ! serverUri.getPath().equals(""))
this.rootpath = serverUri.getPath();
this.attcache = Caffeine.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.maximumSize(1000)
.build();
}
@Override
public FileSystemProvider provider() {
return provider;
}
/**
* Not implemented
*/
@Override
public void close() throws IOException {
}
/**
* Not implemented
* @return null
*/
@Override
public Iterable<FileStore> getFileStores() {
return null;
}
@Override
public Path getPath(String first, String... more) {
String path;
if (more.length == 0) {
path = first;
} else {
StringBuilder sb = new StringBuilder();
sb.append(first);
for (String segment: more) {
if (segment.length() > 0) {
if (sb.length() > 0) {
sb.append(getSeparator());
}
sb.append(segment);
}
}
path = sb.toString();
}
return new WebdavPath(this, path);
}
/**
* Not implemented
* @return null
*/
@Override
public PathMatcher getPathMatcher(String syntaxAndPattern) {
return null;
}
/**
* Not implemented
* @return null
*/
@Override
public Iterable<Path> getRootDirectories() {
final Path rootp = new WebdavPath(this, rootpath);
Iterable<Path> ret = new Iterable<Path>() {
@Override
public Iterator<Path> iterator() {
ArrayList<Path> ap = new ArrayList<Path>(1);
ap.add(rootp);
return ap.iterator();
}
};
return ret;
}
@Override
public String getSeparator() {
return "/";
}
/**
* Not implemented
* @return null
*/
@Override
public UserPrincipalLookupService getUserPrincipalLookupService() {
return null;
}
/**
* Not implemented
* @return false
*/
@Override
public boolean isOpen() {
return false;
}
/**
* Not implemented
* @return false
*/
@Override
public boolean isReadOnly() {
return false;
}
/**
* Not implemented
* @return null
*/
@Override
public WatchService newWatchService() throws IOException {
return null;
}
/**
* Not implemented
* @return null
*/
@Override
public Set<String> supportedFileAttributeViews() {
return null;
}
/**
* Check if one filesystem is equal to another. Checks Host, username and Port.
*/
@Override
public boolean equals(Object other) {
if (!(other instanceof WebdavFileSystem)) {
throw new IllegalArgumentException("Argument must be of instance WebdavFileSystem");
}
WebdavFileSystem current = (WebdavFileSystem)other;
return current.host.equals(this.host) && current.username.equals(this.username) && current.port == this.port;
}
@Override
public int hashCode() {
return super.hashCode();
}
public String getUserName() {
return this.username;
}
String getHost() {
return this.host;
}
int getPort() {
return this.port;
}
public String getPassword() {
return this.password;
}
Sardine getSardine() throws IOException {
if(!(username == null && password == null))
return SardineFactory.begin(username, password, ProxySelector.getDefault());
else
return SardineFactory.begin();
}
public Cache<Path, WebdavFileAttributes> getAttcache() {
return attcache;
}
public void setAttcache(Cache<Path, WebdavFileAttributes> attcache) {
this.attcache = attcache;
}
}
/*
Copyright 2012-2013 University of Stavanger, Norway
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.
note: codes has been edited by ag88 and is not original
*/
package no.maddin.niofs.webdav;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.AccessMode;
import java.nio.file.CopyOption;
import java.nio.file.DirectoryStream;
import java.nio.file.DirectoryStream.Filter;
import java.nio.file.FileStore;
import java.nio.file.FileSystem;
import java.nio.file.FileSystemException;
import java.nio.file.FileSystemNotFoundException;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.NoSuchFileException;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.ProviderMismatchException;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileAttribute;
import java.nio.file.attribute.FileAttributeView;
import java.nio.file.spi.FileSystemProvider;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;
import javax.xml.namespace.QName;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.sardine.DavResource;
import com.github.sardine.Sardine;
import com.github.sardine.impl.SardineException;
import com.github.sardine.model.Allprop;
import com.github.sardine.model.Propfind;
/**
* The WebDAV FileSystemProvider based on Sardine.
*/
public class WebdavFileSystemProvider extends FileSystemProvider {
Logger log = LogManager.getLogger(WebdavFileSystemProvider.class);
private static final String NEED_TO_BE_AN_INSTANCE_OF_WEBDAV_PATH = "Need to be an instance of WebdavPath";
private static final int DEFAULT_PORT = 80;
private final Map<URI, WebdavFileSystem> hosts = new HashMap<>();
public WebdavFileSystemProvider() {
super();
}
@Override
public void copy(Path fileFrom, Path fileTo, CopyOption... options) throws IOException {
if (!(fileFrom instanceof WebdavPath)) {
throw new IllegalArgumentException(fileFrom.toString());
}
if (!(fileTo instanceof WebdavPath)) {
throw new IllegalArgumentException(fileTo.toString());
}
WebdavPath wPathTo = (WebdavPath)fileTo;
WebdavFileSystem webdavHost = (WebdavFileSystem)fileTo.getFileSystem();
Sardine webdav = webdavHost.getSardine();
webdav.put(wPathTo.toUri().toString(), Files.readAllBytes(fileFrom));
}
@Override
public void createDirectory(Path dir, FileAttribute<?>... attrs) throws IOException {
if (!(dir instanceof WebdavPath)) {
throw new IllegalArgumentException(dir.toString());
}
WebdavPath wDir = (WebdavPath)dir;
WebdavFileSystem webdavHost = (WebdavFileSystem)dir.getFileSystem();
Sardine webdav = webdavHost.getSardine();
createDirectoryRecursive(webdav, wDir, attrs);
}
private void createDirectoryRecursive(Sardine webdav, WebdavPath wDir, FileAttribute<?>[] attrs) throws IOException {
if (webdav.exists(wDir.toUri().toString())) {
return;
}
WebdavPath parent = (WebdavPath)wDir.getParent();
if (parent != null) {
createDirectoryRecursive(webdav, parent, attrs);
}
webdav.createDirectory(wDir.toUri().toString());
}
@Override
public void delete(Path dir) throws IOException {
if (!(dir instanceof WebdavPath)) {
throw new IllegalArgumentException(dir.toString());
}
WebdavPath wDir = (WebdavPath)dir;
WebdavFileSystem webdavHost = (WebdavFileSystem)dir.getFileSystem();
Sardine webdav = webdavHost.getSardine();
String dirString = "";
try {
dirString = wDir.toUri().toString();
webdav.delete(dirString);
} catch(SardineException se) {
if (se.getCause() instanceof IOException) {
throw (IOException)se.getCause();
}
if (Objects.equals(se.getResponsePhrase(), "Not Found")) {
throw new NoSuchFileException(dirString);
}
throw new IOException(se);
}
}
/**
* The default implementation in FileSystemProvider will simply call
* delete() in deleteIfExists() and silently ignore any NoSuchFileException.
* In case of Nexus, trying to delete() will result in 503 (Not allowed)
* even if the path points to nowhere.
*/
@Override
public boolean deleteIfExists(Path path) throws IOException {
WebdavFileSystem webdavFs = (WebdavFileSystem)path.getFileSystem();
final String s = path.toUri().toString();
return webdavFs.getSardine().exists(s);
}
@Override
public FileSystem getFileSystem(URI uri) {
try {
return getWebdavHost(uri, true);
} catch(URISyntaxException ex) {
throw new FileSystemNotFoundException(uri.toString());
}
}
@Override
public Path getPath(URI uri) {
try {
WebdavFileSystem host = getWebdavHost(uri, true);
return new WebdavPath(host, uri.getPath());
} catch(URISyntaxException e) {
throw new FileSystemNotFoundException(uri.toString());
}
}
private WebdavFileSystem getWebdavHost(URI uri, boolean create) throws URISyntaxException {
String host = uri.getHost();
int port = uri.getPort();
if (port == -1) {
port = DEFAULT_PORT;
}
String userInfo = uri.getUserInfo();
URI serverUri = new URI(getScheme(), userInfo, host, port, uri.getPath(), null, null);
synchronized (hosts) {
WebdavFileSystem fs = hosts.get(serverUri);
if (fs == null && create) {
fs = new WebdavFileSystem(this, serverUri);
hosts.put(serverUri, fs);
}
return fs;
}
}
@Override
public String getScheme() {
return "webdav";
}
/**
* Unsupported
*/
@Override
public <V extends FileAttributeView> V getFileAttributeView(Path path, Class<V> type, LinkOption... options) {
throw new UnsupportedOperationException();
}
/**
* Unsupported
*/
@Override
public FileStore getFileStore(Path path) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public void checkAccess(Path path, AccessMode... modes) throws IOException {
WebdavFileSystem webdavFs = (WebdavFileSystem)path.getFileSystem();
final String s = path.toUri().toString();
final boolean exists = webdavFs.getSardine().exists(s);
if (!exists) {
throw new NoSuchFileException(s);
}
}
/**
* Unsupported
*/
@Override
public boolean isHidden(Path path) throws IOException {
throw new UnsupportedOperationException();
}
/**
* Unsupported
*/
@Override
public boolean isSameFile(Path path, Path path2) throws IOException {
throw new UnsupportedOperationException();
}
/**
* Unsupported
*/
@Override
public void move(Path source, Path target, CopyOption... options) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public SeekableByteChannel newByteChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs)
throws IOException
{
return new SardineChannel((WebdavPath)path);
}
class DirStream implements DirectoryStream<Path> {
ArrayList<Path> paths;
public DirStream(ArrayList<Path> paths) {
this.paths = paths;
}
@Override
public void close() throws IOException {
}
@Override
public Iterator<Path> iterator() {
return paths.iterator();
}
}
@Override
public DirectoryStream<Path> newDirectoryStream(Path path, Filter<? super Path> filter) throws IOException {
// throw new UnsupportedOperationException();
Marker marker = MarkerManager.getMarker("newDirectoryStream");
log.debug(marker, "");
try {
if (!(path instanceof WebdavPath)) {
IOException e = new IOException(NEED_TO_BE_AN_INSTANCE_OF_WEBDAV_PATH);
log.error(marker, "path {}", path.toString());
log.error(e);
throw e;
}
WebdavFileSystem wfs = (WebdavFileSystem) path.getFileSystem();
Cache<Path, WebdavFileAttributes> cache = wfs.getAttcache();
List<DavResource> resources = wfs.getSardine().list(path.toUri().toString(), 1, true);
ArrayList<Path> paths = new ArrayList<Path>(10);
Iterator<DavResource> iter = resources.iterator();
boolean first = true;
while (iter.hasNext()) {
DavResource res = iter.next();
if (first) {
first = false;
if (res.isDirectory()) {
/*
* in a canonical directory listing, the parent directory queried isn't included
* only its contents this omits that entry so that it 'looks' like a
* conventional directory listing
*/
WebdavPath dp = new WebdavPath((WebdavFileSystem) path.getFileSystem(), res.getPath());
if (dp.equals(path))
continue;
}
}
WebdavPath wpath = new WebdavPath((WebdavFileSystem) path.getFileSystem(), res.getPath());
if(filter != null && !filter.accept(wpath))
continue;
if (cache.getIfPresent(wpath) == null) {
WebdavFileAttributes attr = new WebdavFileAttributes(res);
cache.put(wpath, attr);
}
paths.add(wpath);
}
DirStream dirstream = new DirStream(paths);
return dirstream;
} catch (IOException e) {
log.error(marker, "path {}", path.toString());
log.error(e);
throw e;
}
}
@Override
public FileSystem newFileSystem(URI uri, Map<String, ?> env) throws IOException {
try {
return getWebdavHost(uri, true);
} catch(URISyntaxException e) {
throw new FileSystemException(e.toString());
}
}
@SuppressWarnings("unchecked")
@Override
public <A extends BasicFileAttributes> A readAttributes(Path path, Class<A> type, LinkOption... options)
throws IOException {
Marker marker = MarkerManager.getMarker("readAttributes(path,type)");
if(!(path.getFileSystem() instanceof WebdavFileSystem)) {
log.error(marker, "Invalid filesystem");
throw new FileSystemException("Invalid filesystem");
}
Cache<Path, WebdavFileAttributes> cache = ((WebdavFileSystem) path.getFileSystem()).getAttcache();
if (cache.getIfPresent(path) != null) {
return (A) cache.getIfPresent(path);
}
List<DavResource> resources;
try {
WebdavFileSystem wfs = (WebdavFileSystem)path.getFileSystem();
resources = wfs.getSardine().list(path.toUri().toString(),0,true);
//List<DavResource> resources = wfs.getSardine().list(path.toUri().toString());
if (resources.size() != 1) {
throw new IllegalArgumentException();
}
final DavResource res = resources.get(0);
if (!type.isAssignableFrom(WebdavFileAttributes.class)) {
throw new ProviderMismatchException();
}
WebdavFileAttributes attr = new WebdavFileAttributes(res);
cache.put(path, attr);
return (A) attr;
} catch (IOException e) {
log.warn(marker, "error connecting: {}", path.toUri().toString());
log.error(e);
throw e;
}
}
@Override
public Map<String, Object> readAttributes(Path path, String attributes, LinkOption... arg2) throws IOException {
//throw new UnsupportedOperationException();
Marker marker = MarkerManager.getMarker("readAttributes(path,sattr)");
WebdavFileAttributes wattr;
if(!(path.getFileSystem() instanceof WebdavFileSystem)) {
log.error(marker, "Invalid filesystem");
throw new FileSystemException("Invalid filesystem");
}
Cache<Path, WebdavFileAttributes> cache = ((WebdavFileSystem) path.getFileSystem()).getAttcache();
if (cache.getIfPresent(path) != null)
wattr = cache.getIfPresent(path);
else {
WebdavFileSystem wfs = (WebdavFileSystem)path.getFileSystem();
List<DavResource> resources = wfs.getSardine().list(path.toUri().toString(),0,true);
//List<DavResource> resources = wfs.getSardine().list(path.toUri().toString());
if (resources.size() != 1) {
throw new IllegalArgumentException();
}
final DavResource res = resources.get(0);
wattr = new WebdavFileAttributes(res);
cache.put(path, wattr);
}
TreeMap<String, Object> map = new TreeMap<String, Object>();
String attr[] = attributes.split(",");
for(String a: attr) {
switch(a) {
case "lastModifiedTime":
map.put("lastModifiedTime", wattr.lastModifiedTime());
break;
case "lastAccessTime":
map.put("lastAccessTime", wattr.lastAccessTime());
break;
case "creationTime":
map.put("creationTime", wattr.creationTime());
break;
case "size":
map.put("size", wattr.size());
break;
case "isRegularFile":
map.put("isRegularFile", wattr.isRegularFile());
break;
case "isDirectory":
map.put("isDirectory", wattr.isDirectory());
break;
case "isSymbolicLink":
map.put("isSymbolicLink", wattr.isSymbolicLink());
break;
case "isOther":
map.put("isOther", wattr.isSymbolicLink());
break;
case "fileKey":
map.put("fileKey", wattr.fileKey());
break;
}
}
return map;
}
/**
* Unsupported
*/
@Override
public void setAttribute(Path arg0, String arg1, Object arg2, LinkOption... arg3) throws IOException {
throw new UnsupportedOperationException();
}
}
/*
Copyright 2012-2013 University of Stavanger, Norway
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.
note: codes has been edited by ag88 and is not original
*/
package no.maddin.niofs.webdav;
import java.io.File;
import java.io.IOError;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.FileSystem;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.WatchEvent.Kind;
import java.nio.file.WatchEvent.Modifier;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.StringTokenizer;
import org.apache.commons.codec.digest.UnixCrypt;
/**
* Denotes a WebDAV Path.
*/
/**
* @author andrew
*
*/
public class WebdavPath implements Path {
private static final String NEED_TO_BE_AN_INSTANCE_OF_WEBDAV_PATH = "Need to be an instance of WebdavPath";
private static final String PARENT_PATH = "..";
//private static final String PATH_SEP = "/";
final String PATH_SEP;
//private static final String DEFAULT_ROOT_PATH = PATH_SEP;
private final String DEFAULT_ROOT_PATH;
private ArrayList<String> elements;
private final WebdavFileSystem host;
private boolean isabsolute = false;
WebdavPath(WebdavFileSystem webdavHost, String path) {
this.host = webdavHost;
this.elements = new ArrayList<String>();
PATH_SEP = webdavHost.getSeparator();
DEFAULT_ROOT_PATH = PATH_SEP;
parsePathStr(path);
}
WebdavPath(WebdavFileSystem webdavHost, ArrayList<String> elements, boolean absolute) {
this.host = webdavHost;
PATH_SEP = webdavHost.getSeparator();
DEFAULT_ROOT_PATH = PATH_SEP;
this.elements = elements;
this.isabsolute = absolute;
}
private void parsePathStr(String path) {
if (path == null) {
//this.pathf.add(DEFAULT_ROOT_PATH);
//empty path empty elements, not necessary absolute
} else if (path.equals(DEFAULT_ROOT_PATH)) {
//this.elements.add(DEFAULT_ROOT_PATH);
this.isabsolute = true;
//empty path elements
} else {
String p = path.trim();
if(p.startsWith(PATH_SEP)) {
this.isabsolute = true;
p = p.substring(1);
}
if(p.endsWith(PATH_SEP))
p = p.substring(0,p.length()-1); //omit trailing slash
String ps[] = p.split(PATH_SEP);
for (String s : ps)
elements.add(s);
}
}
public String getPathString() {
StringBuilder sb = new StringBuilder(100);
if (isabsolute)
sb.append(PATH_SEP);
boolean first = true;
for(String f : elements) {
if(first) {
first = false;
} else
sb.append(PATH_SEP);
sb.append(f);
}
return sb.toString();
}
@Override
public String toString() {
return getPathString();
}
@Override
public FileSystem getFileSystem() {
return this.host;
}
@Override
public Path getRoot() {
Iterator<Path> iter = this.host.getRootDirectories().iterator();
Path p = null;
while(iter.hasNext()) {
p = iter.next();
return p;
}
return new WebdavPath(this.host, DEFAULT_ROOT_PATH);
}
@Override
public boolean isAbsolute() {
return isabsolute;
}
@Override
public int compareTo(Path other) {
//throw new UnsupportedOperationException();
if(!(other instanceof WebdavPath))
throw new ClassCastException();
WebdavPath ow = (WebdavPath) other;
if(elements.size() > ow.getElements().size())
return 1;
else if(elements.size() < ow.getElements().size())
return -1;
ArrayList<String> oe = ow.getElements();
for(int i=0; i<elements.size(); i++) {
if(elements.get(i).equals(oe.get(i)))
continue;
return elements.get(i).compareTo(oe.get(i));
}
return 0;
}
@Override
public boolean equals(Object other) {
if(!(other instanceof WebdavPath))
return false;
WebdavPath ow = (WebdavPath) other;
if(ow.getElements().size() > elements.size() ||
ow.getElements().size() < elements.size())
return false;
ArrayList<String> oe = ow.getElements();
for(int i=0; i<elements.size(); i++) {
if(elements.get(i).equals(oe.get(i)))
continue;
return false;
}
return true;
}
@Override
public boolean startsWith(Path other) {
//throw new UnsupportedOperationException();
if(!(other instanceof WebdavPath))
return false;
if(other.getNameCount() > getNameCount())
return false;
WebdavPath wp = (WebdavPath) other;
if (!((WebdavFileSystem) wp.getFileSystem()).equals(host))
return false;
ListIterator<String> io = wp.getElements().listIterator();
while(io.hasNext()) {
int i = io.nextIndex();
if(io.next().equals(elements.get(i)))
continue;
return false;
}
return true;
}
@Override
public boolean startsWith(String other) {
//throw new UnsupportedOperationException();
return startsWith(new WebdavPath(this.host, other));
}
@Override
public boolean endsWith(Path other) {
//throw new UnsupportedOperationException();
if(!(other instanceof WebdavPath))
return false;
if(other.getNameCount() > getNameCount())
return false;
WebdavPath wp = (WebdavPath) other;
if (!((WebdavFileSystem) wp.getFileSystem()).equals(host))
return false;
int si = getNameCount() - other.getNameCount();
ListIterator<String> io = wp.getElements().listIterator();
for(int i=si; i<getNameCount(); i++) {
if(io.hasNext())
if(elements.get(i).equals(io.next()))
continue;
return false;
}
return true;
}
@Override
public boolean endsWith(String other) {
//throw new UnsupportedOperationException();
return endsWith(new WebdavPath(this.host, other));
}
@Override
public Path getFileName() {
if(elements.size()==0)
return null;
else
return new WebdavPath(this.host, elements.get(elements.size()-1));
}
@Override
public Path getName(int index) {
if(elements.size() == 0)
throw new IllegalArgumentException();
if(index >= elements.size() || index < 0)
throw new IllegalArgumentException();
return new WebdavPath(host, elements.get(index));
}
@Override
public int getNameCount() {
return elements.size();
}
@Override
public Path getParent() {
if (elements.size()<=1)
return null;
ArrayList<String> elms = new ArrayList<>(elements.size()-1);
elms.addAll(elements.subList(0, elements.size()-1));
return new WebdavPath(host, elms, true );
}
@Override
public Iterator<Path> iterator() {
List<Path> plist = new LinkedList<>();
for (Path p = this; p != null; p = p.getParent()) {
plist.add(0, p);
}
return plist.iterator();
}
@Override
public Path normalize() {
try {
URI normal = new URI(getPathString()).normalize();
return new WebdavPath(this.host, normal.getPath());
} catch (URISyntaxException e) {
throw new IllegalArgumentException(getPathString(), e);
}
}
@Override
public WatchKey register(WatchService watcher, Kind<?>... events) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public WatchKey register(WatchService watcher, Kind<?>[] events, Modifier... arg2) throws IOException {
throw new UnsupportedOperationException();
}
/*
* Constructs a relative path between this path and a given path.
*
* relativize() is the inverse of resolve().
* This method attempts to construct a relative path that is less this path as preceeding path
* e.g. this "a/b" , other "a/b/c/d" - relativize() = "c/d"
*
* this and other path needs to be both relative
* or both absolute
*
*/
@Override
public Path relativize(Path other) {
if(!(other instanceof WebdavPath))
throw new IllegalArgumentException(NEED_TO_BE_AN_INSTANCE_OF_WEBDAV_PATH);
if( (isAbsolute() && !other.isAbsolute()) ||
(!isAbsolute() && other.isAbsolute()))
throw new IllegalArgumentException(
"Both this path and the other path has to be both absolute or relative");
if (other.getNameCount() < this.getNameCount())
throw new IllegalArgumentException(
"the other path is short than this path");
WebdavPath wp = (WebdavPath) other;
ListIterator<String> io = wp.getElements().listIterator();
ListIterator<String> ia = elements.listIterator();
while(ia.hasNext()) {
String a = ia.next();
if(io.hasNext()) {
String so = io.next();
if(!so.equals(a))
break;
}
}
ArrayList<String> re = new ArrayList<String>(wp.getElements().size() - elements.size());
//copy remaining elements
while(io.hasNext()) {
re.add(io.next());
}
//returns a relative path
return new WebdavPath(host, re, false);
}
/*
* Resolve the given path against this path.
*
* In the simplest case, this method joins the given path to this path
* and returns a resulting path that ends with the given path.
*
* @param other The other path to resolved against this
*
* @return If the other parameter is an absolute path, returns other.
* If other is an empty path, returns this path.
* Otherwise this method considers this path to be a directory and
* resolves the given path against this path.
*/
@Override
public Path resolve(Path other) {
if (other == null) {
return this;
}
if (other.isAbsolute())
return other;
if(!(other instanceof WebdavPath))
throw new IllegalArgumentException(NEED_TO_BE_AN_INSTANCE_OF_WEBDAV_PATH);
WebdavPath wp = (WebdavPath) other;
ArrayList<String> ret = new ArrayList<String>(elements.size() + wp.getElements().size());
ret.addAll(elements);
ret.addAll(wp.getElements());
return new WebdavPath(host, ret, isAbsolute());
}
@Override
public Path resolve(String other) {
return resolve(new WebdavPath(this.host, other));
}
/*
* Resolves the given path against this path's parent path.
*/
@Override
public Path resolveSibling(Path other) {
//throw new UnsupportedOperationException();
if(!(other instanceof WebdavPath))
throw new IllegalArgumentException(NEED_TO_BE_AN_INSTANCE_OF_WEBDAV_PATH);
if(getParent()==null)
return null;
else
return getParent().resolve(other);
}
@Override
public Path resolveSibling(String other) {
//throw new UnsupportedOperationException();
return resolveSibling(new WebdavPath(this.host, other));
}
/*
* Returns a relative Path that is a subsequence of the name elements of this path.
*
* @param beginIndex begin index
* @param endIndex end index
* @return a relative path with elements from elements[beingIndex] to elements[endIndex-1]
* elements[endIndex-1] is included.
*/
@Override
public Path subpath(int beginIndex, int endIndex) {
//throw new UnsupportedOperationException();
if(elements.size() == 0)
throw new IllegalArgumentException();
if( beginIndex < 0 || endIndex <= beginIndex || endIndex > elements.size() )
throw new IllegalArgumentException();
ArrayList<String> subp = new ArrayList<String>(elements.subList(beginIndex, endIndex));
return new WebdavPath(this.host,
subp, false);
}
/*
* if this is not absolute path, returns this path resolved (appended) on root path
*/
@Override
public Path toAbsolutePath() {
if(isAbsolute())
return this;
return getRoot().resolve(this);
}
@Override
public File toFile() {
throw new UnsupportedOperationException();
}
@Override
public Path toRealPath(LinkOption... options) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public URI toUri() {
String scheme = (host.provider() instanceof WebdavsFileSystemProvider) ? "https" : "http";
String server = host.getHost();
int port = host.getPort();
URI sardineUri;
try {
sardineUri = new URI(scheme, null, server, port, getPathString(), null, null);
return sardineUri;
} catch(URISyntaxException e) {
throw new IOError(e);
}
}
public ArrayList<String> getElements() {
return elements;
}
public void setElements(ArrayList<String> elements) {
this.elements = elements;
}
}
package no.maddin.niofs.webdav;
//CHECKSTYLE:OFF
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Iterator;
import java.util.logging.Logger;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestReporter;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.assertThat;
/**
* These are the tests that don't require a running server.
*/
public class WebdavPathTest {
private int webdavPort = -1;
@Test
public void newFileSystemWebdav() throws Exception {
URI uri = new URI("webdav", "user:password","localhost", webdavPort, "/", null, null);
FileSystem fs = FileSystems.newFileSystem(uri, null);
assertThat(fs, is(notNullValue()));
}
@Test
public void newFileSystemWebdavs() throws Exception {
URI uri = new URI("webdavs", "user:password","localhost", webdavPort, "/", null, null);
FileSystem fs = FileSystems.newFileSystem(uri, null);
assertThat(fs, is(notNullValue()));
}
@Test
public void getURI() throws Exception {
URI uri = new URI("webdav", "user:password","localhost", webdavPort, "/", null, null);
Path path = Paths.get(uri);
assertThat(path, is(notNullValue()));
}
@Test
public void normalize() throws Exception {
String dottedPath = "/webdav/../test/something";
URI uri = new URI("webdav", "username:password", "anyhost", webdavPort, dottedPath, null, null);
Path path = Paths.get(uri);
Path result = path.normalize();
assertThat(result, is(instanceOf(WebdavPath.class)));
String resultUri = result.toUri().toString();
assertThat(resultUri, not(containsString("..")));
assertThat(result.isAbsolute(), is(true));
}
final boolean checkclass = true;
private URI makeURI(String path) throws Exception {
URI uri = new URI("webdav", "username:password", "anyhost", webdavPort, path, null, null);
//URI uri = new URI("file", null, null, 0, path, null, null);
return uri;
}
@Test
public void testgetRoot() throws Exception {
Path root = Paths.get(makeURI("/"));
assertThat(root.getRoot().toString().equals("/"), is(true));
if(checkclass)
assertThat(root, is(instanceOf(WebdavPath.class)));
}
@Test
public void testgetParent() throws Exception {
Path a = Paths.get(makeURI("/a/b/c"));
assertThat(a.getParent().toString().equals("/a/b"), is(true));
if(checkclass)
assertThat(a, is(instanceOf(WebdavPath.class)));
}
@Test
public void testiterator_getname() throws Exception {
Path a = Paths.get(makeURI("/a/b/c"));
assertThat(a.getFileName().toString().equals("c"), is(true));
Path root = Paths.get(makeURI("/"));
assertThat(root.getFileName(), nullValue());
try {
root.getName(0);
assertThat(false,is(true));
} catch (IllegalArgumentException e) {
//Logger log = Logger.getLogger("testok");
//log.info("getName empty elements passed");
}
int n = a.getNameCount();
assertThat(n,equalTo(3));
Iterator<Path> iter = a.iterator();
int i = 0;
Path b = null;
while(iter.hasNext()) {
b = iter.next();
assertThat(a.getName(i).toString().equals(b.getFileName().toString()), is(true));
i++;
}
if(checkclass) {
assertThat(a, is(instanceOf(WebdavPath.class)));
assertThat(b, is(instanceOf(WebdavPath.class)));
assertThat(root, is(instanceOf(WebdavPath.class)));
}
}
@Test
public void testtoAbsPath() throws Exception {
Path a = Paths.get(makeURI("/a/b/c"));
assertThat(a.toAbsolutePath().toString().equals("/a/b/c"), is(true));
Path root = Paths.get(makeURI("/"));
Path b = root.relativize(a);
assertThat(b.toString().equals("a/b/c"), is(true));
assertThat(b.toAbsolutePath().toString().equals("/a/b/c"), is(true));
if(checkclass) {
assertThat(a, is(instanceOf(WebdavPath.class)));
assertThat(b, is(instanceOf(WebdavPath.class)));
assertThat(root, is(instanceOf(WebdavPath.class)));
}
}
@Test
public void testequals() throws Exception {
Path a = Paths.get(makeURI("/a/b/c"));
Path b = Paths.get(makeURI("/a/b/e"));
Path c = Paths.get(makeURI("/a/b/c/e"));
Path d = Paths.get(makeURI("/a/b"));
Path e = Paths.get(makeURI("/a/b/c"));
assertThat(a.equals(b), is(false));
assertThat(a.equals(c), is(false));
assertThat(a.equals(d), is(false));
assertThat(a.equals(e), is(true));
if(checkclass) {
assertThat(a, is(instanceOf(WebdavPath.class)));
assertThat(b, is(instanceOf(WebdavPath.class)));
assertThat(c, is(instanceOf(WebdavPath.class)));
assertThat(d, is(instanceOf(WebdavPath.class)));
assertThat(e, is(instanceOf(WebdavPath.class)));
}
}
@Test
public void testcompareTo() throws Exception {
Path a = Paths.get(makeURI("/a/b/c"));
Path b = Paths.get(makeURI("/a/b/e"));
Path c = Paths.get(makeURI("/a/b/c/e"));
Path d = Paths.get(makeURI("/a/b"));
Path e = Paths.get(makeURI("/a/b/c"));
assertThat(a.compareTo(b) < 0, is(true));
assertThat(a.compareTo(c) < 0, is(true));
assertThat(a.compareTo(d) > 0, is(true));
assertThat(a.compareTo(e) == 0, is(true));
if(checkclass) {
assertThat(a, is(instanceOf(WebdavPath.class)));
assertThat(b, is(instanceOf(WebdavPath.class)));
assertThat(c, is(instanceOf(WebdavPath.class)));
assertThat(d, is(instanceOf(WebdavPath.class)));
assertThat(e, is(instanceOf(WebdavPath.class)));
}
}
@Test
public void relativizeresolve() throws Exception {
Path root = Paths.get(makeURI("/"));
assertThat(root.toString().equals("/"), is(true));
String ps = "/a/b";
Path p = Paths.get(makeURI(ps));
assertThat(p.toString().equals("/a/b"), is(true));
String qs = "/c/d";
Path qa =Paths.get(makeURI(qs));;
assertThat(qa.toString().equals("/c/d"), is(true));
Path q = root.relativize(qa); //gets relative path "c/d"
assertThat(q.toString().equals("c/d"), is(true));
assertThat(p.resolve(q).toString().equals("/a/b/c/d"), is(true));
assertThat(p.resolve(q).equals(p.resolve("c/d")), is(true));
assertThat(p.relativize(p.resolve(q)).equals(q), is(true));
if(checkclass) {
assertThat(root, is(instanceOf(WebdavPath.class)));
assertThat(p, is(instanceOf(WebdavPath.class)));
assertThat(q, is(instanceOf(WebdavPath.class)));
}
}
@Test
public void teststartendswith() throws Exception {
Path a = Paths.get(makeURI("/a/b/c"));
Path b = Paths.get(makeURI("/a/b"));
assertThat(a.startsWith(b), is(true));
assertThat(a.startsWith("/a/b"), is(true));
Path root = Paths.get(makeURI("/"));
Path c = root.relativize(Paths.get(makeURI("/b/c")));
assertThat(c.toString().equals("b/c"), is(true));
assertThat(a.endsWith(c), is(true));
assertThat(a.endsWith("b/c"), is(true));
assertThat(a.endsWith(b), is(false));
if(checkclass) {
assertThat(a, is(instanceOf(WebdavPath.class)));
assertThat(b, is(instanceOf(WebdavPath.class)));
assertThat(c, is(instanceOf(WebdavPath.class)));
}
}
@Test
public void testresolvsib_subpath() throws Exception {
Path root = Paths.get(makeURI("/"));
Path a = Paths.get(makeURI("/a/b/c"));
Path b = root.relativize(Paths.get(makeURI("/sib")));
assertThat(a.resolveSibling(b).toString().equals("/a/b/sib"), is(true));
assertThat(a.resolveSibling("sib").toString().equals("/a/b/sib"), is(true));
assertThat(a.subpath(1, 3).toString().equals("b/c"), is(true));
if(checkclass) {
assertThat(a, is(instanceOf(WebdavPath.class)));
assertThat(b, is(instanceOf(WebdavPath.class)));
assertThat(root, is(instanceOf(WebdavPath.class)));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment