001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.commons.vfs.provider.sftp;
018:
019: import com.jcraft.jsch.ChannelSftp;
020: import com.jcraft.jsch.JSchException;
021: import com.jcraft.jsch.Session;
022: import com.jcraft.jsch.SftpException;
023: import org.apache.commons.vfs.FileName;
024: import org.apache.commons.vfs.FileObject;
025: import org.apache.commons.vfs.FileSystem;
026: import org.apache.commons.vfs.FileSystemException;
027: import org.apache.commons.vfs.FileSystemOptions;
028: import org.apache.commons.vfs.UserAuthenticationData;
029: import org.apache.commons.vfs.util.UserAuthenticatorUtils;
030: import org.apache.commons.vfs.provider.AbstractFileSystem;
031: import org.apache.commons.vfs.provider.GenericFileName;
032:
033: import java.io.IOException;
034: import java.util.Collection;
035:
036: /**
037: * Represents the files on an SFTP server.
038: *
039: * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a>
040: * @version $Revision: 480428 $ $Date: 2006-11-28 22:15:24 -0800 (Tue, 28 Nov 2006) $
041: */
042: public class SftpFileSystem extends AbstractFileSystem implements
043: FileSystem {
044:
045: private Session session;
046: // private final JSch jSch;
047: private ChannelSftp idleChannel;
048:
049: protected SftpFileSystem(final GenericFileName rootName,
050: final Session session,
051: final FileSystemOptions fileSystemOptions) {
052: super (rootName, null, fileSystemOptions);
053: this .session = session;
054: }
055:
056: protected void doCloseCommunicationLink() {
057: if (idleChannel != null) {
058: idleChannel.disconnect();
059: idleChannel = null;
060: }
061:
062: if (session != null) {
063: session.disconnect();
064: session = null;
065: }
066: }
067:
068: /**
069: * Returns an SFTP channel to the server.
070: */
071: protected ChannelSftp getChannel() throws IOException {
072: if (this .session == null) {
073: // channel closed. e.g. by freeUnusedResources, but now we need it again
074: Session session;
075: UserAuthenticationData authData = null;
076: try {
077: final GenericFileName rootName = (GenericFileName) getRootName();
078:
079: authData = UserAuthenticatorUtils.authenticate(
080: getFileSystemOptions(),
081: SftpFileProvider.AUTHENTICATOR_TYPES);
082:
083: session = SftpClientFactory.createConnection(rootName
084: .getHostName(), rootName.getPort(),
085: UserAuthenticatorUtils.getData(authData,
086: UserAuthenticationData.USERNAME,
087: UserAuthenticatorUtils.toChar(rootName
088: .getUserName())),
089: UserAuthenticatorUtils.getData(authData,
090: UserAuthenticationData.PASSWORD,
091: UserAuthenticatorUtils.toChar(rootName
092: .getPassword())),
093: getFileSystemOptions());
094: } catch (final Exception e) {
095: throw new FileSystemException(
096: "vfs.provider.sftp/connect.error",
097: getRootName(), e);
098: } finally {
099: UserAuthenticatorUtils.cleanup(authData);
100: }
101:
102: this .session = session;
103: }
104:
105: try {
106: // Use the pooled channel, or create a new one
107: final ChannelSftp channel;
108: if (idleChannel != null) {
109: channel = idleChannel;
110: idleChannel = null;
111: } else {
112: channel = (ChannelSftp) session.openChannel("sftp");
113: channel.connect();
114:
115: Boolean userDirIsRoot = SftpFileSystemConfigBuilder
116: .getInstance().getUserDirIsRoot(
117: getFileSystemOptions());
118: String workingDirectory = getRootName().getPath();
119: if (workingDirectory != null
120: && (userDirIsRoot == null || !userDirIsRoot
121: .booleanValue())) {
122: try {
123: channel.cd(workingDirectory);
124: } catch (SftpException e) {
125: throw new FileSystemException(
126: "vfs.provider.sftp/change-work-directory.error",
127: workingDirectory);
128: }
129: }
130: }
131:
132: return channel;
133: } catch (final JSchException e) {
134: throw new FileSystemException(
135: "vfs.provider.sftp/connect.error", getRootName(), e);
136: }
137: }
138:
139: /**
140: * Returns a channel to the pool.
141: */
142: protected void putChannel(final ChannelSftp channel) {
143: if (idleChannel == null) {
144: // put back the channel only if it is still connected
145: if (channel.isConnected() && !channel.isClosed()) {
146: idleChannel = channel;
147: }
148: } else {
149: channel.disconnect();
150: }
151: }
152:
153: /**
154: * Adds the capabilities of this file system.
155: */
156: protected void addCapabilities(final Collection caps) {
157: caps.addAll(SftpFileProvider.capabilities);
158: }
159:
160: /**
161: * Creates a file object. This method is called only if the requested
162: * file is not cached.
163: */
164: protected FileObject createFile(final FileName name)
165: throws FileSystemException {
166: return new SftpFileObject(name, this );
167: }
168:
169: /**
170: * last mod time is only a int and in seconds, thus can be off by 999
171: *
172: * @return 1000
173: */
174: public double getLastModTimeAccuracy() {
175: return 1000L;
176: }
177: }
|