1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.vfs2.provider.ftp;
18
19 import java.io.IOException;
20 import java.util.Collection;
21 import java.util.concurrent.atomic.AtomicReference;
22
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25 import org.apache.commons.vfs2.Capability;
26 import org.apache.commons.vfs2.FileObject;
27 import org.apache.commons.vfs2.FileSystemException;
28 import org.apache.commons.vfs2.FileSystemOptions;
29 import org.apache.commons.vfs2.VfsLog;
30 import org.apache.commons.vfs2.provider.AbstractFileName;
31 import org.apache.commons.vfs2.provider.AbstractFileSystem;
32 import org.apache.commons.vfs2.provider.GenericFileName;
33
34 /**
35 * An FTP file system.
36 */
37 public class FtpFileSystem extends AbstractFileSystem {
38
39 private static final Log LOG = LogFactory.getLog(FtpFileSystem.class);
40
41 // private final String hostname;
42 // private final int port;
43 // private final String username;
44 // private final String password;
45
46 // An idle client
47 private final AtomicReference<FtpClient> idleClient = new AtomicReference<>();
48
49 /**
50 * Constructs a new instance.
51 *
52 * @param rootName The root of the file system.
53 * @param ftpClient The FtpClient.
54 * @param fileSystemOptions The FileSystemOptions.
55 * @since 2.0 (was protected)
56 */
57 public FtpFileSystem(final GenericFileName rootName, final FtpClient ftpClient,
58 final FileSystemOptions fileSystemOptions) {
59 super(rootName, null, fileSystemOptions);
60 // hostname = rootName.getHostName();
61 // port = rootName.getPort();
62
63 idleClient.set(ftpClient);
64 }
65
66 /**
67 * Adds the capabilities of this file system.
68 */
69 @Override
70 protected void addCapabilities(final Collection<Capability> caps) {
71 caps.addAll(FtpFileProvider.CAPABILITIES);
72 }
73
74 /**
75 * Cleans up the connection to the server.
76 *
77 * @param client The FtpClient.
78 */
79 private void closeConnection(final FtpClient client) {
80 try {
81 // Clean up
82 if (client.isConnected()) {
83 client.disconnect();
84 }
85 } catch (final IOException e) {
86 // getLogger().warn("vfs.provider.ftp/close-connection.error", e);
87 VfsLog.warn(getLogger(), LOG, "vfs.provider.ftp/close-connection.error", e);
88 }
89 }
90
91 /**
92 * Creates a file object.
93 */
94 @Override
95 protected FileObject createFile(final AbstractFileName name) throws FileSystemException {
96 return new FtpFileObject(name, this, getRootName());
97 }
98
99 /**
100 * Gets the wrapper to access this file system.
101 *
102 * @return new instance.
103 * @throws FileSystemException if any error occurs.
104 * @since 2.1
105 */
106 protected FTPClientWrapper createWrapper() throws FileSystemException {
107 return new FTPClientWrapper((GenericFileName) getRoot().getName(), getFileSystemOptions());
108 }
109
110 @Override
111 protected void doCloseCommunicationLink() {
112 final FtpClient idle = idleClient.getAndSet(null);
113 // Clean up the connection
114 if (idle != null) {
115 closeConnection(idle);
116 }
117 }
118
119 /**
120 * Creates an FTP client to use.
121 *
122 * @return An FTPClient.
123 * @throws FileSystemException if an error occurs.
124 */
125 public FtpClient getClient() throws FileSystemException {
126 FtpClient client = idleClient.getAndSet(null);
127
128 if (client == null || !client.isConnected()) {
129 client = createWrapper();
130 }
131
132 return client;
133 }
134
135 /**
136 * Returns an FTP client after use.
137 *
138 * @param client The FTPClient.
139 */
140 public void putClient(final FtpClient client) {
141 // Save client for reuse if none is idle.
142 if (!idleClient.compareAndSet(null, client)) {
143 // An idle client is already present so close the connection.
144 closeConnection(client);
145 }
146 }
147 }