com.goeuro.sync4j.fs.FileSystemProvider Maven / Gradle / Ivy
package com.goeuro.sync4j.fs;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
import java.util.regex.Pattern;
import static com.goeuro.sync4j.fs.LocalFileSystem.defaultLocalFileSystem;
import static java.util.Arrays.asList;
import static java.util.Collections.unmodifiableCollection;
import static java.util.Collections.unmodifiableList;
public interface FileSystemProvider {
@Nonnull
FileSystem provideFor(@Nonnull T path) throws IllegalArgumentException;
@Nonnull
FileSystem provideFor(@Nonnull URI uri) throws IllegalArgumentException;
@Nonnull
FileSystem provideFor(@Nonnull String plain) throws IllegalArgumentException;
@Nonnull
static Builder fileSystemProvider() {
return new Builder();
}
@Immutable
class Default implements FileSystemProvider {
private static final Pattern STARTS_WITH_SCHEME = Pattern.compile("^[a-z]+:");
@Nonnull
private final Collection> fileSystems;
@Nonnull
private final Optional> fallback;
public Default(@Nonnull Collection> fileSystems, @Nonnull Optional> fallback) {
this.fallback = fallback;
this.fileSystems = fileSystems;
}
@Nonnull
@Override
public FileSystem provideFor(@Nonnull T path) throws IllegalArgumentException {
for (final FileSystem> fileSystem : fileSystems()) {
if (fileSystem.couldHandle(path)) {
// noinspection unchecked
return (FileSystem) fileSystem;
}
}
//noinspection unchecked
return fallback
.filter(fileSystem -> fileSystem.couldHandle(path))
.map(fileSystem -> (FileSystem) fileSystem)
.orElseThrow(() -> new IllegalArgumentException("There is no fileSystem that could handle: " + path));
}
@Nonnull
@Override
public FileSystem provideFor(@Nonnull URI uri) throws IllegalArgumentException {
for (final FileSystem> fileSystem : fileSystems()) {
if (fileSystem.couldHandle(uri)) {
// noinspection unchecked
return (FileSystem) fileSystem;
}
}
//noinspection unchecked
return fallback
.filter(fileSystem -> fileSystem.couldHandle(uri))
.map(fileSystem -> (FileSystem) fileSystem)
.orElseThrow(() -> new IllegalArgumentException("There is no fileSystem that could handle: " + uri));
}
@Nonnull
@Override
public FileSystem provideFor(@Nonnull String plain) {
//noinspection unchecked
return toUri(plain)
.>map(this::provideFor)
.orElseGet(() -> fallback
.map(fileSystem -> (FileSystem) fileSystem)
.orElseThrow(() -> new IllegalArgumentException("There is no fileSystem that could handle: " + plain))
);
}
@Nonnull
protected Optional toUri(@Nonnull String plain) {
if (!STARTS_WITH_SCHEME.matcher(plain).find()) {
return Optional.empty();
}
try {
return Optional.of(new URI(plain));
} catch (final URISyntaxException ignored) {
return Optional.empty();
}
}
@Nonnull
protected Collection> fileSystems() {
return fileSystems;
}
@Nonnull
protected Optional> fallback() {
return fallback;
}
}
class Builder {
@Nonnull
protected static final List> DEFAULTS = loadDefaults();
@Nonnull
private static List> loadDefaults() {
final List> result = new ArrayList<>();
for (final FileSystem> candidate : ServiceLoader.load(FileSystem.class)) {
result.add(candidate);
}
return unmodifiableList(result);
}
@Nonnull
private final List> fileSystems = new ArrayList<>();
@Nonnull
private Optional> fallback = Optional.of(defaultLocalFileSystem());
@Nonnull
public Builder withDefaults() {
fileSystems.addAll(DEFAULTS);
return this;
}
@Nonnull
public Builder with(@Nonnull Iterable> fileSystems) {
fileSystems.forEach(this.fileSystems::add);
return this;
}
@Nonnull
public Builder with(@Nonnull FileSystem>... fileSystems) {
return with(asList(fileSystems));
}
@Nonnull
public Builder withFallback(@Nullable FileSystem> fallback) {
this.fallback = Optional.ofNullable(fallback);
return this;
}
@Nonnull
public FileSystemProvider build() {
return new Default(
unmodifiableCollection(fileSystems),
fallback
);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy