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.vfs2.provider.ftp;
018    
019    import java.io.IOException;
020    
021    import org.apache.commons.net.ftp.FTP;
022    import org.apache.commons.net.ftp.FTPClient;
023    import org.apache.commons.net.ftp.FTPClientConfig;
024    import org.apache.commons.net.ftp.FTPReply;
025    import org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory;
026    import org.apache.commons.vfs2.FileSystemException;
027    import org.apache.commons.vfs2.FileSystemOptions;
028    import org.apache.commons.vfs2.util.UserAuthenticatorUtils;
029    
030    /**
031     * Create a FtpClient instance.
032     *
033     * @author <a href="http://commons.apache.org/vfs/team-list.html">Commons VFS team</a>
034     */
035    public final class FtpClientFactory
036    {
037        private static final int BUFSZ = 40;
038    
039        private FtpClientFactory()
040        {
041        }
042    
043        /**
044         * Creates a new connection to the server.
045         *
046         * @param hostname          The host name of the server.
047         * @param port              The port to connect to.
048         * @param username          The name of the user for authentication.
049         * @param password          The user's password.
050         * @param workingDirectory  The base directory.
051         * @param fileSystemOptions The FileSystemOptions.
052         * @return An FTPClient.
053         * @throws FileSystemException if an error occurs while connecting.
054         */
055        public static FTPClient createConnection(String hostname, int port, char[] username, char[] password,
056                                                 String workingDirectory, FileSystemOptions fileSystemOptions)
057            throws FileSystemException
058        {
059            // Determine the username and password to use
060            if (username == null)
061            {
062                username = "anonymous".toCharArray();
063            }
064    
065            if (password == null)
066            {
067                password = "anonymous".toCharArray();
068            }
069    
070            try
071            {
072                final FTPClient client = new FTPClient();
073    
074                configureClient(fileSystemOptions, client);
075    
076                FTPFileEntryParserFactory myFactory =
077                    FtpFileSystemConfigBuilder.getInstance().getEntryParserFactory(fileSystemOptions);
078                if (myFactory != null)
079                {
080                    client.setParserFactory(myFactory);
081                }
082    
083                try
084                {
085                    client.connect(hostname, port);
086    
087                    int reply = client.getReplyCode();
088                    if (!FTPReply.isPositiveCompletion(reply))
089                    {
090                        throw new FileSystemException("vfs.provider.ftp/connect-rejected.error", hostname);
091                    }
092    
093                    // Login
094                    if (!client.login(
095                        UserAuthenticatorUtils.toString(username),
096                        UserAuthenticatorUtils.toString(password)))
097                    {
098                        throw new FileSystemException("vfs.provider.ftp/login.error",
099                            new Object[]{hostname, UserAuthenticatorUtils.toString(username)}, null);
100                    }
101    
102                    // Set binary mode
103                    if (!client.setFileType(FTP.BINARY_FILE_TYPE))
104                    {
105                        throw new FileSystemException("vfs.provider.ftp/set-binary.error", hostname);
106                    }
107    
108                    // Set dataTimeout value
109                    Integer dataTimeout = FtpFileSystemConfigBuilder.getInstance().getDataTimeout(fileSystemOptions);
110                    if (dataTimeout != null)
111                    {
112                        client.setDataTimeout(dataTimeout.intValue());
113                    }
114    
115                    Integer socketTimeout = FtpFileSystemConfigBuilder.getInstance().getSoTimeout(fileSystemOptions);
116                    if (socketTimeout != null)
117                    {
118                        client.setSoTimeout(socketTimeout.intValue());
119                    }
120    
121                    // Change to root by default
122                    // All file operations a relative to the filesystem-root
123                    // String root = getRoot().getName().getPath();
124    
125                    Boolean userDirIsRoot = FtpFileSystemConfigBuilder.getInstance().getUserDirIsRoot(fileSystemOptions);
126                    if (workingDirectory != null && (userDirIsRoot == null || !userDirIsRoot.booleanValue()))
127                    {
128                        if (!client.changeWorkingDirectory(workingDirectory))
129                        {
130                            throw new FileSystemException("vfs.provider.ftp/change-work-directory.error", workingDirectory);
131                        }
132                    }
133    
134                    Boolean passiveMode = FtpFileSystemConfigBuilder.getInstance().getPassiveMode(fileSystemOptions);
135                    if (passiveMode != null && passiveMode.booleanValue())
136                    {
137                        client.enterLocalPassiveMode();
138                    }
139    
140                    String controlEncoding = FtpFileSystemConfigBuilder.getInstance().getControlEncoding(fileSystemOptions);
141                    if (controlEncoding != null)
142                    {
143                        client.setControlEncoding(controlEncoding);
144                    }
145                }
146                catch (final IOException e)
147                {
148                    if (client.isConnected())
149                    {
150                        client.disconnect();
151                    }
152                    throw e;
153                }
154    
155                return client;
156            }
157            catch (final Exception exc)
158            {
159                throw new FileSystemException("vfs.provider.ftp/connect.error", new Object[]{hostname}, exc);
160            }
161        }
162    
163        private static void configureClient(FileSystemOptions fileSystemOptions, FTPClient client)
164        {
165            String key = FtpFileSystemConfigBuilder.getInstance().getEntryParser(fileSystemOptions);
166            if (key != null)
167            {
168                FTPClientConfig config = new FTPClientConfig(key);
169    
170                String serverLanguageCode =
171                    FtpFileSystemConfigBuilder.getInstance().getServerLanguageCode(fileSystemOptions);
172                if (serverLanguageCode != null)
173                {
174                    config.setServerLanguageCode(serverLanguageCode);
175                }
176                String defaultDateFormat =
177                    FtpFileSystemConfigBuilder.getInstance().getDefaultDateFormat(fileSystemOptions);
178                if (defaultDateFormat != null)
179                {
180                    config.setDefaultDateFormatStr(defaultDateFormat);
181                }
182                String recentDateFormat =
183                    FtpFileSystemConfigBuilder.getInstance().getRecentDateFormat(fileSystemOptions);
184                if (recentDateFormat != null)
185                {
186                    config.setRecentDateFormatStr(recentDateFormat);
187                }
188                String serverTimeZoneId =
189                    FtpFileSystemConfigBuilder.getInstance().getServerTimeZoneId(fileSystemOptions);
190                if (serverTimeZoneId != null)
191                {
192                    config.setServerTimeZoneId(serverTimeZoneId);
193                }
194                String[] shortMonthNames =
195                    FtpFileSystemConfigBuilder.getInstance().getShortMonthNames(fileSystemOptions);
196                if (shortMonthNames != null)
197                {
198                    StringBuilder shortMonthNamesStr = new StringBuilder(BUFSZ);
199                    for (int i = 0; i < shortMonthNames.length; i++)
200                    {
201                        if (shortMonthNamesStr.length() > 0)
202                        {
203                            shortMonthNamesStr.append("|");
204                        }
205                        shortMonthNamesStr.append(shortMonthNames[i]);
206                    }
207                    config.setShortMonthNames(shortMonthNamesStr.toString());
208                }
209    
210                client.configure(config);
211            }
212        }
213    }