summaryrefslogtreecommitdiff
path: root/app/src/main/java/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java')
-rw-r--r--app/src/main/java/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java301
1 files changed, 301 insertions, 0 deletions
diff --git a/app/src/main/java/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java b/app/src/main/java/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java
new file mode 100644
index 0000000..b4214be
--- /dev/null
+++ b/app/src/main/java/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java
@@ -0,0 +1,301 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.net.ftp.parser;
+
+import org.apache.commons.net.ftp.Configurable;
+import org.apache.commons.net.ftp.FTPClientConfig;
+
+import java.text.DateFormatSymbols;
+import java.text.ParseException;
+import java.text.ParsePosition;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+/**
+ * Default implementation of the {@link FTPTimestampParser FTPTimestampParser}
+ * interface also implements the {@link org.apache.commons.net.ftp.Configurable Configurable}
+ * interface to allow the parsing to be configured from the outside.
+ *
+ * @see ConfigurableFTPFileEntryParserImpl
+ * @since 1.4
+ */
+public class FTPTimestampParserImpl implements
+ FTPTimestampParser, Configurable
+{
+
+
+ private SimpleDateFormat defaultDateFormat;
+ private SimpleDateFormat recentDateFormat;
+ private boolean lenientFutureDates = false;
+
+
+ /**
+ * The only constructor for this class.
+ */
+ public FTPTimestampParserImpl() {
+ setDefaultDateFormat(DEFAULT_SDF);
+ setRecentDateFormat(DEFAULT_RECENT_SDF);
+ }
+
+ /**
+ * Implements the one {@link FTPTimestampParser#parseTimestamp(String) method}
+ * in the {@link FTPTimestampParser FTPTimestampParser} interface
+ * according to this algorithm:
+ *
+ * If the recentDateFormat member has been defined, try to parse the
+ * supplied string with that. If that parse fails, or if the recentDateFormat
+ * member has not been defined, attempt to parse with the defaultDateFormat
+ * member. If that fails, throw a ParseException.
+ *
+ * This method allows a {@link Calendar} instance to be passed in which represents the
+ * current (system) time.
+ *
+ * @see org.apache.commons.net.ftp.parser.FTPTimestampParser#parseTimestamp(java.lang.String)
+ *
+ * @param timestampStr The timestamp to be parsed
+ */
+ public Calendar parseTimestamp(String timestampStr) throws ParseException {
+ Calendar now = Calendar.getInstance();
+ return parseTimestamp(timestampStr, now);
+ }
+
+ /**
+ * Implements the one {@link FTPTimestampParser#parseTimestamp(String) method}
+ * in the {@link FTPTimestampParser FTPTimestampParser} interface
+ * according to this algorithm:
+ *
+ * If the recentDateFormat member has been defined, try to parse the
+ * supplied string with that. If that parse fails, or if the recentDateFormat
+ * member has not been defined, attempt to parse with the defaultDateFormat
+ * member. If that fails, throw a ParseException.
+ *
+ * @see org.apache.commons.net.ftp.parser.FTPTimestampParser#parseTimestamp(java.lang.String)
+ * @param timestampStr The timestamp to be parsed
+ * @param serverTime The current time for the server
+ * @since 1.5
+ */
+ public Calendar parseTimestamp(String timestampStr, Calendar serverTime) throws ParseException {
+ Calendar now = (Calendar) serverTime.clone();// Copy this, because we may change it
+ now.setTimeZone(this.getServerTimeZone());
+ Calendar working = (Calendar) now.clone();
+ working.setTimeZone(getServerTimeZone());
+ ParsePosition pp = new ParsePosition(0);
+
+ Date parsed = null;
+ if (recentDateFormat != null) {
+ if (lenientFutureDates) {
+ // add a day to "now" so that "slop" doesn't cause a date
+ // slightly in the future to roll back a full year. (Bug 35181)
+ now.add(Calendar.DATE, 1);
+ }
+ parsed = recentDateFormat.parse(timestampStr, pp);
+ }
+ if (parsed != null && pp.getIndex() == timestampStr.length())
+ {
+ working.setTime(parsed);
+ working.set(Calendar.YEAR, now.get(Calendar.YEAR));
+
+ if (working.after(now)) {
+ working.add(Calendar.YEAR, -1);
+ }
+ } else {
+ // Temporarily add the current year to the short date time
+ // to cope with short-date leap year strings.
+ // e.g. Java's DateFormatter will assume that "Feb 29 12:00" refers to
+ // Feb 29 1970 (an invalid date) rather than a potentially valid leap year date.
+ // This is pretty bad hack to work around the deficiencies of the JDK date/time classes.
+ if (recentDateFormat != null) {
+ pp = new ParsePosition(0);
+ int year = now.get(Calendar.YEAR);
+ String timeStampStrPlusYear = timestampStr + " " + year;
+ SimpleDateFormat hackFormatter = new SimpleDateFormat(recentDateFormat.toPattern() + " yyyy",
+ recentDateFormat.getDateFormatSymbols());
+ hackFormatter.setLenient(false);
+ hackFormatter.setTimeZone(recentDateFormat.getTimeZone());
+ parsed = hackFormatter.parse(timeStampStrPlusYear, pp);
+ }
+ if (parsed != null && pp.getIndex() == timestampStr.length() + 5) {
+ working.setTime(parsed);
+ }
+ else {
+ pp = new ParsePosition(0);
+ parsed = defaultDateFormat.parse(timestampStr, pp);
+ // note, length checks are mandatory for us since
+ // SimpleDateFormat methods will succeed if less than
+ // full string is matched. They will also accept,
+ // despite "leniency" setting, a two-digit number as
+ // a valid year (e.g. 22:04 will parse as 22 A.D.)
+ // so could mistakenly confuse an hour with a year,
+ // if we don't insist on full length parsing.
+ if (parsed != null && pp.getIndex() == timestampStr.length()) {
+ working.setTime(parsed);
+ } else {
+ throw new ParseException(
+ "Timestamp could not be parsed with older or recent DateFormat",
+ pp.getIndex());
+ }
+ }
+ }
+ return working;
+ }
+
+ /**
+ * @return Returns the defaultDateFormat.
+ */
+ public SimpleDateFormat getDefaultDateFormat() {
+ return defaultDateFormat;
+ }
+ /**
+ * @return Returns the defaultDateFormat pattern string.
+ */
+ public String getDefaultDateFormatString() {
+ return defaultDateFormat.toPattern();
+ }
+ /**
+ * @param defaultDateFormat The defaultDateFormat to be set.
+ */
+ private void setDefaultDateFormat(String format) {
+ if (format != null) {
+ this.defaultDateFormat = new SimpleDateFormat(format);
+ this.defaultDateFormat.setLenient(false);
+ }
+ }
+ /**
+ * @return Returns the recentDateFormat.
+ */
+ public SimpleDateFormat getRecentDateFormat() {
+ return recentDateFormat;
+ }
+ /**
+ * @return Returns the recentDateFormat.
+ */
+ public String getRecentDateFormatString() {
+ return recentDateFormat.toPattern();
+ }
+ /**
+ * @param recentDateFormat The recentDateFormat to set.
+ */
+ private void setRecentDateFormat(String format) {
+ if (format != null) {
+ this.recentDateFormat = new SimpleDateFormat(format);
+ this.recentDateFormat.setLenient(false);
+ }
+ }
+
+ /**
+ * @return returns an array of 12 strings representing the short
+ * month names used by this parse.
+ */
+ public String[] getShortMonths() {
+ return defaultDateFormat.getDateFormatSymbols().getShortMonths();
+ }
+
+
+ /**
+ * @return Returns the serverTimeZone used by this parser.
+ */
+ public TimeZone getServerTimeZone() {
+ return this.defaultDateFormat.getTimeZone();
+ }
+ /**
+ * sets a TimeZone represented by the supplied ID string into all
+ * of the parsers used by this server.
+ * @param serverTimeZone Time Id java.util.TimeZone id used by
+ * the ftp server. If null the client's local time zone is assumed.
+ */
+ private void setServerTimeZone(String serverTimeZoneId) {
+ TimeZone serverTimeZone = TimeZone.getDefault();
+ if (serverTimeZoneId != null) {
+ serverTimeZone = TimeZone.getTimeZone(serverTimeZoneId);
+ }
+ this.defaultDateFormat.setTimeZone(serverTimeZone);
+ if (this.recentDateFormat != null) {
+ this.recentDateFormat.setTimeZone(serverTimeZone);
+ }
+ }
+
+ /**
+ * Implementation of the {@link Configurable Configurable}
+ * interface. Configures this <code>FTPTimestampParser</code> according
+ * to the following logic:
+ * <p>
+ * Set up the {@link FTPClientConfig#setDefaultDateFormatStr(java.lang.String) defaultDateFormat}
+ * and optionally the {@link FTPClientConfig#setRecentDateFormatStr(String) recentDateFormat}
+ * to values supplied in the config based on month names configured as follows:
+ * </p><p><ul>
+ * <li>If a {@link FTPClientConfig#setShortMonthNames(String) shortMonthString}
+ * has been supplied in the <code>config</code>, use that to parse parse timestamps.</li>
+ * <li>Otherwise, if a {@link FTPClientConfig#setServerLanguageCode(String) serverLanguageCode}
+ * has been supplied in the <code>config</code>, use the month names represented
+ * by that {@link FTPClientConfig#lookupDateFormatSymbols(String) language}
+ * to parse timestamps.</li>
+ * <li>otherwise use default English month names</li>
+ * </ul></p><p>
+ * Finally if a {@link org.apache.commons.net.ftp.FTPClientConfig#setServerTimeZoneId(String) serverTimeZoneId}
+ * has been supplied via the config, set that into all date formats that have
+ * been configured.
+ * </p>
+ */
+ public void configure(FTPClientConfig config) {
+ DateFormatSymbols dfs = null;
+
+ String languageCode = config.getServerLanguageCode();
+ String shortmonths = config.getShortMonthNames();
+ if (shortmonths != null) {
+ dfs = FTPClientConfig.getDateFormatSymbols(shortmonths);
+ } else if (languageCode != null) {
+ dfs = FTPClientConfig.lookupDateFormatSymbols(languageCode);
+ } else {
+ dfs = FTPClientConfig.lookupDateFormatSymbols("en");
+ }
+
+
+ String recentFormatString = config.getRecentDateFormatStr();
+ if (recentFormatString == null) {
+ this.recentDateFormat = null;
+ } else {
+ this.recentDateFormat = new SimpleDateFormat(recentFormatString, dfs);
+ this.recentDateFormat.setLenient(false);
+ }
+
+ String defaultFormatString = config.getDefaultDateFormatStr();
+ if (defaultFormatString == null) {
+ throw new IllegalArgumentException("defaultFormatString cannot be null");
+ }
+ this.defaultDateFormat = new SimpleDateFormat(defaultFormatString, dfs);
+ this.defaultDateFormat.setLenient(false);
+
+ setServerTimeZone(config.getServerTimeZoneId());
+
+ this.lenientFutureDates = config.isLenientFutureDates();
+ }
+ /**
+ * @return Returns the lenientFutureDates.
+ */
+ boolean isLenientFutureDates() {
+ return lenientFutureDates;
+ }
+ /**
+ * @param lenientFutureDates The lenientFutureDates to set.
+ */
+ void setLenientFutureDates(boolean lenientFutureDates) {
+ this.lenientFutureDates = lenientFutureDates;
+ }
+}