--------------------------------------------------
					StubFtpServer Getting Started
		--------------------------------------------------

StubFtpServer - Getting Started
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  <<StubFtpServer>> is a "stub" implementation of an FTP server. It supports the main FTP commands by 
  implementing command handlers for each of the corresponding low-level FTP server commands (e.g. RETR, 
  DELE, LIST). These <CommandHandler>s can be individually configured to return custom data or reply codes, 
  allowing simulation of a complete range of both success and failure scenarios. The <CommandHandler>s can 
  also be interrogated to verify command invocation data such as command parameters and timestamps.

  <<StubFtpServer>> works out of the box with reasonable defaults, but can be fully configured 
  programmatically or within a {{{http://www.springframework.org/}Spring Framework}} (or similar) container.

  Here is how to start the <<StubFtpServer>> with the default configuration. This will return 
  success reply codes, and return empty data (for retrieved files, directory listings, etc.).

+------------------------------------------------------------------------------  
StubFtpServer stubFtpServer = new StubFtpServer();
stubFtpServer.start();
+------------------------------------------------------------------------------  

  If you are running on a system where the default port (21) is already in use or cannot be bound
  from a user process (such as Unix), you will need to use a different server control port. Use the
  <<<StubFtpServer.setServerControlPort(int serverControlPort)>>> method to use a different port
  number. If you specify a value of <<<0>>>, then the server will use a free port number. Then call
  <<<getServerControlPort()>>> AFTER calling <<<start()>>> has been called to determine the actual port
  number being used. Or, you can pass in a specific port number, such as 9187.

* CommandHandlers
~~~~~~~~~~~~~~~~~

  <CommandHandler>s are the heart of the <<StubFtpServer>>.

  <<StubFtpServer>> creates an appropriate default <CommandHandler> for each (supported) FTP server 
  command. See the list of <CommandHandler> classes associated with FTP server commands in 
  {{{./stubftpserver-commandhandlers.html}FTP Commands and CommandHandlers}}.

  You can retrieve the existing <CommandHandler> defined for an FTP server command by calling the
  <<<StubFtpServer.getCommandHandler(String name)>>> method, passing in the FTP server command
  name. For example:
  
+------------------------------------------------------------------------------  
PwdCommandHandler pwdCommandHandler = (PwdCommandHandler) stubFtpServer.getCommandHandler("PWD");
+------------------------------------------------------------------------------  

  You can replace the existing <CommandHandler> defined for an FTP server command by calling the
  <<<StubFtpServer.setCommandHandler(String name, CommandHandler commandHandler)>>> method, passing 
  in the FTP server command name, such as <<<"STOR">>> or <<<"USER">>>, and the 
  <<<CommandHandler>>> instance. For example:
  
+------------------------------------------------------------------------------  
PwdCommandHandler pwdCommandHandler = new PwdCommandHandler();
pwdCommandHandler.setDirectory("some/dir");
stubFtpServer.setCommandHandler("PWD", pwdCommandHandler);
+------------------------------------------------------------------------------  


** Generic CommandHandlers
~~~~~~~~~~~~~~~~~~~~~~~~~~

  <<StubFtpServer>> includes a couple generic <CommandHandler> classes that can be used to replace
  the default command handler for an FTP command. See the Javadoc for more information.
  
  * <<StaticReplyCommadHandler>>

    <<<StaticReplyCommadHandler>>> is a <CommandHandler> that always sends back the configured reply 
    code and text. This can be a useful replacement for a default <CommandHandler> if you want a 
    certain FTP command to always send back an error reply code.
  
  * <<SimpleCompositeCommandHandler>>

    <<<SimpleCompositeCommandHandler>>> is a composite <CommandHandler> that manages an internal 
    ordered list of <CommandHandler>s to which it delegates. Starting with the first 
    <CommandHandler> in the list, each invocation of this composite handler will invoke (delegate to) 
    the current internal <CommandHander>. Then it moves on the next <CommandHandler> in the internal list.


** Configuring CommandHandler for a New (Unsupported) Command
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  If you want to add support for a command that is not provided out of the box by <<StubFtpServer>>,
  you can create a <CommandHandler> instance and set it within the <<StubFtpServer>> using the
  <<<StubFtpServer.setCommandHandler(String name, CommandHandler commandHandler)>>> method in the
  same way that you replace an existing <CommandHandler> (see above). The following example uses
  the <<<StaticReplyCommandHandler>>> to add support for the FEAT command.

+------------------------------------------------------------------------------
final String FEAT_TEXT = "Extensions supported:\n" +
        "MLST size*;create;modify*;perm;media-type\n" +
        "SIZE\n" +
        "COMPRESSION\n" +
        "END";
StaticReplyCommandHandler featCommandHandler = new StaticReplyCommandHandler(211, FEAT_TEXT);
stubFtpServer.setCommandHandler("FEAT", featCommandHandler);
+------------------------------------------------------------------------------


** Creating Your Own Custom CommandHandler Class
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  If one of the existing <CommandHandler> classes does not fulfill your needs, you can alternately create
  your own custom <CommandHandler> class. The only requirement is that it implement the
  <<<org.mockftpserver.core.command.CommandHandler>>> interface. You would, however, likely benefit from
  inheriting from one of the existing abstract <CommandHandler> superclasses, such as
  <<<org.mockftpserver.stub.command.AbstractStubCommandHandler>>> or
  <<<org.mockftpserver.core.command.AbstractCommandHandler>>>. See the javadoc of these classes for
  more information.


* Retrieving Command Invocation Data
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  Each predefined <<StubFtpServer>> <CommandHandler> manages a List of <<<InvocationRecord>>> objects -- one
  for each time the <CommandHandler> is invoked. An <<<InvocationRecord>>> contains the <<<Command>>> 
  that triggered the invocation (containing the command name and parameters), as well as the invocation
  timestamp and client host address. The <<<InvocationRecord>>> also contains a <<<Map>>>, with optional
  <CommandHandler>-specific data. See the Javadoc for more information.
  
  You can retrieve the <<<InvocationRecord>>> from a <CommandHandler> by calling the
  <<<getInvocation(int index)>>> method, passing in the (zero-based) index of the desired
  invocation. You can get the number of invocations for a <CommandHandler> by calling
  <<<numberOfInvocations()>>>. The {{{#Example}Example Test Using Stub Ftp Server}} below illustrates 
  retrieving and interrogating an <<<InvocationRecord>>> from a <CommandHandler>.
  

* {Example} Test Using StubFtpServer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  This section includes a simplified example of FTP client code to be tested, and a JUnit 
  test for it that uses <<StubFtpServer>>.

** FTP Client Code
~~~~~~~~~~~~~~~~~~

  The following <<<RemoteFile>>> class includes a <<<readFile()>>> method that retrieves a remote 
  ASCII file and returns its contents as a String. This class uses the <<<FTPClient>>> from the
  {{{http://commons.apache.org/net/}Apache Commons Net}} framework.

+------------------------------------------------------------------------------  
public class RemoteFile {

    private String server;

    public String readFile(String filename) throws SocketException, IOException {

        FTPClient ftpClient = new FTPClient();
        ftpClient.connect(server);

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        boolean success = ftpClient.retrieveFile(filename, outputStream);
        ftpClient.disconnect();

        if (!success) {
            throw new IOException("Retrieve file failed: " + filename);
        }
        return outputStream.toString();
    }
    
    public void setServer(String server) {
        this.server = server;
    }
    
    // Other methods ...
}
+------------------------------------------------------------------------------  

** JUnit Test For FTP Client Code Using StubFtpServer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  The following <<<RemoteFileTest>>> class includes a couple of JUnit tests that use 
  <<StubFtpServer>>. The test illustrates replacing the default <CommandHandler> with
  a customized handler.

+------------------------------------------------------------------------------  
import java.io.IOException;
import org.mockftpserver.core.command.InvocationRecord;
import org.mockftpserver.stub.StubFtpServer;
import org.mockftpserver.stub.command.RetrCommandHandler;
import org.mockftpserver.test.AbstractTest;

public class RemoteFileTest extends AbstractTest {

    private static final String FILENAME = "dir/sample.txt";

    private RemoteFile remoteFile;
    private StubFtpServer stubFtpServer;
    
    public void testReadFile() throws Exception {

        final String CONTENTS = "abcdef 1234567890";

        // Replace the default RETR CommandHandler; customize returned file contents
        RetrCommandHandler retrCommandHandler = new RetrCommandHandler();
        retrCommandHandler.setFileContents(CONTENTS);
        stubFtpServer.setCommandHandler("RETR", retrCommandHandler);
        
        stubFtpServer.start();
        
        String contents = remoteFile.readFile(FILENAME);

        // Verify returned file contents
        assertEquals("contents", CONTENTS, contents);
        
        // Verify the submitted filename
        InvocationRecord invocationRecord = retrCommandHandler.getInvocation(0);
        String filename = invocationRecord.getString(RetrCommandHandler.PATHNAME_KEY);
        assertEquals("filename", FILENAME, filename);
    }

    /**
     * Test the readFile() method when the FTP transfer fails (returns a non-success reply code) 
     */
    public void testReadFileThrowsException() {

        // Replace the default RETR CommandHandler; return failure reply code
        RetrCommandHandler retrCommandHandler = new RetrCommandHandler();
        retrCommandHandler.setFinalReplyCode(550);
        stubFtpServer.setCommandHandler("RETR", retrCommandHandler);
        
        stubFtpServer.start();

        try {
            remoteFile.readFile(FILENAME);
            fail("Expected IOException");
        }
        catch (IOException expected) {
            // Expected this
        }
    }
    
    protected void setUp() throws Exception {
        super.setUp();
        remoteFile = new RemoteFile();
        remoteFile.setServer("localhost");
        stubFtpServer = new StubFtpServer();
    }

    protected void tearDown() throws Exception {
        super.tearDown();
        stubFtpServer.stop();
    }
}
+------------------------------------------------------------------------------  

  Things to note about the above test:
  
  * The <<<StubFtpServer>>> instance is created in the <<<setUp()>>> method, but is not started
    there because it must be configured differently for each test. The <<<StubFtpServer>>> instance 
    is stopped in the <<<tearDown()>>> method, to ensure that it is stopped, even if the test fails.
  

* Spring Configuration
~~~~~~~~~~~~~~~~~~~~~~

  You can easily configure a <<StubFtpServer>> instance in the
  {{{http://www.springframework.org/}Spring Framework}}. The following example shows a <Spring>
  configuration file.

+------------------------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

  <bean id="stubFtpServer" class="org.mockftpserver.stub.StubFtpServer">

    <property name="commandHandlers">
      <map>
        <entry key="LIST">
          <bean class="org.mockftpserver.stub.command.ListCommandHandler">
            <property name="directoryListing">
              <value>
                11-09-01 12:30PM  406348 File2350.log
                11-01-01 1:30PM &lt;DIR&gt; 0 archive
              </value>
            </property>
          </bean>
        </entry>

        <entry key="PWD">
          <bean class="org.mockftpserver.stub.command.PwdCommandHandler">
            <property name="directory" value="foo/bar" />
          </bean>
        </entry>

        <entry key="DELE">
          <bean class="org.mockftpserver.stub.command.DeleCommandHandler">
            <property name="replyCode" value="450" />
          </bean>
        </entry>

        <entry key="RETR">
          <bean class="org.mockftpserver.stub.command.RetrCommandHandler">
            <property name="fileContents"
              value="Sample file contents line 1&#10;Line 2&#10;Line 3"/>
          </bean>
        </entry>

      </map>
    </property>
  </bean>

</beans>
+------------------------------------------------------------------------------

  This example overrides the default handlers for the following FTP commands:

  * LIST - replies with a predefined directory listing

  * PWD - replies with a predefined directory pathname

  * DELE - replies with an error reply code (450)

  * RETR - replies with predefined contents for a retrieved file

  []

  And here is the Java code to load the above <Spring> configuration file and start the
  configured <<StubFtpServer>>.

+------------------------------------------------------------------------------
ApplicationContext context = new ClassPathXmlApplicationContext("stubftpserver-beans.xml");
stubFtpServer = (StubFtpServer) context.getBean("stubFtpServer");
stubFtpServer.start();
+------------------------------------------------------------------------------


* FTP Command Reply Text ResourceBundle
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  The default text asociated with each FTP command reply code is contained within the
  "ReplyText.properties" ResourceBundle file. You can customize these messages by providing a
  locale-specific ResourceBundle file on the CLASSPATH, according to the normal lookup rules of 
  the ResourceBundle class (e.g., "ReplyText_de.properties"). Alternatively, you can 
  completely replace the ResourceBundle file by calling the calling the 
  <<<StubFtpServer.setReplyTextBaseName(String)>>> method.