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 018package org.apache.commons.net.ftp; 019 020import java.text.DateFormatSymbols; 021import java.util.Collection; 022import java.util.Locale; 023import java.util.Map; 024import java.util.StringTokenizer; 025import java.util.TreeMap; 026 027/** 028 * <p> 029 * This class implements an alternate means of configuring the 030 * {@link org.apache.commons.net.ftp.FTPClient FTPClient} object and 031 * also subordinate objects which it uses. Any class implementing the 032 * {@link org.apache.commons.net.ftp.Configurable Configurable } 033 * interface can be configured by this object. 034 * </p><p> 035 * In particular this class was designed primarily to support configuration 036 * of FTP servers which express file timestamps in formats and languages 037 * other than those for the US locale, which although it is the most common 038 * is not universal. Unfortunately, nothing in the FTP spec allows this to 039 * be determined in an automated way, so manual configuration such as this 040 * is necessary. 041 * </p><p> 042 * This functionality was designed to allow existing clients to work exactly 043 * as before without requiring use of this component. This component should 044 * only need to be explicitly invoked by the user of this package for problem 045 * cases that previous implementations could not solve. 046 * </p> 047 * <h2>Examples of use of FTPClientConfig</h2> 048 * Use cases: 049 * You are trying to access a server that 050 * <ul> 051 * <li>lists files with timestamps that use month names in languages other 052 * than English</li> 053 * <li>lists files with timestamps that use date formats other 054 * than the American English "standard" <code>MM dd yyyy</code></li> 055 * <li>is in different time zone and you need accurate timestamps for 056 * dependency checking as in Ant</li> 057 * </ul> 058 * <p> 059 * Unpaged (whole list) access on a UNIX server that uses French month names 060 * but uses the "standard" <code>MMM d yyyy</code> date formatting 061 * <pre> 062 * FTPClient f=FTPClient(); 063 * FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX); 064 * conf.setServerLanguageCode("fr"); 065 * f.configure(conf); 066 * f.connect(server); 067 * f.login(username, password); 068 * FTPFile[] files = listFiles(directory); 069 * </pre> 070 * <p> 071 * Paged access on a UNIX server that uses Danish month names 072 * and "European" date formatting in Denmark's time zone, when you 073 * are in some other time zone. 074 * <pre> 075 * FTPClient f=FTPClient(); 076 * FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX); 077 * conf.setServerLanguageCode("da"); 078 * conf.setDefaultDateFormat("d MMM yyyy"); 079 * conf.setRecentDateFormat("d MMM HH:mm"); 080 * conf.setTimeZoneId("Europe/Copenhagen"); 081 * f.configure(conf); 082 * f.connect(server); 083 * f.login(username, password); 084 * FTPListParseEngine engine = 085 * f.initiateListParsing("com.whatever.YourOwnParser", directory); 086 * 087 * while (engine.hasNext()) { 088 * FTPFile[] files = engine.getNext(25); // "page size" you want 089 * //do whatever you want with these files, display them, etc. 090 * //expensive FTPFile objects not created until needed. 091 * } 092 * </pre> 093 * <p> 094 * Unpaged (whole list) access on a VMS server that uses month names 095 * in a language not {@link #getSupportedLanguageCodes() supported} by the system. 096 * but uses the "standard" <code>MMM d yyyy</code> date formatting 097 * <pre> 098 * FTPClient f=FTPClient(); 099 * FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_VMS); 100 * conf.setShortMonthNames( 101 * "jan|feb|mar|apr|ma\u00ED|j\u00FAn|j\u00FAl|\u00e1g\u00FA|sep|okt|n\u00F3v|des"); 102 * f.configure(conf); 103 * f.connect(server); 104 * f.login(username, password); 105 * FTPFile[] files = listFiles(directory); 106 * </pre> 107 * <p> 108 * Unpaged (whole list) access on a Windows-NT server in a different time zone. 109 * (Note, since the NT Format uses numeric date formatting, language issues 110 * are irrelevant here). 111 * <pre> 112 * FTPClient f=FTPClient(); 113 * FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT); 114 * conf.setTimeZoneId("America/Denver"); 115 * f.configure(conf); 116 * f.connect(server); 117 * f.login(username, password); 118 * FTPFile[] files = listFiles(directory); 119 * </pre> 120 * Unpaged (whole list) access on a Windows-NT server in a different time zone 121 * but which has been configured to use a unix-style listing format. 122 * <pre> 123 * FTPClient f=FTPClient(); 124 * FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX); 125 * conf.setTimeZoneId("America/Denver"); 126 * f.configure(conf); 127 * f.connect(server); 128 * f.login(username, password); 129 * FTPFile[] files = listFiles(directory); 130 * </pre> 131 * 132 * @since 1.4 133 * @see org.apache.commons.net.ftp.Configurable 134 * @see org.apache.commons.net.ftp.FTPClient 135 * @see org.apache.commons.net.ftp.parser.FTPTimestampParserImpl#configure(FTPClientConfig) 136 * @see org.apache.commons.net.ftp.parser.ConfigurableFTPFileEntryParserImpl 137 */ 138public class FTPClientConfig 139{ 140 141 /** 142 * Identifier by which a unix-based ftp server is known throughout 143 * the commons-net ftp system. 144 */ 145 public static final String SYST_UNIX = "UNIX"; 146 147 /** 148 * Identifier for alternate UNIX parser; same as {@link #SYST_UNIX} but leading spaces are 149 * trimmed from file names. This is to maintain backwards compatibility with 150 * the original behavior of the parser which ignored multiple spaces between the date 151 * and the start of the file name. 152 * @since 3.4 153 */ 154 public static final String SYST_UNIX_TRIM_LEADING = "UNIX_LTRIM"; 155 156 /** 157 * Identifier by which a vms-based ftp server is known throughout 158 * the commons-net ftp system. 159 */ 160 public static final String SYST_VMS = "VMS"; 161 162 /** 163 * Identifier by which a WindowsNT-based ftp server is known throughout 164 * the commons-net ftp system. 165 */ 166 public static final String SYST_NT = "WINDOWS"; 167 168 /** 169 * Identifier by which an OS/2-based ftp server is known throughout 170 * the commons-net ftp system. 171 */ 172 public static final String SYST_OS2 = "OS/2"; 173 174 /** 175 * Identifier by which an OS/400-based ftp server is known throughout 176 * the commons-net ftp system. 177 */ 178 public static final String SYST_OS400 = "OS/400"; 179 180 /** 181 * Identifier by which an AS/400-based ftp server is known throughout 182 * the commons-net ftp system. 183 */ 184 public static final String SYST_AS400 = "AS/400"; 185 186 /** 187 * Identifier by which an MVS-based ftp server is known throughout 188 * the commons-net ftp system. 189 */ 190 public static final String SYST_MVS = "MVS"; 191 192 /** 193 * Some servers return an "UNKNOWN Type: L8" message 194 * in response to the SYST command. We set these to be a Unix-type system. 195 * This may happen if the ftpd in question was compiled without system 196 * information. 197 * 198 * NET-230 - Updated to be UPPERCASE so that the check done in 199 * createFileEntryParser will succeed. 200 * 201 * @since 1.5 202 */ 203 public static final String SYST_L8 = "TYPE: L8"; 204 205 /** 206 * Identifier by which an Netware-based ftp server is known throughout 207 * the commons-net ftp system. 208 * 209 * @since 1.5 210 */ 211 public static final String SYST_NETWARE = "NETWARE"; 212 213 /** 214 * Identifier by which a Mac pre OS-X -based ftp server is known throughout 215 * the commons-net ftp system. 216 * 217 * @since 3.1 218 */ 219 // Full string is "MACOS Peter's Server"; the substring below should be enough 220 public static final String SYST_MACOS_PETER = "MACOS PETER"; // NET-436 221 222 private final String serverSystemKey; 223 private String defaultDateFormatStr; 224 private String recentDateFormatStr; 225 private boolean lenientFutureDates = true; // NET-407 226 private String serverLanguageCode; 227 private String shortMonthNames; 228 private String serverTimeZoneId; 229 private boolean saveUnparseableEntries; 230 231 232 /** 233 * The main constructor for an FTPClientConfig object 234 * @param systemKey key representing system type of the server being 235 * connected to. See {@link #getServerSystemKey() serverSystemKey} 236 * If set to the empty string, then FTPClient uses the system type returned by the server. 237 * However this is not recommended for general use; 238 * the correct system type should be set if it is known. 239 */ 240 public FTPClientConfig(final String systemKey) { 241 this.serverSystemKey = systemKey; 242 } 243 244 /** 245 * Convenience constructor mainly for use in testing. 246 * Constructs a UNIX configuration. 247 */ 248 public FTPClientConfig() { 249 this(SYST_UNIX); 250 } 251 252 /** 253 * Constructor which allows setting of the format string member fields 254 * @param systemKey key representing system type of the server being 255 * connected to. See 256 * {@link #getServerSystemKey() serverSystemKey} 257 * @param defaultDateFormatStr See 258 * {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} 259 * @param recentDateFormatStr See 260 * {@link #setRecentDateFormatStr(String) recentDateFormatStr} 261 * @since 3.6 262 */ 263 public FTPClientConfig(final String systemKey, 264 final String defaultDateFormatStr, 265 final String recentDateFormatStr) 266 { 267 this(systemKey); 268 this.defaultDateFormatStr = defaultDateFormatStr; 269 this.recentDateFormatStr = recentDateFormatStr; 270 } 271 272 /** 273 * Constructor which allows setting of most member fields 274 * @param systemKey key representing system type of the server being 275 * connected to. See 276 * {@link #getServerSystemKey() serverSystemKey} 277 * @param defaultDateFormatStr See 278 * {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} 279 * @param recentDateFormatStr See 280 * {@link #setRecentDateFormatStr(String) recentDateFormatStr} 281 * @param serverLanguageCode See 282 * {@link #setServerLanguageCode(String) serverLanguageCode} 283 * @param shortMonthNames See 284 * {@link #setShortMonthNames(String) shortMonthNames} 285 * @param serverTimeZoneId See 286 * {@link #setServerTimeZoneId(String) serverTimeZoneId} 287 */ 288 public FTPClientConfig(final String systemKey, 289 final String defaultDateFormatStr, 290 final String recentDateFormatStr, 291 final String serverLanguageCode, 292 final String shortMonthNames, 293 final String serverTimeZoneId) 294 { 295 this(systemKey); 296 this.defaultDateFormatStr = defaultDateFormatStr; 297 this.recentDateFormatStr = recentDateFormatStr; 298 this.serverLanguageCode = serverLanguageCode; 299 this.shortMonthNames = shortMonthNames; 300 this.serverTimeZoneId = serverTimeZoneId; 301 } 302 303 /** 304 * Constructor which allows setting of all member fields 305 * @param systemKey key representing system type of the server being 306 * connected to. See 307 * {@link #getServerSystemKey() serverSystemKey} 308 * @param defaultDateFormatStr See 309 * {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} 310 * @param recentDateFormatStr See 311 * {@link #setRecentDateFormatStr(String) recentDateFormatStr} 312 * @param serverLanguageCode See 313 * {@link #setServerLanguageCode(String) serverLanguageCode} 314 * @param shortMonthNames See 315 * {@link #setShortMonthNames(String) shortMonthNames} 316 * @param serverTimeZoneId See 317 * {@link #setServerTimeZoneId(String) serverTimeZoneId} 318 * @param lenientFutureDates See 319 * {@link #setLenientFutureDates(boolean) lenientFutureDates} 320 * @param saveUnparseableEntries See 321 * {@link #setUnparseableEntries(boolean) saveUnparseableEntries} 322 */ 323 public FTPClientConfig(final String systemKey, 324 final String defaultDateFormatStr, 325 final String recentDateFormatStr, 326 final String serverLanguageCode, 327 final String shortMonthNames, 328 final String serverTimeZoneId, 329 final boolean lenientFutureDates, 330 final boolean saveUnparseableEntries) 331 { 332 this(systemKey); 333 this.defaultDateFormatStr = defaultDateFormatStr; 334 this.lenientFutureDates = lenientFutureDates; 335 this.recentDateFormatStr = recentDateFormatStr; 336 this.saveUnparseableEntries = saveUnparseableEntries; 337 this.serverLanguageCode = serverLanguageCode; 338 this.shortMonthNames = shortMonthNames; 339 this.serverTimeZoneId = serverTimeZoneId; 340 } 341 342 // Copy constructor, intended for use by FTPClient only 343 FTPClientConfig(final String systemKey, final FTPClientConfig config) { 344 this.serverSystemKey = systemKey; 345 this.defaultDateFormatStr = config.defaultDateFormatStr; 346 this.lenientFutureDates = config.lenientFutureDates; 347 this.recentDateFormatStr = config.recentDateFormatStr; 348 this.saveUnparseableEntries = config.saveUnparseableEntries; 349 this.serverLanguageCode = config.serverLanguageCode; 350 this.serverTimeZoneId = config.serverTimeZoneId; 351 this.shortMonthNames = config.shortMonthNames; 352 } 353 354 /** 355 * Copy constructor 356 * @param config source 357 * @since 3.6 358 */ 359 public FTPClientConfig(final FTPClientConfig config) { 360 this.serverSystemKey = config.serverSystemKey; 361 this.defaultDateFormatStr = config.defaultDateFormatStr; 362 this.lenientFutureDates = config.lenientFutureDates; 363 this.recentDateFormatStr = config.recentDateFormatStr; 364 this.saveUnparseableEntries = config.saveUnparseableEntries; 365 this.serverLanguageCode = config.serverLanguageCode; 366 this.serverTimeZoneId = config.serverTimeZoneId; 367 this.shortMonthNames = config.shortMonthNames; 368 } 369 370 private static final Map<String, Object> LANGUAGE_CODE_MAP = new TreeMap<>(); 371 static { 372 373 // if there are other commonly used month name encodings which 374 // correspond to particular locales, please add them here. 375 376 377 378 // many locales code short names for months as all three letters 379 // these we handle simply. 380 LANGUAGE_CODE_MAP.put("en", Locale.ENGLISH); 381 LANGUAGE_CODE_MAP.put("de",Locale.GERMAN); 382 LANGUAGE_CODE_MAP.put("it",Locale.ITALIAN); 383 LANGUAGE_CODE_MAP.put("es", new Locale("es", "", "")); // spanish 384 LANGUAGE_CODE_MAP.put("pt", new Locale("pt", "", "")); // portuguese 385 LANGUAGE_CODE_MAP.put("da", new Locale("da", "", "")); // danish 386 LANGUAGE_CODE_MAP.put("sv", new Locale("sv", "", "")); // swedish 387 LANGUAGE_CODE_MAP.put("no", new Locale("no", "", "")); // norwegian 388 LANGUAGE_CODE_MAP.put("nl", new Locale("nl", "", "")); // dutch 389 LANGUAGE_CODE_MAP.put("ro", new Locale("ro", "", "")); // romanian 390 LANGUAGE_CODE_MAP.put("sq", new Locale("sq", "", "")); // albanian 391 LANGUAGE_CODE_MAP.put("sh", new Locale("sh", "", "")); // serbo-croatian 392 LANGUAGE_CODE_MAP.put("sk", new Locale("sk", "", "")); // slovak 393 LANGUAGE_CODE_MAP.put("sl", new Locale("sl", "", "")); // slovenian 394 395 396 // some don't 397 LANGUAGE_CODE_MAP.put("fr", 398 "jan|f\u00e9v|mar|avr|mai|jun|jui|ao\u00fb|sep|oct|nov|d\u00e9c"); //french 399 400 } 401 402 /** 403 * Getter for the serverSystemKey property. This property 404 * specifies the general type of server to which the client connects. 405 * Should be either one of the <code>FTPClientConfig.SYST_*</code> codes 406 * or else the fully qualified class name of a parser implementing both 407 * the <code>FTPFileEntryParser</code> and <code>Configurable</code> 408 * interfaces. 409 * @return Returns the serverSystemKey property. 410 */ 411 public String getServerSystemKey() { 412 return serverSystemKey; 413 } 414 415 /** 416 * getter for the {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} 417 * property. 418 * @return Returns the defaultDateFormatStr property. 419 */ 420 public String getDefaultDateFormatStr() { 421 return defaultDateFormatStr; 422 } 423 424 /** 425 * getter for the {@link #setRecentDateFormatStr(String) recentDateFormatStr} property. 426 * @return Returns the recentDateFormatStr property. 427 */ 428 429 public String getRecentDateFormatStr() { 430 return recentDateFormatStr; 431 } 432 433 /** 434 * getter for the {@link #setServerTimeZoneId(String) serverTimeZoneId} property. 435 * @return Returns the serverTimeZoneId property. 436 */ 437 public String getServerTimeZoneId() { 438 return serverTimeZoneId; 439 } 440 441 /** 442 * <p> 443 * getter for the {@link #setShortMonthNames(String) shortMonthNames} 444 * property. 445 * </p> 446 * @return Returns the shortMonthNames. 447 */ 448 public String getShortMonthNames() { 449 return shortMonthNames; 450 } 451 452 /** 453 * <p> 454 * getter for the {@link #setServerLanguageCode(String) serverLanguageCode} property. 455 * </p> 456 * @return Returns the serverLanguageCode property. 457 */ 458 public String getServerLanguageCode() { 459 return serverLanguageCode; 460 } 461 462 /** 463 * <p> 464 * getter for the {@link #setLenientFutureDates(boolean) lenientFutureDates} property. 465 * </p> 466 * @return Returns the lenientFutureDates (default true). 467 * @since 1.5 468 */ 469 public boolean isLenientFutureDates() { 470 return lenientFutureDates; 471 } 472 /** 473 * <p> 474 * setter for the defaultDateFormatStr property. This property 475 * specifies the main date format that will be used by a parser configured 476 * by this configuration to parse file timestamps. If this is not 477 * specified, such a parser will use as a default value, the most commonly 478 * used format which will be in as used in <code>en_US</code> locales. 479 * </p><p> 480 * This should be in the format described for 481 * <code>java.text.SimpleDateFormat</code>. 482 * property. 483 * </p> 484 * @param defaultDateFormatStr The defaultDateFormatStr to set. 485 */ 486 public void setDefaultDateFormatStr(final String defaultDateFormatStr) { 487 this.defaultDateFormatStr = defaultDateFormatStr; 488 } 489 490 /** 491 * <p> 492 * setter for the recentDateFormatStr property. This property 493 * specifies a secondary date format that will be used by a parser 494 * configured by this configuration to parse file timestamps, typically 495 * those less than a year old. If this is not specified, such a parser 496 * will not attempt to parse using an alternate format. 497 * </p> 498 * <p> 499 * This is used primarily in unix-based systems. 500 * </p> 501 * <p> 502 * This should be in the format described for 503 * <code>java.text.SimpleDateFormat</code>. 504 * </p> 505 * @param recentDateFormatStr The recentDateFormatStr to set. 506 */ 507 public void setRecentDateFormatStr(final String recentDateFormatStr) { 508 this.recentDateFormatStr = recentDateFormatStr; 509 } 510 511 /** 512 * <p> 513 * setter for the lenientFutureDates property. This boolean property 514 * (default: true) only has meaning when a 515 * {@link #setRecentDateFormatStr(String) recentDateFormatStr} property 516 * has been set. In that case, if this property is set true, then the 517 * parser, when it encounters a listing parseable with the recent date 518 * format, will only consider a date to belong to the previous year if 519 * it is more than one day in the future. This will allow all 520 * out-of-synch situations (whether based on "slop" - i.e. servers simply 521 * out of synch with one another or because of time zone differences - 522 * but in the latter case it is highly recommended to use the 523 * {@link #setServerTimeZoneId(String) serverTimeZoneId} property 524 * instead) to resolve correctly. 525 * </p><p> 526 * This is used primarily in unix-based systems. 527 * </p> 528 * @param lenientFutureDates set true to compensate for out-of-synch 529 * conditions. 530 */ 531 public void setLenientFutureDates(final boolean lenientFutureDates) { 532 this.lenientFutureDates = lenientFutureDates; 533 } 534 /** 535 * <p> 536 * setter for the serverTimeZoneId property. This property 537 * allows a time zone to be specified corresponding to that known to be 538 * used by an FTP server in file listings. This might be particularly 539 * useful to clients such as Ant that try to use these timestamps for 540 * dependency checking. 541 * </p><p> 542 * This should be one of the identifiers used by 543 * <code>java.util.TimeZone</code> to refer to time zones, for example, 544 * <code>America/Chicago</code> or <code>Asia/Rangoon</code>. 545 * </p> 546 * @param serverTimeZoneId The serverTimeZoneId to set. 547 */ 548 public void setServerTimeZoneId(final String serverTimeZoneId) { 549 this.serverTimeZoneId = serverTimeZoneId; 550 } 551 552 /** 553 * <p> 554 * setter for the shortMonthNames property. 555 * This property allows the user to specify a set of month names 556 * used by the server that is different from those that may be 557 * specified using the {@link #setServerLanguageCode(String) serverLanguageCode} 558 * property. 559 * </p><p> 560 * This should be a string containing twelve strings each composed of 561 * three characters, delimited by pipe (|) characters. Currently, 562 * only 8-bit ASCII characters are known to be supported. For example, 563 * a set of month names used by a hypothetical Icelandic FTP server might 564 * conceivably be specified as 565 * <code>"jan|feb|mar|apr|maí|jún|júl|ágú|sep|okt|nóv|des"</code>. 566 * </p> 567 * @param shortMonthNames The value to set to the shortMonthNames property. 568 */ 569 public void setShortMonthNames(final String shortMonthNames) { 570 this.shortMonthNames = shortMonthNames; 571 } 572 573 /** 574 * <p> 575 * setter for the serverLanguageCode property. This property allows 576 * user to specify a 577 * <a href="http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt"> 578 * two-letter ISO-639 language code</a> that will be used to 579 * configure the set of month names used by the file timestamp parser. 580 * If neither this nor the {@link #setShortMonthNames(String) shortMonthNames} 581 * is specified, parsing will assume English month names, which may or 582 * may not be significant, depending on whether the date format(s) 583 * specified via {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} 584 * and/or {@link #setRecentDateFormatStr(String) recentDateFormatStr} are using 585 * numeric or alphabetic month names. 586 * </p> 587 * <p>If the code supplied is not supported here, <code>en_US</code> 588 * month names will be used. We are supporting here those language 589 * codes which, when a <code> java.util.Locale</code> is constucted 590 * using it, and a <code>java.text.SimpleDateFormat</code> is 591 * constructed using that Locale, the array returned by the 592 * SimpleDateFormat's <code>getShortMonths()</code> method consists 593 * solely of three 8-bit ASCII character strings. Additionally, 594 * languages which do not meet this requirement are included if a 595 * common alternative set of short month names is known to be used. 596 * This means that users who can tell us of additional such encodings 597 * may get them added to the list of supported languages by contacting 598 * the Apache Commons Net team. 599 * </p> 600 * <p><strong> 601 * Please note that this attribute will NOT be used to determine a 602 * locale-based date format for the language. </strong> 603 * Experience has shown that many if not most FTP servers outside the 604 * United States employ the standard <code>en_US</code> date format 605 * orderings of <code>MMM d yyyy</code> and <code>MMM d HH:mm</code> 606 * and attempting to deduce this automatically here would cause more 607 * problems than it would solve. The date format must be changed 608 * via the {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} and/or 609 * {@link #setRecentDateFormatStr(String) recentDateFormatStr} parameters. 610 * </p> 611 * @param serverLanguageCode The value to set to the serverLanguageCode property. 612 */ 613 public void setServerLanguageCode(final String serverLanguageCode) { 614 this.serverLanguageCode = serverLanguageCode; 615 } 616 617 /** 618 * Looks up the supplied language code in the internally maintained table of 619 * language codes. Returns a DateFormatSymbols object configured with 620 * short month names corresponding to the code. If there is no corresponding 621 * entry in the table, the object returned will be that for 622 * <code>Locale.US</code> 623 * @param languageCode See {@link #setServerLanguageCode(String) serverLanguageCode} 624 * @return a DateFormatSymbols object configured with short month names 625 * corresponding to the supplied code, or with month names for 626 * <code>Locale.US</code> if there is no corresponding entry in the internal 627 * table. 628 */ 629 public static DateFormatSymbols lookupDateFormatSymbols(final String languageCode) 630 { 631 final Object lang = LANGUAGE_CODE_MAP.get(languageCode); 632 if (lang != null) { 633 if (lang instanceof Locale) { 634 return new DateFormatSymbols((Locale) lang); 635 } else if (lang instanceof String){ 636 return getDateFormatSymbols((String) lang); 637 } 638 } 639 return new DateFormatSymbols(Locale.US); 640 } 641 642 /** 643 * Returns a DateFormatSymbols object configured with short month names 644 * as in the supplied string 645 * @param shortmonths This should be as described in 646 * {@link #setShortMonthNames(String) shortMonthNames} 647 * @return a DateFormatSymbols object configured with short month names 648 * as in the supplied string 649 */ 650 public static DateFormatSymbols getDateFormatSymbols(final String shortmonths) 651 { 652 final String[] months = splitShortMonthString(shortmonths); 653 final DateFormatSymbols dfs = new DateFormatSymbols(Locale.US); 654 dfs.setShortMonths(months); 655 return dfs; 656 } 657 658 private static String[] splitShortMonthString(final String shortmonths) { 659 final StringTokenizer st = new StringTokenizer(shortmonths, "|"); 660 final int monthcnt = st.countTokens(); 661 if (12 != monthcnt) { 662 throw new IllegalArgumentException( 663 "expecting a pipe-delimited string containing 12 tokens"); 664 } 665 final String[] months = new String[13]; 666 int pos = 0; 667 while(st.hasMoreTokens()) { 668 months[pos++] = st.nextToken(); 669 } 670 months[pos]=""; 671 return months; 672 } 673 674 /** 675 * Returns a Collection of all the language codes currently supported 676 * by this class. See {@link #setServerLanguageCode(String) serverLanguageCode} 677 * for a functional descrption of language codes within this system. 678 * 679 * @return a Collection of all the language codes currently supported 680 * by this class 681 */ 682 public static Collection<String> getSupportedLanguageCodes() { 683 return LANGUAGE_CODE_MAP.keySet(); 684 } 685 686 /** 687 * Allow list parsing methods to create basic FTPFile entries if parsing fails. 688 * <p> 689 * In this case, the FTPFile will contain only the unparsed entry {@link FTPFile#getRawListing()} 690 * and {@link FTPFile#isValid()} will return {@code false} 691 * @param saveUnparseable if true, then create FTPFile entries if parsing fails 692 * @since 3.4 693 */ 694 public void setUnparseableEntries(final boolean saveUnparseable) { 695 this.saveUnparseableEntries = saveUnparseable; 696 } 697 698 /** 699 * @return true if list parsing should return FTPFile entries even for unparseable response lines 700 * <p> 701 * If true, the FTPFile for any unparseable entries will contain only the unparsed entry 702 * {@link FTPFile#getRawListing()} and {@link FTPFile#isValid()} will return {@code false} 703 * @since 3.4 704 */ 705 public boolean getUnparseableEntries() { 706 return this.saveUnparseableEntries; 707 } 708 709}