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 }