commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sco...@apache.org
Subject cvs commit: jakarta-commons/net/src/test/org/apache/commons/net/ftp/parser VMSFTPEntryParserTest.java
Date Sat, 10 Jan 2004 15:36:41 GMT
scohen      2004/01/10 07:36:41

  Modified:    net/src/java/org/apache/commons/net/ftp FTPClient.java
                        FTPFileEntryParser.java FTPFileIterator.java
                        FTPFileList.java FTPFileListParserImpl.java
               net/src/java/org/apache/commons/net/ftp/parser
                        VMSFTPEntryParser.java
               net/src/test/org/apache/commons/net/ftp/parser
                        VMSFTPEntryParserTest.java
  Added:       net/src/java/org/apache/commons/net/ftp/parser
                        VMSVersioningFTPEntryParser.java
  Log:
  Solve the VMSVersioning problem a different way.  Created new subclass of VMSFTPEntryParser,
VMSVersioningFTPEntryParser, and rollback many other changes of the last few days which no
longer were necessary.  This implementation is a much simpler solution to this problem and
will allow for the smooth removal of the deprecated FTPFileListParser interface in 2.0.
  
  Revision  Changes    Path
  1.26      +3 -3      jakarta-commons/net/src/java/org/apache/commons/net/ftp/FTPClient.java
  
  Index: FTPClient.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/net/src/java/org/apache/commons/net/ftp/FTPClient.java,v
  retrieving revision 1.25
  retrieving revision 1.26
  diff -u -r1.25 -r1.26
  --- FTPClient.java	9 Jan 2004 09:07:03 -0000	1.25
  +++ FTPClient.java	10 Jan 2004 15:36:40 -0000	1.26
  @@ -2268,7 +2268,7 @@
        *    FTPClient f=FTPClient();
        *    f.connect(server);
        *    f.login(username, password);
  -     *    FTPFileList list = createFTPFileList(directory, parser);
  +     *    FTPFileList list = f.createFileList(directory, parser);
        *    FTPFileIterator iter = list.iterator();
        * 
        *    while (iter.hasNext()) {
  @@ -2333,13 +2333,13 @@
               return null;
           }
   
  -        FTPFileList list =
  -            parser.createFTPFileList(socket.getInputStream());
  +        FTPFileList list = FTPFileList.create(socket.getInputStream(), parser);
   
           socket.close();
   
           completePendingCommand();
   
  +//        return parser.removeDuplicates(list);
           return list;
       }
   
  
  
  
  1.13      +14 -13    jakarta-commons/net/src/java/org/apache/commons/net/ftp/FTPFileEntryParser.java
  
  Index: FTPFileEntryParser.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/net/src/java/org/apache/commons/net/ftp/FTPFileEntryParser.java,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- FTPFileEntryParser.java	9 Jan 2004 09:07:03 -0000	1.12
  +++ FTPFileEntryParser.java	10 Jan 2004 15:36:40 -0000	1.13
  @@ -80,7 +80,7 @@
    *    FTPClient f=FTPClient();
    *    f.connect(server);
    *    f.login(username, password);
  - *    FTPFileList list = createFTPFileList(directory, parser);
  + *    FTPFileList list = f.createFileList(directory, parser);
    *    FTPFileIterator iter = list.iterator();
    * 
    *    while (iter.hasNext()) {
  @@ -162,20 +162,21 @@
        */
       String readNextEntry(BufferedReader reader) throws IOException;
   
  +    
       /**
  -     * Creates an <code>FTPFileList</code> object from a stream containing
  -     * a file listing.
  -     *
  -     * @param stream The input stream created by reading the socket on which 
  -     * the output of the LIST command was returned
  +     * This method is a hook for those implementers (such as 
  +     * VMSVersioningFTPEntryParser, and possibly others) which return
  +     * multiple files with the same name to remove the duplicates.
        * 
  -     * @return the <code>FTPFileList</code> created.
  -     * Will be null if the listing cannot be read from the stream.
  -     * @exception IOException
  -     *                   Thrown on any failure to read from the stream.
  +     * Implementations for systems that do not allow duplicates will
  +     * implement a NO-OP here.
  +     * 
  +     * @param original Original list which may contain duplicates
  +     * 
  +     * @return Original list purged of duplicates
        */
  -    public FTPFileList createFTPFileList(InputStream stream)
  -        throws IOException;
  +    FTPFileList removeDuplicates(FTPFileList original);
  +
   
   }
   
  
  
  
  1.8       +225 -11   jakarta-commons/net/src/java/org/apache/commons/net/ftp/FTPFileIterator.java
  
  Index: FTPFileIterator.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/net/src/java/org/apache/commons/net/ftp/FTPFileIterator.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- FTPFileIterator.java	9 Jan 2004 09:07:03 -0000	1.7
  +++ FTPFileIterator.java	10 Jan 2004 15:36:40 -0000	1.8
  @@ -57,7 +57,6 @@
   import java.util.Vector;
   
   /**
  - * FTPFileIterator.java
    * This class implements a bidirectional iterator over an FTPFileList.
    * Elements may be retrieved one at at time using the hasNext() - next()
    * syntax familiar from Java 2 collections.  Alternatively, entries may
  @@ -68,16 +67,135 @@
    * @see org.apache.commons.net.ftp.FTPFileList
    * @see org.apache.commons.net.ftp.FTPFileEntryParser
    */
  -public abstract class FTPFileIterator
  +class FTPFileIterator 
   {
       /**
  +     * a vector of strings, each representing a possibly valid ftp file
  +     * entry
  +     */
  +    private Vector rawlines;
  +    
  +    /**
  +     * the parser to which this iterator delegates its parsing duties
  +     */
  +    private FTPFileEntryParser parser;
  +
  +    /**
  +     * constant shorthand for the situation where the raw listing has not 
  +     * yet been scanned
  +     */
  +    private static final int UNINIT = -1;
  +    
  +    /**
  +     * constant shorthand for the situation where the raw listing has been 
  +     * scanned and found to have no valid entry.
  +     */
  +    private static final int DIREMPTY = -2;
  +    
  +    /**
  +     * this iterator's current position within <code>rawlines</code>.
  +     */
  +    private int itemptr = 0;
  +    
  +    /**
  +     * number within <code>rawlines</code> of the first valid file entry.
  +     */
  +    private int firstGoodEntry = UNINIT;
  +
  +    /**
  +     * "Package-private" constructor.  Only the FTPFileList can
  +     * create an iterator, using it's iterator() method.  The list
  +     * will be iterated with the list's default parser.
  +     *
  +     * @param rawlist the FTPFileList to be iterated
  +     */
  +    FTPFileIterator (FTPFileList rawlist)
  +    {
  +        this(rawlist, rawlist.getParser());
  +    }
  +
  +    /**
  +     * "Package-private" constructor.  Only the FTPFileList can
  +     * create an iterator, using it's iterator() method.  The list will be
  +     * iterated with a supplied parser
  +     *
  +     * @param rawlist the FTPFileList to be iterated
  +     * @param parser the system specific parser for raw FTP entries.
  +     */
  +    FTPFileIterator (FTPFileList rawlist,
  +                            FTPFileEntryParser parser)
  +    {
  +        this.rawlines = rawlist.getLines();
  +        this.parser = parser;
  +    }
  +
  +    /**
  +     * Delegates to this object's parser member the job of parsing an
  +     * entry.
  +     * 
  +     * @param entry  A string containing one entry, as determined by the 
  +     * parser's getNextEntry() method.
  +     * 
  +     * @return an FTPFile object representing this entry or null if it can't be 
  +     *         parsed as a file
  +     */
  +    private FTPFile parseFTPEntry(String entry)
  +    {
  +        return this.parser.parseFTPEntry(entry);
  +    }
  +
  +    /**
  +     * Skips over any introductory lines and stuff in the listing that does
  +     * not represent files, returning the line number of the first entry
  +     * that does represent a file.
  +     * 
  +     * @return the line number within <code>rawlines</code> of the first good

  +     * entry in the array or DIREMPTY if there are no good entries.
  +     */
  +    private int getFirstGoodEntry()
  +    {
  +        FTPFile entry = null;
  +        for (int iter = 0; iter < this.rawlines.size(); iter++)
  +        {
  +            String line = (String) this.rawlines.elementAt(iter);
  +            entry = parseFTPEntry(line);
  +            if (null != entry)
  +            {
  +                return iter;
  +            }
  +        }
  +        return DIREMPTY;
  +    }
  +
  +    /**
  +     * resets iterator to the beginning of the list.
  +     */
  +    private void init()
  +    {
  +        this.itemptr = 0;
  +        this.firstGoodEntry = UNINIT;
  +    }
  +
  +    /**
  +     * shorthand for an empty return value.
  +     */
  +    private static final FTPFile[] EMPTY = new FTPFile[0];
  +
  +    /**
        * Returns a list of FTPFile objects for ALL files listed in the server's
        * LIST output.
        *
        * @return a list of FTPFile objects for ALL files listed in the server's
        * LIST output.
        */
  -    public abstract FTPFile[] getFiles();
  +    public FTPFile[] getFiles()
  +    {
  +        if (this.itemptr != DIREMPTY)
  +        {
  +            init();
  +        }
  +        return getNext(0);
  +    }
   
       /**
        * Returns an array of at most <code>quantityRequested</code> FTPFile 
  @@ -100,8 +218,39 @@
        * list and at least the number of elements which  exist in the list at 
        * and after its current position.
        */
  -    public abstract FTPFile[] getNext(int quantityRequested);
  +    public FTPFile[] getNext(int quantityRequested)
  +    {
  +
  +        // if we haven't gotten past the initial junk do so.
  +        if (this.firstGoodEntry == UNINIT)
  +        {
  +            this.firstGoodEntry = getFirstGoodEntry();
  +        }
  +        if (this.firstGoodEntry == DIREMPTY)
  +        {
  +            return EMPTY;
  +        }
  +
  +        int max = this.rawlines.size() - this.firstGoodEntry;
   
  +        // now that we know the maximum we can possibly get,
  +        // resolve a 0 request to ask for that many.
  +
  +        int howMany = (quantityRequested == 0) ? max : quantityRequested;
  +        howMany = (howMany + this.itemptr < this.rawlines.size())
  +                   ? howMany
  +                   : this.rawlines.size() - this.itemptr;
  +
  +        FTPFile[] output = new FTPFile[howMany];
  +
  +        for (int i = 0, e = this.firstGoodEntry + this.itemptr ;
  +                i < howMany; i++, e++)
  +        {
  +            output[i] = parseFTPEntry((String) this.rawlines.elementAt(e));
  +            this.itemptr++;
  +        }
  +        return output;
  +    }
   
       /**
        * Method for determining whether getNext() will successfully return a
  @@ -110,7 +259,21 @@
        * @return true if there exist any files after the one currently pointed
        * to by the internal iterator, false otherwise.
        */
  -    public abstract boolean hasNext();
  +    public boolean hasNext()
  +    {
  +        int fge = this.firstGoodEntry;
  +        if (fge == DIREMPTY)
  +        {
  +            //directory previously found empty - return false
  +            return false;
  +        }
  +        else if (fge < 0)
  +        {
  +            // we haven't scanned the list yet so do it first
  +            fge = getFirstGoodEntry();
  +        }
  +        return fge + this.itemptr < this.rawlines.size();
  +    }
   
       /**
        * Returns a single parsed FTPFile object corresponding to the raw input
  @@ -123,7 +286,18 @@
        * at the position of the internal iterator over the list of raw input
        * lines maintained by this object or null if no such object exists.
        */
  -    public abstract FTPFile next();
  +    public FTPFile next()
  +    {
  +        FTPFile[] file = getNext(1);
  +        if (file.length > 0)
  +        {
  +            return file[0];
  +        }
  +        else
  +        {
  +            return null;
  +        }
  +    }
   
       /**
        * Returns an array of at most <code>quantityRequested</code> FTPFile 
  @@ -145,7 +319,22 @@
        * this iterator within its list and at least the number of elements which
        * exist in the list prior to its current position.
        */
  -    public abstract FTPFile[] getPrevious(int quantityRequested);
  +    public FTPFile[] getPrevious(int quantityRequested)
  +    {
  +        int howMany = quantityRequested;
  +        // can't retreat further than we've previously advanced
  +        if (howMany > this.itemptr)
  +        {
  +            howMany = this.itemptr;
  +        }
  +        FTPFile[] output = new FTPFile[howMany];
  +        for (int i = howMany, e = this.firstGoodEntry + this.itemptr; i > 0;)
  +        {
  +            output[--i] = parseFTPEntry((String) this.rawlines.elementAt(--e));
  +            this.itemptr--;
  +        }
  +        return output;
  +    }
   
       /**
        * Method for determining whether getPrevious() will successfully return a
  @@ -154,7 +343,22 @@
        * @return true if there exist any files before the one currently pointed
        * to by the internal iterator, false otherwise.
        */
  -    public abstract boolean hasPrevious();
  +    public boolean hasPrevious()
  +    {
  +        int fge = this.firstGoodEntry;
  +        if (fge == DIREMPTY)
  +        {
  +            //directory previously found empty - return false
  +            return false;
  +        }
  +        else if (fge < 0)
  +        {
  +            // we haven't scanned the list yet so do it first
  +            fge = getFirstGoodEntry();
  +        }
  +
  +        return this.itemptr > fge;
  +    }
   
       /**
        * Returns a single parsed FTPFile object corresponding to the raw input
  @@ -167,9 +371,19 @@
        * at the position immediately preceding that of the internal iterator
        * over the list of raw input lines maintained by this object.
        */
  -    public abstract FTPFile previous();
  +    public FTPFile previous()
  +    {
  +        FTPFile[] file = getPrevious(1);
  +        if (file.length > 0)
  +        {
  +            return file[0];
  +        }
  +        else
  +        {
  +            return null;
  +        }
  +    }
   }
  -
   
   /* Emacs configuration
    * Local variables:        **
  
  
  
  1.8       +97 -12    jakarta-commons/net/src/java/org/apache/commons/net/ftp/FTPFileList.java
  
  Index: FTPFileList.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/net/src/java/org/apache/commons/net/ftp/FTPFileList.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- FTPFileList.java	9 Jan 2004 09:07:03 -0000	1.7
  +++ FTPFileList.java	10 Jan 2004 15:36:40 -0000	1.8
  @@ -58,10 +58,10 @@
   import java.io.IOException;
   import java.io.InputStream;
   import java.io.InputStreamReader;
  +import java.util.ListIterator;
   import java.util.Vector;
   
   /**
  - * FTPFileList.java
    * This class encapsulates a listing of files from an FTP server.  It is
    * initialized with an input stream which is read and the input split into
    * lines, each of which (after some possible initial verbiage) represents
  @@ -81,9 +81,35 @@
    * @see org.apache.commons.net.ftp.FTPFileIterator
    * @see org.apache.commons.net.ftp.FTPFileEntryParser
    */
  -public abstract class FTPFileList
  +public class FTPFileList 
   {
       /**
  +     * storage for the raw lines of input read from the FTP server
  +     */
  +    private Vector lines = null;
  +    /**
  +     * the FTPFileEntryParser assigned to be used with this lister
  +     */
  +    private FTPFileEntryParser parser;
  +    /**
  +     * private status code for an empty directory
  +     */
  +    private static final int EMPTY_DIR = -2;
  +
  +    /**
  +     * The only constructor for FTPFileList, private because
  +     * construction only invoked at create()
  +     *
  +     * @param parser a <code>FTPFileEntryParser</code> value that knows
  +     * how to parse the entries returned by a particular FTP site.
  +     */
  +    private FTPFileList (FTPFileEntryParser parser)
  +    {
  +        this.parser = parser;
  +        this.lines = new Vector();
  +    }
  +
  +    /**
        * The only way to create an <code>FTPFileList</code> object.  Invokes
        * the private constructor and then reads the stream  supplied stream to
        * build the intermediate array of "lines" which will later be parsed
  @@ -99,27 +125,69 @@
        * be read from the stream.
        * @exception IOException
        *                   Thrown on any failure to read from the socket.
  -     * @deprecated This method is no longer used internally by the API
  -     *  and should not be called by API users.  It will be removed in
  -     *  version 2.0.
        */
       public static FTPFileList create(InputStream stream,
                                         FTPFileEntryParser parser)
               throws IOException
       {
  -        DefaultFTPFileList list = new DefaultFTPFileList(parser);
  +        FTPFileList list = new FTPFileList(parser);
           list.readStream(stream);
  -        return list;
  +        return parser.removeDuplicates(list);
       } 
   
       /**
  +     * internal method for reading the input into the <code>lines</code> vector.
  +     * 
  +     * @param stream The socket stream on which the input will be read.
  +     * 
  +     * @exception IOException thrown on any failure to read the stream
  +     */
  +    public void readStream(InputStream stream) throws IOException
  +    {
  +        BufferedReader reader =
  +            new BufferedReader(new InputStreamReader(stream));
  +
  +        String line = this.parser.readNextEntry(reader);
  +
  +        while (line != null)
  +        {
  +            this.lines.addElement(line);
  +            line = this.parser.readNextEntry(reader);
  +        }
  +        reader.close();
  +    }
  +
  +    /**
  +     * Accessor for this object's default parser.
  +     * 
  +     * @return this object's default parser.
  +     */
  +    FTPFileEntryParser getParser()
  +    {
  +        return this.parser;
  +    }
  +
  +    /**
  +     * Package private accessor for the collection of raw input lines.
  +     * 
  +     * @return vector containing all the raw input lines returned from the FTP 
  +     * server
  +     */
  +    Vector getLines()
  +    {
  +        return this.lines;
  +    }
  +
  +    /**
        * create an iterator over this list using the parser with which this list 
        * was initally created
        * 
        * @return an iterator over this list using the list's default parser.
        */
  -    public abstract FTPFileIterator iterator();
  -
  +    public FTPFileIterator iterator()
  +    {
  +        return new FTPFileIterator(this);
  +    }
       /**
        * create an iterator over this list using the supplied parser
        * 
  @@ -128,7 +196,10 @@
        * 
        * @return an iterator over this list using the supplied parser.
        */
  -    public abstract FTPFileIterator iterator(FTPFileEntryParser parser);
  +    public FTPFileIterator iterator(FTPFileEntryParser parser)
  +    {
  +        return new FTPFileIterator(this, parser);
  +    }
   
   
       /**
  @@ -138,7 +209,21 @@
        * @return  an array of FTPFile objects for all the files in the directory 
        * listinge
        */
  -    public abstract FTPFile[] getFiles();
  +    public FTPFile[] getFiles()
  +    {
  +        return iterator().getFiles();
  +    }
  +
  +    /**
  +     * return a ListIterator to the internal Vector of lines, used in purging
  +     * duplicates.
  +     * 
  +     * @return a ListIterator to the internal Vector of lines, used in purging
  +     *         duplicates.
  +     */
  +    ListIterator getInternalIterator() {
  +        return this.lines.listIterator();
  +    }
   }
   
   /* Emacs configuration
  
  
  
  1.7       +33 -10    jakarta-commons/net/src/java/org/apache/commons/net/ftp/FTPFileListParserImpl.java
  
  Index: FTPFileListParserImpl.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/net/src/java/org/apache/commons/net/ftp/FTPFileListParserImpl.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- FTPFileListParserImpl.java	9 Jan 2004 09:07:03 -0000	1.6
  +++ FTPFileListParserImpl.java	10 Jan 2004 15:36:40 -0000	1.7
  @@ -58,6 +58,8 @@
   import java.io.BufferedReader;
   import java.io.IOException;
   
  +import java.util.ListIterator;
  +
   import org.apache.oro.text.regex.Pattern;
   import org.apache.oro.text.regex.MalformedPatternException;
   import org.apache.oro.text.regex.PatternMatcher;
  @@ -137,20 +139,12 @@
        ***/
       public FTPFile[] parseFileList(InputStream listStream) throws IOException 
       {
  -        FTPFileList ffl = createFTPFileList(listStream);
  +        FTPFileList ffl = FTPFileList.create(listStream, this);
           return ffl.getFiles();
   
       }
   
  -    public FTPFileList createFTPFileList(InputStream stream)
  -        throws IOException
  -    {
  -        DefaultFTPFileList list = new DefaultFTPFileList(this);
  -        list.readStream(stream);
  -        return list;
  -    }
  -
  -
  + 
       /**
        * Convenience method delegates to the internal MatchResult's matches()
        * method.
  @@ -234,6 +228,35 @@
       public String readNextEntry(BufferedReader reader) throws IOException 
       {
           return reader.readLine();
  +    }
  +    /**
  +     * Implement hook provided for those implementers (such as
  +     * VMSVersioningFTPEntryParser, and possibly others) which return
  +     * multiple files with the same name to remove the duplicates by
  +     * defining a no-op method which simply returns the original
  +     * FTPFileList.  This method should not be overridden except in 
  +     * parsers that really have to remove duplicates.
  +     *
  +     * @param original Original list 
  +     *
  +     * @return Original list
  +     */
  +    public FTPFileList removeDuplicates(FTPFileList original) {
  +        return original;
  +    }
  +
  +    /**
  +     * return a ListIterator to the internal Vector of lines of <code>list</code>,

  +     * used in purging duplicates.
  +     * 
  +     * This method could go away if FTPFileEntryParser were moved down into the 
  +     * parser package.
  +     * 
  +     * @return a ListIterator to the internal Vector of lines, used in purging
  +     *         duplicates.
  +     */
  +    protected ListIterator getInternalIteratorForFtpFileList(FTPFileList list) {
  +        return list.getInternalIterator();
       }
   }
   
  
  
  
  1.14      +14 -212   jakarta-commons/net/src/java/org/apache/commons/net/ftp/parser/VMSFTPEntryParser.java
  
  Index: VMSFTPEntryParser.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/net/src/java/org/apache/commons/net/ftp/parser/VMSFTPEntryParser.java,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- VMSFTPEntryParser.java	9 Jan 2004 16:35:36 -0000	1.13
  +++ VMSFTPEntryParser.java	10 Jan 2004 15:36:40 -0000	1.14
  @@ -70,9 +70,7 @@
   import org.apache.oro.text.regex.MalformedPatternException;
   
   import org.apache.commons.net.ftp.FTPFile;
  -import org.apache.commons.net.ftp.FTPFileIterator;
   import org.apache.commons.net.ftp.FTPFileList;
  -import org.apache.commons.net.ftp.DefaultFTPFileList;
   import org.apache.commons.net.ftp.FTPFileListParserImpl;
   
   /**
  @@ -93,138 +91,7 @@
    */
   public class VMSFTPEntryParser extends FTPFileListParserImpl
   {
  -    private static class DuplicateFilteringFileIterator extends FTPFileIterator
  -    {
  -        FTPFile[] files;
  -        int next;
  -
  -        public DuplicateFilteringFileIterator(FTPFileIterator iterator) {
  -            FTPFile[] tempFiles = iterator.getFiles();
  -            Hashtable filesHash = new Hashtable();
  -            String fileName;
  -
  -
  -            for (int index = 0; index < tempFiles.length; index++) {
  -                fileName = tempFiles[index].getName();
  -
  -                if (!filesHash.containsKey(fileName)) {
  -                    filesHash.put(fileName, (FTPFile) tempFiles[index]);
  -                }
  -            }
  -
  -            files = new FTPFile[filesHash.size()];
  -
  -            Enumeration e = filesHash.keys();
  -            int index = 0;
  -
  -            while (e.hasMoreElements()) {
  -                FTPFile ftpf = (FTPFile) filesHash.get(e.nextElement());
  -                files[index++] = ftpf;
  -            }
  -
  -            next = 0;
  -        }
  -            
  -        public FTPFile[] getFiles() {
  -            FTPFile[] result = new FTPFile[files.length];
  -            System.arraycopy(files, 0, result, 0, result.length);
  -            return result;
  -        }
  -
  -        public FTPFile[] getNext(int quantityRequested) {
  -            FTPFile[] result;
  -            int remaining;
  -
  -            remaining = files.length - next;
  -
  -            if(quantityRequested > remaining)
  -                quantityRequested = remaining;
  -            else if(quantityRequested < 0)
  -                quantityRequested = 0;
  -            else if(quantityRequested == 0) {
  -                // interpret a 0 as meaning all remaining items.
  -                // ask Steve if this is what he intended.
  -                quantityRequested = remaining;
  -            }
  -
  -            result = new FTPFile[quantityRequested];
  -            System.arraycopy(files, next, result, 0, result.length);
  -            next+=quantityRequested;
  -
  -            return result;
  -        }
  -
  -        public boolean hasNext() {
  -            return (next < files.length && files.length > 0);
  -        }
  -
  -        public FTPFile next() {
  -            FTPFile result = null;
  -
  -            if(hasNext()) {
  -                result = files[next];
  -                ++next;
  -            }
  -
  -            return result;
  -        }
  -
  -        public FTPFile[] getPrevious(int quantityRequested) {
  -            FTPFile[] result;
  -            int start = 0;
  -
  -            if(quantityRequested > next)
  -                quantityRequested = next;
  -            else if(quantityRequested < 0)
  -                quantityRequested = 0;
  -            else if(quantityRequested == 0) {
  -                // interpret a 0 as meaning all items between 0 and next.
  -                // ask Steve if this is what he intended.
  -                quantityRequested = next;
  -            } else
  -                start = next - quantityRequested;
  -
  -            result = new FTPFile[quantityRequested];
  -            System.arraycopy(files, start, result, 0, result.length);
  -            next = start;
  -
  -            return result;
  -        }
  -
  -        public boolean hasPrevious() {
  -            return (next > 0 && files.length > 0);
  -        }
  -
  -        public FTPFile previous() {
  -            FTPFile result = null;
  -
  -            if(hasPrevious()) {
  -                --next;
  -                result = files[next];
  -            }
  -
  -            return result;
  -        }
  -    }
  -
  -
  -    private class DuplicateFilteringFileList extends DefaultFTPFileList {
  -
  -        public DuplicateFilteringFileList() {
  -            super(VMSFTPEntryParser.this);
  -        }
  -
  -        public FTPFileIterator iterator() {
  -            return new DuplicateFilteringFileIterator(super.iterator());
  -        }
  -    }
  -
   
  -    /**
  -     * settable option of whether or not to include versioning information 
  -     * with the file list.
  -     */
  -    private boolean versioning;
   
       /**
        * months abbreviations looked for by this parser.  Also used
  @@ -247,25 +114,9 @@
           + "\\([a-zA-Z]*,[a-zA-Z]*,[a-zA-Z]*,[a-zA-Z]*\\)";
   
   
  -    /** Pattern for splitting owner listing. */
  -    private static final Pattern OWNER_SPLIT_PATTERN;
  -
  -    static {
  -        Perl5Compiler compiler = new Perl5Compiler();
  -
  -        try {
  -            OWNER_SPLIT_PATTERN =
  -                compiler.compile(",", Perl5Compiler.READ_ONLY_MASK);
  -        } catch(MalformedPatternException mpe) {
  -            throw new IllegalStateException(
  -                "Pattern compilation failed in VMSFTPEntryParser " +
  -                "static initialization block.");
  -        }
  -    }
   
       /**
  -     * Convenience Constructor for a VMSFTPEntryParser object.  Sets the 
  -     * <code>versioning</code> member false
  +     * Constructor for a VMSFTPEntryParser object.   
        * 
        * @exception IllegalArgumentException
        * Thrown if the regular expression is unparseable.  Should not be seen 
  @@ -274,25 +125,7 @@
        */
       public VMSFTPEntryParser()
       {
  -        this(false);
  -    }
  -
  -
  -    /**
  -     * Constructor for a VMSFTPEntryParser object.  Sets the versioning member 
  -     * to the supplied value.
  -     *  
  -     * @param versioning Value to which versioning is to be set.
  -     * 
  -     * @exception IllegalArgumentException
  -     * Thrown if the regular expression is unparseable.  Should not be seen 
  -     * under normal conditions.  It it is seen, this is a sign that 
  -     * <code>REGEX</code> is  not a valid regular expression.
  -     */
  -    public VMSFTPEntryParser(boolean versioning)
  -    {
           super(REGEX);
  -        this.versioning = versioning;
       }
   
   
  @@ -311,51 +144,10 @@
        * @exception IOException  If an I/O error occurs reading the listStream.
        ***/
       public FTPFile[] parseFileList(InputStream listStream) throws IOException {
  -        return createFTPFileList(listStream).getFiles();
  +        return FTPFileList.create(listStream, this).getFiles();
       }
   
   
  -    public FTPFileList createFTPFileList(InputStream listStream)
  -        throws IOException
  -    {
  -        FTPFileList list;
  -        BufferedReader reader =
  -            new BufferedReader(new InputStreamReader(listStream));
  -        String listing = null;
  -
  -        String line = reader.readLine();
  -        while (line != null) {
  -            if ((line.trim().equals("")) ||
  -                (line.startsWith("Directory")) ||
  -                (line.startsWith("Total"))
  -               ) {
  -                line = reader.readLine();
  -                continue;
  -            }
  -            if (listing == null) {
  -                listing = line;
  -            } else {
  -                listing += "\r\n" + line;
  -            }
  -            line = reader.readLine();
  -        }
  -        reader.close();
  -
  -        byte[] bytes = listing.getBytes();
  -        ByteArrayInputStream listingStream = new ByteArrayInputStream(bytes);
  -
  -        if(versioning)
  -            list = super.createFTPFileList(listingStream);
  -        else {
  -            DefaultFTPFileList dlist;
  -            dlist = new DuplicateFilteringFileList();
  -            dlist.readStream(listingStream);
  -            list = dlist;
  -        }
  -
  -        return list;
  -    }
  -
   
       /**
        * Parses a line of a VMS FTP server file listing and converts it into a
  @@ -412,7 +204,7 @@
               }
               //set FTPFile name
               //Check also for versions to be returned or not
  -            if (versioning) 
  +            if (isVersioning()) 
               {
                   f.setName(name);
               } 
  @@ -470,6 +262,11 @@
           StringBuffer entry = new StringBuffer();
           while (line != null)
           {
  +            if (line.startsWith("Directory") || line.startsWith("Total")) {
  +                line = reader.readLine();
  +                continue;
  +            }
  +
               entry.append(line);
               if (line.trim().endsWith(")"))
               {
  @@ -479,6 +276,11 @@
           }
           return (entry.length() == 0 ? null : entry.toString());
       }
  +
  +    protected boolean isVersioning() {
  +        return false;
  +    }
  +
   }
   
   /* Emacs configuration
  
  
  
  1.1                  jakarta-commons/net/src/java/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.java
  
  Index: VMSVersioningFTPEntryParser.java
  ===================================================================
  package org.apache.commons.net.ftp.parser;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001-2004 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache Commons" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  import java.util.Calendar;
  import java.util.HashMap;
  import java.util.ListIterator;
  import java.util.StringTokenizer;
  import java.io.BufferedReader;
  import java.io.ByteArrayInputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.InputStreamReader;
  
  import org.apache.oro.text.regex.Pattern;
  import org.apache.oro.text.regex.Perl5Matcher;
  import org.apache.oro.text.regex.Perl5Compiler;
  import org.apache.oro.text.regex.MatchResult;
  import org.apache.oro.text.regex.Util;
  import org.apache.oro.text.regex.MalformedPatternException;
  
  import org.apache.commons.net.ftp.FTPFile;
  import org.apache.commons.net.ftp.FTPFileList;
  import org.apache.commons.net.ftp.FTPFileListParserImpl;
  
  /**
   * Special implementation VMSFTPEntryParser with versioning turned on.
   * This parser removes all duplicates and only leaves the version with the highest
   * version number for each filename.
   * 
   * This is a sample of VMS LIST output
   *   
   *  "1-JUN.LIS;1              9/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,RE)",
   *  "1-JUN.LIS;2              9/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,RE)",
   *  "DATA.DIR;1               1/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,RE)",
   * <P>
   * 
   * @author  <a href="Winston.Ojeda@qg.com">Winston Ojeda</a>
   * @author <a href="mailto:scohen@apache.org">Steve Cohen</a>
   * @author <a href="sestegra@free.fr">Stephane ESTE-GRACIAS</a>
   * @version $Id: VMSVersioningFTPEntryParser.java,v 1.1 2004/01/10 15:36:40 scohen Exp $
   * 
   * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions)
   */
  public class VMSVersioningFTPEntryParser extends VMSFTPEntryParser
  {
  
      private Perl5Matcher _preparse_matcher_;
      private Pattern _preparse_pattern_;
      private static final String PRE_PARSE_REGEX =
          "(.*);([0-9]+)\\s*.*"; 
  
      /**
       * Constructor for a VMSFTPEntryParser object.  Sets the versioning member 
       * to the supplied value.
       *  
       * @param versioning Value to which versioning is to be set.
       * 
       * @exception IllegalArgumentException
       * Thrown if the regular expression is unparseable.  Should not be seen 
       * under normal conditions.  It it is seen, this is a sign that 
       * <code>REGEX</code> is  not a valid regular expression.
       */
      public VMSVersioningFTPEntryParser()
      {
          super();
          try 
          {
              _preparse_matcher_ = new Perl5Matcher();
              _preparse_pattern_ = new Perl5Compiler().compile(PRE_PARSE_REGEX);
          } 
          catch (MalformedPatternException e) 
          {
              throw new IllegalArgumentException (
                  "Unparseable regex supplied:  " + PRE_PARSE_REGEX);
          }
  
      }
  
  
      private class NameVersion {
          String name;
          int versionNumber;
          NameVersion(String name, String vers) {
              this.name = name;
              this.versionNumber = Integer.parseInt(vers);
          }
      }
  
      /**
       * Implement hook provided for those implementers (such as
       * VMSVersioningFTPEntryParser, and possibly others) which return
       * multiple files with the same name to remove the duplicates ..
       *
       * @param original Original list
       *
       * @return Original list purged of duplicates
       */
      public FTPFileList removeDuplicates(FTPFileList original) {
          HashMap existingEntries = new HashMap();
          ListIterator iter = getInternalIteratorForFtpFileList(original);
          while (iter.hasNext()) {
              String entry = ((String)iter.next()).trim();
              MatchResult result = null;
              if (_preparse_matcher_.matches(entry, _preparse_pattern_)) {
                  result = _preparse_matcher_.getMatch();
                  String name = result.group(1);
                  String version = result.group(2);
                  NameVersion nv = new NameVersion(name, version);
                  NameVersion existing = (NameVersion) existingEntries.get(name);
                  if (null != existing) {
                      if (nv.versionNumber < existing.versionNumber) {
                          iter.remove();  // removal removes from original list.
                          continue;
                      }
                  }
                  existingEntries.put(name, nv);
              }
              
          }
          // we've now removed all entries less than with less than the largest
          // version number for each name that were listed after the largest.
          // we now must remove those with smaller than the largest version number
          // for each name that were found before the largest
          while (iter.hasPrevious()) {
              String entry = ((String)iter.previous()).trim();
              MatchResult result = null;
              if (_preparse_matcher_.matches(entry, _preparse_pattern_)) {
                  result = _preparse_matcher_.getMatch();
                  String name = result.group(1);
                  String version = result.group(2);
                  NameVersion nv = new NameVersion(name, version);
                  NameVersion existing = (NameVersion) existingEntries.get(name);
                  if (null != existing) {
                      if (nv.versionNumber < existing.versionNumber) {
                          iter.remove(); // removal removes from original list.
                      }
                  }
              }
              
          }
          return original;
      }
  
      protected boolean isVersioning() {
          return true;
      }
  
  }
  
  /* Emacs configuration
   * Local variables:        **
   * mode:             java  **
   * c-basic-offset:   4     **
   * indent-tabs-mode: nil   **
   * End:                    **
   */
  
  
  
  1.10      +33 -8     jakarta-commons/net/src/test/org/apache/commons/net/ftp/parser/VMSFTPEntryParserTest.java
  
  Index: VMSFTPEntryParserTest.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/net/src/test/org/apache/commons/net/ftp/parser/VMSFTPEntryParserTest.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- VMSFTPEntryParserTest.java	2 Jan 2004 03:39:07 -0000	1.9
  +++ VMSFTPEntryParserTest.java	10 Jan 2004 15:36:41 -0000	1.10
  @@ -60,6 +60,7 @@
   import junit.framework.TestSuite;
   
   import org.apache.commons.net.ftp.FTPFile;
  +import org.apache.commons.net.ftp.FTPFileList;
   import org.apache.commons.net.ftp.FTPFileEntryParser;
   
   /**
  @@ -105,8 +106,11 @@
       private static final String fullListing = "Directory USER1:[TEMP]\r\n\r\n"+
       "1-JUN.LIS;1              9/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,RE)\r\n"+

       "2-JUN.LIS;1              9/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,)\r\n"+

  -    "3-JUN.LIS;1              9/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,)\r\n"+
  -    "\r\nTotal 3 files"; 
  +    "3-JUN.LIS;1              9/9           3-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,)\r\n"+
  +    "3-JUN.LIS;4              9/9           7-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,)\r\n"+
  +    "3-JUN.LIS;2              9/9           4-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,)\r\n"+
  +    "3-JUN.LIS;3              9/9           6-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,)\r\n"+
  +    "\r\nTotal 6 files"; 
       
       /**
        * @see junit.framework.TestCase#TestCase(String)
  @@ -117,18 +121,39 @@
       }  
   
       /**
  -     * Test the legacy interface for parsing file lists.
  +     * Test the parsing of the whole list.
        * @throws IOException
        */
  -    public void testParseFileList() throws IOException
  +    public void testWholeListParse() throws IOException
       {        
           VMSFTPEntryParser parser = new VMSFTPEntryParser();
  -        FTPFile[] files = parser.parseFileList(new ByteArrayInputStream(fullListing.getBytes()));
  -        assertEquals(3, files.length);
  -        assertFileInListing(files, "1-JUN.LIS");
  +        FTPFile[] files = FTPFileList.create(
  +            new ByteArrayInputStream(fullListing.getBytes()), parser).getFiles();
  +        assertEquals(6, files.length);
           assertFileInListing(files, "2-JUN.LIS");
           assertFileInListing(files, "3-JUN.LIS");
  +        assertFileInListing(files, "1-JUN.LIS");
           assertFileNotInListing(files, "1-JUN.LIS;1");
  +
  +    }
  +
  +    /**
  +     * Test the parsing of the whole list.
  +     * @throws IOException
  +     */
  +    public void testWholeListParseWithVersioning() throws IOException
  +    {        
  +
  +        VMSFTPEntryParser parser = new VMSVersioningFTPEntryParser();
  +        FTPFile[] files = FTPFileList.create(
  +            new ByteArrayInputStream(fullListing.getBytes()), parser).getFiles();
  +        assertEquals(3, files.length);
  +        assertFileInListing(files, "1-JUN.LIS;1");
  +        assertFileInListing(files, "2-JUN.LIS;1");
  +        assertFileInListing(files, "3-JUN.LIS;4");
  +        assertFileNotInListing(files, "3-JUN.LIS;1");
  +        assertFileNotInListing(files, "3-JUN.LIS");
  +        
       }
   
       public void assertFileInListing(FTPFile[] listing, String name) {
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Mime
View raw message