You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2015/07/01 12:57:50 UTC

[09/10] mina-sshd git commit: [SSHD-509] Use targeted derived NamedFactory(ies) for the various generic parameters

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a6e2bf9e/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileChannel.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileChannel.java b/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileChannel.java
deleted file mode 100644
index 0d4f826..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileChannel.java
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.
- */
-package org.apache.sshd.client.sftp;
-
-import static org.apache.sshd.common.sftp.SftpConstants.SSH_FX_LOCK_CONFLICT;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.MappedByteBuffer;
-import java.nio.channels.AsynchronousCloseException;
-import java.nio.channels.ClosedChannelException;
-import java.nio.channels.FileChannel;
-import java.nio.channels.FileLock;
-import java.nio.channels.OverlappingFileLockException;
-import java.nio.channels.ReadableByteChannel;
-import java.nio.channels.WritableByteChannel;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.apache.sshd.client.SftpException;
-import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.ValidateUtils;
-
-public class SftpFileChannel extends FileChannel {
-
-    private final SftpPath p;
-    private final Collection<SftpClient.OpenMode> modes;
-    private final SftpClient sftp;
-    private final SftpClient.CloseableHandle handle;
-    private final Object lock = new Object();
-    private volatile long pos;
-    private volatile Thread blockingThread;
-
-    public SftpFileChannel(SftpPath p, Collection<SftpClient.OpenMode> modes) throws IOException {
-        this.p = ValidateUtils.checkNotNull(p, "No target path", GenericUtils.EMPTY_OBJECT_ARRAY);
-        this.modes = ValidateUtils.checkNotNull(modes, "No channel modes specified", GenericUtils.EMPTY_OBJECT_ARRAY);
-        
-        SftpFileSystem  fs=p.getFileSystem();
-        sftp = fs.getClient();
-        handle = sftp.open(p.toString(), modes);
-    }
-
-    @Override
-    public int read(ByteBuffer dst) throws IOException {
-        return (int) doRead(Collections.singletonList(dst), -1);
-    }
-
-    @Override
-    public int read(ByteBuffer dst, long position) throws IOException {
-        if (position < 0) {
-            throw new IllegalArgumentException("read(" + p + ") illegal position to read from: " + position);
-        }
-        return (int) doRead(Collections.singletonList(dst), position);
-    }
-
-    @Override
-    public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
-        List<ByteBuffer> buffers = Arrays.asList(dsts).subList(offset, offset + length);
-        return doRead(buffers, -1);
-    }
-
-    public static final Set<SftpClient.OpenMode> READ_MODES=
-            Collections.unmodifiableSet(EnumSet.of(SftpClient.OpenMode.Read));
-
-    protected long doRead(List<ByteBuffer> buffers, long position) throws IOException {
-        ensureOpen(READ_MODES);
-        synchronized (lock) {
-            boolean completed = false;
-            boolean eof = false;
-            long curPos = position >= 0 ? position : pos;
-            try {
-                long totalRead = 0;
-                beginBlocking();
-                loop:
-                for (ByteBuffer buffer : buffers) {
-                    while (buffer.remaining() > 0) {
-                        ByteBuffer wrap = buffer;
-                        if (!buffer.hasArray()) {
-                            wrap = ByteBuffer.allocate(Math.min(8192, buffer.remaining()));
-                        }
-                        int read = sftp.read(handle, curPos, wrap.array(), wrap.arrayOffset() + wrap.position(), wrap.remaining());
-                        if (read > 0) {
-                            if (wrap == buffer) {
-                                wrap.position(wrap.position() + read);
-                            } else {
-                                buffer.put(wrap.array(), wrap.arrayOffset(), read);
-                            }
-                            curPos += read;
-                            totalRead += read;
-                        } else {
-                            eof = read == -1;
-                            break loop;
-                        }
-                    }
-                }
-                completed = true;
-                return totalRead > 0 ? totalRead : eof ? -1 : 0;
-            } finally {
-                if (position < 0) {
-                    pos = curPos;
-                }
-                endBlocking(completed);
-            }
-        }
-    }
-
-    @Override
-    public int write(ByteBuffer src) throws IOException {
-        return (int) doWrite(Collections.singletonList(src), -1);
-    }
-
-    @Override
-    public int write(ByteBuffer src, long position) throws IOException {
-        if (position < 0) {
-            throw new IllegalArgumentException("write(" + p + ") illegal position to write to: " + position);
-        }
-        return (int) doWrite(Collections.singletonList(src), position);
-    }
-
-    @Override
-    public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {
-        List<ByteBuffer> buffers = Arrays.asList(srcs).subList(offset, offset + length);
-        return doWrite(buffers, -1);
-    }
-
-    public static final Set<SftpClient.OpenMode> WRITE_MODES=
-            Collections.unmodifiableSet(
-                EnumSet.of(SftpClient.OpenMode.Write, SftpClient.OpenMode.Append, SftpClient.OpenMode.Create, SftpClient.OpenMode.Truncate));
-
-    protected long doWrite(List<ByteBuffer> buffers, long position) throws IOException {
-        ensureOpen(WRITE_MODES);
-        synchronized (lock) {
-            boolean completed = false;
-            long curPos = position >= 0 ? position : pos;
-            try {
-                long totalWritten = 0;
-                beginBlocking();
-                for (ByteBuffer buffer : buffers) {
-                    while (buffer.remaining() > 0) {
-                        ByteBuffer wrap = buffer;
-                        if (!buffer.hasArray()) {
-                            wrap = ByteBuffer.allocate(Math.min(8192, buffer.remaining()));
-                            buffer.get(wrap.array(), wrap.arrayOffset(), wrap.remaining());
-                        }
-                        int written = wrap.remaining();
-                        sftp.write(handle, curPos, wrap.array(), wrap.arrayOffset() + wrap.position(), written);
-                        if (wrap == buffer) {
-                            wrap.position(wrap.position() + written);
-                        }
-                        curPos += written;
-                        totalWritten += written;
-                    }
-                }
-                completed = true;
-                return totalWritten;
-            } finally {
-                if (position < 0) {
-                    pos = curPos;
-                }
-                endBlocking(completed);
-            }
-        }
-    }
-
-    @Override
-    public long position() throws IOException {
-        ensureOpen(Collections.<SftpClient.OpenMode>emptySet());
-        return pos;
-    }
-
-    @Override
-    public FileChannel position(long newPosition) throws IOException {
-        if (newPosition < 0) {
-            throw new IllegalArgumentException("position(" + p + ") illegal file channel position: " + newPosition);
-        }
-
-        ensureOpen(Collections.<SftpClient.OpenMode>emptySet());
-        synchronized (lock) {
-            pos = newPosition;
-            return this;
-        }
-    }
-
-    @Override
-    public long size() throws IOException {
-        ensureOpen(Collections.<SftpClient.OpenMode>emptySet());
-        return sftp.stat(handle).size;
-    }
-
-    @Override
-    public FileChannel truncate(long size) throws IOException {
-        ensureOpen(Collections.<SftpClient.OpenMode>emptySet());
-        sftp.setStat(handle, new SftpClient.Attributes().size(size));
-        return this;
-    }
-
-    @Override
-    public void force(boolean metaData) throws IOException {
-        ensureOpen(Collections.<SftpClient.OpenMode>emptySet());
-    }
-
-    @Override
-    public long transferTo(long position, long count, WritableByteChannel target) throws IOException {
-        if ((position < 0) || (count < 0)) {
-            throw new IllegalArgumentException("transferTo(" + p + ") illegal position (" + position + ") or count (" + count + ")");
-        }
-        ensureOpen(READ_MODES);
-        synchronized (lock) {
-            boolean completed = false;
-            boolean eof = false;
-            long curPos = position;
-            try {
-                beginBlocking();
-
-                int bufSize = (int) Math.min(count, 32768);
-                byte[] buffer = new byte[bufSize];
-                long totalRead = 0L;
-                while (totalRead < count) {
-                    int read = sftp.read(handle, curPos, buffer, 0, buffer.length);
-                    if (read > 0) {
-                        ByteBuffer wrap = ByteBuffer.wrap(buffer);
-                        while (wrap.remaining() > 0) {
-                            target.write(wrap);
-                        }
-                        curPos += read;
-                        totalRead += read;
-                    } else {
-                        eof = read == -1;
-                    }
-                }
-                completed = true;
-                return totalRead > 0 ? totalRead : eof ? -1 : 0;
-            } finally {
-                endBlocking(completed);
-            }
-        }
-    }
-
-    @Override
-    public long transferFrom(ReadableByteChannel src, long position, long count) throws IOException {
-        if ((position < 0) || (count < 0)) {
-            throw new IllegalArgumentException("transferFrom(" + p + ") illegal position (" + position + ") or count (" + count + ")");
-        }
-        ensureOpen(WRITE_MODES);
-
-        synchronized(lock) {
-            boolean completed = false;
-            long curPos = position >= 0 ? position : pos;
-            try {
-                long totalRead = 0;
-                beginBlocking();
-
-                byte[] buffer = new byte[32768];
-                while (totalRead < count) {
-                    ByteBuffer wrap = ByteBuffer.wrap(buffer, 0, (int) Math.min(buffer.length, count - totalRead));
-                    int read = src.read(wrap);
-                    if (read > 0) {
-                        sftp.write(handle, curPos, buffer, 0, read);
-                        curPos += read;
-                        totalRead += read;
-                    } else {
-                        break;
-                    }
-                }
-                completed = true;
-                return totalRead;
-            } finally {
-                endBlocking(completed);
-            }
-        }
-    }
-
-    @Override
-    public MappedByteBuffer map(MapMode mode, long position, long size) throws IOException {
-        throw new UnsupportedOperationException("map(" + p + ")[" + mode + "," + position + "," + size + "] N/A");
-    }
-
-    @Override
-    public FileLock lock(long position, long size, boolean shared) throws IOException {
-        return tryLock(position, size, shared);
-    }
-
-    @Override
-    public FileLock tryLock(final long position, final long size, boolean shared) throws IOException {
-        ensureOpen(Collections.<SftpClient.OpenMode>emptySet());
-
-        try {
-            sftp.lock(handle, position, size, 0);
-        } catch (SftpException e) {
-            if (e.getStatus() == SSH_FX_LOCK_CONFLICT) {
-                throw new OverlappingFileLockException();
-            }
-            throw e;
-        }
-
-        return new FileLock(this, position, size, shared) {
-            private final AtomicBoolean valid = new AtomicBoolean(true);
-
-            @Override
-            public boolean isValid() {
-                return acquiredBy().isOpen() && valid.get();
-            }
-
-            @SuppressWarnings("synthetic-access")
-            @Override
-            public void release() throws IOException {
-                if (valid.compareAndSet(true, false)) {
-                    sftp.unlock(handle, position, size);
-                }
-            }
-        };
-    }
-
-    @Override
-    protected void implCloseChannel() throws IOException {
-        try {
-            final Thread thread = blockingThread;
-            if (thread != null) {
-                thread.interrupt();
-            }
-        } finally {
-            try {
-                handle.close();
-            } finally {
-                sftp.close();
-            }
-        }
-    }
-
-    private void beginBlocking() {
-        begin();
-        blockingThread = Thread.currentThread();
-    }
-
-    private void endBlocking(boolean completed) throws AsynchronousCloseException {
-        blockingThread = null;
-        end(completed);
-    }
-
-    /**
-     * Checks that the channel is open and that its current mode contains
-     * at least one of the required ones
-     * @param reqModes The required modes - ignored if {@code null}/empty
-     * @throws IOException If channel not open or the required modes are not
-     * satisfied
-     */
-    private void ensureOpen(Collection<SftpClient.OpenMode> reqModes) throws IOException {
-        if (!isOpen()) {
-            throw new ClosedChannelException();
-        }
-        
-        if (GenericUtils.size(reqModes) > 0) {
-            for (SftpClient.OpenMode m : reqModes) {
-                if (this.modes.contains(m)) {
-                    return;
-                }
-            }
-            
-            throw new IOException("ensureOpen(" + p + ") current channel modes (" + this.modes + ") do contain any of the required: " + reqModes);
-        }
-    }
-
-    @Override
-    public String toString() {
-        return Objects.toString(p);
-    }
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a6e2bf9e/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystem.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystem.java b/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystem.java
deleted file mode 100644
index 026d13c..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystem.java
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.
- */
-package org.apache.sshd.client.sftp;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.file.attribute.GroupPrincipal;
-import java.nio.file.attribute.UserPrincipal;
-import java.nio.file.attribute.UserPrincipalLookupService;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Queue;
-import java.util.Set;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.sshd.client.session.ClientSession;
-import org.apache.sshd.common.file.util.BaseFileSystem;
-import org.apache.sshd.common.file.util.ImmutableList;
-
-public class SftpFileSystem extends BaseFileSystem<SftpPath> {
-
-    private final ClientSession session;
-    private final Queue<SftpClient> pool;
-    private final ThreadLocal<Wrapper> wrappers = new ThreadLocal<>();
-    private SftpPath defaultDir;
-    private int readBufferSize = SftpClient.DEFAULT_READ_BUFFER_SIZE;
-    private int writeBufferSize = SftpClient.DEFAULT_WRITE_BUFFER_SIZE;
-
-    public SftpFileSystem(SftpFileSystemProvider provider, ClientSession session) throws IOException {
-        super(provider);
-        this.session = session;
-        this.pool = new LinkedBlockingQueue<>(8);
-        try (SftpClient client = getClient()) {
-            defaultDir = getPath(client.canonicalPath("."));
-        }
-    }
-
-    public int getReadBufferSize() {
-        return readBufferSize;
-    }
-
-    public void setReadBufferSize(int size) {
-        if (size < SftpClient.MIN_READ_BUFFER_SIZE) {
-            throw new IllegalArgumentException("Insufficient read buffer size: " + size + ", min.=" + SftpClient.MIN_READ_BUFFER_SIZE);
-        }
-
-        readBufferSize = size;
-    }
-
-    public int getWriteBufferSize() {
-        return writeBufferSize;
-    }
-
-    public void setWriteBufferSize(int size) {
-        if (size < SftpClient.MIN_WRITE_BUFFER_SIZE) {
-            throw new IllegalArgumentException("Insufficient write buffer size: " + size + ", min.=" + SftpClient.MIN_WRITE_BUFFER_SIZE);
-        }
-
-        writeBufferSize = size;
-    }
-
-    @Override
-    protected SftpPath create(String root, ImmutableList<String> names) {
-        return new SftpPath(this, root, names);
-    }
-
-    public ClientSession getSession() {
-        return session;
-    }
-
-    @SuppressWarnings("synthetic-access")
-    public SftpClient getClient() throws IOException {
-        Wrapper wrapper = wrappers.get();
-        if (wrapper == null) {
-            while (wrapper == null) {
-                SftpClient client = pool.poll();
-                if (client == null) {
-                    client = session.createSftpClient();
-                }
-                if (!client.isClosing()) {
-                    wrapper = new Wrapper(client, getReadBufferSize(), getWriteBufferSize());
-                }
-            }
-            wrappers.set(wrapper);
-        } else {
-            wrapper.increment();
-        }
-        return wrapper;
-    }
-
-    @Override
-    public void close() throws IOException {
-        if (isOpen()) {
-            session.close(true);
-        }
-    }
-
-    @Override
-    public boolean isOpen() {
-        return !session.isClosing();
-    }
-
-    @Override
-    public Set<String> supportedFileAttributeViews() {
-        Set<String> set = new HashSet<>();
-        set.addAll(Arrays.asList("basic", "posix", "owner"));
-        return Collections.unmodifiableSet(set);
-    }
-
-    @Override
-    public UserPrincipalLookupService getUserPrincipalLookupService() {
-        return new DefaultUserPrincipalLookupService();
-    }
-
-    @Override
-    public SftpPath getDefaultDir() {
-        return defaultDir;
-    }
-
-    private class Wrapper extends AbstractSftpClient {
-
-        private final SftpClient delegate;
-        private final AtomicInteger count = new AtomicInteger(1);
-        private final int readSize, writeSize;
-
-        private Wrapper(SftpClient delegate, int readSize, int writeSize) {
-            this.delegate = delegate;
-            this.readSize = readSize;
-            this.writeSize = writeSize;
-        }
-
-        @Override
-        public int getVersion() {
-            return delegate.getVersion();
-        }
-
-        @Override
-        public boolean isClosing() {
-            return false;
-        }
-
-        @SuppressWarnings("synthetic-access")
-        @Override
-        public void close() throws IOException {
-            if (count.decrementAndGet() == 0) {
-                if (!pool.offer(delegate)) {
-                    delegate.close();
-                }
-                wrappers.set(null);
-            }
-        }
-
-        public void increment() {
-            count.incrementAndGet();
-        }
-
-        @Override
-        public CloseableHandle open(String path, Collection<OpenMode> options) throws IOException {
-            return delegate.open(path, options);
-        }
-
-        @Override
-        public void close(Handle handle) throws IOException {
-            delegate.close(handle);
-        }
-
-        @Override
-        public void remove(String path) throws IOException {
-            delegate.remove(path);
-        }
-
-        @Override
-        public void rename(String oldPath, String newPath, Collection<CopyMode> options) throws IOException {
-            delegate.rename(oldPath, newPath, options);
-        }
-
-        @Override
-        public int read(Handle handle, long fileOffset, byte[] dst, int dstoff, int len) throws IOException {
-            return delegate.read(handle, fileOffset, dst, dstoff, len);
-        }
-
-        @Override
-        public void write(Handle handle, long fileOffset, byte[] src, int srcoff, int len) throws IOException {
-            delegate.write(handle, fileOffset, src, srcoff, len);
-        }
-
-        @Override
-        public void mkdir(String path) throws IOException {
-            delegate.mkdir(path);
-        }
-
-        @Override
-        public void rmdir(String path) throws IOException {
-            delegate.rmdir(path);
-        }
-
-        @Override
-        public CloseableHandle openDir(String path) throws IOException {
-            return delegate.openDir(path);
-        }
-
-        @Override
-        public DirEntry[] readDir(Handle handle) throws IOException {
-            return delegate.readDir(handle);
-        }
-
-        @Override
-        public String canonicalPath(String canonical) throws IOException {
-            return delegate.canonicalPath(canonical);
-        }
-
-        @Override
-        public Attributes stat(String path) throws IOException {
-            return delegate.stat(path);
-        }
-
-        @Override
-        public Attributes lstat(String path) throws IOException {
-            return delegate.lstat(path);
-        }
-
-        @Override
-        public Attributes stat(Handle handle) throws IOException {
-            return delegate.stat(handle);
-        }
-
-        @Override
-        public void setStat(String path, Attributes attributes) throws IOException {
-            delegate.setStat(path, attributes);
-        }
-
-        @Override
-        public void setStat(Handle handle, Attributes attributes) throws IOException {
-            delegate.setStat(handle, attributes);
-        }
-
-        @Override
-        public String readLink(String path) throws IOException {
-            return delegate.readLink(path);
-        }
-
-        @Override
-        public void symLink(String linkPath, String targetPath) throws IOException {
-            delegate.symLink(linkPath, targetPath);
-        }
-
-        @Override
-        public Iterable<DirEntry> readDir(String path) throws IOException {
-            return delegate.readDir(path);
-        }
-
-        @Override
-        public InputStream read(String path) throws IOException {
-            return read(path, readSize);
-        }
-
-        @Override
-        public InputStream read(String path, OpenMode... mode) throws IOException {
-            return read(path, readSize, mode);
-        }
-
-        @Override
-        public InputStream read(String path, Collection<OpenMode> mode) throws IOException {
-            return read(path, readSize, mode);
-        }
-
-        @Override
-        public InputStream read(String path, int bufferSize, Collection<OpenMode> mode) throws IOException {
-            return delegate.read(path, bufferSize, mode);
-        }
-
-        @Override
-        public OutputStream write(String path) throws IOException {
-            return write(path, writeSize);
-        }
-
-        @Override
-        public OutputStream write(String path, OpenMode... mode) throws IOException {
-            return write(path, writeSize, mode);
-        }
-
-        @Override
-        public OutputStream write(String path, Collection<OpenMode> mode) throws IOException {
-            return write(path, writeSize, mode);
-        }
-
-        @Override
-        public OutputStream write(String path, int bufferSize, Collection<OpenMode> mode) throws IOException {
-            return delegate.write(path, bufferSize, mode);
-        }
-
-        @Override
-        public void link(String linkPath, String targetPath, boolean symbolic) throws IOException {
-            delegate.link(linkPath, targetPath, symbolic);
-        }
-
-        @Override
-        public void lock(Handle handle, long offset, long length, int mask) throws IOException {
-            delegate.lock(handle, offset, length, mask);
-        }
-
-        @Override
-        public void unlock(Handle handle, long offset, long length) throws IOException {
-            delegate.unlock(handle, offset, length);
-        }
-    }
-
-    protected static class DefaultUserPrincipalLookupService extends UserPrincipalLookupService {
-
-        @Override
-        public UserPrincipal lookupPrincipalByName(String name) throws IOException {
-            return new DefaultUserPrincipal(name);
-        }
-
-        @Override
-        public GroupPrincipal lookupPrincipalByGroupName(String group) throws IOException {
-            return new DefaultGroupPrincipal(group);
-        }
-    }
-
-    protected static class DefaultUserPrincipal implements UserPrincipal {
-
-        private final String name;
-
-        public DefaultUserPrincipal(String name) {
-            if (name == null) {
-                throw new IllegalArgumentException("name is null");
-            }
-            this.name = name;
-        }
-
-        @Override
-        public String getName() {
-            return name;
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
-            DefaultUserPrincipal that = (DefaultUserPrincipal) o;
-            return name.equals(that.name);
-        }
-
-        @Override
-        public int hashCode() {
-            return name.hashCode();
-        }
-
-        @Override
-        public String toString() {
-            return name;
-        }
-    }
-
-    protected static class DefaultGroupPrincipal extends DefaultUserPrincipal implements GroupPrincipal {
-
-        public DefaultGroupPrincipal(String name) {
-            super(name);
-        }
-
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a6e2bf9e/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystemProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystemProvider.java b/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystemProvider.java
deleted file mode 100644
index 2ac72b1..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystemProvider.java
+++ /dev/null
@@ -1,892 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.
- */
-package org.apache.sshd.client.sftp;
-
-import static org.apache.sshd.common.sftp.SftpConstants.SFTP_V3;
-import static org.apache.sshd.common.sftp.SftpConstants.S_IRGRP;
-import static org.apache.sshd.common.sftp.SftpConstants.S_IROTH;
-import static org.apache.sshd.common.sftp.SftpConstants.S_IRUSR;
-import static org.apache.sshd.common.sftp.SftpConstants.S_IWGRP;
-import static org.apache.sshd.common.sftp.SftpConstants.S_IWOTH;
-import static org.apache.sshd.common.sftp.SftpConstants.S_IWUSR;
-import static org.apache.sshd.common.sftp.SftpConstants.S_IXGRP;
-import static org.apache.sshd.common.sftp.SftpConstants.S_IXOTH;
-import static org.apache.sshd.common.sftp.SftpConstants.S_IXUSR;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URI;
-import java.nio.channels.FileChannel;
-import java.nio.channels.SeekableByteChannel;
-import java.nio.file.AccessDeniedException;
-import java.nio.file.AccessMode;
-import java.nio.file.CopyOption;
-import java.nio.file.DirectoryStream;
-import java.nio.file.FileAlreadyExistsException;
-import java.nio.file.FileStore;
-import java.nio.file.FileSystem;
-import java.nio.file.FileSystemAlreadyExistsException;
-import java.nio.file.FileSystemException;
-import java.nio.file.FileSystemNotFoundException;
-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.StandardCopyOption;
-import java.nio.file.StandardOpenOption;
-import java.nio.file.attribute.BasicFileAttributeView;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.nio.file.attribute.FileAttribute;
-import java.nio.file.attribute.FileAttributeView;
-import java.nio.file.attribute.FileTime;
-import java.nio.file.attribute.GroupPrincipal;
-import java.nio.file.attribute.PosixFileAttributeView;
-import java.nio.file.attribute.PosixFileAttributes;
-import java.nio.file.attribute.PosixFilePermission;
-import java.nio.file.attribute.UserPrincipal;
-import java.nio.file.spi.FileSystemProvider;
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.sshd.client.ClientBuilder;
-import org.apache.sshd.client.SftpException;
-import org.apache.sshd.client.SshClient;
-import org.apache.sshd.client.session.ClientSession;
-import org.apache.sshd.client.sftp.SftpClient.Attributes;
-import org.apache.sshd.common.FactoryManagerUtils;
-import org.apache.sshd.common.SshException;
-import org.apache.sshd.common.config.SshConfigFileReader;
-import org.apache.sshd.common.sftp.SftpConstants;
-import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.ValidateUtils;
-import org.apache.sshd.common.util.io.IoUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class SftpFileSystemProvider extends FileSystemProvider {
-    public static final String READ_BUFFER_PROP_NAME = "sftp-fs-read-buffer-size";
-        public static final int DEFAULT_READ_BUFFER_SIZE = SftpClient.DEFAULT_READ_BUFFER_SIZE;
-    public static final String WRITE_BUFFER_PROP_NAME = "sftp-fs-write-buffer-size";
-        public static final int DEFAULT_WRITE_BUFFER_SIZE = SftpClient.DEFAULT_WRITE_BUFFER_SIZE;
-    public static final String CONNECT_TIME_PROP_NAME = "sftp-fs-connect-time";
-        public static final long DEFAULT_CONNECT_TIME = SftpClient.DEFAULT_WAIT_TIMEOUT;
-
-    private final SshClient client;
-    private final Map<String, SftpFileSystem> fileSystems = new HashMap<String, SftpFileSystem>();
-    protected final Logger log;
-
-    public SftpFileSystemProvider() {
-        this(null);
-    }
-
-    public SftpFileSystemProvider(SshClient client) {
-        this.log = LoggerFactory.getLogger(getClass());
-        if (client == null) {
-            // TODO: make this configurable using system properties
-            client = ClientBuilder.builder().build();
-        }
-        this.client = client;
-        this.client.start();
-    }
-
-    @Override
-    public String getScheme() {
-        return SftpConstants.SFTP_SUBSYSTEM_NAME;
-    }
-
-    @Override
-    public FileSystem newFileSystem(URI uri, Map<String, ?> env) throws IOException {
-        synchronized (fileSystems) {
-            String authority = uri.getAuthority();
-            SftpFileSystem fileSystem = fileSystems.get(authority);
-            if (fileSystem != null) {
-                throw new FileSystemAlreadyExistsException(authority);
-            }
-            String host = ValidateUtils.checkNotNullAndNotEmpty(uri.getHost(), "Host not provided", GenericUtils.EMPTY_OBJECT_ARRAY);
-            String userInfo = ValidateUtils.checkNotNullAndNotEmpty(uri.getUserInfo(), "UserInfo not provided", GenericUtils.EMPTY_OBJECT_ARRAY);
-            String[] ui = GenericUtils.split(userInfo, ':');
-            int port = uri.getPort();
-            if (port <= 0) {
-                port = SshConfigFileReader.DEFAULT_PORT;
-            }
-
-            ClientSession session=null;
-            try {
-                session = client.connect(ui[0], host, port)
-                                .verify(FactoryManagerUtils.getLongProperty(env, CONNECT_TIME_PROP_NAME, DEFAULT_CONNECT_TIME))
-                                .getSession()
-                                ;
-                session.addPasswordIdentity(ui[1]);
-                session.auth().verify();
-                fileSystem = new SftpFileSystem(this, session);
-                fileSystem.setReadBufferSize(FactoryManagerUtils.getIntProperty(env, READ_BUFFER_PROP_NAME, DEFAULT_READ_BUFFER_SIZE));
-                fileSystem.setWriteBufferSize(FactoryManagerUtils.getIntProperty(env, WRITE_BUFFER_PROP_NAME, DEFAULT_WRITE_BUFFER_SIZE));
-                fileSystems.put(authority, fileSystem);
-                return fileSystem;
-            } catch(Exception e) {
-                if (session != null) {
-                    try {
-                        session.close();
-                    } catch(IOException t) {
-                        if (log.isDebugEnabled()) {
-                            log.debug("Failed (" + t.getClass().getSimpleName() + ")"
-                                    + " to close session for new file system on " + host + ":" + port
-                                    + " due to " + e.getClass().getSimpleName() + "[" + e.getMessage() + "]"
-                                    + ": " + t.getMessage());
-                        }
-                    }
-                }
-                
-                if (e instanceof IOException) {
-                    throw (IOException) e;
-                } else if (e instanceof RuntimeException) {
-                    throw (RuntimeException) e;
-                } else {
-                    throw new IOException(e);
-                }
-            }
-        }
-    }
-
-    @Override
-    public FileSystem getFileSystem(URI uri) {
-        synchronized (fileSystems) {
-            String authority = uri.getAuthority();
-            SftpFileSystem fileSystem = fileSystems.get(authority);
-            if (fileSystem == null) {
-                throw new FileSystemNotFoundException(authority);
-            }
-            return fileSystem;
-        }
-    }
-
-    @Override
-    public Path getPath(URI uri) {
-        FileSystem fs = getFileSystem(uri);
-        return fs.getPath(uri.getPath());
-    }
-
-    @Override
-    public SeekableByteChannel newByteChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs) throws IOException {
-        return newFileChannel(path, options, attrs);
-    }
-
-    @Override
-    public FileChannel newFileChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs) throws IOException {
-        Collection<SftpClient.OpenMode> modes = EnumSet.noneOf(SftpClient.OpenMode.class);
-        for (OpenOption option : options) {
-            if (option == StandardOpenOption.READ) {
-                modes.add(SftpClient.OpenMode.Read);
-            } else if (option == StandardOpenOption.APPEND) {
-                modes.add(SftpClient.OpenMode.Append);
-            } else if (option == StandardOpenOption.CREATE) {
-                modes.add(SftpClient.OpenMode.Create);
-            } else if (option == StandardOpenOption.TRUNCATE_EXISTING) {
-                modes.add(SftpClient.OpenMode.Truncate);
-            } else if (option == StandardOpenOption.WRITE) {
-                modes.add(SftpClient.OpenMode.Write);
-            } else if (option == StandardOpenOption.CREATE_NEW) {
-                modes.add(SftpClient.OpenMode.Create);
-                modes.add(SftpClient.OpenMode.Exclusive);
-            } else if (option == StandardOpenOption.SPARSE) {
-                /*
-                 * As per the Javadoc:
-                 * 
-                 *      The option is ignored when the file system does not
-                 *  support the creation of sparse files
-                 */
-                continue;
-            } else {
-                throw new IllegalArgumentException("newFileChannel(" + path + ") unsupported open option: " + option);
-            }
-        }
-        if (modes.isEmpty()) {
-            modes.add(SftpClient.OpenMode.Read);
-            modes.add(SftpClient.OpenMode.Write);
-        }
-        // TODO: attrs
-        return new SftpFileChannel(toSftpPath(path), modes);
-    }
-
-    @Override
-    public DirectoryStream<Path> newDirectoryStream(Path dir, DirectoryStream.Filter<? super Path> filter) throws IOException {
-        final SftpPath p = toSftpPath(dir);
-        return new DirectoryStream<Path>() {
-            private final SftpFileSystem fs = p.getFileSystem();
-            private final SftpClient sftp = fs.getClient();
-            private final Iterable<SftpClient.DirEntry> iter = sftp.readDir(p.toString());
-
-            @Override
-            public Iterator<Path> iterator() {
-                return new Iterator<Path>() {
-                    @SuppressWarnings("synthetic-access")
-                    private final Iterator<SftpClient.DirEntry> it = iter.iterator();
-
-                    @Override
-                    public boolean hasNext() {
-                        return it.hasNext();
-                    }
-
-                    @Override
-                    public Path next() {
-                        SftpClient.DirEntry entry = it.next();
-                        return p.resolve(entry.filename);
-                    }
-
-                    @Override
-                    public void remove() {
-                        throw new UnsupportedOperationException("newDirectoryStream(" + p + ") Iterator#remove() N/A");
-                    }
-                };
-            }
-
-            @Override
-            public void close() throws IOException {
-                sftp.close();
-            }
-        };
-    }
-
-    @Override
-    public void createDirectory(Path dir, FileAttribute<?>... attrs) throws IOException {
-        SftpPath p = toSftpPath(dir);
-        SftpFileSystem fs = p.getFileSystem();
-        try (SftpClient sftp = fs.getClient()) {
-            try {
-                sftp.mkdir(dir.toString());
-            } catch (SftpException e) {
-                int sftpStatus=e.getStatus();
-                if ((sftp.getVersion() == SFTP_V3) && (sftpStatus == SftpConstants.SSH_FX_FAILURE)) {
-                    try {
-                        Attributes attributes = sftp.stat(dir.toString());
-                        if (attributes != null) {
-                            throw new FileAlreadyExistsException(p.toString());
-                        }
-                    } catch (SshException e2) {
-                        e.addSuppressed(e2);
-                    }
-                }
-                if (sftpStatus == SftpConstants.SSH_FX_FILE_ALREADY_EXISTS) {
-                    throw new FileAlreadyExistsException(p.toString());
-                }
-                throw e;
-            }
-            for (FileAttribute<?> attr : attrs) {
-                setAttribute(p, attr.name(), attr.value());
-            }
-        }
-    }
-
-    @Override
-    public void delete(Path path) throws IOException {
-        SftpPath p = toSftpPath(path);
-        checkAccess(p, AccessMode.WRITE);
-        
-        SftpFileSystem fs = p.getFileSystem();
-        try (SftpClient sftp = fs.getClient()) {
-            BasicFileAttributes attributes = readAttributes(path, BasicFileAttributes.class);
-            if (attributes.isDirectory()) {
-                sftp.rmdir(path.toString());
-            } else {
-                sftp.remove(path.toString());
-            }
-        }
-    }
-
-    @Override
-    public void copy(Path source, Path target, CopyOption... options) throws IOException {
-        SftpPath src = toSftpPath(source);
-        SftpPath dst = toSftpPath(target);
-        if (src.getFileSystem() != dst.getFileSystem()) {
-            throw new ProviderMismatchException("Mismatched file system providers for " + src + " vs. " + dst);
-        }
-        checkAccess(src);
-
-        boolean replaceExisting = false;
-        boolean copyAttributes = false;
-        boolean noFollowLinks = false;
-        for (CopyOption opt : options) {
-            replaceExisting |= opt == StandardCopyOption.REPLACE_EXISTING;
-            copyAttributes |= opt == StandardCopyOption.COPY_ATTRIBUTES;
-            noFollowLinks |= opt == LinkOption.NOFOLLOW_LINKS;
-        }
-        LinkOption[] linkOptions = IoUtils.getLinkOptions(!noFollowLinks);
-
-        // attributes of source file
-        BasicFileAttributes attrs = readAttributes(source, BasicFileAttributes.class, linkOptions);
-        if (attrs.isSymbolicLink())
-            throw new IOException("Copying of symbolic links not supported");
-
-        // delete target if it exists and REPLACE_EXISTING is specified
-        Boolean status=IoUtils.checkFileExists(target, linkOptions);
-        if (status == null) {
-            throw new AccessDeniedException("Existence cannot be determined for copy target: " + target);
-        }
-
-        if (replaceExisting) {
-            deleteIfExists(target);
-        } else {
-            if (status.booleanValue()) {
-                throw new FileAlreadyExistsException(target.toString());
-            }
-        }
-
-        // create directory or copy file
-        if (attrs.isDirectory()) {
-            createDirectory(target);
-        } else {
-            try (InputStream in = newInputStream(source);
-                 OutputStream os = newOutputStream(target)) {
-                IoUtils.copy(in, os);
-            }
-        }
-
-        // copy basic attributes to target
-        if (copyAttributes) {
-            BasicFileAttributeView view = getFileAttributeView(target, BasicFileAttributeView.class, linkOptions);
-            try {
-                view.setTimes(attrs.lastModifiedTime(), attrs.lastAccessTime(), attrs.creationTime());
-            } catch (Throwable x) {
-                // rollback
-                try {
-                    delete(target);
-                } catch (Throwable suppressed) {
-                    x.addSuppressed(suppressed);
-                }
-                throw x;
-            }
-        }
-    }
-
-    @Override
-    public void move(Path source, Path target, CopyOption... options) throws IOException {
-        SftpPath src = toSftpPath(source);
-        SftpFileSystem fsSrc = src.getFileSystem(); 
-        SftpPath dst = toSftpPath(target);
-        
-        if (src.getFileSystem() != dst.getFileSystem()) {
-            throw new ProviderMismatchException("Mismatched file system providers for " + src + " vs. " + dst);
-        }
-        checkAccess(src);
-
-        boolean replaceExisting = false;
-        boolean copyAttributes = false;
-        boolean noFollowLinks = false;
-        for (CopyOption opt : options) {
-            replaceExisting |= opt == StandardCopyOption.REPLACE_EXISTING;
-            copyAttributes |= opt == StandardCopyOption.COPY_ATTRIBUTES;
-            noFollowLinks |= opt == LinkOption.NOFOLLOW_LINKS;
-        }
-        LinkOption[] linkOptions = IoUtils.getLinkOptions(noFollowLinks);
-
-        // attributes of source file
-        BasicFileAttributes attrs = readAttributes(source, BasicFileAttributes.class, linkOptions);
-        if (attrs.isSymbolicLink()) {
-            throw new IOException("Copying of symbolic links not supported");
-        }
-
-        // delete target if it exists and REPLACE_EXISTING is specified
-        Boolean status=IoUtils.checkFileExists(target, linkOptions);
-        if (status == null) {
-            throw new AccessDeniedException("Existence cannot be determined for move target " + target);
-        }
-
-        if (replaceExisting) {
-            deleteIfExists(target);
-        } else if (status.booleanValue()) {
-            throw new FileAlreadyExistsException(target.toString());
-        }
-
-        try (SftpClient sftp = fsSrc.getClient()) {
-            sftp.rename(src.toString(), dst.toString());
-        }
-
-        // copy basic attributes to target
-        if (copyAttributes) {
-            BasicFileAttributeView view = getFileAttributeView(target, BasicFileAttributeView.class, linkOptions);
-            try {
-                view.setTimes(attrs.lastModifiedTime(), attrs.lastAccessTime(), attrs.creationTime());
-            } catch (Throwable x) {
-                // rollback
-                try {
-                    delete(target);
-                } catch (Throwable suppressed) {
-                    x.addSuppressed(suppressed);
-                }
-                throw x;
-            }
-        }
-    }
-
-    @Override
-    public boolean isSameFile(Path path1, Path path2) throws IOException {
-        SftpPath p1 = toSftpPath(path1);
-        SftpPath p2 = toSftpPath(path2);
-        if (p1.getFileSystem() != p2.getFileSystem()) {
-            throw new ProviderMismatchException("Mismatched file system providers for " + p1 + " vs. " + p2);
-        }
-        checkAccess(p1);
-        checkAccess(p2);
-        return p1.equals(p2);
-    }
-
-    @Override
-    public boolean isHidden(Path path) throws IOException {
-        return false;
-    }
-
-    @Override
-    public FileStore getFileStore(Path path) throws IOException {
-        throw new FileSystemException(path.toString(), path.toString(), "getFileStore(" + path + ") N/A");
-    }
-
-    @Override
-    public void createSymbolicLink(Path link, Path target, FileAttribute<?>... attrs) throws IOException {
-        SftpPath l = toSftpPath(link);
-        SftpFileSystem fsLink = l.getFileSystem();
-        SftpPath t = toSftpPath(target);
-        if (fsLink != t.getFileSystem()) {
-            throw new ProviderMismatchException("Mismatched file system providers for " + l + " vs. " + t);
-        }
-        try (SftpClient client = fsLink.getClient()) {
-            client.symLink(l.toString(), t.toString());
-        }
-    }
-
-    @Override
-    public Path readSymbolicLink(Path link) throws IOException {
-        SftpPath l = toSftpPath(link);
-        SftpFileSystem fsLink = l.getFileSystem();
-        try (SftpClient client = fsLink.getClient()) {
-            return fsLink.getPath(client.readLink(l.toString()));
-        }
-    }
-
-    @Override
-    public void checkAccess(Path path, AccessMode... modes) throws IOException {
-        SftpPath p = toSftpPath(path);
-        boolean w = false;
-        boolean x = false;
-        if (GenericUtils.length(modes) > 0) {
-            for (AccessMode mode : modes) {
-                switch (mode) {
-                    case READ:
-                        break;
-                    case WRITE:
-                        w = true;
-                        break;
-                    case EXECUTE:
-                        x = true;
-                        break;
-                    default:
-                        throw new UnsupportedOperationException("Unsupported mode: " + mode);
-                }
-            }
-        }
-
-        BasicFileAttributes attrs = getFileAttributeView(p, BasicFileAttributeView.class).readAttributes();
-        if ((attrs == null) && !(p.isAbsolute() && p.getNameCount() == 0)) {
-            throw new NoSuchFileException(path.toString());
-        }
-        
-        SftpFileSystem fs = p.getFileSystem();
-        if (x || (w && fs.isReadOnly())) {
-            throw new AccessDeniedException(path.toString());
-        }
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public <V extends FileAttributeView> V getFileAttributeView(final Path path, Class<V> type, final LinkOption... options) {
-        if (type.isAssignableFrom(PosixFileAttributeView.class)) {
-            return (V) new PosixFileAttributeView() {
-                @Override
-                public String name() {
-                    return "view";
-                }
-
-                @SuppressWarnings("synthetic-access")
-                @Override
-                public PosixFileAttributes readAttributes() throws IOException {
-                    SftpPath p = toSftpPath(path);
-                    SftpFileSystem fs = p.getFileSystem();
-                    final SftpClient.Attributes attributes;
-                    try (SftpClient client =fs.getClient()) {
-                        try {
-                            if (followLinks(options)) {
-                                attributes = client.stat(p.toString());
-                            } else {
-                                attributes = client.lstat(p.toString());
-                            }
-                        } catch (SftpException e) {
-                            if (e.getStatus() == SftpConstants.SSH_FX_NO_SUCH_FILE) {
-                                throw new NoSuchFileException(p.toString());
-                            }
-                            throw e;
-                        }
-                    }
-                    return new PosixFileAttributes() {
-                        @Override
-                        public UserPrincipal owner() {
-                            return attributes.owner != null ? new SftpFileSystem.DefaultGroupPrincipal(attributes.owner) : null;
-                        }
-
-                        @Override
-                        public GroupPrincipal group() {
-                            return attributes.group != null ? new SftpFileSystem.DefaultGroupPrincipal(attributes.group) : null;
-                        }
-
-                        @Override
-                        public Set<PosixFilePermission> permissions() {
-                            return permissionsToAttributes(attributes.perms);
-                        }
-
-                        @Override
-                        public FileTime lastModifiedTime() {
-                            return FileTime.from(attributes.mtime, TimeUnit.SECONDS);
-                        }
-
-                        @Override
-                        public FileTime lastAccessTime() {
-                            return FileTime.from(attributes.atime, TimeUnit.SECONDS);
-                        }
-
-                        @Override
-                        public FileTime creationTime() {
-                            return FileTime.from(attributes.ctime, TimeUnit.SECONDS);
-                        }
-
-                        @Override
-                        public boolean isRegularFile() {
-                            return attributes.isRegularFile();
-                        }
-
-                        @Override
-                        public boolean isDirectory() {
-                            return attributes.isDirectory();
-                        }
-
-                        @Override
-                        public boolean isSymbolicLink() {
-                            return attributes.isSymbolicLink();
-                        }
-
-                        @Override
-                        public boolean isOther() {
-                            return attributes.isOther();
-                        }
-
-                        @Override
-                        public long size() {
-                            return attributes.size;
-                        }
-
-                        @Override
-                        public Object fileKey() {
-                            // TODO
-                            return null;
-                        }
-                    };
-                }
-
-                @Override
-                public void setTimes(FileTime lastModifiedTime, FileTime lastAccessTime, FileTime createTime) throws IOException {
-                    if (lastModifiedTime != null) {
-                        setAttribute(path, "lastModifiedTime", lastModifiedTime, options);
-                    }
-                    if (lastAccessTime != null) {
-                        setAttribute(path, "lastAccessTime", lastAccessTime, options);
-                    }
-                    if (createTime != null) {
-                        setAttribute(path, "createTime", createTime, options);
-                    }
-                }
-
-                @Override
-                public void setPermissions(Set<PosixFilePermission> perms) throws IOException {
-                    setAttribute(path, "permissions", perms, options);
-                }
-
-                @Override
-                public void setGroup(GroupPrincipal group) throws IOException {
-                    setAttribute(path, "group", group, options);
-                }
-
-                @Override
-                public UserPrincipal getOwner() throws IOException {
-                    return readAttributes().owner();
-                }
-
-                @Override
-                public void setOwner(UserPrincipal owner) throws IOException {
-                    setAttribute(path, "owner", owner, options);
-                }
-            };
-        } else {
-            throw new UnsupportedOperationException("getFileAttributeView(" + path + ") view not supported: " + type.getSimpleName());
-        }
-    }
-
-    @Override
-    public <A extends BasicFileAttributes> A readAttributes(Path path, Class<A> type, LinkOption... options) throws IOException {
-        if (type.isAssignableFrom(PosixFileAttributes.class)) {
-            return type.cast(getFileAttributeView(path, PosixFileAttributeView.class, options).readAttributes());
-        }
-
-        throw new UnsupportedOperationException("readAttributes(" + path + ")[" + type.getSimpleName() + "] N/A");
-    }
-
-    @Override
-    public Map<String, Object> readAttributes(Path path, String attributes, LinkOption... options) throws IOException {
-        String view;
-        String attrs;
-        int i = attributes.indexOf(':');
-        if (i == -1) {
-            view = "basic";
-            attrs = attributes;
-        } else {
-            view = attributes.substring(0, i++);
-            attrs = attributes.substring(i);
-        }
-        SftpPath p = toSftpPath(path);
-        SftpFileSystem fs = p.getFileSystem();
-        Collection<String> views = fs.supportedFileAttributeViews();
-        if (GenericUtils.isEmpty(views) || (!views.contains(view))) {
-            throw new UnsupportedOperationException("readAttributes(" + path + ")[" + attributes + "] view " + view + " not supported: " + views);
-        }
-
-        PosixFileAttributes v = readAttributes(path, PosixFileAttributes.class, options);
-        if ("*".equals(attrs)) {
-            attrs = "lastModifiedTime,lastAccessTime,creationTime,size,isRegularFile,isDirectory,isSymbolicLink,isOther,fileKey,owner,permissions,group";
-        }
-        Map<String, Object> map = new HashMap<>();
-        for (String attr : attrs.split(",")) {
-            switch (attr) {
-                case "lastModifiedTime":
-                    map.put(attr, v.lastModifiedTime());
-                    break;
-                case "lastAccessTime":
-                    map.put(attr, v.lastAccessTime());
-                    break;
-                case "creationTime":
-                    map.put(attr, v.creationTime());
-                    break;
-                case "size":
-                    map.put(attr, Long.valueOf(v.size()));
-                    break;
-                case "isRegularFile":
-                    map.put(attr, Boolean.valueOf(v.isRegularFile()));
-                    break;
-                case "isDirectory":
-                    map.put(attr, Boolean.valueOf(v.isDirectory()));
-                    break;
-                case "isSymbolicLink":
-                    map.put(attr, Boolean.valueOf(v.isSymbolicLink()));
-                    break;
-                case "isOther":
-                    map.put(attr, Boolean.valueOf(v.isOther()));
-                    break;
-                case "fileKey":
-                    map.put(attr, v.fileKey());
-                    break;
-                case "owner":
-                    map.put(attr, v.owner());
-                    break;
-                case "permissions":
-                    map.put(attr, v.permissions());
-                    break;
-                case "group":
-                    map.put(attr, v.group());
-                    break;
-                default:
-                    if (log.isTraceEnabled()) {
-                        log.trace("readAttributes({})[{}] ignored {}={}", path, attributes, attr, v);
-                    }
-            }
-        }
-        return map;
-    }
-
-    @Override
-    public void setAttribute(Path path, String attribute, Object value, LinkOption... options) throws IOException {
-        String view;
-        String attr;
-        int i = attribute.indexOf(':');
-        if (i == -1) {
-            view = "basic";
-            attr = attribute;
-        } else {
-            view = attribute.substring(0, i++);
-            attr = attribute.substring(i);
-        }
-        SftpPath p = toSftpPath(path);
-        SftpFileSystem fs = p.getFileSystem();
-        Collection<String> views = fs.supportedFileAttributeViews();
-        if (GenericUtils.isEmpty(views) || (!view.contains(view))) {
-            throw new UnsupportedOperationException("setAttribute(" + path + ")[" + attribute + "=" + value + "] view " + view + " not supported: " + views);
-        }
-
-        SftpClient.Attributes attributes = new SftpClient.Attributes();
-        switch (attr) {
-            case "lastModifiedTime":
-                attributes.mtime((int) ((FileTime) value).to(TimeUnit.SECONDS));
-                break;
-            case "lastAccessTime":
-                attributes.atime((int) ((FileTime) value).to(TimeUnit.SECONDS));
-                break;
-            case "creationTime":
-                attributes.ctime((int) ((FileTime) value).to(TimeUnit.SECONDS));
-                break;
-            case "size":
-                attributes.size(((Number) value).longValue());
-                break;
-            case "permissions": {
-                @SuppressWarnings("unchecked")
-                Set<PosixFilePermission>    attrSet = (Set<PosixFilePermission>) value;
-                attributes.perms(attributesToPermissions(path, attrSet));
-                }
-                break;
-            case "owner":
-                attributes.owner(((UserPrincipal) value).getName());
-                break;
-            case "group":
-                attributes.group(((GroupPrincipal) value).getName());
-                break;
-            case "isRegularFile":
-            case "isDirectory":
-            case "isSymbolicLink":
-            case "isOther":
-            case "fileKey":
-                throw new UnsupportedOperationException("setAttribute(" + path + ")[" + attribute + "=" + value + "]"
-                                                       + " unknown view=" + view + " attribute: " + attr);
-            default:
-                if (log.isTraceEnabled()) {
-                    log.trace("setAttribute({})[{}] ignore {}={}", path, attribute, attr, value);
-                }
-        }
-
-        try (SftpClient client = fs.getClient()) {
-            client.setStat(p.toString(), attributes);
-        }
-    }
-
-    private SftpPath toSftpPath(Path path) {
-        ValidateUtils.checkNotNull(path, "No path provided", GenericUtils.EMPTY_OBJECT_ARRAY);
-        if (!(path instanceof SftpPath)) {
-            throw new ProviderMismatchException("Path is not SFTP: " + path);
-        }
-        return (SftpPath) path;
-    }
-
-    static boolean followLinks(LinkOption... paramVarArgs) {
-        boolean bool = true;
-        for (LinkOption localLinkOption : paramVarArgs) {
-            if (localLinkOption == LinkOption.NOFOLLOW_LINKS) {
-                bool = false;
-            }
-        }
-        return bool;
-    }
-
-    private Set<PosixFilePermission> permissionsToAttributes(int perms) {
-        Set<PosixFilePermission> p = new HashSet<>();
-        if ((perms & S_IRUSR) != 0) {
-            p.add(PosixFilePermission.OWNER_READ);
-        }
-        if ((perms & S_IWUSR) != 0) {
-            p.add(PosixFilePermission.OWNER_WRITE);
-        }
-        if ((perms & S_IXUSR) != 0) {
-            p.add(PosixFilePermission.OWNER_EXECUTE);
-        }
-        if ((perms & S_IRGRP) != 0) {
-            p.add(PosixFilePermission.GROUP_READ);
-        }
-        if ((perms & S_IWGRP) != 0) {
-            p.add(PosixFilePermission.GROUP_WRITE);
-        }
-        if ((perms & S_IXGRP) != 0) {
-            p.add(PosixFilePermission.GROUP_EXECUTE);
-        }
-        if ((perms & S_IROTH) != 0) {
-            p.add(PosixFilePermission.OTHERS_READ);
-        }
-        if ((perms & S_IWOTH) != 0) {
-            p.add(PosixFilePermission.OTHERS_WRITE);
-        }
-        if ((perms & S_IXOTH) != 0) {
-            p.add(PosixFilePermission.OTHERS_EXECUTE);
-        }
-        return p;
-    }
-
-    protected int attributesToPermissions(Path path, Collection<PosixFilePermission> perms) {
-        if (GenericUtils.isEmpty(perms)) {
-            return 0;
-        }
-
-        int pf = 0;
-        for (PosixFilePermission p : perms) {
-            switch (p) {
-                case OWNER_READ:
-                    pf |= S_IRUSR;
-                    break;
-                case OWNER_WRITE:
-                    pf |= S_IWUSR;
-                    break;
-                case OWNER_EXECUTE:
-                    pf |= S_IXUSR;
-                    break;
-                case GROUP_READ:
-                    pf |= S_IRGRP;
-                    break;
-                case GROUP_WRITE:
-                    pf |= S_IWGRP;
-                    break;
-                case GROUP_EXECUTE:
-                    pf |= S_IXGRP;
-                    break;
-                case OTHERS_READ:
-                    pf |= S_IROTH;
-                    break;
-                case OTHERS_WRITE:
-                    pf |= S_IWOTH;
-                    break;
-                case OTHERS_EXECUTE:
-                    pf |= S_IXOTH;
-                    break;
-                default:
-                    if (log.isTraceEnabled()) {
-                        log.trace("attributesToPermissions(" + path + ") ignored " + p);
-                    }
-            }
-        }
-
-        return pf;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a6e2bf9e/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpPath.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpPath.java b/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpPath.java
deleted file mode 100644
index d4e0b0b..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpPath.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.
- */
-package org.apache.sshd.client.sftp;
-
-import java.io.IOException;
-import java.nio.file.FileSystem;
-import java.nio.file.LinkOption;
-import java.nio.file.spi.FileSystemProvider;
-
-import org.apache.sshd.common.file.util.BasePath;
-import org.apache.sshd.common.file.util.ImmutableList;
-
-public class SftpPath extends BasePath<SftpPath, SftpFileSystem> {
-    public SftpPath(SftpFileSystem fileSystem, String root, ImmutableList<String> names) {
-        super(fileSystem, root, names);
-    }
-
-    @Override
-    public SftpPath toRealPath(LinkOption... options) throws IOException {
-//        try (SftpClient client = fileSystem.getClient()) {
-//            client.realP
-//        }
-        // TODO: handle links
-        SftpPath absolute = toAbsolutePath();
-        FileSystem fs = getFileSystem();
-        FileSystemProvider provider = fs.provider();
-        provider.checkAccess(absolute);
-        return absolute;
-    }
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a6e2bf9e/sshd-core/src/main/java/org/apache/sshd/client/subsystem/SubsystemClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/SubsystemClient.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/SubsystemClient.java
new file mode 100644
index 0000000..7f86bd7
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/SubsystemClient.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.sshd.client.subsystem;
+
+import java.nio.channels.Channel;
+
+import org.apache.sshd.common.NamedResource;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface SubsystemClient extends NamedResource, Channel {
+    // marker interface for subsystems
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a6e2bf9e/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java
new file mode 100644
index 0000000..fc7a02b
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.sshd.client.subsystem.sftp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+
+import org.apache.sshd.common.subsystem.sftp.SftpConstants;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public abstract class AbstractSftpClient extends AbstractLoggingBean implements SftpClient {
+    protected AbstractSftpClient() {
+        super();
+    }
+    
+    @Override
+    public String getName() {
+        return SftpConstants.SFTP_SUBSYSTEM_NAME;
+    }
+
+    @Override
+    public CloseableHandle open(String path) throws IOException {
+        return open(path, Collections.<OpenMode>emptySet());
+    }
+    
+    @Override
+    public CloseableHandle open(String path, OpenMode ... options) throws IOException {
+        return open(path, GenericUtils.of(options));
+    }
+
+    @Override
+    public void rename(String oldPath, String newPath) throws IOException {
+        rename(oldPath, newPath, Collections.<CopyMode>emptySet());
+    }
+    
+    @Override
+    public void rename(String oldPath, String newPath, CopyMode ... options) throws IOException {
+        rename(oldPath, newPath, GenericUtils.of(options));
+    }
+
+    @Override
+    public InputStream read(String path) throws IOException {
+        return read(path, DEFAULT_READ_BUFFER_SIZE);
+    }
+
+    @Override
+    public InputStream read(String path, int bufferSize) throws IOException {
+        return read(path, bufferSize, EnumSet.of(OpenMode.Read));
+    }
+
+    @Override
+    public InputStream read(String path, OpenMode ... mode) throws IOException {
+        return read(path, DEFAULT_READ_BUFFER_SIZE, mode);
+    }
+
+    @Override
+    public InputStream read(String path, int bufferSize, OpenMode ... mode) throws IOException {
+        return read(path, bufferSize, GenericUtils.of(mode));
+    }
+
+    @Override
+    public InputStream read(String path, Collection<OpenMode>  mode) throws IOException {
+        return read(path, DEFAULT_READ_BUFFER_SIZE, mode);
+    }
+
+    @Override
+    public int read(Handle handle, long fileOffset, byte[] dst) throws IOException {
+        return read(handle, fileOffset, dst, 0, dst.length);
+    }
+
+    @Override
+    public OutputStream write(String path) throws IOException {
+        return write(path, DEFAULT_WRITE_BUFFER_SIZE);
+    }
+
+    @Override
+    public OutputStream write(String path, int bufferSize) throws IOException {
+        return write(path, bufferSize, EnumSet.of(OpenMode.Write, OpenMode.Create, OpenMode.Truncate));
+    }
+
+    @Override
+    public OutputStream write(String path, OpenMode ... mode) throws IOException {
+        return write(path, DEFAULT_WRITE_BUFFER_SIZE, mode);
+    }
+
+    @Override
+    public OutputStream write(String path, Collection<OpenMode> mode) throws IOException {
+        return write(path, DEFAULT_WRITE_BUFFER_SIZE, mode);
+    }
+
+    @Override
+    public OutputStream write(String path, int bufferSize, OpenMode ... mode) throws IOException {
+        return write(path, bufferSize, GenericUtils.of(mode));
+    }
+
+    @Override
+    public void write(Handle handle, long fileOffset, byte[] src) throws IOException {
+        write(handle, fileOffset, src, 0, src.length);
+    }
+
+    @Override
+    public void symLink(String linkPath, String targetPath) throws IOException {
+        link(linkPath, targetPath, true);
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a6e2bf9e/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/DefaultCloseableHandle.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/DefaultCloseableHandle.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/DefaultCloseableHandle.java
new file mode 100644
index 0000000..868ff10
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/DefaultCloseableHandle.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.sshd.client.subsystem.sftp;
+
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.sshd.client.subsystem.sftp.SftpClient.CloseableHandle;
+import org.apache.sshd.common.util.ValidateUtils;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class DefaultCloseableHandle extends CloseableHandle {
+    private final AtomicBoolean open = new AtomicBoolean(true);
+    private final SftpClient client;
+
+    public DefaultCloseableHandle(SftpClient client, String id) {
+        super(id);
+        this.client = ValidateUtils.checkNotNull(client, "No client for id=%s", id);
+    }
+
+    public final SftpClient getSftpClient() {
+        return client;
+    }
+
+    @Override
+    public boolean isOpen() {
+        return open.get();
+    }
+
+    @Override
+    public void close() throws IOException {
+        if (open.getAndSet(false)) {
+            client.close(this);
+        }
+    }
+}