001: /**
002: *
003: * edtFTPj
004: *
005: * Copyright (C) 2000-2004 Enterprise Distributed Technologies Ltd
006: *
007: * www.enterprisedt.com
008: *
009: * This library is free software; you can redistribute it and/or
010: * modify it under the terms of the GNU Lesser General Public
011: * License as published by the Free Software Foundation; either
012: * version 2.1 of the License, or (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017: * Lesser General Public License for more details.
018: *
019: * You should have received a copy of the GNU Lesser General Public
020: * License along with this library; if not, write to the Free Software
021: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
022: *
023: * Bug fixes, suggestions and comments should be should posted on
024: * http://www.enterprisedt.com/forums/index.php
025: *
026: * Change Log:
027: *
028: * $Log: FTPFileFactory.java,v $
029: * Revision 1.16 2007-10-12 05:21:44 bruceb
030: * multiple locale stuff
031: *
032: * Revision 1.15 2007/02/26 07:15:52 bruceb
033: * Add getVMSParser() method
034: *
035: * Revision 1.14 2006/10/27 15:38:16 bruceb
036: * renamed logger
037: *
038: * Revision 1.13 2006/10/11 08:54:34 hans
039: * made cvsId final
040: *
041: * Revision 1.12 2006/05/24 11:35:54 bruceb
042: * fix VMS problem for listings over 3+ lines
043: *
044: * Revision 1.11 2006/01/08 19:10:19 bruceb
045: * better error information
046: *
047: * Revision 1.10 2005/06/10 15:43:41 bruceb
048: * more VMS tweaks
049: *
050: * Revision 1.9 2005/06/03 11:26:05 bruceb
051: * VMS stuff
052: *
053: * Revision 1.8 2005/04/01 13:57:35 bruceb
054: * added some useful debug
055: *
056: * Revision 1.7 2004/10/19 16:15:16 bruceb
057: * swap to unix if seems like unix listing
058: *
059: * Revision 1.6 2004/10/18 15:57:16 bruceb
060: * set locale
061: *
062: * Revision 1.5 2004/08/31 10:45:50 bruceb
063: * removed unused import
064: *
065: * Revision 1.4 2004/07/23 08:31:52 bruceb
066: * parser rotation
067: *
068: * Revision 1.3 2004/05/01 11:44:21 bruceb
069: * modified for server returning "total 3943" as first line
070: *
071: * Revision 1.2 2004/04/17 23:42:07 bruceb
072: * file parsing part II
073: *
074: * Revision 1.1 2004/04/17 18:37:23 bruceb
075: * new parse functionality
076: *
077: */package com.enterprisedt.net.ftp;
078:
079: import java.text.ParseException;
080: import java.util.Locale;
081:
082: import com.enterprisedt.util.debug.Logger;
083:
084: /**
085: * Factory for creating FTPFile objects
086: *
087: * @author Bruce Blackshaw
088: * @version $Revision: 1.16 $
089: */
090: public class FTPFileFactory {
091:
092: /**
093: * Revision control id
094: */
095: public static final String cvsId = "@(#)$Id: FTPFileFactory.java,v 1.16 2007-10-12 05:21:44 bruceb Exp $";
096:
097: /**
098: * Logging object
099: */
100: private static Logger log = Logger.getLogger("FTPFileFactory");
101:
102: /**
103: * Windows server comparison string
104: */
105: final static String WINDOWS_STR = "WINDOWS";
106:
107: /**
108: * UNIX server comparison string
109: */
110: final static String UNIX_STR = "UNIX";
111:
112: /**
113: * VMS server comparison string
114: */
115: final static String VMS_STR = "VMS";
116:
117: /**
118: * SYST string
119: */
120: private String system;
121:
122: /**
123: * Cached windows parser
124: */
125: private WindowsFileParser windows = new WindowsFileParser();
126:
127: /**
128: * Cached unix parser
129: */
130: private UnixFileParser unix = new UnixFileParser();
131:
132: /**
133: * Cached vms parser
134: */
135: private VMSFileParser vms = new VMSFileParser();
136:
137: /**
138: * Current parser
139: */
140: private FTPFileParser parser = null;
141:
142: /**
143: * Original parser
144: */
145: private FTPFileParser origParser = null;
146:
147: /**
148: * True if using VMS parser
149: */
150: private boolean usingVMS = false;
151:
152: /**
153: * Rotate parsers when a ParseException is thrown?
154: */
155: private boolean rotateParsers = true;
156:
157: /**
158: * Locales to try out
159: */
160: private Locale[] localesToTry;
161:
162: /**
163: * Index of locale to try next
164: */
165: private int localeIndex = 0;
166:
167: /**
168: * Constructor
169: *
170: * @param system SYST string
171: */
172: public FTPFileFactory(String system) throws FTPException {
173: setParser(system);
174: }
175:
176: /**
177: * Constructor. User supplied parser. Note that parser
178: * rotation (in case of a ParseException) is disabled if
179: * a parser is explicitly supplied
180: *
181: * @param parser the parser to use
182: */
183: public FTPFileFactory(FTPFileParser parser) {
184: this .parser = parser;
185: origParser = parser;
186: rotateParsers = false;
187: }
188:
189: /**
190: * Return a reference to the VMS parser being used.
191: * This allows the user to set VMS-specific settings on
192: * the parser.
193: *
194: * @return VMSFileParser object
195: */
196: public VMSFileParser getVMSParser() {
197: return vms;
198: }
199:
200: /**
201: * Set the locale for date parsing of listings
202: *
203: * @param locale locale to set
204: */
205: public void setLocale(Locale locale) {
206: windows.setLocale(locale);
207: unix.setLocale(locale);
208: vms.setLocale(locale);
209: parser.setLocale(locale); // might be user supplied
210: }
211:
212: /**
213: * Set the locales to try for date parsing of listings
214: *
215: * @param locales locales to try
216: */
217: public void setLocales(Locale[] locales) {
218: this .localesToTry = locales;
219: setLocale(locales[0]);
220: localeIndex = 1;
221: }
222:
223: /**
224: * Set the remote server type
225: *
226: * @param system SYST string
227: */
228: private void setParser(String system) {
229: this .system = system;
230: if (system.toUpperCase().startsWith(WINDOWS_STR))
231: parser = windows;
232: else if (system.toUpperCase().startsWith(UNIX_STR))
233: parser = unix;
234: else if (system.toUpperCase().startsWith(VMS_STR)) {
235: parser = vms;
236: usingVMS = true;
237: } else {
238: parser = unix;
239: log.warn("Unknown SYST '" + system
240: + "' - defaulting to Unix parsing");
241: }
242: origParser = parser;
243: }
244:
245: /**
246: * Reinitialize the parsers
247: */
248: private void reinitializeParsers() {
249: windows.setIgnoreDateParseErrors(false);
250: unix.setIgnoreDateParseErrors(false);
251: vms.setIgnoreDateParseErrors(false);
252: parser.setIgnoreDateParseErrors(false);
253: }
254:
255: /**
256: * Parse an array of raw file information returned from the
257: * FTP server
258: *
259: * @param files array of strings
260: * @return array of FTPFile objects
261: */
262: public FTPFile[] parse(String[] files) throws ParseException {
263:
264: reinitializeParsers();
265:
266: FTPFile[] temp = new FTPFile[files.length];
267:
268: // quick check if no files returned
269: if (files.length == 0)
270: return temp;
271:
272: int count = 0;
273: boolean checkedUnix = false;
274: boolean reparse = false;
275: int reparseCount = 1;
276: for (int i = 0; i < files.length; i++) {
277: if (reparse) { // rotated parsers, try this line again
278: i -= reparseCount;
279: reparse = false;
280: reparseCount = 1;
281: }
282: try {
283: if (files[i] == null || files[i].trim().length() == 0)
284: continue;
285:
286: // swap to Unix if looks like Unix listing
287: if (!checkedUnix && parser != unix
288: && UnixFileParser.isUnix(files[i])) {
289: parser = unix;
290: checkedUnix = true;
291: log.info("Swapping Windows parser to Unix");
292: }
293:
294: FTPFile file = null;
295: if (usingVMS) {
296: // vms uses more than 1 line for some file listings. We must keep going
297: // thru till we've got everything
298: reparseCount = 1;
299: StringBuffer filename = new StringBuffer(files[i]);
300: while (i + 1 < files.length
301: && files[i + 1].indexOf(';') < 0) {
302: filename.append(" ").append(files[i + 1]);
303: i++;
304: reparseCount++;
305: }
306: file = parser.parse(filename.toString());
307: } else {
308: file = parser.parse(files[i]);
309: }
310: // we skip null returns - these are duff lines we know about and don't
311: // really want to throw an exception
312: if (file != null) {
313: temp[count++] = file;
314: }
315: } catch (ParseException ex) {
316: // for date exceptions, try going thru the locales
317: if (ex.getMessage().toUpperCase().indexOf(
318: "UNPARSEABLE DATE") >= 0) {
319: if (localesToTry != null
320: && localesToTry.length > localeIndex) {
321: log.info("Trying "
322: + localesToTry[localeIndex].toString()
323: + " locale");
324: setLocale(localesToTry[localeIndex]);
325: localeIndex++;
326: count = 0;
327: i = -1; // account for the increment to set i back to 0
328: continue;
329: }
330: // from this point start again ignoring date errors (we've rotated parsers and
331: // tried all our locales)
332: if (!rotateParsers) {
333: count = 0;
334: i = -1; // account for the increment to set i back to 0
335: parser = origParser;
336: parser.setIgnoreDateParseErrors(true);
337: log.debug("Ignoring date parsing errors");
338: continue;
339: }
340: }
341:
342: StringBuffer msg = new StringBuffer(
343: "Failed to parse line '");
344: msg.append(files[i]).append("' (").append(
345: ex.getMessage()).append(")");
346: log.info(msg.toString());
347: if (rotateParsers) { // first error, let's try swapping parsers
348: rotateParsers = false; // only do once
349: rotateParsers();
350: if (localesToTry != null) {
351: setLocale(localesToTry[0]);
352: localeIndex = 1;
353: }
354: count = 0;
355: i = -1; // account for the increment to set i back to 0
356: } else {// rethrow
357: throw new ParseException(msg.toString(), ex
358: .getErrorOffset());
359: }
360: }
361: }
362: FTPFile[] result = new FTPFile[count];
363: System.arraycopy(temp, 0, result, 0, count);
364: return result;
365: }
366:
367: /**
368: * Swap from one parser to the other. We can just check
369: * object references
370: */
371: private void rotateParsers() {
372: usingVMS = false;
373: if (parser == unix) {
374: parser = windows;
375: log.info("Rotated parser to Windows");
376: } else if (parser == windows) {
377: parser = unix;
378: log.info("Rotated parser to Unix");
379: }
380: }
381:
382: /**
383: * Get the SYST string
384: *
385: * @return the system string.
386: */
387: public String getSystem() {
388: return system;
389: }
390:
391: }
|