View Javadoc
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.net.Proxy;
20  import java.nio.charset.Charset;
21  import java.time.Duration;
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.List;
25  
26  import org.apache.commons.lang3.Range;
27  import org.apache.commons.net.ftp.FTPReply;
28  import org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory;
29  import org.apache.commons.vfs2.FileContent;
30  import org.apache.commons.vfs2.FileSystem;
31  import org.apache.commons.vfs2.FileSystemConfigBuilder;
32  import org.apache.commons.vfs2.FileSystemOptions;
33  
34  /**
35   * The config builder for various FTP configuration options.
36   */
37  public class FtpFileSystemConfigBuilder extends FileSystemConfigBuilder {
38  
39      private static final String PREFIX = FtpFileSystemConfigBuilder.class.getName();
40  
41      private static final FtpFileSystemConfigBuilder BUILDER = new FtpFileSystemConfigBuilder();
42  
43      private static final String AUTODETECT_UTF8 = PREFIX + ".AUTODETECT_UTF8";
44      private static final String CONNECT_TIMEOUT = PREFIX + ".CONNECT_TIMEOUT";
45      private static final String DATA_TIMEOUT = PREFIX + ".DATA_TIMEOUT";
46      private static final String DEFAULT_DATE_FORMAT = PREFIX + ".DEFAULT_DATE_FORMAT";
47      private static final String ENCODING = PREFIX + ".ENCODING";
48      private static final String FACTORY_KEY = FTPFileEntryParserFactory.class.getName() + ".KEY";
49      private static final String FILE_TYPE = PREFIX + ".FILE_TYPE";
50      private static final String PASSIVE_MODE = PREFIX + ".PASSIVE";
51      private static final String ACTIVE_PORT_RANGE = PREFIX + ".ACTIVE_PORT_RANGE";
52      private static final String PROXY = PREFIX + ".PROXY";
53      private static final String RECENT_DATE_FORMAT = PREFIX + ".RECENT_DATE_FORMAT";
54      private static final String REMOTE_VERIFICATION = PREFIX + ".REMOTE_VERIFICATION";
55      private static final String SERVER_LANGUAGE_CODE = PREFIX + ".SERVER_LANGUAGE_CODE";
56      private static final String SERVER_TIME_ZONE_ID = PREFIX + ".SERVER_TIME_ZONE_ID";
57      private static final String SHORT_MONTH_NAMES = PREFIX + ".SHORT_MONTH_NAMES";
58      private static final String SO_TIMEOUT = PREFIX + ".SO_TIMEOUT";
59      private static final String CONTROL_KEEP_ALIVE_TIMEOUT = PREFIX + ".CONTROL_KEEP_ALIVE_TIMEOUT";
60      private static final String CONTROL_KEEP_ALIVE_REPLY_TIMEOUT = PREFIX + ".CONTROL_KEEP_ALIVE_REPLY_TIMEOUT";
61      private static final String USER_DIR_IS_ROOT = PREFIX + ".USER_DIR_IS_ROOT";
62      private static final String TRANSFER_ABORTED_OK_REPLY_CODES = PREFIX + ".TRANSFER_ABORTED_OK_REPLY_CODES";
63      private static final String MDTM_LAST_MODIFED_TIME = PREFIX + ".MDTM_LAST_MODIFED_TIME";
64  
65      /**
66       * Gets the singleton instance.
67       *
68       * @return the singleton instance.
69       */
70      public static FtpFileSystemConfigBuilder getInstance() {
71          return BUILDER;
72      }
73  
74      /**
75       * Gets special retry code.
76       *
77       * See VFS-674, its accompanying PR and https://github.com/apache/commons-vfs/pull/51 as to why 426 and 550 are here.
78       *
79       * @return special retry code.
80       */
81      public static List<Integer> getSaneTransferAbortedOkReplyCodes() {
82          // See VFS-674, its accompanying PR and https://github.com/apache/commons-vfs/pull/51 as to why 426 and 550 are here
83          return new ArrayList<>(Arrays.asList(FTPReply.TRANSFER_ABORTED, FTPReply.FILE_UNAVAILABLE));
84      }
85  
86      private FtpFileSystemConfigBuilder() {
87          super("ftp.");
88      }
89  
90      /**
91       * Create new config builder with specified prefix string.
92       *
93       * @param prefix prefix string to use for parameters of this config builder.
94       * @since 2.1
95       */
96      protected FtpFileSystemConfigBuilder(final String prefix) {
97          super(prefix);
98      }
99  
100     /**
101      * Gets the active port range.
102      *
103      * @param options The FileSystemOptions.
104      * @return the Range of active ports
105      * @since 2.10.0
106      */
107     public Range<Integer> getActivePortRange(final FileSystemOptions options) {
108         return getParam(options, ACTIVE_PORT_RANGE);
109     }
110 
111     /**
112      * Gets whether to try to autodetect the server encoding (only UTF8 is supported).
113      *
114      * @param options The FileSystemOptions.
115      * @return True if autodetection should be done.
116      * @since 2.4
117      */
118     public Boolean getAutodetectUtf8(final FileSystemOptions options) {
119         return getBoolean(options, AUTODETECT_UTF8);
120     }
121 
122     @Override
123     protected Class<? extends FileSystem> getConfigClass() {
124         return FtpFileSystem.class;
125     }
126 
127     /**
128      * Gets the timeout in milliseconds to use for the socket connection.
129      *
130      * @param options The FileSystemOptions.
131      * @return The timeout in milliseconds to use for the socket connection.
132      * @since 2.1
133      * @deprecated Use {@link #getConnectTimeoutDuration(FileSystemOptions)}.
134      */
135     @Deprecated
136     public Integer getConnectTimeout(final FileSystemOptions options) {
137         return getDurationInteger(options, CONNECT_TIMEOUT);
138     }
139 
140     /**
141      * Gets the timeout in milliseconds to use for the socket connection.
142      *
143      * @param options The FileSystemOptions.
144      * @return The timeout in milliseconds to use for the socket connection.
145      * @since 2.8.0
146      */
147     public Duration getConnectTimeoutDuration(final FileSystemOptions options) {
148         return getDuration(options, CONNECT_TIMEOUT);
149     }
150 
151     /**
152      * Gets the control encoding.
153      *
154      * @param options The FileSystemOptions.
155      * @return The control encoding.
156      * @since 2.0
157      * @deprecated Use {@link #getControlEncodingCharset(FileSystemOptions)}.
158      */
159     @Deprecated
160     public String getControlEncoding(final FileSystemOptions options) {
161         return getString(options, ENCODING);
162     }
163 
164     /**
165      * Gets the control encoding.
166      *
167      * @param options The FileSystemOptions.
168      * @return The control encoding.
169      * @since 2.11.0
170      */
171     public Charset getControlEncodingCharset(final FileSystemOptions options) {
172         return getCharset(options, ENCODING);
173     }
174 
175     /**
176      * Gets the controlKeepAliveReplyTimeout duration.
177      *
178      * @param options The FileSystem options
179      * @return The controlKeepAliveReplyTimeout duration.
180      * @since 2.8.0
181      */
182     public Duration getControlKeepAliveReplyTimeout(final FileSystemOptions options) {
183         return getDuration(options, CONTROL_KEEP_ALIVE_REPLY_TIMEOUT);
184     }
185 
186     /**
187      * Gets the controlKeepAliveTimeout duration.
188      *
189      * @param options The FileSystem options
190      * @return The controlKeepAliveTimeout duration.
191      * @since 2.8.0
192      */
193     public Duration getControlKeepAliveTimeout(final FileSystemOptions options) {
194         return getDuration(options, CONTROL_KEEP_ALIVE_TIMEOUT);
195     }
196 
197     /**
198      * Gets timeout for opening the data channel in milliseconds.
199      *
200      * @param options The FileSystemOptions.
201      * @return The timeout for opening the data channel in milliseconds.
202      * @see #setDataTimeout
203      * @deprecated Use {@link #getDataTimeoutDuration(FileSystemOptions)}.
204      */
205     @Deprecated
206     public Integer getDataTimeout(final FileSystemOptions options) {
207         return getDurationInteger(options, DATA_TIMEOUT);
208     }
209 
210     /**
211      * Gets the timeout for opening the data channel.
212      *
213      * @param options The FileSystemOptions.
214      * @return The timeout for opening the data channel.
215      * @see #setDataTimeout
216      * @since 2.8.0
217      */
218     public Duration getDataTimeoutDuration(final FileSystemOptions options) {
219         return getDuration(options, DATA_TIMEOUT);
220     }
221 
222     /**
223      * Gets the default date format used by the server. See {@link org.apache.commons.net.ftp.FTPClientConfig} for
224      * details and examples.
225      *
226      * @param options The FileSystemOptions
227      * @return The default date format.
228      */
229     public String getDefaultDateFormat(final FileSystemOptions options) {
230         return getString(options, DEFAULT_DATE_FORMAT);
231     }
232 
233     /**
234      * Gets the key to the EntryParser.
235      *
236      * @param options The FileSystemOptions.
237      * @see #setEntryParser
238      * @return the key to the EntryParser.
239      */
240     public String getEntryParser(final FileSystemOptions options) {
241         return getString(options, FACTORY_KEY);
242     }
243 
244     /**
245      * Gets the FTPFileEntryParserFactory parameter.
246      *
247      * @param options The FileSystemOptions.
248      * @see #setEntryParserFactory
249      * @return The FTPFileEntryParserFactory parameter.
250      */
251     public FTPFileEntryParserFactory getEntryParserFactory(final FileSystemOptions options) {
252         return getParam(options, FTPFileEntryParserFactory.class.getName());
253     }
254 
255     /**
256      * Gets the file type parameter.
257      *
258      * @param options The FileSystemOptions.
259      * @return A FtpFileType
260      * @since 2.1
261      */
262     public FtpFileType getFileType(final FileSystemOptions options) {
263         return getEnum(FtpFileType.class, options, FILE_TYPE);
264     }
265 
266     /**
267      * Gets the option to use FTP MDTM for {@link FileContent#getLastModifiedTime()}.
268      *
269      * @param options The FileSystemOptions.
270      * @return true if MDTM should be used.
271      * @since 2.8.0
272      */
273     public Boolean getMdtmLastModifiedTime(final FileSystemOptions options) {
274         return getBoolean(options, MDTM_LAST_MODIFED_TIME);
275     }
276 
277     /**
278      * Tests whether passive mode is set.
279      *
280      * @param options The FileSystemOptions.
281      * @return whether passive mode is set.
282      * @see #setPassiveMode
283      */
284     public Boolean getPassiveMode(final FileSystemOptions options) {
285         return getBoolean(options, PASSIVE_MODE);
286     }
287 
288     /**
289      * Gets the Proxy.
290      *
291      * @param options The FileSystemOptions.
292      * @return the Proxy
293      * @since 2.1
294      */
295     public Proxy getProxy(final FileSystemOptions options) {
296         return getParam(options, PROXY);
297     }
298 
299     /**
300      * See {@link org.apache.commons.net.ftp.FTPClientConfig} for details and examples.
301      *
302      * @param options The FileSystemOptions.
303      * @return The recent date format.
304      */
305     public String getRecentDateFormat(final FileSystemOptions options) {
306         return getString(options, RECENT_DATE_FORMAT);
307     }
308 
309     /**
310      * Gets whether to use remote verification.
311      *
312      * @param options The FileSystemOptions.
313      * @return True if remote verification should be done.
314      */
315     public Boolean getRemoteVerification(final FileSystemOptions options) {
316         return getBoolean(options, REMOTE_VERIFICATION);
317     }
318 
319     /**
320      * Gets the language code used by the server. See {@link org.apache.commons.net.ftp.FTPClientConfig} for details and
321      * examples.
322      *
323      * @param options The FilesystemOptions.
324      * @return The language code of the server.
325      */
326     public String getServerLanguageCode(final FileSystemOptions options) {
327         return getString(options, SERVER_LANGUAGE_CODE);
328     }
329 
330     /**
331      * See {@link org.apache.commons.net.ftp.FTPClientConfig} for details and examples.
332      *
333      * @param options The FileSystemOptions.
334      * @return The server timezone id.
335      */
336     public String getServerTimeZoneId(final FileSystemOptions options) {
337         return getString(options, SERVER_TIME_ZONE_ID);
338     }
339 
340     /**
341      * See {@link org.apache.commons.net.ftp.FTPClientConfig} for details and examples.
342      *
343      * @param options The FileSystemOptions.
344      * @return An array of short month names.
345      */
346     public String[] getShortMonthNames(final FileSystemOptions options) {
347         return getParam(options, SHORT_MONTH_NAMES);
348     }
349 
350     /**
351      * Gets The so timeout duration in milliseconds.
352      *
353      * @param options The FileSystem options.
354      * @return The so timeout duration in milliseconds.
355      * @see #getDataTimeout
356      * @since 2.0
357      * @deprecated Use {@link #getSoTimeoutDuration(FileSystemOptions)}.
358      */
359     @Deprecated
360     public Integer getSoTimeout(final FileSystemOptions options) {
361         return getDurationInteger(options, SO_TIMEOUT);
362     }
363 
364     /**
365      * Gets The so timeout duration.
366      *
367      * @param options The FileSystem options.
368      * @return The timeout value in milliseconds.
369      * @see #getDataTimeout
370      * @since 2.8.0
371      */
372     public Duration getSoTimeoutDuration(final FileSystemOptions options) {
373         return getDuration(options, SO_TIMEOUT);
374     }
375 
376     /**
377      * Gets the list of reply codes (apart from 200) that are considered as OK when prematurely closing a stream.
378      *
379      * @param options The FileSystem options.
380      * @return The list of reply codes (apart from 200) that are considered as OK when prematurely closing a stream.
381      * @since 2.4
382      */
383     public List<Integer> getTransferAbortedOkReplyCodes(final FileSystemOptions options) {
384         return getParam(options, TRANSFER_ABORTED_OK_REPLY_CODES);
385     }
386 
387     /**
388      * Tests whether if VFS should treat the user directory as the root directory. Defaults to
389      * {@code Boolean.TRUE} if the method {@link #setUserDirIsRoot(FileSystemOptions, boolean)} has not been
390      * invoked.
391      *
392      * @param options The FileSystemOptions.
393      * @return {@code Boolean.TRUE} if VFS treats the user directory as the root directory.
394      * @see #setUserDirIsRoot
395      */
396     public Boolean getUserDirIsRoot(final FileSystemOptions options) {
397         return getBoolean(options, USER_DIR_IS_ROOT, Boolean.TRUE);
398     }
399 
400     /**
401      * Sets the active port range.
402      *
403      * @param options   The FileSystemOptions.
404      * @param portRange the Range of active ports
405      * @since 2.10.0
406      */
407     public void setActivePortRange(final FileSystemOptions options, final Range<Integer> portRange) {
408         setParam(options, ACTIVE_PORT_RANGE, portRange);
409     }
410 
411     /**
412      * Sets whether to try to autodetect the server encoding (only UTF8 is supported).
413      *
414      * @param options The FileSystemOptions.
415      * @param autodetectUTF8 true if autodetection should be done.
416      * @since 2.4
417      */
418     public void setAutodetectUtf8(final FileSystemOptions options, final Boolean autodetectUTF8) {
419         setParam(options, AUTODETECT_UTF8, autodetectUTF8);
420     }
421 
422     /**
423      * Sets the timeout for the initial control connection.
424      * <p>
425      * If you set the connectTimeout to {@code null} no connectTimeout will be set.
426      * </p>
427      *
428      * @param options The FileSystemOptions.
429      * @param duration the timeout duration in milliseconds
430      * @since 2.8.0
431      */
432     public void setConnectTimeout(final FileSystemOptions options, final Duration duration) {
433         setParam(options, CONNECT_TIMEOUT, duration);
434     }
435 
436     /**
437      * Sets the timeout for the initial control connection.
438      * <p>
439      * If you set the connectTimeout to {@code null} no connectTimeout will be set.
440      * </p>
441      *
442      * @param options The FileSystemOptions.
443      * @param duration the timeout duration.
444      * @since 2.1
445      * @deprecated Use {@link #setConnectTimeout(FileSystemOptions, Duration)}.
446      */
447     @Deprecated
448     public void setConnectTimeout(final FileSystemOptions options, final Integer duration) {
449         setConnectTimeout(options, Duration.ofMillis(duration));
450     }
451 
452     /**
453      * See {@link org.apache.commons.net.ftp.FTP#setControlEncoding} for details and examples.
454      *
455      * @param options The FileSystemOptions.
456      * @param encoding the encoding to use
457      * @since 2.11.0
458      */
459     public void setControlEncoding(final FileSystemOptions options, final Charset encoding) {
460         setParam(options, ENCODING, encoding);
461     }
462 
463     /**
464      * See {@link org.apache.commons.net.ftp.FTP#setControlEncoding} for details and examples.
465      *
466      * @param options The FileSystemOptions.
467      * @param encoding the encoding to use
468      * @since 2.0
469      * @deprecated Use {@link #setControlEncoding(FileSystemOptions, Charset)}.
470      */
471     @Deprecated
472     public void setControlEncoding(final FileSystemOptions options, final String encoding) {
473         setParam(options, ENCODING, encoding);
474     }
475 
476     /**
477      * Sets the control keep alive reply timeout for the FTP client.
478      *
479      * @param options The FileSystem options.
480      * @param duration timeout duration.
481      * @since 2.8.0
482      */
483     public void setControlKeepAliveReplyTimeout(final FileSystemOptions options, final Duration duration) {
484         setParam(options, CONTROL_KEEP_ALIVE_REPLY_TIMEOUT, duration);
485     }
486 
487     /**
488      * Sets the control keep alive timeout for the FTP client.
489      * <p>
490      * Sets the {@code controlKeepAliveTimeout} to ensure the socket be alive after download huge file.
491      * </p>
492      *
493      * @param options The FileSystem options.
494      * @param duration The timeout duration.
495      * @since 2.8.0
496      */
497     public void setControlKeepAliveTimeout(final FileSystemOptions options, final Duration duration) {
498         setParam(options, CONTROL_KEEP_ALIVE_TIMEOUT, duration);
499     }
500 
501     /**
502      * Sets the data timeout for the FTP client.
503      * <p>
504      * If you set the {@code dataTimeout} to {@code null}, no dataTimeout will be set on the FTP client.
505      * </p>
506      *
507      * @param options The FileSystemOptions.
508      * @param duration The timeout duration.
509      * @since 2.8.0
510      */
511     public void setDataTimeout(final FileSystemOptions options, final Duration duration) {
512         setParam(options, DATA_TIMEOUT, duration);
513     }
514 
515     /**
516      * Sets the data timeout for the FTP client.
517      * <p>
518      * If you set the {@code dataTimeout} to {@code null}, no dataTimeout will be set on the FTP client.
519      * </p>
520      *
521      * @param options The FileSystemOptions.
522      * @param duration The timeout value.
523      * @deprecated Use {@link #setDataTimeout(FileSystemOptions, Duration)}.
524      */
525     @Deprecated
526     public void setDataTimeout(final FileSystemOptions options, final Integer duration) {
527         setDataTimeout(options, Duration.ofMillis(duration));
528     }
529 
530     /**
531      * Sets the default date format used by the server. See {@link org.apache.commons.net.ftp.FTPClientConfig} for
532      * details and examples.
533      *
534      * @param options The FileSystemOptions.
535      * @param defaultDateFormat The default date format.
536      */
537     public void setDefaultDateFormat(final FileSystemOptions options, final String defaultDateFormat) {
538         setParam(options, DEFAULT_DATE_FORMAT, defaultDateFormat);
539     }
540 
541     /**
542      * Sets the FQCN of your FileEntryParser used to parse the directory listing from your server.
543      * <p>
544      * If you do not use the default commons-net FTPFileEntryParserFactory e.g. by using {@link #setEntryParserFactory}
545      * this is the "key" parameter passed as argument into your custom factory.
546      * </p>
547      *
548      * @param options The FileSystemOptions.
549      * @param key The key.
550      */
551     public void setEntryParser(final FileSystemOptions options, final String key) {
552         setParam(options, FACTORY_KEY, key);
553     }
554 
555     /**
556      * FTPFileEntryParserFactory which will be used for ftp-entry parsing.
557      *
558      * @param options The FileSystemOptions.
559      * @param factory instance of your factory
560      */
561     public void setEntryParserFactory(final FileSystemOptions options, final FTPFileEntryParserFactory factory) {
562         setParam(options, FTPFileEntryParserFactory.class.getName(), factory);
563     }
564 
565     /**
566      * Sets the file type parameter.
567      *
568      * @param options The FileSystemOptions.
569      * @param ftpFileType A FtpFileType
570      * @since 2.1
571      */
572     public void setFileType(final FileSystemOptions options, final FtpFileType ftpFileType) {
573         setParam(options, FILE_TYPE, ftpFileType);
574     }
575 
576     /**
577      * Sets the option to use FTP MDTM for {@link FileContent#getLastModifiedTime()}.
578      *
579      * @param options The FileSystemOptions.
580      * @param mdtm true if MDTM should be used.
581      * @since 2.8.0
582      */
583     public void setMdtmLastModifiedTime(final FileSystemOptions options, final boolean mdtm) {
584         setParam(options, MDTM_LAST_MODIFED_TIME, toBooleanObject(mdtm));
585     }
586 
587     /**
588      * Enter into passive mode.
589      *
590      * @param options The FileSystemOptions.
591      * @param passiveMode true if passive mode should be used.
592      */
593     public void setPassiveMode(final FileSystemOptions options, final boolean passiveMode) {
594         setParam(options, PASSIVE_MODE, toBooleanObject(passiveMode));
595     }
596 
597     /**
598      * Sets the Proxy.
599      * <p>
600      * You might need to make sure that {@link #setPassiveMode(FileSystemOptions, boolean) passive mode} is activated.
601      * </p>
602      *
603      * @param options the FileSystem options.
604      * @param proxy the Proxy
605      * @since 2.1
606      */
607     public void setProxy(final FileSystemOptions options, final Proxy proxy) {
608         setParam(options, PROXY, proxy);
609     }
610 
611     /**
612      * See {@link org.apache.commons.net.ftp.FTPClientConfig} for details and examples.
613      *
614      * @param options The FileSystemOptions.
615      * @param recentDateFormat The recent date format.
616      */
617     public void setRecentDateFormat(final FileSystemOptions options, final String recentDateFormat) {
618         setParam(options, RECENT_DATE_FORMAT, recentDateFormat);
619     }
620 
621     /**
622      * Sets whether to use remote verification.
623      *
624      * @param options The FileSystemOptions.
625      * @param remoteVerification True if verification should be done.
626      */
627     public void setRemoteVerification(final FileSystemOptions options, final boolean remoteVerification) {
628         setParam(options, REMOTE_VERIFICATION, remoteVerification);
629     }
630 
631     /**
632      * Sets the language code used by the server. See {@link org.apache.commons.net.ftp.FTPClientConfig} for details and
633      * examples.
634      *
635      * @param options The FileSystemOptions.
636      * @param serverLanguageCode The servers language code.
637      */
638     public void setServerLanguageCode(final FileSystemOptions options, final String serverLanguageCode) {
639         setParam(options, SERVER_LANGUAGE_CODE, serverLanguageCode);
640     }
641 
642     /**
643      * See {@link org.apache.commons.net.ftp.FTPClientConfig} for details and examples.
644      *
645      * @param options The FileSystemOptions.
646      * @param serverTimeZoneId The server timezone id.
647      */
648     public void setServerTimeZoneId(final FileSystemOptions options, final String serverTimeZoneId) {
649         setParam(options, SERVER_TIME_ZONE_ID, serverTimeZoneId);
650     }
651 
652     /**
653      * See {@link org.apache.commons.net.ftp.FTPClientConfig} for details and examples.
654      *
655      * @param options The FileSystemOptions.
656      * @param shortMonthNames an array of short month name Strings.
657      */
658     public void setShortMonthNames(final FileSystemOptions options, final String[] shortMonthNames) {
659         String[] clone = null;
660         if (shortMonthNames != null) {
661             clone = Arrays.copyOf(shortMonthNames, shortMonthNames.length);
662         }
663 
664         setParam(options, SHORT_MONTH_NAMES, clone);
665     }
666 
667     /**
668      * Sets the socket timeout for the FTP client.
669      * <p>
670      * If you set the {@code soTimeout} to {@code null}, no socket timeout will be set on the FTP client.
671      * </p>
672      *
673      * @param options The FileSystem options.
674      * @param timeout The timeout value in milliseconds.
675      * @since 2.8.0
676      */
677     public void setSoTimeout(final FileSystemOptions options, final Duration timeout) {
678         setParam(options, SO_TIMEOUT, timeout);
679     }
680 
681     /**
682      * Sets the socket timeout for the FTP client.
683      * <p>
684      * If you set the {@code soTimeout} to {@code null}, no socket timeout will be set on the FTP client.
685      * </p>
686      *
687      * @param options The FileSystem options.
688      * @param timeout The timeout value in milliseconds.
689      * @since 2.0
690      * @deprecated Use {@link #setSoTimeout(FileSystemOptions, Duration)}.
691      */
692     @Deprecated
693     public void setSoTimeout(final FileSystemOptions options, final Integer timeout) {
694         setSoTimeout(options, Duration.ofMillis(timeout));
695     }
696 
697     /**
698      * Sets the list of reply codes that are considered as OK when prematurely closing a stream.
699      * <p>
700      * If you set the {@code replyCodes} to an empty list, all reply codes besides 200 will be
701      * considered as an error.
702      * </p>
703      *
704      * @param options The FileSystem options.
705      * @param replyCodes The reply codes.
706      * @since 2.4
707      */
708     public void setTransferAbortedOkReplyCodes(final FileSystemOptions options, final List<Integer> replyCodes) {
709         setParam(options, TRANSFER_ABORTED_OK_REPLY_CODES, replyCodes);
710     }
711 
712     /**
713      * Use user directory as root (do not change to fs root).
714      *
715      * @param options The FileSystemOptions.
716      * @param userDirIsRoot true if the user directory should be treated as the root.
717      */
718     public void setUserDirIsRoot(final FileSystemOptions options, final boolean userDirIsRoot) {
719         setParam(options, USER_DIR_IS_ROOT, toBooleanObject(userDirIsRoot));
720     }
721 }