incubator-ftpserver-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From n..@apache.org
Subject svn commit: r487385 [1/2] - in /incubator/ftpserver/trunk/core/src: java/org/apache/ftpserver/ java/org/apache/ftpserver/command/ java/org/apache/ftpserver/listing/ test/org/apache/ftpserver/ test/org/apache/ftpserver/clienttests/ test/org/apache/ftpse...
Date Thu, 14 Dec 2006 23:20:53 GMT
Author: ngn
Date: Thu Dec 14 15:20:49 2006
New Revision: 487385

URL: http://svn.apache.org/viewvc?view=rev&rev=487385
Log:
Refactored DirectoryLister to make it easier to extend and test. 
Added a lot of test in this area.

Added:
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/DirectoryLister.java
      - copied, changed from r485806, incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/DirectoryLister.java
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/FileFilter.java   (with props)
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/FileFormater.java   (with props)
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/LISTFileFormater.java   (with props)
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/ListArgument.java   (with props)
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/ListArgumentParser.java   (with props)
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/MLSTFileFormater.java   (with props)
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/NLSTFileFormater.java   (with props)
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/RegexFileFilter.java   (with props)
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/VisibleFileFilter.java   (with props)
    incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/listing/
    incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/listing/DirectoryListerTest.java
      - copied, changed from r485806, incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/DirectoryListerTest.java
    incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/listing/LISTFileFormaterTest.java   (with props)
    incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/listing/ListArgumentParserTest.java   (with props)
    incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/listing/ListArgumentTest.java   (with props)
    incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/listing/MLSTFileFormaterTest.java   (with props)
    incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/listing/NLSTFileFormaterTest.java   (with props)
Removed:
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/DirectoryLister.java
    incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/DirectoryListerTest.java
Modified:
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/RequestHandler.java
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/LIST.java
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/MLSD.java
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/MLST.java
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/NLST.java
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/OPTS_MLST.java
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/PASS.java
    incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/clienttests/ListTest.java

Modified: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/RequestHandler.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/RequestHandler.java?view=diff&rev=487385&r1=487384&r2=487385
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/RequestHandler.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/RequestHandler.java Thu Dec 14 15:20:49 2006
@@ -27,20 +27,30 @@
 import java.net.InetAddress;
 import java.net.Socket;
 import java.net.SocketException;
+import java.util.HashMap;
+import java.util.Map;
 
 import javax.net.ssl.SSLException;
 
 import org.apache.commons.logging.Log;
-import org.apache.ftpserver.ftplet.*;
-import org.apache.ftpserver.interfaces.ConnectionObserver;
+import org.apache.ftpserver.ftplet.DataType;
+import org.apache.ftpserver.ftplet.FileSystemView;
+import org.apache.ftpserver.ftplet.FtpException;
+import org.apache.ftpserver.ftplet.FtpRequest;
+import org.apache.ftpserver.ftplet.Ftplet;
+import org.apache.ftpserver.ftplet.FtpletEnum;
+import org.apache.ftpserver.ftplet.Structure;
+import org.apache.ftpserver.ftplet.User;
 import org.apache.ftpserver.interfaces.Command;
 import org.apache.ftpserver.interfaces.CommandFactory;
 import org.apache.ftpserver.interfaces.Connection;
 import org.apache.ftpserver.interfaces.ConnectionManager;
+import org.apache.ftpserver.interfaces.ConnectionObserver;
+import org.apache.ftpserver.interfaces.IpRestrictor;
 import org.apache.ftpserver.interfaces.ServerFtpConfig;
 import org.apache.ftpserver.interfaces.ServerFtpStatistics;
-import org.apache.ftpserver.interfaces.IpRestrictor;
 import org.apache.ftpserver.interfaces.Ssl;
+import org.apache.ftpserver.listing.DirectoryLister;
 import org.apache.ftpserver.util.IoUtils;
 
 
@@ -65,6 +75,7 @@
     private DirectoryLister directoryLister;
     private DataType dataType    = DataType.ASCII;
     private Structure structure  = Structure.FILE;
+    private Map attributes = new HashMap();
     
     
     /**
@@ -116,20 +127,6 @@
     public ServerFtpConfig getConfig() {
         return fconfig;
     }
-    
-    /**
-     * Get directory lister.
-     */
-    public DirectoryLister getDirectoryLister() {
-        return directoryLister;
-    }
-    
-    /**
-     * Set directory lister.
-     */
-    public void setDirectoryLister(DirectoryLister lister) {
-        directoryLister = lister;
-    }
                 
     /**
      * Get the data type.
@@ -150,6 +147,25 @@
      */
     public Structure getStructure() {
         return structure;
+    }
+    
+    /**
+     * Get a session attribute.
+     * @param name The name of the attribute
+     * 
+     * @return The attribute value, or null if the attribute does not exist
+     */
+    public Object getAttribute(String name) {
+        return attributes.get(name);
+    }
+    
+    /**
+     * Set a session attribute.
+     * @param name The name of the attribute
+     * @param value The value of the attribute
+     */
+    public void setAttribute(String name, Object value) {
+        attributes.put(name, value);
     }
     
     /**

Modified: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/LIST.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/LIST.java?view=diff&rev=487385&r1=487384&r2=487385
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/LIST.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/LIST.java Thu Dec 14 15:20:49 2006
@@ -25,12 +25,15 @@
 import java.io.Writer;
 import java.net.SocketException;
 
-import org.apache.ftpserver.DirectoryLister;
 import org.apache.ftpserver.FtpRequestImpl;
 import org.apache.ftpserver.FtpWriter;
 import org.apache.ftpserver.RequestHandler;
 import org.apache.ftpserver.ftplet.FtpException;
 import org.apache.ftpserver.interfaces.Command;
+import org.apache.ftpserver.listing.DirectoryLister;
+import org.apache.ftpserver.listing.LISTFileFormater;
+import org.apache.ftpserver.listing.ListArgument;
+import org.apache.ftpserver.listing.ListArgumentParser;
 import org.apache.ftpserver.util.IoUtils;
 
 /**
@@ -50,6 +53,9 @@
 public 
 class LIST implements Command {
     
+    private static final LISTFileFormater LIST_FILE_FORMATER = new LISTFileFormater();
+    private DirectoryLister directoryLister = new DirectoryLister();
+    
     /**
      * Execute command.
      */
@@ -75,16 +81,16 @@
             
             // transfer listing data
             boolean failure = false;
-            boolean syntaxError = false;
             Writer writer = null;
             try {
             
                 // open stream
                 writer = new OutputStreamWriter(os, "UTF-8");
                 
-                // transfer data
-                DirectoryLister dirLister = handler.getDirectoryLister();
-                syntaxError = !dirLister.doLIST(request.getArgument(), writer);
+                // parse argument
+                ListArgument parsedArg = ListArgumentParser.parse(request.getArgument());
+                
+                writer.write(directoryLister.listFiles(parsedArg, request.getFileSystemView(), LIST_FILE_FORMATER));
             }
             catch(SocketException ex) {
                 ex.printStackTrace();
@@ -95,14 +101,12 @@
                 ex.printStackTrace();
                 failure = true;
                 out.send(551, "LIST", null);
-            }
-            finally {
-                IoUtils.close(writer);
-            }
-            
-            // if listing syntax error - send message
-            if(syntaxError) {
+            } catch(IllegalArgumentException e) {
+                // if listing syntax error - send message
                 out.send(501, "LIST", null);
+            } finally {
+                writer.flush();
+                IoUtils.close(writer);
             }
             
             // if data transfer ok - send transfer complete message

Modified: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/MLSD.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/MLSD.java?view=diff&rev=487385&r1=487384&r2=487385
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/MLSD.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/MLSD.java Thu Dec 14 15:20:49 2006
@@ -25,12 +25,16 @@
 import java.io.Writer;
 import java.net.SocketException;
 
-import org.apache.ftpserver.DirectoryLister;
 import org.apache.ftpserver.FtpRequestImpl;
 import org.apache.ftpserver.FtpWriter;
 import org.apache.ftpserver.RequestHandler;
 import org.apache.ftpserver.ftplet.FtpException;
 import org.apache.ftpserver.interfaces.Command;
+import org.apache.ftpserver.listing.DirectoryLister;
+import org.apache.ftpserver.listing.FileFormater;
+import org.apache.ftpserver.listing.ListArgument;
+import org.apache.ftpserver.listing.ListArgumentParser;
+import org.apache.ftpserver.listing.MLSTFileFormater;
 import org.apache.ftpserver.util.IoUtils;
 
 /**
@@ -47,6 +51,8 @@
 public 
 class MLSD implements Command {
 
+    private DirectoryLister directoryLister = new DirectoryLister();
+    
     /**
      * Execute command.
      */
@@ -72,16 +78,17 @@
             
             // print listing data
             boolean failure = false;
-            boolean syntaxError = false;
             Writer writer = null;
             try {
                 
                 // open stream
                 writer = new OutputStreamWriter(os, "UTF-8");
                 
-                // transfer data
-                DirectoryLister dirLister = handler.getDirectoryLister();
-                syntaxError = !dirLister.doMLSD(request.getArgument(), writer);
+                // parse argument
+                ListArgument parsedArg = ListArgumentParser.parse(request.getArgument());
+                
+                FileFormater formater = new MLSTFileFormater((String[])handler.getAttribute("MLST.types"));
+                writer.write(directoryLister.listFiles(parsedArg, request.getFileSystemView(), formater));
             }
             catch(SocketException ex) {
                 failure = true;
@@ -90,14 +97,13 @@
             catch(IOException ex) {
                 failure = true;
                 out.send(551, "MLSD", null);
+            } catch(IllegalArgumentException e) {
+                // if listing syntax error - send message
+                out.send(501, "MLSD", null);
             }
             finally {
+                writer.flush();
                 IoUtils.close(writer);
-            }
-            
-            // if listing syntax error - send message
-            if(syntaxError) {
-                out.send(501, "MLSD", null);
             }
             
             // if data transfer ok - send transfer complete message

Modified: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/MLST.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/MLST.java?view=diff&rev=487385&r1=487384&r2=487385
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/MLST.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/MLST.java Thu Dec 14 15:20:49 2006
@@ -20,13 +20,17 @@
 package org.apache.ftpserver.command;
 
 import java.io.IOException;
-import java.io.StringWriter;
 
-import org.apache.ftpserver.DirectoryLister;
 import org.apache.ftpserver.FtpRequestImpl;
 import org.apache.ftpserver.FtpWriter;
 import org.apache.ftpserver.RequestHandler;
+import org.apache.ftpserver.ftplet.FileObject;
+import org.apache.ftpserver.ftplet.FtpException;
 import org.apache.ftpserver.interfaces.Command;
+import org.apache.ftpserver.listing.FileFormater;
+import org.apache.ftpserver.listing.ListArgument;
+import org.apache.ftpserver.listing.ListArgumentParser;
+import org.apache.ftpserver.listing.MLSTFileFormater;
 
 /**
  * <code>MLST &lt;SP&gt; &lt;pathname&gt; &lt;CRLF&gt;</code><br>
@@ -48,16 +52,21 @@
         // reset state variables
         request.resetState();
         
-        // print file information
-        DirectoryLister dirLister = handler.getDirectoryLister();
-        StringWriter sw = new StringWriter();
-        if(!dirLister.doMLST(request.getArgument(), sw)) {
-            out.send(501, "MLST", null);
-        }
-        else {
-            String output = sw.toString();
-            out.send(250, "MLST", output);
+//      parse argument
+        ListArgument parsedArg = ListArgumentParser.parse(request.getArgument());
+        
+        FileObject file = null;
+        try {
+            file = request.getFileSystemView().getFileObject(parsedArg.getFile());
+            if(file != null && file.doesExist()) {
+                FileFormater formater = new MLSTFileFormater((String[])handler.getAttribute("MLST.types"));
+                out.send(250, "MLST", formater.format(file));
+            } else {            
+                out.send(501, "MLST", null);
+            }
         }
-        sw.close();
+        catch(FtpException ex) {
+            out.send(501, "MLST", null);
+        }     
     }   
 }

Modified: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/NLST.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/NLST.java?view=diff&rev=487385&r1=487384&r2=487385
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/NLST.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/NLST.java Thu Dec 14 15:20:49 2006
@@ -25,12 +25,17 @@
 import java.io.Writer;
 import java.net.SocketException;
 
-import org.apache.ftpserver.DirectoryLister;
 import org.apache.ftpserver.FtpRequestImpl;
 import org.apache.ftpserver.FtpWriter;
 import org.apache.ftpserver.RequestHandler;
 import org.apache.ftpserver.ftplet.FtpException;
 import org.apache.ftpserver.interfaces.Command;
+import org.apache.ftpserver.listing.DirectoryLister;
+import org.apache.ftpserver.listing.FileFormater;
+import org.apache.ftpserver.listing.LISTFileFormater;
+import org.apache.ftpserver.listing.ListArgument;
+import org.apache.ftpserver.listing.ListArgumentParser;
+import org.apache.ftpserver.listing.NLSTFileFormater;
 import org.apache.ftpserver.util.IoUtils;
 
 /**
@@ -48,6 +53,10 @@
 public 
 class NLST implements Command {
 
+    private static final NLSTFileFormater NLST_FILE_FORMATER = new NLSTFileFormater();
+    private static final LISTFileFormater LIST_FILE_FORMATER = new LISTFileFormater();
+    private DirectoryLister directoryLister = new DirectoryLister();
+    
     /**
      * Execute command
      */
@@ -73,16 +82,23 @@
             
             // print listing data
             boolean failure = false;
-            boolean syntaxError = false;
             Writer writer = null;
             try {
                 
                 // open stream
                 writer = new OutputStreamWriter(os, "UTF-8");
                 
-                // transfer data
-                DirectoryLister dirLister = handler.getDirectoryLister();
-                syntaxError = !dirLister.doNLST(request.getArgument(), writer);
+                // parse argument
+                ListArgument parsedArg = ListArgumentParser.parse(request.getArgument());
+                
+                FileFormater formater;
+                if(parsedArg.hasOption('l')) {
+                    formater = LIST_FILE_FORMATER;
+                } else {
+                    formater = NLST_FILE_FORMATER;
+                }
+                
+                writer.write(directoryLister.listFiles(parsedArg, request.getFileSystemView(), formater));
             }
             catch(SocketException ex) {
                 failure = true;
@@ -91,14 +107,12 @@
             catch(IOException ex) {
                 failure = true;
                 out.send(551, "NLST", null);
-            }
-            finally {
+            } catch(IllegalArgumentException e) {
+                // if listing syntax error - send message
+                out.send(501, "LIST", null);
+            } finally {
+                writer.flush();
                 IoUtils.close(writer);
-            }
-            
-            // if listing syntax error - send message
-            if(syntaxError) {
-                out.send(501, "NLST", null);
             }
             
             // if data transfer ok - send transfer complete message

Modified: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/OPTS_MLST.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/OPTS_MLST.java?view=diff&rev=487385&r1=487384&r2=487385
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/OPTS_MLST.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/OPTS_MLST.java Thu Dec 14 15:20:49 2006
@@ -22,7 +22,6 @@
 import java.io.IOException;
 import java.util.StringTokenizer;
 
-import org.apache.ftpserver.DirectoryLister;
 import org.apache.ftpserver.FtpRequestImpl;
 import org.apache.ftpserver.FtpWriter;
 import org.apache.ftpserver.RequestHandler;
@@ -39,6 +38,13 @@
 public 
 class OPTS_MLST implements Command {
     
+    private final static String[] AVAILABLE_TYPES = {
+        "Size",
+        "Modify",
+        "Type",
+        "Perm"
+    };
+    
     /**
      * Execute command.
      */
@@ -66,12 +72,40 @@
         }
         
         // set the list types
-        DirectoryLister dirLister = handler.getDirectoryLister();
-        if(dirLister.setSelectedTypes(types)) {
+        String[] validatedTypes = validateSelectedTypes(types);
+        if(validatedTypes != null) {
+            handler.setAttribute("MLST.types", validatedTypes);
             out.send(200, "OPTS.MLST", listTypes);
         }
         else {
             out.send(501, "OPTS.MLST", listTypes);
         }
+    }
+    
+    private String[] validateSelectedTypes(String types[]) {
+        
+        // ignore null types
+        if(types == null) {
+            return null;
+        }
+        
+        // check all the types
+        for(int i=0; i<types.length; ++i) {
+            boolean bMatch = false;
+            for(int j=0; j<AVAILABLE_TYPES.length; ++j) {
+                if(AVAILABLE_TYPES[j].equals(types[i])) {
+                    bMatch = true;
+                    break;
+                }
+            }
+            if(!bMatch) {
+                return null;
+            }
+        }
+        
+        // set the user types
+        String[] selectedTypes = new String[types.length];
+        System.arraycopy(types, 0, selectedTypes, 0, types.length);
+        return selectedTypes;
     }
 }

Modified: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/PASS.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/PASS.java?view=diff&rev=487385&r1=487384&r2=487385
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/PASS.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/PASS.java Thu Dec 14 15:20:49 2006
@@ -22,11 +22,16 @@
 import java.io.IOException;
 
 import org.apache.commons.logging.Log;
-import org.apache.ftpserver.DirectoryLister;
 import org.apache.ftpserver.FtpRequestImpl;
 import org.apache.ftpserver.FtpWriter;
 import org.apache.ftpserver.RequestHandler;
-import org.apache.ftpserver.ftplet.*;
+import org.apache.ftpserver.ftplet.FileSystemManager;
+import org.apache.ftpserver.ftplet.FileSystemView;
+import org.apache.ftpserver.ftplet.FtpException;
+import org.apache.ftpserver.ftplet.Ftplet;
+import org.apache.ftpserver.ftplet.FtpletEnum;
+import org.apache.ftpserver.ftplet.User;
+import org.apache.ftpserver.ftplet.UserManager;
 import org.apache.ftpserver.interfaces.Command;
 import org.apache.ftpserver.interfaces.ConnectionManager;
 import org.apache.ftpserver.interfaces.ServerFtpConfig;
@@ -153,7 +158,6 @@
             // update different objects
             FileSystemManager fmanager = fconfig.getFileSystemManager(); 
             FileSystemView fsview = fmanager.createFileSystemView(user);
-            handler.setDirectoryLister(new DirectoryLister(fsview));
             request.setLogin(fsview);
             stat.setLogin(handler);
 

Copied: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/DirectoryLister.java (from r485806, incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/DirectoryLister.java)
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/DirectoryLister.java?view=diff&rev=487385&p1=incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/DirectoryLister.java&r1=485806&p2=incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/DirectoryLister.java&r2=487385
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/DirectoryLister.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/DirectoryLister.java Thu Dec 14 15:20:49 2006
@@ -17,17 +17,13 @@
  * under the License.
  */  
 
-package org.apache.ftpserver;
+package org.apache.ftpserver.listing;
 
 import java.io.IOException;
-import java.io.Writer;
-import java.util.StringTokenizer;
 
 import org.apache.ftpserver.ftplet.FileObject;
 import org.apache.ftpserver.ftplet.FileSystemView;
 import org.apache.ftpserver.ftplet.FtpException;
-import org.apache.ftpserver.util.DateUtils;
-import org.apache.ftpserver.util.RegularExpr;
 
 /**
  * This class prints file listing.
@@ -38,343 +34,47 @@
 public 
 class DirectoryLister {
 
-    private final static char[] NEWLINE  = {'\r', '\n'};
-    private final static char DELIM    = ' ';
-    private final static String[] AVAILABLE_TYPES = {
-        "Size",
-        "Modify",
-        "Type",
-        "Perm"
-    };
     
-    
-    private FileSystemView fileSystemView;
-    
-    protected boolean isAllOption;
-    protected boolean isDetailOption; 
-    
-    protected String file;
-    protected String pattern;
-    private char permission[] = new char[10];
-    
-    private String[] selectedTypes = new String[] {"Size", "Modify", "Type"};
-    
-    
-    /**
-     * Constructor - set the file system view.
-     */
-    public DirectoryLister(FileSystemView fileSystemView) {
-        this.fileSystemView = fileSystemView;
-        for(int i=3; i<10; ++i) {
-            permission[i] = '-';
-        }
-    }
-    
-    /**
-     * Get selected types.
-     */
-    public String[] getSelectedTypes() {
-        String types[] = new String[selectedTypes.length];
-        System.arraycopy(selectedTypes, 0, types, 0, selectedTypes.length);
-        return types;
-    }
-    
-    /**
-     * Returns true if, and only if, the string passed was
-     * successfully parsed as valid types.
-     */
-    public boolean setSelectedTypes(String types[]) {
-        
-        // ignore null types
-        if(types == null) {
-            return false;
-        }
-        
-        // check all the types
-        for(int i=0; i<types.length; ++i) {
-            boolean bMatch = false;
-            for(int j=0; j<AVAILABLE_TYPES.length; ++j) {
-                if(AVAILABLE_TYPES[j].equals(types[i])) {
-                    bMatch = true;
-                    break;
-                }
-            }
-            if(!bMatch) {
-                return false;
-            }
-        }
-        
-        // set the user types
-        selectedTypes = new String[types.length];
-        System.arraycopy(types, 0, selectedTypes, 0, types.length);
-        return true;
-    }
-    
-    /**
-     * Print file list. The server will return a stream of names of 
-     * files and no other information if detail listing flag is false.
-     * <pre>
-     *   -l : detail listing
-     *   -a : display all (including hidden files)
-     * </pre>
-     */
-    public boolean doNLST(String argument, Writer out) throws IOException {
-        
-        // parse argument
-        if(!parse(argument)) {
-            return false;
-        }
-        
-        // get all the file objects
-        FileObject[] files = listFiles();
-        if(files == null) {
-            return false;
-        }
-        
-        RegularExpr regexp = null;
-        if(pattern != null) {
-            regexp = new RegularExpr(pattern);
-        }
+    private String traverseFiles(final FileObject[] files, final FileFilter filter, final FileFormater formater) {
+        StringBuffer sb = new StringBuffer();
         for(int i=0; i<files.length; i++) {
             if(files[i] == null) {
                 continue;
             }
-            if ( (!isAllOption) && files[i].isHidden() ) {
-                continue;
-            }
-            if( (regexp != null) && (!regexp.isMatch(files[i].getShortName())) ) {
-                continue;
-            }
             
-            if(isDetailOption) {
-                printLine(files[i], out);
+            if(filter == null || filter.accept(files[i])) {
+                sb.append(formater.format(files[i]));
             }
-            else {
-                out.write(files[i].getShortName());
-            }
-            out.write(NEWLINE);
-        }
-        out.flush();
-        return true;
-    }
-    
-    /**
-     * Print file list. Detail listing.
-     * <pre>
-     *   -a : display all (including hidden files)
-     * </pre>
-     * @return true if success
-     */
-    public boolean doLIST(String argument, Writer out) throws IOException {
-        
-        // parse argument
-        if(!parse(argument)) {
-            return false;
-        }
-        
-        // get all the file objects
-        FileObject[] files = listFiles();
-        if(files == null) {
-            return false;
-        }
-        
-        // Arrays.sort(files, new FileComparator());
-        RegularExpr regexp = null;
-        if(pattern != null) {
-            regexp = new RegularExpr(pattern);
-        }
-        for(int i=0; i<files.length; i++) {
-            if(files[i] == null) {
-                continue;
-            }
-            if ( (!isAllOption) && files[i].isHidden() ) {
-                continue;
-            }
-            if( (regexp != null) && (!regexp.isMatch(files[i].getShortName())) ) {
-                continue;
-            }
-            printLine(files[i], out);
-            out.write(NEWLINE);
          }
-        out.flush();
-        return true;
-    }
-    
-    /**
-     * Print path info. Machine listing. It prints the listing
-     * information for a single file.
-     *
-     * @return true if success
-     */
-    public boolean doMLST(String argument, Writer out) throws IOException {
-
-        // check argument
-        if(argument == null) {
-            argument = "./";
-        }
-        
-        FileObject file = null;
-        try {
-            file = fileSystemView.getFileObject(argument);
-            if(file == null) {
-                return false;
-            }
-            if(!file.doesExist()) {
-                return false;
-            }
-        }
-        catch(FtpException ex) {
-        }
-        if(file == null) {
-            return false;
-        }
         
-        printMLine(file, out);
-        return true;
+        return sb.toString();
     }
     
-    /**
-     * Print directory contents. Machine listing.
-     * <pre>
-     *   -a : display all (including hidden files)
-     * </pre>
-     * 
-     * @return true if success
-     */
-    public boolean doMLSD(String argument, Writer out) throws IOException {
-        
-        // parse argument
-        if(!parse(argument)) {
-            return false;
-        }
+    public String listFiles(final ListArgument argument, final FileSystemView fileSystemView, final FileFormater formater) throws IOException {
+       
+        StringBuffer sb = new StringBuffer();
         
         // get all the file objects
-        FileObject[] files = listFiles();
-        if(files == null) {
-            return false;
-        }
-        
-        // Arrays.sort(files, new FileComparator());
-        RegularExpr regexp = null;
-        if(pattern != null) {
-            regexp = new RegularExpr(pattern);
-        }
-        for(int i=0; i<files.length; i++) {
-            if(files[i] == null) {
-                continue;
-            }
-            if ( (!isAllOption) && files[i].isHidden() ) {
-                continue;
+        FileObject[] files = listFiles(fileSystemView, argument.getFile());
+        if(files != null) {
+            FileFilter filter = null;
+            if ( (argument.hasOption('a'))) {
+                filter = new VisibleFileFilter();
             }
-            if( (regexp != null) && (!regexp.isMatch(files[i].getShortName())) ) {
-                continue;
-            }
-            printMLine(files[i], out);
-            out.write(NEWLINE);
-         }
-        out.flush();
-        return true;
-    }
-    
-    /**
-     * Parse argument.
-     */
-    protected boolean parse(String argument) {
-        String lsFileName = "./";
-        String options = "";
-        String pattern = "*";
-        
-        // find options and file name (may have regular expression)
-        if(argument != null) {
-            argument = argument.trim();
-            StringBuffer optionsSb = new StringBuffer(4);
-            StringBuffer lsFileNameSb = new StringBuffer(16);
-            StringTokenizer st = new StringTokenizer(argument, " ", true);
-            while(st.hasMoreTokens()) {
-                String token = st.nextToken();
-                
-                if(lsFileNameSb.length() != 0) {
-                    // file name started - append to file name buffer
-                    lsFileNameSb.append(token);
-                }
-                else if(token.equals(" ")) {
-                    // delimiter and file not started - ignore
-                    continue;
-                } 
-                else if(token.charAt(0) == '-') {
-                    // token and file name not started - append to options buffer
-                    if (token.length() > 1) {
-                        optionsSb.append(token.substring(1));
-                    }
-                }
-                else {
-                    // filename - append to the filename buffer
-                    lsFileNameSb.append(token);
-                }
+            if(argument.getPattern() != null) {
+                filter = new RegexFileFilter(argument.getPattern(), filter);
             }
             
-            if(lsFileNameSb.length() != 0) {
-                lsFileName = lsFileNameSb.toString();
-            }
-            options = optionsSb.toString();
+            sb.append(traverseFiles(files, filter, formater));
         }
-        isAllOption = options.indexOf('a') != -1;
-        isDetailOption = options.indexOf('l') != -1;
         
-        // check regular expression
-        if( (lsFileName.indexOf('*') == -1) &&
-            (lsFileName.indexOf('?') == -1) &&
-            (lsFileName.indexOf('[') == -1) ) {
-            this.pattern = null;
-            file = lsFileName;
-            return true;
-        }
-        
-        // get the directory part and the egular expression part
-        try {
-            int slashIndex = lsFileName.lastIndexOf('/');
-            if(slashIndex == -1) {
-                pattern = lsFileName;
-                lsFileName = "./";
-            }
-            else if( slashIndex != (lsFileName.length() -1) ) {
-                pattern = lsFileName.substring(slashIndex+1);
-                lsFileName = lsFileName.substring(0, slashIndex+1);
-            }
-            else {
-                return false;
-            }
-            
-            // check path
-            FileObject file = fileSystemView.getFileObject(lsFileName);
-            if(file == null) {
-                return false;
-            }
-            
-            // parent is not a directory - no need to process
-            if(!file.isDirectory()) {
-                return false;
-            }
-        }
-        catch(FtpException ex) {
-            ex.printStackTrace();
-            return false;
-        }
-
-        file = lsFileName;
-        if( "*".equals(pattern) || "".equals(pattern) ) {
-            this.pattern = null;
-        }
-        else {
-            this.pattern = pattern;
-        }
-        return true;
+        return sb.toString();
     }
     
     /**
      * Get the file list.
      */
-    private FileObject[] listFiles() {
+    private FileObject[] listFiles(FileSystemView fileSystemView, String file) {
     	FileObject[] files = null;
     	try {
 	    	FileObject virtualFile = fileSystemView.getFileObject(file);
@@ -388,116 +88,5 @@
     	catch(FtpException ex) {
     	}
     	return files;
-    }
-    
-    /**
-     * Get each directory line.
-     */
-    private void printLine(FileObject file, Writer out) throws IOException {
-        out.write(getPermission(file));
-        out.write(DELIM);
-        out.write(DELIM);
-        out.write(DELIM);
-        out.write(String.valueOf(file.getLinkCount()));
-        out.write(DELIM);
-        out.write(file.getOwnerName());
-        out.write(DELIM);
-        out.write(file.getGroupName());
-        out.write(DELIM);
-        out.write(getLength(file));
-        out.write(DELIM);
-        out.write(getLastModified(file));
-        out.write(DELIM);
-        out.write(file.getShortName());
-    }
-    
-    /**
-     * Get permission string.
-     */
-    private char[] getPermission(FileObject file) {
-        permission[0] = file.isDirectory() ? 'd' : '-';
-        permission[1] = file.hasReadPermission() ? 'r' : '-';
-        permission[2] = file.hasWritePermission() ? 'w' : '-';
-        return permission;
-    }
-    
-    /**
-     * Get size
-     */
-    private String getLength(FileObject file) {
-        String initStr = "            ";
-        long sz = 0;
-        if(file.isFile()) {
-            sz = file.getSize();
-        }
-        String szStr = String.valueOf(sz);
-        if(szStr.length() > initStr.length()) {
-            return szStr;
-        }
-        return initStr.substring(0, initStr.length() - szStr.length()) + szStr;
-    }
-    
-    /**
-     * Get last modified date string.
-     */
-    private String getLastModified(FileObject file) {
-        return DateUtils.getUnixDate( file.getLastModified() );
-    }
-    
-    /**
-     * Print each file line.
-     */
-    private void printMLine(FileObject file, Writer out) throws IOException {
-        for(int i=0; i<selectedTypes.length; ++i) {
-            String type = selectedTypes[i];
-            if(type.equalsIgnoreCase("size")) {
-                out.write("Size=");
-                out.write(String.valueOf(file.getSize()));
-                out.write(';');
-            }
-            else if(type.equalsIgnoreCase("modify")) {
-                String timeStr = DateUtils.getFtpDate( file.getLastModified() );
-                out.write("Modify=");
-                out.write(timeStr);
-                out.write(';');
-            }
-            else if(type.equalsIgnoreCase("type")) {
-                if(file.isFile()) {
-                    out.write("Type=file;");
-                }
-                else if(file.isDirectory()) {
-                    out.write("Type=dir;");
-                }
-            }
-            else if(type.equalsIgnoreCase("perm")) {
-                out.write("Perm=");
-                if(file.hasReadPermission()) {
-                    if(file.isFile()) {
-                        out.write('r');
-                    }
-                    else if(file.isDirectory()) {
-                        out.write('e');
-                        out.write('l');
-                    }
-                }
-                if(file.hasWritePermission()) {
-                    if(file.isFile()) {
-                        out.write('a');
-                        out.write('d');
-                        out.write('f');
-                        out.write('w');
-                    }
-                    else if(file.isDirectory()) {
-                        out.write('f');
-                        out.write('p');
-                        out.write('c');
-                        out.write('m');
-                    }
-                }
-                out.write(';');
-            }
-        }
-        out.write(' ');
-        out.write(file.getShortName());
     }
 }

Added: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/FileFilter.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/FileFilter.java?view=auto&rev=487385
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/FileFilter.java (added)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/FileFilter.java Thu Dec 14 15:20:49 2006
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.ftpserver.listing;
+
+import org.apache.ftpserver.ftplet.FileObject;
+
+/**
+ * Interface for selecting files based on some critera.
+ * @see java.io.FileFilter
+ */
+public interface FileFilter {
+
+    /**
+     * Decide if the {@link FileObject} should be selected
+     * @param file The {@link FileObject}
+     * @return true if the {@link FileObject} was selected
+     */
+    boolean accept(FileObject file);
+
+}

Propchange: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/FileFilter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/FileFormater.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/FileFormater.java?view=auto&rev=487385
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/FileFormater.java (added)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/FileFormater.java Thu Dec 14 15:20:49 2006
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.ftpserver.listing;
+
+import org.apache.ftpserver.ftplet.FileObject;
+
+/**
+ * Interface for formating output based on a {@link FileObject}
+ */
+public interface FileFormater {
+
+    /**
+     * Format the file
+     * @param file The {@link FileObject}
+     * @return The formated string based on the {@link FileObject}
+     */
+    String format(FileObject file);
+
+}

Propchange: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/FileFormater.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/LISTFileFormater.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/LISTFileFormater.java?view=auto&rev=487385
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/LISTFileFormater.java (added)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/LISTFileFormater.java Thu Dec 14 15:20:49 2006
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.ftpserver.listing;
+
+import java.util.Arrays;
+
+import org.apache.ftpserver.ftplet.FileObject;
+import org.apache.ftpserver.util.DateUtils;
+
+/**
+ * Formats files according to the LIST specification
+ */
+public class LISTFileFormater implements FileFormater {
+
+    private final static char DELIM = ' ';
+    private final static char[] NEWLINE  = {'\r', '\n'};
+    
+    /**
+     * @see FileFormater#format(FileObject)
+     */
+    public String format(FileObject file) {
+        StringBuffer sb = new StringBuffer();
+        sb.append(getPermission(file));
+        sb.append(DELIM);
+        sb.append(DELIM);
+        sb.append(DELIM);
+        sb.append(String.valueOf(file.getLinkCount()));
+        sb.append(DELIM);
+        sb.append(file.getOwnerName());
+        sb.append(DELIM);
+        sb.append(file.getGroupName());
+        sb.append(DELIM);
+        sb.append(getLength(file));
+        sb.append(DELIM);
+        sb.append(getLastModified(file));
+        sb.append(DELIM);
+        sb.append(file.getShortName());
+        sb.append(NEWLINE);
+
+        return sb.toString();
+    }
+    
+    /**
+     * Get size
+     */
+    private String getLength(FileObject file) {
+        String initStr = "            ";
+        long sz = 0;
+        if(file.isFile()) {
+            sz = file.getSize();
+        }
+        String szStr = String.valueOf(sz);
+        if(szStr.length() > initStr.length()) {
+            return szStr;
+        }
+        return initStr.substring(0, initStr.length() - szStr.length()) + szStr;
+    }
+    
+    /**
+     * Get last modified date string.
+     */
+    private String getLastModified(FileObject file) {
+        return DateUtils.getUnixDate( file.getLastModified() );
+    }
+    
+    /**
+     * Get permission string.
+     */
+    private char[] getPermission(FileObject file) {
+        char permission[] = new char[10];
+        Arrays.fill(permission, '-');
+        
+        permission[0] = file.isDirectory() ? 'd' : '-';
+        permission[1] = file.hasReadPermission() ? 'r' : '-';
+        permission[2] = file.hasWritePermission() ? 'w' : '-';
+        return permission;
+    }
+
+    /*public String format(FileObject[] files) {
+        StringBuffer sb = new StringBuffer();
+        
+        for (int i = 0; i < files.length; i++) {
+            sb.append(format(files[i]));
+            sb.append(NEWLINE);
+        }
+        return sb.toString();
+    }*/
+
+}

Propchange: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/LISTFileFormater.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/ListArgument.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/ListArgument.java?view=auto&rev=487385
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/ListArgument.java (added)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/ListArgument.java Thu Dec 14 15:20:49 2006
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.ftpserver.listing;
+
+/**
+ * Contains the parsed argument for a list command (e.g. LIST or NLST)
+ */
+public class ListArgument {
+
+    private String file;
+    private String pattern;
+    private char[] options;
+    
+    /**
+     * @param file The file path including the directory
+     * @param pattern A regular expression pattern that files must match
+     * @param options List options, such as -la
+     */
+    public ListArgument(String file, String pattern, char[] options) {
+        this.file = file;
+        this.pattern = pattern;
+        if(options == null) {
+            this.options = new char[0];
+        } else {
+            this.options = options;
+        }
+    }
+    
+    /**
+     * The listing options, 
+     * @return All options
+     */
+    public char[] getOptions() {
+        return options;
+    }
+    
+    /**
+     * The regular expression pattern that files must match
+     * @return The regular expression
+     */
+    public String getPattern() {
+        return pattern;
+    }
+    
+    /**
+     * Checks if a certain option is set
+     * @param option The option to check
+     * @return true if the option is set
+     */
+    public boolean hasOption(char option) {
+        for (int i = 0; i < options.length; i++) {
+            if(option == options[i]) {
+                return true;
+            }
+        }
+        
+        return false;
+    }
+
+    /**
+     * The file path including the directory
+     * @return The file path
+     */
+    public String getFile() {
+        return file;
+    }
+
+
+
+}

Propchange: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/ListArgument.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/ListArgumentParser.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/ListArgumentParser.java?view=auto&rev=487385
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/ListArgumentParser.java (added)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/ListArgumentParser.java Thu Dec 14 15:20:49 2006
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.ftpserver.listing;
+
+import java.util.StringTokenizer;
+
+/**
+ * Parses a list argument (e.g. for LIST or NLST) into a {@link ListArgument}
+ */
+public class ListArgumentParser {
+    
+    /**
+     * Parse the argument
+     * @param argument The argument string
+     * @return The parsed argument
+     * @throws IllegalArgumentException If the argument string is incorrectly formated
+     */
+    public static ListArgument parse(String argument) {
+        String file = "./";
+        String options = "";
+        String pattern = "*";
+        
+        // find options and file name (may have regular expression)
+        if(argument != null) {
+            argument = argument.trim();
+            StringBuffer optionsSb = new StringBuffer(4);
+            StringBuffer fileSb = new StringBuffer(16);
+            StringTokenizer st = new StringTokenizer(argument, " ", true);
+            while(st.hasMoreTokens()) {
+                String token = st.nextToken();
+                
+                if(fileSb.length() != 0) {
+                    // file name started - append to file name buffer
+                    fileSb.append(token);
+                }
+                else if(token.equals(" ")) {
+                    // delimiter and file not started - ignore
+                    continue;
+                } 
+                else if(token.charAt(0) == '-') {
+                    // token and file name not started - append to options buffer
+                    if (token.length() > 1) {
+                        optionsSb.append(token.substring(1));
+                    }
+                }
+                else {
+                    // filename - append to the filename buffer
+                    fileSb.append(token);
+                }
+            }
+            
+            if(fileSb.length() != 0) {
+                file = fileSb.toString();
+            }
+            options = optionsSb.toString();
+        }
+        
+        int slashIndex = file.lastIndexOf('/');
+        if(slashIndex == -1) {
+            if(containsPattern(file)) {
+                pattern = file;
+                file = "./";
+            }
+        } else if( slashIndex != (file.length() -1) ) {
+            String after = file.substring(slashIndex+1);
+            
+            if(containsPattern(after)) {
+                pattern = file.substring(slashIndex+1);
+                file = file.substring(0, slashIndex+1);
+            }            
+            
+            if(containsPattern(file)) {
+                throw new IllegalArgumentException("Directory path can not contain regular expression");
+            }
+        }
+
+        if( "*".equals(pattern) || "".equals(pattern) ) {
+            pattern = null;
+        }
+        
+        
+        return new ListArgument(file, pattern, options.toCharArray());
+    }
+
+    private static boolean containsPattern(String file) {
+        return file.indexOf('*') > -1 || 
+               file.indexOf('?') > -1 ||
+               file.indexOf('[') > -1;
+
+    }
+}

Propchange: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/ListArgumentParser.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/MLSTFileFormater.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/MLSTFileFormater.java?view=auto&rev=487385
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/MLSTFileFormater.java (added)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/MLSTFileFormater.java Thu Dec 14 15:20:49 2006
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.ftpserver.listing;
+
+import org.apache.ftpserver.ftplet.FileObject;
+import org.apache.ftpserver.util.DateUtils;
+
+/**
+ * Formats files according to the MLST specification
+ */
+public class MLSTFileFormater implements FileFormater {
+
+    private static final String[] DEFAULT_TYPES = new String[] {"Size", "Modify", "Type"};
+
+    private final static char[] NEWLINE  = {'\r', '\n'};
+    
+    private String[] selectedTypes = DEFAULT_TYPES;
+    
+    /**
+     * @param selectedTypes The types to show in the formated file
+     */
+    public MLSTFileFormater(String[] selectedTypes) {
+        if(selectedTypes != null) {
+            this.selectedTypes = selectedTypes;
+        }
+    }
+    
+    /**
+     * @see FileFormater#format(FileObject)
+     */
+    public String format(FileObject file) {
+        StringBuffer sb = new StringBuffer();
+        
+        for(int i=0; i<selectedTypes.length; ++i) {
+            String type = selectedTypes[i];
+            if(type.equalsIgnoreCase("size")) {
+                sb.append("Size=");
+                sb.append(String.valueOf(file.getSize()));
+                sb.append(';');
+            }
+            else if(type.equalsIgnoreCase("modify")) {
+                String timeStr = DateUtils.getFtpDate( file.getLastModified() );
+                sb.append("Modify=");
+                sb.append(timeStr);
+                sb.append(';');
+            }
+            else if(type.equalsIgnoreCase("type")) {
+                if(file.isFile()) {
+                    sb.append("Type=file;");
+                }
+                else if(file.isDirectory()) {
+                    sb.append("Type=dir;");
+                }
+            }
+            else if(type.equalsIgnoreCase("perm")) {
+                sb.append("Perm=");
+                if(file.hasReadPermission()) {
+                    if(file.isFile()) {
+                        sb.append('r');
+                    }
+                    else if(file.isDirectory()) {
+                        sb.append('e');
+                        sb.append('l');
+                    }
+                }
+                if(file.hasWritePermission()) {
+                    if(file.isFile()) {
+                        sb.append('a');
+                        sb.append('d');
+                        sb.append('f');
+                        sb.append('w');
+                    }
+                    else if(file.isDirectory()) {
+                        sb.append('f');
+                        sb.append('p');
+                        sb.append('c');
+                        sb.append('m');
+                    }
+                }
+                sb.append(';');
+            }
+        }
+        sb.append(' ');
+        sb.append(file.getShortName());
+        
+        sb.append(NEWLINE);
+
+        return sb.toString();
+    }
+}

Propchange: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/MLSTFileFormater.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/NLSTFileFormater.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/NLSTFileFormater.java?view=auto&rev=487385
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/NLSTFileFormater.java (added)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/NLSTFileFormater.java Thu Dec 14 15:20:49 2006
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.ftpserver.listing;
+
+import org.apache.ftpserver.ftplet.FileObject;
+
+/**
+ * Formats files according to the NLST specification
+ */
+public class NLSTFileFormater implements FileFormater {
+
+    private final static char[] NEWLINE  = {'\r', '\n'};
+    
+    /**
+     * @see FileFormater#format(FileObject)
+     */
+    public String format(FileObject file) {
+        StringBuffer sb = new StringBuffer();
+        sb.append(file.getShortName());
+        sb.append(NEWLINE);
+
+        return sb.toString();
+    }
+}

Propchange: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/NLSTFileFormater.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/RegexFileFilter.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/RegexFileFilter.java?view=auto&rev=487385
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/RegexFileFilter.java (added)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/RegexFileFilter.java Thu Dec 14 15:20:49 2006
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.ftpserver.listing;
+
+import org.apache.ftpserver.ftplet.FileObject;
+import org.apache.ftpserver.util.RegularExpr;
+
+/**
+ * Selects files which short name matches a regular expression
+ */
+public class RegexFileFilter implements FileFilter {
+
+    private RegularExpr regex;
+    private FileFilter wrappedFilter;
+    
+    /**
+     * Constructor with a regular expression
+     * @param regex The regular expression to select by
+     */
+    public RegexFileFilter(String regex) {
+        this.regex = new RegularExpr(regex);
+    }
+
+    /**
+     * Constructor with a wrapped filter, allows for chaining filters
+     * @param regex The regular expression to select by
+     * @param wrappedFilter The {@link FileFilter} to wrap
+     */
+    public RegexFileFilter(String regex, FileFilter wrappedFilter) {
+        this(regex);
+        
+        this.wrappedFilter = wrappedFilter;
+    }
+    
+    /**
+     * @see FileFilter#accept(FileObject)
+     */
+    public boolean accept(FileObject file) {
+        if(wrappedFilter != null && !wrappedFilter.accept(file)) {
+            return false;
+        }
+        
+        return regex.isMatch(file.getShortName());
+    }
+
+}

Propchange: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/RegexFileFilter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/VisibleFileFilter.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/VisibleFileFilter.java?view=auto&rev=487385
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/VisibleFileFilter.java (added)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/VisibleFileFilter.java Thu Dec 14 15:20:49 2006
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.ftpserver.listing;
+
+import org.apache.ftpserver.ftplet.FileObject;
+
+/**
+ * Selects files that are visible
+ */
+public class VisibleFileFilter implements FileFilter {
+
+    private FileFilter wrappedFilter;
+    
+    /**
+     * Default constructor
+     */
+    public VisibleFileFilter() {
+        // default cstr
+    }
+
+    /**
+     * Constructor with a wrapped filter, allows for chaining filters
+     * @param wrappedFilter The {@link FileFilter} to wrap
+     */
+    public VisibleFileFilter(FileFilter wrappedFilter) {
+        this.wrappedFilter = wrappedFilter;
+    }
+    
+    /**
+     * @see FileFilter#accept(FileObject)
+     */
+    public boolean accept(FileObject file) {
+        if(wrappedFilter != null && !wrappedFilter.accept(file)) {
+            return false;
+        }
+        
+        return !file.isHidden();
+    }
+}

Propchange: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listing/VisibleFileFilter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/clienttests/ListTest.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/clienttests/ListTest.java?view=diff&rev=487385&r1=487384&r2=487385
==============================================================================
--- incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/clienttests/ListTest.java (original)
+++ incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/clienttests/ListTest.java Thu Dec 14 15:20:49 2006
@@ -23,7 +23,9 @@
 
 import org.apache.commons.net.ftp.FTPClientConfig;
 import org.apache.commons.net.ftp.FTPFile;
+import org.apache.commons.net.ftp.FTPReply;
 import org.apache.ftpserver.test.TestUtil;
+import org.apache.ftpserver.util.DateUtils;
 
 
 public class ListTest extends ClientTestTemplate {
@@ -82,6 +84,7 @@
         assertTrue(file.isDirectory());
         
     }
+    
     public void testListFile() throws Exception {
         
         TEST_DIR1.mkdirs();
@@ -100,6 +103,22 @@
         assertTrue(file.isFile());
         assertFalse(file.isDirectory());
     }
+    
+    public void testListFileNoArgument() throws Exception {
+        TEST_DIR1.mkdirs();
+        
+        FTPFile[] files = client.listFiles();
+        
+        assertEquals(1, files.length);
+        
+        FTPFile file = getFile(files, TEST_DIR1.getName());
+        assertEquals(TEST_DIR1.getName(), file.getName());
+        assertEquals(0, file.getSize());
+        assertEquals("group", file.getGroup());
+        assertEquals("user", file.getUser());
+        assertFalse(file.isFile());
+        assertTrue(file.isDirectory());
+    }
 
     public void testListFiles() throws Exception {
         TEST_FILE1.createNewFile();
@@ -178,6 +197,33 @@
         assertEquals(1, files.length);
         
         TestUtil.assertInArrays(TEST_FILE2.getName(), files);
+    }
+    
+    public void testMLST() throws Exception {
+        TEST_FILE1.createNewFile();
+        
+        assertTrue(FTPReply.isPositiveCompletion(client.sendCommand("MLST " + TEST_FILE1.getName())));
+        
+        String[] reply = client.getReplyString().split("\\r\\n");
+        
+        assertEquals("Size=0;Modify=" + DateUtils.getFtpDate(TEST_FILE1.lastModified()) + ";Type=file; " + TEST_FILE1.getName(), reply[1]);
+    }
+    
+    public void testOPTSMLST() throws Exception {
+        TEST_FILE1.createNewFile();
+        
+        assertTrue(FTPReply.isPositiveCompletion(client.sendCommand("OPTS MLST Size;Modify")));
+        assertTrue(FTPReply.isPositiveCompletion(client.sendCommand("MLST " + TEST_FILE1.getName())));
+        
+        String[] reply = client.getReplyString().split("\\r\\n");
+        
+        assertEquals("Size=0;Modify=" + DateUtils.getFtpDate(TEST_FILE1.lastModified()) + "; " + TEST_FILE1.getName(), reply[1]);
+    }
+    
+    public void testOPTSMLSTInvalidType() throws Exception {
+        TEST_FILE1.createNewFile();
+        
+        assertTrue(FTPReply.isNegativePermanent(client.sendCommand("OPTS MLST Foo;Size")));
     }
     
     private FTPFile getFile(FTPFile[] files, String name) {

Copied: incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/listing/DirectoryListerTest.java (from r485806, incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/DirectoryListerTest.java)
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/listing/DirectoryListerTest.java?view=diff&rev=487385&p1=incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/DirectoryListerTest.java&r1=485806&p2=incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/listing/DirectoryListerTest.java&r2=487385
==============================================================================
--- incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/DirectoryListerTest.java (original)
+++ incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/listing/DirectoryListerTest.java Thu Dec 14 15:20:49 2006
@@ -17,32 +17,23 @@
  * under the License.
  */  
 
-package org.apache.ftpserver;
+package org.apache.ftpserver.listing;
 
 import java.io.File;
-import java.io.StringWriter;
-import java.util.Date;
-import java.util.Formatter;
-import java.util.StringTokenizer;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 import junit.framework.TestCase;
 
 import org.apache.ftpserver.filesystem.NativeFileSystemView;
 import org.apache.ftpserver.ftplet.FileSystemView;
-import org.apache.ftpserver.test.OS;
+import org.apache.ftpserver.listing.DirectoryLister;
+import org.apache.ftpserver.listing.FileFormater;
+import org.apache.ftpserver.listing.ListArgument;
+import org.apache.ftpserver.listing.NLSTFileFormater;
 import org.apache.ftpserver.test.TestUtil;
 import org.apache.ftpserver.usermanager.BaseUser;
-import org.apache.ftpserver.util.DateUtils;
 import org.apache.ftpserver.util.IoUtils;
 
-import sun.management.StringFlag;
-
 public class DirectoryListerTest extends TestCase {
-    private static final String DELIMITER = "\\r\\n";
-    private static final String LIST_PATTERN_TEMPLATE = "^%sr--------\\s\\s\\s%s\\suser\\sgroup\\s+%s\\s%s\\s%s$";
-    
     private static final File TEST_TMP_DIR = new File("test-tmp");
     protected static final File ROOT_DIR = new File(TEST_TMP_DIR, "ftproot");
     
@@ -57,10 +48,6 @@
 
     private static final byte[] TEST_DATA = "TESTDATA".getBytes();
     
-    private static final String[] MONTHS = new String[]{
-        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
-        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
-    };
     
     private DirectoryLister directoryLister;
 
@@ -70,7 +57,7 @@
         BaseUser baseUser = new BaseUser();
         baseUser.setHomeDirectory(ROOT_DIR.getAbsolutePath());
         fileSystemView = new NativeFileSystemView(baseUser) {};
-        directoryLister = new DirectoryLister(fileSystemView);
+        directoryLister = new DirectoryLister();
         
         assertTrue(ROOT_DIR.mkdirs());
         assertTrue(TEST_DIR1.mkdirs());
@@ -81,205 +68,16 @@
         assertTrue(TEST_DIR_IN_DIR1.mkdir());
     }
 
-    /*
-     * Test method for 'org.apache.ftpserver.DirectoryLister.parse(String)'
-     */
-    public void testParse() {
-        assertEquals(true, directoryLister.parse("-ls /abcd"));
-        assertEquals("/abcd", directoryLister.file);
-        assertEquals(true, directoryLister.isDetailOption);
-        assertEquals(false, directoryLister.isAllOption);
-
-        assertEquals(true, directoryLister.parse("-ls /ab cd"));
-        assertEquals("/ab cd", directoryLister.file);
-        assertEquals(true, directoryLister.isDetailOption);
-        assertEquals(false, directoryLister.isAllOption);
-    }
-    
-    public void testLIST() throws Exception {
-        StringWriter writer = new StringWriter();
-        assertTrue(directoryLister.doLIST(TEST_DIR1.getName(), writer));
+   
+    public void testListFiles() throws Exception {
+        ListArgument arg = new ListArgument(TEST_DIR1.getName(), null, null);
+        FileFormater formater = new NLSTFileFormater();
         
-        String[] lines = writer.toString().split(DELIMITER);
-
-        assertEquals(3, lines.length);
-        assertLISTLine(lines[0], TEST_DIR_IN_DIR1);
-        assertLISTLine(lines[1], TEST_FILE1_IN_DIR1);
-        assertLISTLine(lines[2], TEST_FILE2_IN_DIR1);
-    }
-    
-    public void testLISTOnFile() throws Exception {
-        StringWriter writer = new StringWriter();
-        assertTrue(directoryLister.doLIST(TEST_DIR1.getName() + "/" + TEST_FILE1_IN_DIR1.getName(), writer));
+        String actual = directoryLister.listFiles(arg, fileSystemView, formater);
         
-        String[] lines = writer.toString().split(DELIMITER);
-
-        assertEquals(1, lines.length);
-        assertLISTLine(lines[0], TEST_FILE1_IN_DIR1);
+        assertEquals("dir3\r\ntest3.txt\r\ntest4.txt\r\n", actual);
     }
-    
-    /**
-     * Should show the exact same output
-     */
-    public void testLISTLong() throws Exception {
-        StringWriter shortWriter = new StringWriter();
-        StringWriter longWriter = new StringWriter();
-
-        assertTrue(directoryLister.doLIST(TEST_DIR1.getName(), shortWriter));
-        assertTrue(directoryLister.doLIST("-l " + TEST_DIR1.getName(), longWriter));
-        
-        assertEquals(shortWriter.toString(), longWriter.toString());
-    }
-    
-    public void testLISTEmptyDir() throws Exception {
-        StringWriter writer = new StringWriter();
-        assertTrue(directoryLister.doLIST(TEST_DIR2.getName(), writer));
-
-        assertEquals(0, writer.toString().trim().length());
-    }
-
-    /**
-     * This test only works on Linux as there is no way
-     * of creating a hidden file in Java on Windows
-     */
-    public void testLISTHiddenFileNotShown() throws Exception {
-        if(!OS.isFamilyUnix()) {
-            return;
-        }
-        
-        File hiddenFile = new File(TEST_DIR1, ".hidden.txt");
-        hiddenFile.createNewFile();
-        
-        StringWriter writer = new StringWriter();
-        assertTrue(directoryLister.doLIST(TEST_DIR1.getName(), writer));
-        
-        String[] lines = writer.toString().split(DELIMITER);
-        
-        assertEquals(3, lines.length);
-        assertLISTLine(lines[0], TEST_DIR_IN_DIR1);
-        assertLISTLine(lines[1], TEST_FILE1_IN_DIR1);
-        assertLISTLine(lines[2], TEST_FILE2_IN_DIR1);
-    }
-    
-    /**
-     * This test only works on Linux as there is no way
-     * of creating a hidden file in Java on Windows
-     */
-    public void testLISTHiddenFileShown() throws Exception {
-        if(!OS.isFamilyUnix()) {
-            return;
-        }
-        
-        File hiddenFile = new File(TEST_DIR1, ".hidden.txt");
-        hiddenFile.createNewFile();
-        
-        StringWriter writer = new StringWriter();
-        assertTrue(directoryLister.doLIST("-a " + TEST_DIR1.getName(), writer));
-        
-        String[] lines = writer.toString().split(DELIMITER);
-        
-        assertEquals(4, lines.length);
-        assertLISTLine(lines[0], TEST_DIR_IN_DIR1);
-        assertLISTLine(lines[1], hiddenFile);
-        assertLISTLine(lines[2], TEST_FILE1_IN_DIR1);
-        assertLISTLine(lines[3], TEST_FILE2_IN_DIR1);
-    }
-
-    
-    private void assertLISTLine(String actual, File file) {
-        String[] args = new String[5];
-        args[0] = file.isDirectory() ? "d" : "-";
-        args[1] = file.isDirectory() ? "3" : "1";
-        args[2] = Long.toString(file.length());
-        args[3] = DateUtils.getUnixDate(file.lastModified()).replace(" ", "\\s");
-        args[4] = file.getName();
-       
-        String pattern = String.format(LIST_PATTERN_TEMPLATE, args);
-       
-        assertTrue(Pattern.matches(pattern, actual));
-    }
-    
-    public void testMLSD() throws Exception {
-        StringWriter writer = new StringWriter();
-        directoryLister.doMLSD(TEST_DIR1.getName(), writer);
-        
-        String[] lines = writer.toString().split(DELIMITER);
-        
-        assertEquals(3, lines.length);
-        assertMLSTLine(lines[0], TEST_DIR_IN_DIR1);
-        assertMLSTLine(lines[1], TEST_FILE1_IN_DIR1);
-        assertMLSTLine(lines[2], TEST_FILE2_IN_DIR1);
-        
-    }
-    
-    public void testMLST() throws Exception {
-        StringWriter writer = new StringWriter();
-        directoryLister.doMLST(TEST_FILE1.getName(), writer);
-        
-        assertMLSTLine(writer.toString(), TEST_FILE1);
-    }
-    
-    private void assertMLSTLine(String actual, File file) { 
-        StringTokenizer tokenizer = new StringTokenizer(actual, "=;");
-        
-        int tokenCount = tokenizer.countTokens();
-        
-        for(int i = 1; i<tokenCount; i = i+2) {
-            String key = tokenizer.nextToken();
-            String value = tokenizer.nextToken();
-            
-            if(key.equals("Size")) {
-                assertEquals(Long.toString(file.length()), value);
-            } else if(key.equals("Modify")) {
-                    assertEquals(DateUtils.getFtpDate(file.lastModified()), value);
-            } else if(key.equals("Type")) {
-                if(file.isDirectory()) {
-                    assertEquals("dir", value);
-                } else {
-                    assertEquals("file", value);
-                }
-            } else {
-                fail("Unknown key: " + key);
-            }
-        }
-        
-        assertEquals(" " + file.getName(), tokenizer.nextElement());
-    }
-    
-    public void testNLST() throws Exception {
-        StringWriter writer = new StringWriter();
-        directoryLister.doNLST(TEST_DIR1.getName(), writer);
-        
-        String[] lines = writer.toString().split(DELIMITER);
-        
-        assertEquals(3, lines.length);
-        assertEquals(TEST_DIR_IN_DIR1.getName(),   lines[0]);
-        assertEquals(TEST_FILE1_IN_DIR1.getName(), lines[1]);
-        assertEquals(TEST_FILE2_IN_DIR1.getName(), lines[2]);
-    }
-
-    public void testNLSTOnFile() throws Exception {
-        StringWriter writer = new StringWriter();
-        directoryLister.doNLST(TEST_DIR1.getName() + "/" + TEST_FILE1_IN_DIR1.getName(), writer);
-        
-        String[] lines = writer.toString().split(DELIMITER);
-        
-        assertEquals(TEST_FILE1_IN_DIR1.getName(),   lines[0]);
-    }
-
-    /**
-     * Should show the same output as LIST
-     */
-    public void testNLSTLong() throws Exception {
-        StringWriter listWriter = new StringWriter();
-        StringWriter nlstWriter = new StringWriter();
-
-        assertTrue(directoryLister.doLIST(TEST_DIR1.getName(), listWriter));
-        assertTrue(directoryLister.doNLST("-l " + TEST_DIR1.getName(), nlstWriter));
-        
-        assertEquals(listWriter.toString(), nlstWriter.toString());
-    }
-    
+ 
     /* (non-Javadoc)
      * @see junit.framework.TestCase#tearDown()
      */

Added: incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/listing/LISTFileFormaterTest.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/listing/LISTFileFormaterTest.java?view=auto&rev=487385
==============================================================================
--- incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/listing/LISTFileFormaterTest.java (added)
+++ incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/listing/LISTFileFormaterTest.java Thu Dec 14 15:20:49 2006
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.ftpserver.listing;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Date;
+
+import junit.framework.TestCase;
+
+import org.apache.ftpserver.ftplet.FileObject;
+import org.apache.ftpserver.listing.LISTFileFormater;
+
+public class LISTFileFormaterTest extends TestCase {
+
+    private static final Date LAST_MODIFIED_IN_2005 = new Date(105, 1, 2, 3, 4);
+    private static final FileObject TEST_FILE = new MockFileObject();
+    private static final String TEST_FILE_FORMAT = "-r--------   1 owner group           13 Feb  2  2005 short\r\n";
+    private static final String TEST_DIR_FORMAT =  "dr--------   3 owner group            0 Feb  2  2005 short\r\n";
+    
+    public LISTFileFormater formater = new LISTFileFormater();
+    
+    public static class MockFileObject implements FileObject {
+        public InputStream createInputStream(long offset) throws IOException {
+            return null;
+        }
+
+        public OutputStream createOutputStream(long offset) throws IOException {
+            return null;
+        }
+
+        public boolean delete() {
+            return false;
+        }
+
+        public boolean doesExist() {
+            return false;
+        }
+
+        public String getFullName() {
+            return "fullname";
+        }
+
+        public String getGroupName() {
+            return "group";
+        }
+
+        public long getLastModified() {
+            return LAST_MODIFIED_IN_2005.getTime();
+        }
+
+        public int getLinkCount() {
+            return 1;
+        }
+
+        public String getOwnerName() {
+            return "owner";
+        }
+
+        public String getShortName() {
+            return "short";
+        }
+
+        public long getSize() {
+            return 13;
+        }
+
+        public boolean hasDeletePermission() {
+            return false;
+        }
+
+        public boolean hasReadPermission() {
+            return true;
+        }
+
+        public boolean hasWritePermission() {
+            return false;
+        }
+
+        public boolean isDirectory() {
+            return false;
+        }
+
+        public boolean isFile() {
+            return true;
+        }
+
+        public boolean isHidden() {
+            return false;
+        }
+
+        public FileObject[] listFiles() {
+            return null;
+        }
+
+        public boolean mkdir() {
+            return false;
+        }
+
+        public boolean move(FileObject destination) {
+            return false;
+        }
+    }
+    
+    public void testSingleFile() {
+        assertEquals(TEST_FILE_FORMAT, formater.format(TEST_FILE));
+    }
+
+    public void testSingleDir() {
+        FileObject dir = new MockFileObject() {
+            public int getLinkCount() {
+                return 3;
+            }
+
+            public boolean isDirectory() {
+                return true;
+            }
+
+            public boolean isFile() {
+                return false;
+            }
+            
+        };
+        
+        assertEquals(TEST_DIR_FORMAT, formater.format(dir));
+    }
+
+}
\ No newline at end of file

Propchange: incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/listing/LISTFileFormaterTest.java
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message