View Javadoc

    1   /*
    2    * Copyright 2005 The Apache Software Foundation
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *     http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  package org.apache.commons.net.ftp.parser;
    17
    18  import java.text.DateFormatSymbols;
    19  import java.text.ParseException;
    20  import java.text.ParsePosition;
    21  import java.text.SimpleDateFormat;
    22  import java.util.Calendar;
    23  import java.util.Date;
    24  import java.util.TimeZone;
    25
    26  import org.apache.commons.net.ftp.Configurable;
    27  import org.apache.commons.net.ftp.FTPClientConfig;
    28
    29  /***
    30   * Default implementation of the {@link  FTPTimestampParser  FTPTimestampParser}
    31   * interface also implements the {@link  org.apache.commons.net.ftp.Configurable  Configurable}
    32   * interface to allow the parsing to be configured from the outside.
    33   *
    34   * @see ConfigurableFTPFileEntryParserImpl
    35   * @since 1.4
    36   */
    37  public class FTPTimestampParserImpl implements
    38  		FTPTimestampParser, Configurable
    39  {
    40
    41
    42  	private SimpleDateFormat defaultDateFormat;
    43  	private SimpleDateFormat recentDateFormat;
    44
    45
    46  	/***
    47  	 * The only constructor for this class.
    48  	 */
    49  	public FTPTimestampParserImpl() {
    50  		setDefaultDateFormat(DEFAULT_SDF);
    51  		setRecentDateFormat(DEFAULT_RECENT_SDF);
    52  	}
    53
    54  	/***
    55  	 * Implements the one {@link  FTPTimestampParser#parseTimestamp(String)  method}
    56  	 * in the {@link  FTPTimestampParser  FTPTimestampParser} interface
    57  	 * according to this algorithm:
    58  	 *
    59  	 * If the recentDateFormat member has been defined, try to parse the
    60  	 * supplied string with that.  If that parse fails, or if the recentDateFormat
    61  	 * member has not been defined, attempt to parse with the defaultDateFormat
    62  	 * member.  If that fails, throw a ParseException.
    63  	 *
    64  	 * @see org.apache.commons.net.ftp.parser.FTPTimestampParser#parseTimestamp(java.lang.String)
    65  	 */
    66  	/* (non-Javadoc)
    67  	 *
    68  	 */
    69  	public Calendar parseTimestamp(String timestampStr) throws ParseException {
    70  		Calendar now = Calendar.getInstance();
    71  		now.setTimeZone(this.getServerTimeZone());
    72
    73  		Calendar working = Calendar.getInstance();
    74  		working.setTimeZone(this.getServerTimeZone());
    75  		ParsePosition pp = new ParsePosition(0);
    76
    77  		Date parsed = null;
    78  		if (this.recentDateFormat != null) {
    79  			parsed = recentDateFormat.parse(timestampStr, pp);
    80  		}
    81  		if (parsed != null && pp.getIndex() == timestampStr.length())
    82  		{
    83  			working.setTime(parsed);
    84  			working.set(Calendar.YEAR, now.get(Calendar.YEAR));
    85  			if (working.after(now)) {
    86  				working.add(Calendar.YEAR, -1);
    87  			}
    88  		} else {
    89  			pp = new ParsePosition(0);
    90  			parsed = defaultDateFormat.parse(timestampStr, pp);
    91  			// note, length checks are mandatory for us since
    92  			// SimpleDateFormat methods will succeed if less than
    93  			// full string is matched.  They will also accept,
    94  			// despite "leniency" setting, a two-digit number as
    95  			// a valid year (e.g. 22:04 will parse as 22 A.D.)
    96  			// so could mistakenly confuse an hour with a year,
    97  			// if we don't insist on full length parsing.
    98  			if (parsed != null && pp.getIndex() == timestampStr.length()) {
    99  				working.setTime(parsed);
    100 			} else {
    101 				throw new ParseException(
    102 					"Timestamp could not be parsed with older or recent DateFormat",
    103 					pp.getIndex());
    104 			}
    105 		}
    106 		return working;
    107 	}
    108
    109 	/***
    110 	 * @return Returns the defaultDateFormat.
    111 	 */
    112 	public SimpleDateFormat getDefaultDateFormat() {
    113 		return defaultDateFormat;
    114 	}
    115 	/***
    116 	 * @return Returns the defaultDateFormat pattern string.
    117 	 */
    118 	public String getDefaultDateFormatString() {
    119 		return defaultDateFormat.toPattern();
    120 	}
    121 	/***
    122 	 * @param defaultDateFormat The defaultDateFormat to be set.
    123 	 */
    124 	private void setDefaultDateFormat(String format) {
    125 		if (format != null) {
    126 			this.defaultDateFormat = new SimpleDateFormat(format);
    127 			this.defaultDateFormat.setLenient(false);
    128 		}
    129 	}
    130 	/***
    131 	 * @return Returns the recentDateFormat.
    132 	 */
    133 	public SimpleDateFormat getRecentDateFormat() {
    134 		return recentDateFormat;
    135 	}
    136 	/***
    137 	 * @return Returns the recentDateFormat.
    138 	 */
    139 	public String getRecentDateFormatString() {
    140 		return recentDateFormat.toPattern();
    141 	}
    142 	/***
    143 	 * @param recentDateFormat The recentDateFormat to set.
    144 	 */
    145 	private void setRecentDateFormat(String format) {
    146 		if (format != null) {
    147 			this.recentDateFormat = new SimpleDateFormat(format);
    148 			this.recentDateFormat.setLenient(false);
    149 		}
    150 	}
    151
    152 	/***
    153 	 * @return returns an array of 12 strings representing the short
    154 	 * month names used by this parse.
    155 	 */
    156 	public String[] getShortMonths() {
    157 		return defaultDateFormat.getDateFormatSymbols().getShortMonths();
    158 	}
    159
    160
    161 	/***
    162 	 * @return Returns the serverTimeZone used by this parser.
    163 	 */
    164 	public TimeZone getServerTimeZone() {
    165 		return this.defaultDateFormat.getTimeZone();
    166 	}
    167 	/***
    168 	 * sets a TimeZone represented by the supplied ID string into all
    169 	 * of the parsers used by this server.
    170 	 * @param serverTimeZone Time Id java.util.TimeZone id used by
    171 	 * the ftp server.  If null the client's local time zone is assumed.
    172 	 */
    173 	private void setServerTimeZone(String serverTimeZoneId) {
    174 		TimeZone serverTimeZone = TimeZone.getDefault();
    175 		if (serverTimeZoneId != null) {
    176 			serverTimeZone = TimeZone.getTimeZone(serverTimeZoneId);
    177 		}
    178 		this.defaultDateFormat.setTimeZone(serverTimeZone);
    179 		if (this.recentDateFormat != null) {
    180 			this.recentDateFormat.setTimeZone(serverTimeZone);
    181 		}
    182 	}
    183
    184 	/***
    185 	 * Implementation of the {@link  Configurable  Configurable}
    186 	 * interface. Configures this <code>FTPTimestampParser</code> according
    187 	 * to the following logic:
    188 	 * <p>
    189 	 * Set up the {@link  FTPClientConfig#setDefaultDateFormatStr(java.lang.String) defaultDateFormat}
    190 	 * and optionally the {@link  FTPClientConfig#setRecentDateFormatStr(String) recentDateFormat}
    191 	 * to values supplied in the config based on month names configured as follows:
    192 	 * </p><p><ul>
    193 	 * <li>If a {@link  FTPClientConfig#setShortMonthNames(String) shortMonthString}
    194 	 * has been supplied in the <code>config</code>, use that to parse  parse timestamps.</li>
    195 	 * <li>Otherwise, if a {@link  FTPClientConfig#setServerLanguageCode(String) serverLanguageCode}
    196 	 * has been supplied in the <code>config</code>, use the month names represented
    197 	 * by that {@link  FTPClientConfig#lookupDateFormatSymbols(String) language}
    198 	 * to parse timestamps.</li>
    199 	 * <li>otherwise use default English month names</li>
    200 	 * </ul></p><p>
    201 	 * Finally if a {@link  org.apache.commons.net.ftp.FTPClientConfig#setServerTimeZoneId(String) serverTimeZoneId}
    202 	 * has been supplied via the config, set that into all date formats that have
    203 	 * been configured.
    204 	 * </p>
    205 	 */
    206 	public void configure(FTPClientConfig config) {
    207 		DateFormatSymbols dfs = null;
    208
    209 		String languageCode = config.getServerLanguageCode();
    210 		String shortmonths = config.getShortMonthNames();
    211 		if (shortmonths != null) {
    212 			dfs = FTPClientConfig.getDateFormatSymbols(shortmonths);
    213 		} else if (languageCode != null) {
    214 			dfs = FTPClientConfig.lookupDateFormatSymbols(languageCode);
    215 		} else {
    216 			dfs = FTPClientConfig.lookupDateFormatSymbols("en");
    217 		}
    218
    219
    220 		String recentFormatString = config.getRecentDateFormatStr();
    221 		if (recentFormatString == null) {
    222 		    this.recentDateFormat = null;
    223 		} else {
    224 			this.recentDateFormat = new SimpleDateFormat(recentFormatString, dfs);
    225 			this.recentDateFormat.setLenient(false);
    226 		}
    227
    228 		String defaultFormatString = config.getDefaultDateFormatStr();
    229 		if (defaultFormatString == null) {
    230 			throw new IllegalArgumentException("defaultFormatString cannot be null");
    231 		}
    232 		this.defaultDateFormat = new SimpleDateFormat(defaultFormatString, dfs);
    233 		this.defaultDateFormat.setLenient(false);
    234
    235 		setServerTimeZone(config.getServerTimeZoneId());
    236 	}
    237 }