/* * Copyright 2012 jMethods, Inc. * * Licensed 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 com.myjavaworld.ftp; import java.io.BufferedReader; import java.io.IOException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.List; import java.util.Locale; /** * The default implementation of <code>ListParser</code> interface. This parser * parses standard UNIX style listing produced by the FTP servers and converts * them to <code>RemoteFile</code> objects. * * @author Sai Pullabhotla, psai [at] jMethods [dot] com * @version 2.0 */ public class DefaultListParser implements ListParser { /** * We need to substitute this if a file's modified date does not contain the * year information. */ private static final int CURRENT_YEAR = Calendar.getInstance().get( Calendar.YEAR); /** * Assume all UNIX FTP servers output the last modified date of a file in * MMM dd yyyy hh:mm" format. */ private final SimpleDateFormat unixDateFormat = new SimpleDateFormat( "MMM dd yyyy hh:mm", Locale.US); /** * Number of milli seconds in a year */ private static final long MILLIS_IN_YEAR; static { GregorianCalendar gc = new GregorianCalendar(); if (gc.isLeapYear(CURRENT_YEAR)) { MILLIS_IN_YEAR = 366L * 24L * 60L * 60L * 1000L; } else { MILLIS_IN_YEAR = 365L * 24L * 60L * 60L * 1000L; } } public RemoteFile[] parse(RemoteFile parent, BufferedReader reader) throws ParseException, IOException { RemoteFile[] list = new RemoteFile[0]; List<RemoteFile> l = new ArrayList<RemoteFile>(50); String line = null; // Some FTP servers return the first line something like // "total xxxx bytes. ". Lets ignore the fist line if it starts // with the word "total", because the UNIX listing must start with // the file attributes. line = reader.readLine(); // System.out.println(line); if (line != null && line.trim().length() > 0) { if (!line.trim().toLowerCase().startsWith("total")) { l.add(parse(parent, line)); } } // Parse all other lines after the first line until the // end of the stream is reached or a ParseException is thrown. while ((line = reader.readLine()) != null) { // System.out.println(line); if (line.trim().length() > 0) { l.add(parse(parent, line)); } } list = new RemoteFile[l.size()]; list = l.toArray(list); return list; } public RemoteFile parse(RemoteFile parent, String line) throws ParseException { String rawData = line; try { // Attributes & isDirectory int spaceIndex = rawData.indexOf(' '); String attributes = rawData.substring(0, spaceIndex); boolean dir = attributes.charAt(0) == 'd'; // if the length of this field is more than 10, we might have a // server that is returning advanced file attributes such as ACLs. // If the length of this filed is more than 11, thn we in addition // to the advanced attributes, the number of links are more than 99. int linkCount = 0; boolean gotLinkCount = false; if (attributes.length() > 10) { if (attributes.length() == 11) { // we don't have to anything. } else { // Check the character at 11th position char ch = attributes.charAt(10); if (Character.isDigit(ch)) { linkCount = Integer.parseInt(attributes.substring(10)); attributes = attributes.substring(0, 10); } else { linkCount = Integer.parseInt(attributes.substring(11)); attributes = attributes.substring(0, 11); } gotLinkCount = true; } } rawData = rawData.substring(spaceIndex).trim(); if (!gotLinkCount) { // No. of Symbolic links spaceIndex = rawData.indexOf(' '); linkCount = Integer.parseInt(rawData.substring(0, spaceIndex)); rawData = rawData.substring(spaceIndex).trim(); } // Owner spaceIndex = rawData.indexOf(' '); String owner = rawData.substring(0, spaceIndex); rawData = rawData.substring(spaceIndex).trim(); // Group spaceIndex = rawData.indexOf(' '); String group = rawData.substring(0, spaceIndex); rawData = rawData.substring(spaceIndex).trim(); // Size spaceIndex = rawData.indexOf(' '); long size = Long.parseLong(rawData.substring(0, spaceIndex)); rawData = rawData.substring(spaceIndex).trim(); // Month spaceIndex = rawData.indexOf(' '); String month = rawData.substring(0, spaceIndex); rawData = rawData.substring(spaceIndex).trim(); // Date spaceIndex = rawData.indexOf(' '); String date = rawData.substring(0, spaceIndex); rawData = rawData.substring(spaceIndex).trim(); // Year spaceIndex = rawData.indexOf(' '); String year = rawData.substring(0, spaceIndex); rawData = rawData.substring(spaceIndex).trim(); // Name String name = rawData; return new DefaultRemoteFile(parent.getPath(), name, dir, size, parseDate(month, date, year), attributes, linkCount, owner, group); } catch (Exception exp) { // System.err.println("*** Parsing Exception ***"); throw new ParseException(line, 0); } } public RemoteFile createRemoteFile(String path) { return createRemoteFile(path, true); } public RemoteFile createRemoteFile(String path, boolean dir) { return new DefaultRemoteFile(path, dir); } public RemoteFile createRemoteFile(String parent, String name) { return createRemoteFile(parent, name, true); } public RemoteFile createRemoteFile(String parent, String name, boolean dir) { return new DefaultRemoteFile(parent, name, dir); } public RemoteFile createRemoteFile(RemoteFile parent, String name) { return createRemoteFile(parent.getPath(), name, true); } public RemoteFile createRemoteFile(RemoteFile parent, String name, boolean dir) { return createRemoteFile(parent.getPath(), name, dir); } public String getName() { return "Default List Parser"; } public String getDescription() { return "Parses standard UNIX style listing. "; } public String getVendor() { return "MyJavaWorld.com"; } public String getVersion() { return "1.0"; } private long parseDate(String month, String date, String year) throws ParseException { long millis = 0L; if (year.indexOf(':') >= 0) { millis = unixDateFormat.parse( month + " " + date + " " + CURRENT_YEAR + " " + year) .getTime(); if (millis - System.currentTimeMillis() > 0) { millis -= MILLIS_IN_YEAR; } } else { millis = unixDateFormat.parse( month + " " + date + " " + year + " 00:00").getTime(); } return millis; } public static void main(String[] args) throws ParseException { DefaultListParser parser = new DefaultListParser(); RemoteFile parent = parser.createRemoteFile("/"); RemoteFile file = parser .parse(parent, "drwxrwxrwx+ 329 root analysts 9216 Sep 8 18:00 backup"); System.out.println(file.getName() + "\t" + file.getLinkCount() + "\t" + file.getGroup() + "\t" + file.getOwner() + "\t" + file.getSize() + "\t" + new Date(file.getLastModified()) + "\t" + file.getAttributes()); } }