001: /*
002: * Copyright 2005 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.apache.commons.net.ftp.parser;
017:
018: import java.text.DateFormatSymbols;
019: import java.text.ParseException;
020: import java.text.ParsePosition;
021: import java.text.SimpleDateFormat;
022: import java.util.Calendar;
023: import java.util.Date;
024: import java.util.TimeZone;
025:
026: import org.apache.commons.net.ftp.Configurable;
027: import org.apache.commons.net.ftp.FTPClientConfig;
028:
029: /**
030: * Default implementation of the {@link FTPTimestampParser FTPTimestampParser}
031: * interface also implements the {@link org.apache.commons.net.ftp.Configurable Configurable}
032: * interface to allow the parsing to be configured from the outside.
033: *
034: * @see ConfigurableFTPFileEntryParserImpl
035: * @since 1.4
036: */
037: public class FTPTimestampParserImpl implements FTPTimestampParser,
038: Configurable {
039:
040: private SimpleDateFormat defaultDateFormat;
041: private SimpleDateFormat recentDateFormat;
042:
043: /**
044: * The only constructor for this class.
045: */
046: public FTPTimestampParserImpl() {
047: setDefaultDateFormat(DEFAULT_SDF);
048: setRecentDateFormat(DEFAULT_RECENT_SDF);
049: }
050:
051: /**
052: * Implements the one {@link FTPTimestampParser#parseTimestamp(String) method}
053: * in the {@link FTPTimestampParser FTPTimestampParser} interface
054: * according to this algorithm:
055: *
056: * If the recentDateFormat member has been defined, try to parse the
057: * supplied string with that. If that parse fails, or if the recentDateFormat
058: * member has not been defined, attempt to parse with the defaultDateFormat
059: * member. If that fails, throw a ParseException.
060: *
061: * @see org.apache.commons.net.ftp.parser.FTPTimestampParser#parseTimestamp(java.lang.String)
062: */
063: /* (non-Javadoc)
064: *
065: */
066: public Calendar parseTimestamp(String timestampStr)
067: throws ParseException {
068: Calendar now = Calendar.getInstance();
069: now.setTimeZone(this .getServerTimeZone());
070:
071: Calendar working = Calendar.getInstance();
072: working.setTimeZone(this .getServerTimeZone());
073: ParsePosition pp = new ParsePosition(0);
074:
075: Date parsed = null;
076: if (this .recentDateFormat != null) {
077: parsed = recentDateFormat.parse(timestampStr, pp);
078: }
079: if (parsed != null && pp.getIndex() == timestampStr.length()) {
080: working.setTime(parsed);
081: working.set(Calendar.YEAR, now.get(Calendar.YEAR));
082: if (working.after(now)) {
083: working.add(Calendar.YEAR, -1);
084: }
085: } else {
086: pp = new ParsePosition(0);
087: parsed = defaultDateFormat.parse(timestampStr, pp);
088: // note, length checks are mandatory for us since
089: // SimpleDateFormat methods will succeed if less than
090: // full string is matched. They will also accept,
091: // despite "leniency" setting, a two-digit number as
092: // a valid year (e.g. 22:04 will parse as 22 A.D.)
093: // so could mistakenly confuse an hour with a year,
094: // if we don't insist on full length parsing.
095: if (parsed != null
096: && pp.getIndex() == timestampStr.length()) {
097: working.setTime(parsed);
098: } else {
099: throw new ParseException(
100: "Timestamp could not be parsed with older or recent DateFormat",
101: pp.getIndex());
102: }
103: }
104: return working;
105: }
106:
107: /**
108: * @return Returns the defaultDateFormat.
109: */
110: public SimpleDateFormat getDefaultDateFormat() {
111: return defaultDateFormat;
112: }
113:
114: /**
115: * @return Returns the defaultDateFormat pattern string.
116: */
117: public String getDefaultDateFormatString() {
118: return defaultDateFormat.toPattern();
119: }
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: /**
132: * @return Returns the recentDateFormat.
133: */
134: public SimpleDateFormat getRecentDateFormat() {
135: return recentDateFormat;
136: }
137:
138: /**
139: * @return Returns the recentDateFormat.
140: */
141: public String getRecentDateFormatString() {
142: return recentDateFormat.toPattern();
143: }
144:
145: /**
146: * @param recentDateFormat The recentDateFormat to set.
147: */
148: private void setRecentDateFormat(String format) {
149: if (format != null) {
150: this .recentDateFormat = new SimpleDateFormat(format);
151: this .recentDateFormat.setLenient(false);
152: }
153: }
154:
155: /**
156: * @return returns an array of 12 strings representing the short
157: * month names used by this parse.
158: */
159: public String[] getShortMonths() {
160: return defaultDateFormat.getDateFormatSymbols()
161: .getShortMonths();
162: }
163:
164: /**
165: * @return Returns the serverTimeZone used by this parser.
166: */
167: public TimeZone getServerTimeZone() {
168: return this .defaultDateFormat.getTimeZone();
169: }
170:
171: /**
172: * sets a TimeZone represented by the supplied ID string into all
173: * of the parsers used by this server.
174: * @param serverTimeZone Time Id java.util.TimeZone id used by
175: * the ftp server. If null the client's local time zone is assumed.
176: */
177: private void setServerTimeZone(String serverTimeZoneId) {
178: TimeZone serverTimeZone = TimeZone.getDefault();
179: if (serverTimeZoneId != null) {
180: serverTimeZone = TimeZone.getTimeZone(serverTimeZoneId);
181: }
182: this .defaultDateFormat.setTimeZone(serverTimeZone);
183: if (this .recentDateFormat != null) {
184: this .recentDateFormat.setTimeZone(serverTimeZone);
185: }
186: }
187:
188: /**
189: * Implementation of the {@link Configurable Configurable}
190: * interface. Configures this <code>FTPTimestampParser</code> according
191: * to the following logic:
192: * <p>
193: * Set up the {@link FTPClientConfig#setDefaultDateFormatStr(java.lang.String) defaultDateFormat}
194: * and optionally the {@link FTPClientConfig#setRecentDateFormatStr(String) recentDateFormat}
195: * to values supplied in the config based on month names configured as follows:
196: * </p><p><ul>
197: * <li>If a {@link FTPClientConfig#setShortMonthNames(String) shortMonthString}
198: * has been supplied in the <code>config</code>, use that to parse parse timestamps.</li>
199: * <li>Otherwise, if a {@link FTPClientConfig#setServerLanguageCode(String) serverLanguageCode}
200: * has been supplied in the <code>config</code>, use the month names represented
201: * by that {@link FTPClientConfig#lookupDateFormatSymbols(String) language}
202: * to parse timestamps.</li>
203: * <li>otherwise use default English month names</li>
204: * </ul></p><p>
205: * Finally if a {@link org.apache.commons.net.ftp.FTPClientConfig#setServerTimeZoneId(String) serverTimeZoneId}
206: * has been supplied via the config, set that into all date formats that have
207: * been configured.
208: * </p>
209: */
210: public void configure(FTPClientConfig config) {
211: DateFormatSymbols dfs = null;
212:
213: String languageCode = config.getServerLanguageCode();
214: String shortmonths = config.getShortMonthNames();
215: if (shortmonths != null) {
216: dfs = FTPClientConfig.getDateFormatSymbols(shortmonths);
217: } else if (languageCode != null) {
218: dfs = FTPClientConfig.lookupDateFormatSymbols(languageCode);
219: } else {
220: dfs = FTPClientConfig.lookupDateFormatSymbols("en");
221: }
222:
223: String recentFormatString = config.getRecentDateFormatStr();
224: if (recentFormatString == null) {
225: this .recentDateFormat = null;
226: } else {
227: this .recentDateFormat = new SimpleDateFormat(
228: recentFormatString, dfs);
229: this .recentDateFormat.setLenient(false);
230: }
231:
232: String defaultFormatString = config.getDefaultDateFormatStr();
233: if (defaultFormatString == null) {
234: throw new IllegalArgumentException(
235: "defaultFormatString cannot be null");
236: }
237: this .defaultDateFormat = new SimpleDateFormat(
238: defaultFormatString, dfs);
239: this .defaultDateFormat.setLenient(false);
240:
241: setServerTimeZone(config.getServerTimeZoneId());
242: }
243: }
|