starting work on jadaptive ssh client
This commit is contained in:
parent
0f0f6bfa09
commit
f39c974e74
9 changed files with 625 additions and 0 deletions
5
files-sftp-jadaptive-fs/build.gradle
Normal file
5
files-sftp-jadaptive-fs/build.gradle
Normal file
|
@ -0,0 +1,5 @@
|
|||
dependencies {
|
||||
api project(':files-api')
|
||||
api libs.maverick.synergy.client
|
||||
testImplementation libs.net.security
|
||||
}
|
3
files-sftp-jadaptive-fs/src/main/java/module-info.java
Normal file
3
files-sftp-jadaptive-fs/src/main/java/module-info.java
Normal file
|
@ -0,0 +1,3 @@
|
|||
module org.xbib.files.sftp.jadaptive.fs {
|
||||
requires org.xbib.files;
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package org.xbib.files.sftp.jadaptive.fs;
|
||||
|
||||
import java.io.IOException;
|
||||
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.Set;
|
||||
|
||||
public class SftpFileSystem extends FileSystem {
|
||||
|
||||
@Override
|
||||
public FileSystemProvider provider() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSeparator() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Path> getRootDirectories() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<FileStore> getFileStores() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> supportedFileAttributeViews() {
|
||||
return Set.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPath(String s, String... strings) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathMatcher getPathMatcher(String s) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserPrincipalLookupService getUserPrincipalLookupService() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WatchService newWatchService() throws IOException {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
package org.xbib.files.sftp.jadaptive.fs;
|
||||
|
||||
public class SftpFileSystemProvider {
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package org.xbib.files.sftp.jadaptive.fs.spi;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
|
||||
import org.xbib.files.sftp.jadaptive.fs.SftpFileSystem;
|
||||
import org.xbib.files.sftp.jadaptive.fs.SftpFileSystemProvider;
|
||||
|
||||
public class SFTPContext implements Closeable {
|
||||
|
||||
final SftpFileSystemProvider provider;
|
||||
|
||||
final SftpFileSystem fileSystem;
|
||||
|
||||
public SFTPContext(URI uri, Map<String, ?> env) throws IOException {
|
||||
this.sshClient = ClientBuilder.builder().build();
|
||||
Object object = env.get("workers");
|
||||
if (object instanceof Integer) {
|
||||
sshClient.setNioWorkers((Integer) object);
|
||||
} else if (object instanceof String) {
|
||||
sshClient.setNioWorkers(Integer.parseInt((String) object));
|
||||
} else {
|
||||
// we do not require a vast pool of threads
|
||||
sshClient.setNioWorkers(1);
|
||||
}
|
||||
sshClient.start();
|
||||
this.provider = new SftpFileSystemProvider(sshClient);
|
||||
this.fileSystem = provider.newFileSystem(uri, env);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
sshClient.stop();
|
||||
sshClient.close();
|
||||
fileSystem.close();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,476 @@
|
|||
package org.xbib.files.sftp.jadaptive.fs.spi;
|
||||
|
||||
import org.xbib.files.FileService;
|
||||
import org.xbib.files.FileWalker;
|
||||
import org.xbib.files.WrappedDirectoryStream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
import java.nio.file.CopyOption;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.FileVisitOption;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.LinkOption;
|
||||
import java.nio.file.OpenOption;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.nio.file.attribute.FileAttribute;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.nio.file.attribute.PosixFileAttributeView;
|
||||
import java.nio.file.attribute.PosixFileAttributes;
|
||||
import java.nio.file.attribute.PosixFilePermission;
|
||||
import java.nio.file.attribute.PosixFilePermissions;
|
||||
import java.time.Instant;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class SFTPFileService implements FileService {
|
||||
|
||||
private static final int BUFFER_SIZE = 128 * 1024;
|
||||
|
||||
private static final Set<PosixFilePermission> DEFAULT_DIR_PERMISSIONS =
|
||||
PosixFilePermissions.fromString("rwxr-xr-x");
|
||||
|
||||
private static final Set<PosixFilePermission> DEFAULT_FILE_PERMISSIONS =
|
||||
PosixFilePermissions.fromString("rw-r--r--");
|
||||
|
||||
private final URI uri;
|
||||
|
||||
private final Map<String, ?> env;
|
||||
|
||||
public SFTPFileService(URI uri, Map<String, ?> env) {
|
||||
this.uri = uri;
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean exists(String path) throws IOException {
|
||||
return performWithContext(ctx -> Files.exists(ctx.fileSystem.getPath(path)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isExecutable(String path) throws IOException {
|
||||
return performWithContext(ctx -> Files.isExecutable(ctx.fileSystem.getPath(path)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isDirectory(String path) throws IOException {
|
||||
return performWithContext(ctx -> Files.isDirectory(ctx.fileSystem.getPath(path)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isRegularFile(String path) throws IOException {
|
||||
return performWithContext(ctx -> Files.isRegularFile(ctx.fileSystem.getPath(path)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isHidden(String path) throws IOException {
|
||||
return performWithContext(ctx -> Files.isHidden(ctx.fileSystem.getPath(path)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isSameFile(String path1, String path2) throws IOException {
|
||||
return performWithContext(ctx -> Files.isSameFile(ctx.fileSystem.getPath(path1), ctx.fileSystem.getPath(path2)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isSymbolicLink(String path) throws IOException {
|
||||
return performWithContext(ctx -> Files.isSymbolicLink(ctx.fileSystem.getPath(path)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isReadable(String path) throws IOException {
|
||||
return performWithContext(ctx -> Files.isReadable(ctx.fileSystem.getPath(path)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isWritable(String path) throws IOException {
|
||||
return performWithContext(ctx -> Files.isWritable(ctx.fileSystem.getPath(path)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createFile(String path, FileAttribute<?>... attributes) throws IOException {
|
||||
performWithContext(ctx -> Files.createFile(ctx.fileSystem.getPath(path), attributes));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createDirectory(String path, FileAttribute<?>... attributes) throws IOException {
|
||||
performWithContext(ctx -> Files.createDirectory(ctx.fileSystem.getPath(path), attributes));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createDirectories(String path, FileAttribute<?>... attributes) throws IOException {
|
||||
performWithContext(ctx -> Files.createDirectories(ctx.fileSystem.getPath(path), attributes));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String path, String attribute, Object value) throws IOException {
|
||||
performWithContext(ctx -> Files.setAttribute(ctx.fileSystem.getPath(path), attribute, value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(String path, String attribute) throws IOException {
|
||||
return performWithContext(ctx -> Files.getAttribute(ctx.fileSystem.getPath(path), attribute));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPermissions(String path, Set<PosixFilePermission> permissions) throws IOException {
|
||||
performWithContext(ctx -> Files.setPosixFilePermissions(ctx.fileSystem.getPath(path), permissions));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<PosixFilePermission> getPermissions(String path) throws IOException {
|
||||
return performWithContext(ctx -> Files.getPosixFilePermissions(ctx.fileSystem.getPath(path)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastModifiedTime(String path, Instant lastModified) throws IOException {
|
||||
performWithContext(ctx -> Files.setLastModifiedTime(ctx.fileSystem.getPath(path), FileTime.from(lastModified)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant getLastModifiedTime(String path) throws IOException{
|
||||
return performWithContext(ctx -> Files.getLastModifiedTime(ctx.fileSystem.getPath(path)).toInstant());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPosixFileAttributes(String path,
|
||||
String owner,
|
||||
String group,
|
||||
Instant lastModifiedTime,
|
||||
Instant lastAccessTime,
|
||||
Instant createTime) throws IOException {
|
||||
performWithContext(ctx -> {
|
||||
PosixFileAttributeView view = Files.getFileAttributeView(ctx.fileSystem.getPath(path),
|
||||
PosixFileAttributeView.class, LinkOption.NOFOLLOW_LINKS);
|
||||
view.setOwner(ctx.fileSystem.getUserPrincipalLookupService().lookupPrincipalByName(owner));
|
||||
view.setGroup(ctx.fileSystem.getUserPrincipalLookupService().lookupPrincipalByGroupName(group));
|
||||
view.setTimes(FileTime.from(lastModifiedTime),
|
||||
FileTime.from(lastAccessTime),
|
||||
FileTime.from(createTime));
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public PosixFileAttributes getPosixFileAttributes(String path) throws IOException {
|
||||
return performWithContext(ctx -> Files.getFileAttributeView(ctx.fileSystem.getPath(path),
|
||||
PosixFileAttributeView.class, LinkOption.NOFOLLOW_LINKS).readAttributes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOwner(String path, String owner) throws IOException {
|
||||
performWithContext(ctx -> Files.setOwner(ctx.fileSystem.getPath(path),
|
||||
ctx.fileSystem.getUserPrincipalLookupService().lookupPrincipalByName(owner)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOwner(String path) throws IOException {
|
||||
return performWithContext(ctx -> Files.getOwner(ctx.fileSystem.getPath(path)).getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroup(String path, String group) throws IOException {
|
||||
performWithContext(ctx -> {
|
||||
PosixFileAttributeView view = Files.getFileAttributeView(ctx.fileSystem.getPath(path),
|
||||
PosixFileAttributeView.class, LinkOption.NOFOLLOW_LINKS);
|
||||
view.setGroup(ctx.fileSystem.getUserPrincipalLookupService().lookupPrincipalByGroupName(group));
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroup(String path) throws IOException {
|
||||
return performWithContext(ctx -> Files.getFileAttributeView(ctx.fileSystem.getPath(path),
|
||||
PosixFileAttributeView.class, LinkOption.NOFOLLOW_LINKS).readAttributes().group().getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upload(Path source,
|
||||
String target,
|
||||
CopyOption... copyOptions) throws IOException {
|
||||
upload(source, target, DEFAULT_DIR_PERMISSIONS, DEFAULT_FILE_PERMISSIONS, copyOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upload(Path source,
|
||||
String target,
|
||||
Set<PosixFilePermission> dirPermissions,
|
||||
Set<PosixFilePermission> filePermissions,
|
||||
CopyOption... copyOptions) throws IOException {
|
||||
performWithContext(ctx -> {
|
||||
doUpload(ctx, Files.newByteChannel(source), ctx.fileSystem.getPath(target),
|
||||
dirPermissions, filePermissions, copyOptions);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upload(Path source,
|
||||
Path target,
|
||||
CopyOption... copyOptions) throws IOException {
|
||||
upload(source, target, DEFAULT_DIR_PERMISSIONS, DEFAULT_FILE_PERMISSIONS, copyOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upload(Path source,
|
||||
Path target,
|
||||
Set<PosixFilePermission> dirPermissions,
|
||||
Set<PosixFilePermission> filePermissions,
|
||||
CopyOption... copyOptions) throws IOException {
|
||||
performWithContext(ctx -> {
|
||||
doUpload(ctx, Files.newByteChannel(source), target, dirPermissions, filePermissions, copyOptions);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upload(InputStream source,
|
||||
String target,
|
||||
CopyOption... copyOptions) throws IOException {
|
||||
upload(source, target, DEFAULT_DIR_PERMISSIONS, DEFAULT_FILE_PERMISSIONS, copyOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upload(InputStream source,
|
||||
Path target,
|
||||
CopyOption... copyOptions) throws IOException {
|
||||
upload(source, target, DEFAULT_DIR_PERMISSIONS, DEFAULT_FILE_PERMISSIONS, copyOptions);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void download(Path source,
|
||||
Path target,
|
||||
CopyOption... copyOptions) throws IOException {
|
||||
performWithContext(ctx -> {
|
||||
download(ctx, source, target, copyOptions);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(String source,
|
||||
Path target,
|
||||
CopyOption... copyOptions) throws IOException {
|
||||
performWithContext(ctx -> {
|
||||
download(ctx, ctx.fileSystem.getPath(source), target, copyOptions);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(Path source,
|
||||
OutputStream target) throws IOException {
|
||||
performWithContext(ctx -> {
|
||||
download(ctx, source, target);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(String source,
|
||||
OutputStream target) throws IOException {
|
||||
performWithContext(ctx -> {
|
||||
download(ctx, ctx.fileSystem.getPath(source), target);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copy(String source, String target, CopyOption... copyOptions) throws IOException {
|
||||
performWithContext(ctx -> Files.copy(ctx.fileSystem.getPath(source), ctx.fileSystem.getPath(target), copyOptions));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rename(String source, String target, CopyOption... copyOptions) throws IOException {
|
||||
performWithContext(ctx -> Files.move(ctx.fileSystem.getPath(source), ctx.fileSystem.getPath(target), copyOptions));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(String source) throws IOException {
|
||||
performWithContext(ctx -> Files.deleteIfExists(ctx.fileSystem.getPath(source)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DirectoryStream<Path> stream(String path, String glob) throws IOException {
|
||||
SFTPContext ctx = new SFTPContext(uri, env);
|
||||
return new WrappedDirectoryStream<>(ctx, Files.newDirectoryStream(ctx.fileSystem.getPath(path), glob));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DirectoryStream<Path> stream(String path, DirectoryStream.Filter<Path> filter) throws IOException {
|
||||
SFTPContext ctx = new SFTPContext(uri, env);
|
||||
return new WrappedDirectoryStream<>(ctx, Files.newDirectoryStream(ctx.fileSystem.getPath(path), filter));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<Path> list(String path) throws IOException {
|
||||
SFTPContext ctx = new SFTPContext(uri, env);
|
||||
return FileWalker.list(new WrappedDirectoryStream<>(ctx, Files.newDirectoryStream(ctx.fileSystem.getPath(path))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<Path> walk(String path, FileVisitOption... options) throws IOException {
|
||||
SFTPContext ctx = new SFTPContext(uri, env);
|
||||
return FileWalker.walk(ctx, ctx.fileSystem.getPath(path), Integer.MAX_VALUE, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<Path> walk(String path, int maxdepth, FileVisitOption... options) throws IOException {
|
||||
SFTPContext ctx = new SFTPContext(uri, env);
|
||||
return FileWalker.walk(ctx, ctx.fileSystem.getPath(path), maxdepth, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upload(InputStream source,
|
||||
Path target,
|
||||
Set<PosixFilePermission> dirPermissions,
|
||||
Set<PosixFilePermission> filePermissions,
|
||||
CopyOption... copyOptions) throws IOException {
|
||||
performWithContext(ctx -> {
|
||||
doUpload(ctx, Channels.newChannel(source), target,
|
||||
dirPermissions, filePermissions, copyOptions);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upload(InputStream source,
|
||||
String target,
|
||||
Set<PosixFilePermission> dirPermissions,
|
||||
Set<PosixFilePermission> filePermissions,
|
||||
CopyOption... copyOptions) throws IOException {
|
||||
performWithContext(ctx -> {
|
||||
doUpload(ctx, Channels.newChannel(source), ctx.fileSystem.getPath(target),
|
||||
dirPermissions, filePermissions, copyOptions);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private void doUpload(SFTPContext ctx,
|
||||
ReadableByteChannel source,
|
||||
Path target,
|
||||
Set<PosixFilePermission> dirPerms,
|
||||
Set<PosixFilePermission> filePerms,
|
||||
CopyOption... copyOptions) throws IOException {
|
||||
prepareForWrite(target, dirPerms, filePerms);
|
||||
transfer(source, ctx.provider.newByteChannel(target, prepareWriteOptions(copyOptions)));
|
||||
}
|
||||
|
||||
private void download(SFTPContext ctx,
|
||||
Path source,
|
||||
OutputStream outputStream) throws IOException {
|
||||
download(ctx, source, Channels.newChannel(outputStream));
|
||||
}
|
||||
|
||||
private void download(SFTPContext ctx,
|
||||
Path source,
|
||||
WritableByteChannel writableByteChannel) throws IOException {
|
||||
transfer(ctx.provider.newByteChannel(source, prepareReadOptions()), writableByteChannel);
|
||||
}
|
||||
|
||||
private void download(SFTPContext ctx,
|
||||
Path source,
|
||||
Path target,
|
||||
CopyOption... copyOptions) throws IOException {
|
||||
prepareForRead(target);
|
||||
transfer(ctx.provider.newByteChannel(source, prepareReadOptions(copyOptions)),
|
||||
Files.newByteChannel(target, prepareWriteOptions(copyOptions)));
|
||||
}
|
||||
|
||||
private void prepareForRead(Path path) throws IOException {
|
||||
if (path == null) {
|
||||
return;
|
||||
}
|
||||
Path parent = path.getParent();
|
||||
if (parent != null) {
|
||||
if (!Files.exists(parent)) {
|
||||
Files.createDirectories(parent);
|
||||
}
|
||||
}
|
||||
if (!Files.exists(path)) {
|
||||
Files.createFile(path);
|
||||
}
|
||||
}
|
||||
|
||||
private void prepareForWrite(Path path,
|
||||
Set<PosixFilePermission> dirPerms,
|
||||
Set<PosixFilePermission> filePerms) throws IOException {
|
||||
if (path == null) {
|
||||
return;
|
||||
}
|
||||
Path parent = path.getParent();
|
||||
if (parent != null) {
|
||||
if (!Files.exists(parent)) {
|
||||
Files.createDirectories(parent);
|
||||
}
|
||||
PosixFileAttributeView posixFileAttributeView =
|
||||
Files.getFileAttributeView(parent, PosixFileAttributeView.class);
|
||||
posixFileAttributeView.setPermissions(dirPerms);
|
||||
}
|
||||
if (!Files.exists(path)) {
|
||||
Files.createFile(path);
|
||||
}
|
||||
PosixFileAttributeView posixFileAttributeView =
|
||||
Files.getFileAttributeView(path, PosixFileAttributeView.class);
|
||||
posixFileAttributeView.setPermissions(filePerms);
|
||||
}
|
||||
|
||||
private Set<? extends OpenOption> prepareReadOptions(CopyOption... copyOptions) {
|
||||
// ignore user copy options
|
||||
return EnumSet.of(StandardOpenOption.READ);
|
||||
}
|
||||
|
||||
private Set<? extends OpenOption> prepareWriteOptions(CopyOption... copyOptions) {
|
||||
Set<? extends OpenOption> options = null;
|
||||
for (CopyOption copyOption : copyOptions) {
|
||||
if (copyOption == StandardCopyOption.REPLACE_EXISTING) {
|
||||
options = EnumSet.of(StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
}
|
||||
}
|
||||
if (options == null) {
|
||||
// we can not use CREATE_NEW, file is already there because of prepareForWrite() -> Files.createFile()
|
||||
options = EnumSet.of(StandardOpenOption.CREATE, StandardOpenOption.WRITE);
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
private void transfer(ReadableByteChannel readableByteChannel,
|
||||
WritableByteChannel writableByteChannel) throws IOException {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
|
||||
int read;
|
||||
while ((read = readableByteChannel.read(buffer)) > 0) {
|
||||
buffer.flip();
|
||||
while (read > 0) {
|
||||
read -= writableByteChannel.write(buffer);
|
||||
}
|
||||
buffer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T performWithContext(WithContext<T> action) throws IOException {
|
||||
SFTPContext ctx = null;
|
||||
try {
|
||||
if (uri != null) {
|
||||
ctx = new SFTPContext(uri, env);
|
||||
return action.perform(ctx);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} finally {
|
||||
if (ctx != null) {
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package org.xbib.files.sftp.jadaptive.fs.spi;
|
||||
|
||||
import org.xbib.files.FileService;
|
||||
import org.xbib.files.FileServiceProvider;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
|
||||
public class SFTPFileServiceProvider implements FileServiceProvider {
|
||||
|
||||
@Override
|
||||
public FileService provide(URI uri, Map<String, ?> env) {
|
||||
return uri.isAbsolute() && uri.getScheme().equals("sftp") ? new SFTPFileService(uri, env) : null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package org.xbib.files.sftp.jadaptive.fs.spi;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
interface WithContext<T> {
|
||||
T perform(SFTPContext ctx) throws IOException;
|
||||
}
|
|
@ -18,6 +18,7 @@ dependencyResolutionManagement {
|
|||
version('gradle', '8.7')
|
||||
version('net', '4.4.0')
|
||||
library('net-security', 'org.xbib', 'net-security').versionRef('net')
|
||||
library('maverick-synergy-client', 'com.sshtools', 'maverick-synergy-client').version('3.1.1')
|
||||
}
|
||||
testLibs {
|
||||
version('junit', '5.10.2')
|
||||
|
@ -41,5 +42,6 @@ include 'files-ftp-fs'
|
|||
include 'files-ftp-mock'
|
||||
include 'files-sftp'
|
||||
include 'files-sftp-fs'
|
||||
include 'files-sftp-jadaptive-fs'
|
||||
include 'files-webdav'
|
||||
include 'files-webdav-fs'
|
||||
|
|
Loading…
Reference in a new issue