You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by ng...@apache.org on 2008/06/09 16:29:10 UTC

svn commit: r665702 - in /mina/ftpserver/trunk/core: ./ src/main/java/org/apache/ftpserver/ src/main/java/org/apache/ftpserver/config/ src/main/java/org/apache/ftpserver/config/spring/ src/main/java/org/apache/ftpserver/interfaces/ src/main/resources/M...

Author: ngn
Date: Mon Jun  9 07:29:09 2008
New Revision: 665702

URL: http://svn.apache.org/viewvc?rev=665702&view=rev
Log:
First stab at an implementation of Spring based configuration (FTPSERVER-124)

Added:
    mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/
    mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/
    mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/CommandFactoryBeanDefinitionParser.java
    mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/FileSystemBeanDefinitionParser.java
    mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/FtpServerNamespaceHandler.java
    mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/ListenerBeanDefinitionParser.java
    mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/ServerBeanDefinitionParser.java
    mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/SpringUtil.java
    mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/UserManagerBeanDefinitionParser.java
    mina/ftpserver/trunk/core/src/main/resources/META-INF/
    mina/ftpserver/trunk/core/src/main/resources/META-INF/spring.handlers
    mina/ftpserver/trunk/core/src/main/resources/META-INF/spring.schemas
    mina/ftpserver/trunk/core/src/main/resources/org/apache/ftpserver/config/
    mina/ftpserver/trunk/core/src/main/resources/org/apache/ftpserver/config/spring/
    mina/ftpserver/trunk/core/src/main/resources/org/apache/ftpserver/config/spring/ftpserver-1.0.xsd
    mina/ftpserver/trunk/core/src/test/java/org/apache/ftpserver/config/
    mina/ftpserver/trunk/core/src/test/java/org/apache/ftpserver/config/spring/
    mina/ftpserver/trunk/core/src/test/java/org/apache/ftpserver/config/spring/SpringConfigTest.java
    mina/ftpserver/trunk/core/src/test/java/org/apache/ftpserver/config/spring/TestFtplet.java
    mina/ftpserver/trunk/core/src/test/resources/spring-config/
    mina/ftpserver/trunk/core/src/test/resources/spring-config/config-spring-1.xml
Modified:
    mina/ftpserver/trunk/core/pom.xml
    mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/FtpServer.java
    mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/interfaces/CommandFactory.java

Modified: mina/ftpserver/trunk/core/pom.xml
URL: http://svn.apache.org/viewvc/mina/ftpserver/trunk/core/pom.xml?rev=665702&r1=665701&r2=665702&view=diff
==============================================================================
--- mina/ftpserver/trunk/core/pom.xml (original)
+++ mina/ftpserver/trunk/core/pom.xml Mon Jun  9 07:29:09 2008
@@ -28,6 +28,9 @@
 				<directory>src/main/resources</directory>
 				<includes>
 					<include>**/*.properties</include>
+					<include>**/*.handlers</include>
+					<include>**/*.schemas</include>
+					<include>**/*.xsd</include>
 				</includes>
 			</resource>
 		</resources>
@@ -91,6 +94,12 @@
 			<artifactId>hsqldb</artifactId>
 			<scope>test</scope>
 		</dependency>
-	</dependencies>
+	  <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-beans</artifactId>
+      <version>2.5.2</version>
+    </dependency>
+    
+  </dependencies>
 
 </project>

Modified: mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/FtpServer.java
URL: http://svn.apache.org/viewvc/mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/FtpServer.java?rev=665702&r1=665701&r2=665702&view=diff
==============================================================================
--- mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/FtpServer.java (original)
+++ mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/FtpServer.java Mon Jun  9 07:29:09 2008
@@ -22,7 +22,12 @@
 
 import java.util.Map;
 
+import org.apache.ftpserver.ftplet.FileSystemManager;
+import org.apache.ftpserver.ftplet.Ftplet;
+import org.apache.ftpserver.ftplet.UserManager;
+import org.apache.ftpserver.interfaces.CommandFactory;
 import org.apache.ftpserver.interfaces.FtpServerContext;
+import org.apache.ftpserver.interfaces.MessageResource;
 import org.apache.ftpserver.listener.Listener;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -52,8 +57,9 @@
     }
 
     /**
-     * Constructor. Set the server context.
-     * @throws Exception 
+     * Constructor. Set a custom the server context.
+     * @throws Exception
+     * TODO consider removing 
      */
     public FtpServer(FtpServerContext serverContext) throws Exception {
         this.serverContext = serverContext;
@@ -145,7 +151,123 @@
         return serverContext;
     }
 
+    /**
+     * Set a custom server context to be used for this server
+     * @param serverContext The custom server context
+     */
 	public void setServerContext(FtpServerContext serverContext) {
 		this.serverContext = serverContext;
 	}
+	
+    private DefaultFtpServerContext checkAndGetContext() {
+        if(getServerContext() instanceof DefaultFtpServerContext) {
+            return (DefaultFtpServerContext) getServerContext();
+        } else {
+            throw new IllegalStateException("Custom FtpServerContext provided, setters can not be used on FtpServer");
+        }
+    }
+    
+    /**
+     * Get all listeners available one this server
+     * @return The current listeners
+     */
+    public Map<String, Listener> getListeners() {
+        return getServerContext().getListeners();
+    }
+
+    /**
+     * Set the listeners for this server, replaces existing listeners
+     * @param listeners The listeners to use for this server with the name as the key
+     *   and the listener as the value
+     * @throws IllegalStateException If a custom server context has been set
+     */
+    public void setListeners(Map<String, Listener> listeners) {
+        checkAndGetContext().setListeners(listeners);
+    }
+    
+    /**
+     * Get all {@link Ftplet}s registered at this server
+     * @return All {@link Ftplet}s
+     */
+    public Map<String, Ftplet> getFtplets() {
+        return getServerContext().getFtpletContainer().getFtplets();
+    }
+
+    /**
+     * Set the {@link Ftplet}s to be active for this server. Replaces existing {@link Ftplet}s
+     * @param ftplets Ftplets as a map with the name as the key and the Ftplet as the value
+     * @throws IllegalStateException If a custom server context has been set
+     */
+    public void setFtplets(Map<String, Ftplet> ftplets) {
+        getServerContext().getFtpletContainer().setFtplets(ftplets);
+    }
+
+    /**
+     * Retrieve the user manager used with this server
+     * @return The user manager
+     */
+    public UserManager getUserManager() {
+        return getServerContext().getUserManager();
+    }
+
+    /**
+     * Set the user manager to be used for this server
+     * @param userManager The {@link UserManager}
+     * @throws IllegalStateException If a custom server context has been set
+     */
+    public void setUserManager(UserManager userManager) {
+        checkAndGetContext().setUserManager(userManager);
+    }
+    
+    /**
+     * Retrieve the file system used with this server
+     * @return The {@link FileSystemManager}
+     */
+    public FileSystemManager getFileSystem() {
+        return getServerContext().getFileSystemManager();
+    }
+
+    /**
+     * Set the file system to be used for this server
+     * @param fileSystem The {@link FileSystemManager}
+     * @throws IllegalStateException If a custom server context has been set
+     */
+    public void setFileSystem(FileSystemManager fileSystem) {
+        checkAndGetContext().setFileSystemManager(fileSystem);
+    }
+    
+    /**
+     * Retrieve the command factory used with this server
+     * @return The {@link CommandFactory}
+     */
+    public CommandFactory getCommandFactory() {
+        return getServerContext().getCommandFactory();
+    }
+
+    /**
+     * Set the command factory to be used for this server
+     * @param commandFactory The {@link CommandFactory}
+     * @throws IllegalStateException If a custom server context has been set
+     */
+    public void setCommandFactory(CommandFactory commandFactory) {
+        checkAndGetContext().setCommandFactory(commandFactory);
+    }
+    
+    /**
+     * Retrieve the message resource used with this server
+     * @return The {@link MessageResource}
+     */
+    public MessageResource getMessageResource() {
+        return getServerContext().getMessageResource();
+    }
+
+    /**
+     * Set the message resource to be used with this server
+     * @param messageResource The {@link MessageResource}
+     * @throws IllegalStateException If a custom server context has been set
+     */
+    public void setMessageResource(MessageResource messageResource) {
+        checkAndGetContext().setMessageResource(messageResource);
+    }
+
 }

Added: mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/CommandFactoryBeanDefinitionParser.java
URL: http://svn.apache.org/viewvc/mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/CommandFactoryBeanDefinitionParser.java?rev=665702&view=auto
==============================================================================
--- mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/CommandFactoryBeanDefinitionParser.java (added)
+++ mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/CommandFactoryBeanDefinitionParser.java Mon Jun  9 07:29:09 2008
@@ -0,0 +1,49 @@
+package org.apache.ftpserver.config.spring;
+
+import java.util.List;
+
+import org.apache.ftpserver.DefaultCommandFactory;
+import org.apache.ftpserver.interfaces.CommandFactory;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.ManagedMap;
+import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.util.StringUtils;
+import org.w3c.dom.Element;
+
+/**
+ * Parses the FtpServer "commands" element into a Spring
+ * bean graph
+ */
+public class CommandFactoryBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected Class<? extends CommandFactory> getBeanClass(Element element) {
+        return DefaultCommandFactory.class;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
+        ManagedMap commands = new ManagedMap();
+        
+        List<Element> childs = SpringUtil.getChildElements(element);
+
+        for(Element commandElm : childs) {
+            String name = commandElm.getAttribute("name");
+            Object bean = SpringUtil.parseSpringChildElement(commandElm, parserContext, builder); 
+            commands.put(name, bean);
+        }
+        
+        builder.addPropertyValue("commandMap", commands);
+        
+        if(StringUtils.hasText(element.getAttribute("use-default"))) {
+            builder.addPropertyValue("useDefaultCommands", Boolean.parseBoolean(element.getAttribute("use-default")));
+        }
+    }
+}

Added: mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/FileSystemBeanDefinitionParser.java
URL: http://svn.apache.org/viewvc/mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/FileSystemBeanDefinitionParser.java?rev=665702&view=auto
==============================================================================
--- mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/FileSystemBeanDefinitionParser.java (added)
+++ mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/FileSystemBeanDefinitionParser.java Mon Jun  9 07:29:09 2008
@@ -0,0 +1,37 @@
+package org.apache.ftpserver.config.spring;
+
+import org.apache.ftpserver.filesystem.NativeFileSystemManager;
+import org.apache.ftpserver.ftplet.FileSystemManager;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.util.StringUtils;
+import org.w3c.dom.Element;
+
+/**
+ * Parses the FtpServer "native-filesystem" element into a Spring
+ * bean graph
+ */
+public class FileSystemBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected Class<? extends FileSystemManager> getBeanClass(Element element) {
+        return NativeFileSystemManager.class;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
+        if(StringUtils.hasText(element.getAttribute("case-insensitive"))) {
+            builder.addPropertyValue("caseInsensitive", Boolean.parseBoolean(element.getAttribute("case-insensitive")));
+        }
+        if(StringUtils.hasText(element.getAttribute("create-home"))) {
+            builder.addPropertyValue("create-home", Boolean.parseBoolean(element.getAttribute("create-home")));
+        }
+    }
+}

Added: mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/FtpServerNamespaceHandler.java
URL: http://svn.apache.org/viewvc/mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/FtpServerNamespaceHandler.java?rev=665702&view=auto
==============================================================================
--- mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/FtpServerNamespaceHandler.java (added)
+++ mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/FtpServerNamespaceHandler.java Mon Jun  9 07:29:09 2008
@@ -0,0 +1,37 @@
+package org.apache.ftpserver.config.spring;
+
+import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
+
+/**
+ * Registration point for FtpServer bean defintion parsers
+ */
+public class FtpServerNamespaceHandler extends NamespaceHandlerSupport {
+
+    /**
+     * The FtpServer Spring config namespace
+     */
+    public static final String FTPSERVER_NS = "http://mina.apache.org/ftpserver/spring/v1";
+
+   
+    /**
+     * Register the necessary element names with the appropriate
+     * bean definition parser
+     */
+    public FtpServerNamespaceHandler() {
+        registerBeanDefinitionParser("server", new ServerBeanDefinitionParser());        
+        registerBeanDefinitionParser("nio-listener", new ListenerBeanDefinitionParser());        
+        registerBeanDefinitionParser("file-user-manager", new UserManagerBeanDefinitionParser());        
+        registerBeanDefinitionParser("db-user-manager", new UserManagerBeanDefinitionParser());        
+        registerBeanDefinitionParser("native-filesystem", new FileSystemBeanDefinitionParser());        
+        registerBeanDefinitionParser("commands", new CommandFactoryBeanDefinitionParser());
+        
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void init() {
+        // do nothing
+    }
+
+}

Added: mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/ListenerBeanDefinitionParser.java
URL: http://svn.apache.org/viewvc/mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/ListenerBeanDefinitionParser.java?rev=665702&view=auto
==============================================================================
--- mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/ListenerBeanDefinitionParser.java (added)
+++ mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/ListenerBeanDefinitionParser.java Mon Jun  9 07:29:09 2008
@@ -0,0 +1,234 @@
+package org.apache.ftpserver.config.spring;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.ftpserver.DefaultDataConnectionConfig;
+import org.apache.ftpserver.DefaultDataConnectionConfig.Active;
+import org.apache.ftpserver.DefaultDataConnectionConfig.Passive;
+import org.apache.ftpserver.interfaces.DataConnectionConfig;
+import org.apache.ftpserver.listener.mina.MinaListener;
+import org.apache.ftpserver.ssl.DefaultSslConfiguration;
+import org.apache.ftpserver.ssl.SslConfiguration;
+import org.apache.mina.filter.firewall.Subnet;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.util.StringUtils;
+import org.w3c.dom.Element;
+
+/**
+ * Parses the FtpServer "nio-listener" element into a Spring
+ * bean graph
+ */
+public class ListenerBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected Class<MinaListener> getBeanClass(Element element) {
+        return MinaListener.class;
+    }
+
+    /**
+     * Parse CIDR notations into MINA {@link Subnet}s. 
+     * TODO: move to Mina
+     */
+    private Subnet parseSubnet(String subnet) {
+        if(subnet == null) {
+            throw new NullPointerException("subnet can not be null");
+        }
+        
+        String[] tokens = subnet.split("/");
+
+        String ipString;
+        String maskString;
+        if(tokens.length == 2) {
+            ipString = tokens[0];
+            maskString = tokens[1];
+        } else if(tokens.length == 1) {
+            ipString = tokens[0];
+            maskString = "32";
+        } else {
+            throw new IllegalArgumentException("Illegal subnet format: " + subnet);
+        }
+
+        InetAddress address;
+        try {
+            address = InetAddress.getByName(ipString);
+        } catch (UnknownHostException e) {
+            throw new IllegalArgumentException("Illegal IP address in subnet: " + subnet);
+        }
+        
+        int mask = Integer.parseInt(maskString);
+        if(mask < 0 || mask > 32) {
+            throw new IllegalArgumentException("Mask must be in the range 0-32");
+        }
+        
+        return new Subnet(address, mask);
+    }
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
+        if(StringUtils.hasText(element.getAttribute("port"))) {
+            builder.addPropertyValue("port", Integer.parseInt(element.getAttribute("port")));
+        }
+        
+        SslConfiguration ssl = parseSsl(element);
+        if(ssl != null) {
+            builder.addPropertyValue("ssl", ssl);
+        }
+        
+        Element dataConElm = SpringUtil.getChildElement(element, FtpServerNamespaceHandler.FTPSERVER_NS, "data-connection");
+        if(dataConElm != null) {
+            DataConnectionConfig dc = parseDataConnection(dataConElm);
+            builder.addPropertyValue("dataConnection", dc);
+        }
+        
+        Element blacklistElm = SpringUtil.getChildElement(element, FtpServerNamespaceHandler.FTPSERVER_NS, "blacklist");
+        if(blacklistElm != null && StringUtils.hasText(blacklistElm.getTextContent())) {
+            String[] blocks = blacklistElm.getTextContent().split("[\\s,]+");
+            List<Subnet> subnets = new ArrayList<Subnet>();
+            
+            for(String block : blocks) {
+                subnets.add(parseSubnet(block));
+            }
+            
+            builder.addPropertyValue("blockedSubnets", subnets);
+        }
+        
+        if(StringUtils.hasText(element.getAttribute("idle-timeout"))) {
+            builder.addPropertyValue("idleTimeout", SpringUtil.parseInt(element, "idle-timeout", 300));
+        }
+        if(StringUtils.hasText(element.getAttribute("port"))) {
+            builder.addPropertyValue("port", SpringUtil.parseInt(element, "port", 21));
+        }
+        InetAddress localAddress = SpringUtil.parseInetAddress(element, "local-address");
+        if(localAddress != null) {
+            builder.addPropertyValue("localAddress", localAddress);
+        }
+        builder.addPropertyValue("implicitSsl", SpringUtil.parseBoolean(element, "implicit-ssl", false));
+    }
+    
+    
+    private SslConfiguration parseSsl(Element parent) {
+        Element sslElm = SpringUtil.getChildElement(parent, FtpServerNamespaceHandler.FTPSERVER_NS, "ssl");
+        
+        if(sslElm != null) {
+            DefaultSslConfiguration ssl = new DefaultSslConfiguration();
+        
+            Element keyStoreElm = SpringUtil.getChildElement(sslElm, FtpServerNamespaceHandler.FTPSERVER_NS, "keystore");
+            if(keyStoreElm != null) {
+                ssl.setKeystoreFile(SpringUtil.parseFile(keyStoreElm, "file"));
+                ssl.setKeystorePassword(SpringUtil.parseString(keyStoreElm, "password"));
+                
+                String type = SpringUtil.parseString(keyStoreElm, "type");
+                if(type != null) {
+                    ssl.setKeystoreType(type);
+                }
+
+                String keyAlias = SpringUtil.parseString(keyStoreElm, "key-alias");
+                if(keyAlias != null) {
+                    ssl.setKeyAlias(keyAlias);
+                }
+                
+                String keyPassword = SpringUtil.parseString(keyStoreElm, "key-password");
+                if(keyPassword != null) {
+                    ssl.setKeyPassword(keyPassword);
+                }
+                
+                String algorithm = SpringUtil.parseString(keyStoreElm, "algorithm");
+                if(algorithm != null) {
+                    ssl.setKeystoreAlgorithm(algorithm);
+                }
+            }
+            
+            Element trustStoreElm = SpringUtil.getChildElement(sslElm, FtpServerNamespaceHandler.FTPSERVER_NS, "truststore");
+            if(trustStoreElm != null) {
+                ssl.setTruststoreFile(SpringUtil.parseFile(trustStoreElm, "file"));
+                ssl.setTruststorePassword(SpringUtil.parseString(trustStoreElm, "password"));
+                
+                String type = SpringUtil.parseString(trustStoreElm, "type");
+                if(type != null) {
+                    ssl.setTruststoreType(type);
+                }
+                
+                String algorithm = SpringUtil.parseString(trustStoreElm, "algorithm");
+                if(algorithm != null) {
+                    ssl.setTruststoreAlgorithm(algorithm);
+                }
+            }
+            
+            String clientAuthStr = SpringUtil.parseString(sslElm, "client-authentication");
+            if(clientAuthStr != null) { 
+                ssl.setClientAuthentication(clientAuthStr);
+            } 
+            
+            String enabledCiphersuites = SpringUtil.parseString(sslElm, "enabled-ciphersuites");
+            if(enabledCiphersuites != null) { 
+                ssl.setEnabledCipherSuites(enabledCiphersuites.split(" "));
+            }  
+        
+            return ssl;
+        } else {
+            return null;
+        }
+        
+    
+    }
+    
+    private DataConnectionConfig parseDataConnection(Element element) {
+        DefaultDataConnectionConfig dc = new DefaultDataConnectionConfig();
+        
+        SslConfiguration ssl = parseSsl(element);
+        if(ssl != null) {
+            dc.setSsl(ssl);
+        }
+        
+        Element activeElm = SpringUtil.getChildElement(element, FtpServerNamespaceHandler.FTPSERVER_NS, "active");
+        if(activeElm != null) {
+            Active active = new Active();
+            active.setEnable(SpringUtil.parseBoolean(activeElm, "enabled", true));
+            active.setIpCheck(SpringUtil.parseBoolean(activeElm, "ip-check", false));
+            active.setLocalPort(SpringUtil.parseInt(activeElm, "local-port", 0));
+            
+            InetAddress localAddress = SpringUtil.parseInetAddress(activeElm, "local-address");
+            if(localAddress != null) {
+                active.setLocalAddress(localAddress);
+            }
+            
+            dc.setActive(active);
+        }
+        
+        Element passiveElm = SpringUtil.getChildElement(element, FtpServerNamespaceHandler.FTPSERVER_NS, "passive");
+        if(passiveElm != null) {
+            Passive passive = new Passive();
+
+            InetAddress address = SpringUtil.parseInetAddress(passiveElm, "address");
+            if(address != null) {
+                passive.setAddress(address);
+            }
+
+            InetAddress externalAddress = SpringUtil.parseInetAddress(passiveElm, "external-address");
+            if(externalAddress != null) {
+                passive.setExternalAddress(externalAddress);
+            }
+            
+            String ports = SpringUtil.parseString(passiveElm, "ports");
+            if(ports != null) {
+                passive.setPorts(ports);
+            }
+            dc.setPassive(passive);
+        }
+
+        return dc;
+    }
+
+
+}

Added: mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/ServerBeanDefinitionParser.java
URL: http://svn.apache.org/viewvc/mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/ServerBeanDefinitionParser.java?rev=665702&view=auto
==============================================================================
--- mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/ServerBeanDefinitionParser.java (added)
+++ mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/ServerBeanDefinitionParser.java Mon Jun  9 07:29:09 2008
@@ -0,0 +1,141 @@
+package org.apache.ftpserver.config.spring;
+
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ftpserver.FtpServer;
+import org.apache.ftpserver.FtpServerConfigurationException;
+import org.apache.ftpserver.interfaces.MessageResource;
+import org.apache.ftpserver.message.MessageResourceImpl;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.ManagedMap;
+import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.util.StringUtils;
+import org.w3c.dom.Element;
+
+/**
+ * Parses the FtpServer "server" element into a Spring
+ * bean graph
+ */
+public class ServerBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
+
+
+    /**
+     * {@inheritDoc}
+     */
+    protected Class<? extends FtpServer> getBeanClass(Element element) {
+        return FtpServer.class;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
+        List<Element> childs = SpringUtil.getChildElements(element);
+        for(Element childElm : childs) {
+            String childName = childElm.getLocalName();
+            
+            if("listeners".equals(childName)) {
+                Map listeners = parseListeners(childElm, parserContext, builder);
+                
+                if(listeners.size() > 0) {
+                    builder.addPropertyValue("listeners", listeners);
+                }
+            } else if("ftplets".equals(childName)) {
+                Map ftplets = parseFtplets(childElm, parserContext, builder);
+                builder.addPropertyValue("ftplets", ftplets);
+            } else if("file-user-manager".equals(childName) ||
+                    "db-user-manager".equals(childName)) {
+                Object userManager = parserContext.getDelegate().parseCustomElement(childElm, builder.getBeanDefinition());
+                builder.addPropertyValue("userManager", userManager);
+            } else if("user-manager".equals(childName)) {
+                builder.addPropertyValue("userManager", SpringUtil.parseSpringChildElement(childElm, parserContext, builder));
+            } else if("native-filesystem".equals(childName)) {
+                Object fileSystem = parserContext.getDelegate().parseCustomElement(childElm, builder.getBeanDefinition());
+                builder.addPropertyValue("fileSystem", fileSystem);
+            } else if("filesystem".equals(childName)) {
+                builder.addPropertyValue("fileSystem", SpringUtil.parseSpringChildElement(childElm, parserContext, builder));
+            } else if("commands".equals(childName)) {
+                Object commandFactory = parserContext.getDelegate().parseCustomElement(childElm, builder.getBeanDefinition());
+                builder.addPropertyValue("commandFactory", commandFactory);
+            } else if("messages".equals(childName)) {
+                MessageResource mr = parseMessageResource(childElm, parserContext, builder);
+                builder.addPropertyValue("messageResource", mr);
+
+            } else {
+                throw new FtpServerConfigurationException("Unknown configuration name: " + childName);
+            }
+        }
+    }
+
+    /**
+     * Parse the "messages" element
+     */
+    private MessageResource parseMessageResource(Element childElm, ParserContext parserContext,
+            BeanDefinitionBuilder builder) {
+        
+        MessageResourceImpl mr = new MessageResourceImpl();
+        
+        if(StringUtils.hasText(childElm.getAttribute("languages"))) {
+            String langString = childElm.getAttribute("languages");
+            
+            String[] languages = langString.split("[\\s,]+");
+            
+            mr.setLanguages(languages);
+        }
+        
+        if(StringUtils.hasText(childElm.getAttribute("directory"))) {
+            mr.setCustomMessageDirectory(new File(childElm.getAttribute("directory")));
+            
+        }
+
+        return mr;
+    }
+
+    /**
+     * Parse the "ftplets" element
+     */
+    private Map parseFtplets(Element childElm, ParserContext parserContext, BeanDefinitionBuilder builder) {
+        ManagedMap ftplets = new ManagedMap();
+
+        List<Element> childs = SpringUtil.getChildElements(childElm);
+
+        for(Element ftpletElm : childs) {            
+            ftplets.put(ftpletElm.getAttribute("name"), 
+                    SpringUtil.parseSpringChildElement(ftpletElm, parserContext, builder));
+        }
+        
+        return ftplets;
+    }
+
+    /**
+     * Parse listeners elements
+     */
+    @SuppressWarnings("unchecked")
+    private Map parseListeners(Element listenersElm, ParserContext parserContext, BeanDefinitionBuilder builder) {
+        ManagedMap listeners = new ManagedMap();
+
+        List<Element> childs = SpringUtil.getChildElements(listenersElm);
+
+        for(Element listenerElm : childs) {
+            Object listener = null;
+            String ln = listenerElm.getLocalName();
+            if("nio-listener".equals(ln)) {
+                listener = parserContext.getDelegate().parseCustomElement(listenerElm, builder.getBeanDefinition());
+            } else if ("listener".equals(ln)) {
+                listener = SpringUtil.parseSpringChildElement(listenerElm, parserContext, builder);
+            } else {
+                throw new FtpServerConfigurationException("Unknown listener element " + ln);
+            }
+            
+            String name = listenerElm.getAttribute("name");
+
+            listeners.put(name, listener);
+        }
+        
+        return listeners;
+    }
+}

Added: mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/SpringUtil.java
URL: http://svn.apache.org/viewvc/mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/SpringUtil.java?rev=665702&view=auto
==============================================================================
--- mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/SpringUtil.java (added)
+++ mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/SpringUtil.java Mon Jun  9 07:29:09 2008
@@ -0,0 +1,151 @@
+package org.apache.ftpserver.config.spring;
+
+import java.io.File;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.ftpserver.FtpServerConfigurationException;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.util.StringUtils;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * Various util methods for the Spring config parsing and configuration
+ */
+public class SpringUtil {
+
+    /**
+     * Get all child elements for the element
+     * @param elm The element for which to locate children
+     * @return All children
+     */
+    public static List<Element> getChildElements(Element elm) {
+        List<Element> elements = new ArrayList<Element>();
+        NodeList childs = elm.getChildNodes();
+        for(int i = 0; i<childs.getLength(); i++) {
+            Node child = childs.item(i);
+            
+            if(child instanceof Element) {
+                elements.add((Element) child);
+            }
+        }
+        
+        return elements;
+    }
+    
+    /**
+     * Get the first child element matching the local name and namespace
+     * @param parent The element for which to locate the child
+     * @param ns The namespace to match, or null for any namespace
+     * @param localName The local name to match, or null for any local name
+     * @return The first child matching the criteria
+     */
+    public static Element getChildElement(Element parent, String ns, String localName) {
+        List<Element> elements = getChildElements(parent);
+        
+        for(Element element : elements) {
+            if((ns == null || ns.equals(element.getNamespaceURI()) &&
+                    (localName == null || localName.equals(element.getLocalName())))) {
+                return element;
+            }
+        }
+        
+        return null;
+    }
+
+    /**
+     * Parse specific Spring elements, bean and ref
+     * @param parent The element in which we will look for Spring elements
+     * @param parserContext The Spring parser context
+     * @param builder The Spring bean definition builder
+     * @return The Spring bean definition
+     */
+    public static Object parseSpringChildElement(Element parent, ParserContext parserContext, BeanDefinitionBuilder builder) {
+        Element springElm = getChildElement(parent, null, null);
+        
+        String ln = springElm.getLocalName();
+        if("bean".equals(ln)) {
+            return parserContext.getDelegate().parseBeanDefinitionElement(springElm, builder.getBeanDefinition());
+        } else if("ref".equals(ln)) {
+            return parserContext.getDelegate().parsePropertySubElement(springElm, builder.getBeanDefinition());
+        } else {
+            throw new FtpServerConfigurationException("Unknown spring element " + ln);
+        }
+    }
+
+    /**
+     * Parses a attribute value into a boolean. 
+     * If the attribute is missing or has no content, a default value is returned
+     * @param parent The element
+     * @param attrName The attribute name
+     * @param defaultValue The default value
+     * @return The value, or the default value
+     */
+    public static boolean parseBoolean(Element parent, String attrName, boolean defaultValue) {
+        if(StringUtils.hasText(parent.getAttribute(attrName))) {
+            return Boolean.parseBoolean(parent.getAttribute(attrName));
+        }
+        return defaultValue;
+    }
+    
+    /**
+     * Parses a attribute value into an integer. 
+     * If the attribute is missing or has no content, a default value is returned
+     * @param parent The element
+     * @param attrName The attribute name
+     * @param defaultValue The default value
+     * @return The value, or the default value
+     */
+    public static int parseInt(Element parent, String attrName, int defaultValue) {
+        if(StringUtils.hasText(parent.getAttribute(attrName))) {
+            return Integer.parseInt(parent.getAttribute(attrName));
+        }
+        return defaultValue;
+    }
+    
+    /**
+     * Return the string value of an attribute, or null if the attribute is missing
+     * @param parent The element
+     * @param attrName The attribute name
+     * @return The attribute string value
+     */
+    public static String parseString(Element parent, String attrName) {
+        return parent.getAttribute(attrName);
+    }
+    
+    /**
+     * Return an attribute value as a {@link File}
+     * @param parent The element
+     * @param attrName The attribute name
+     * @return The file representing the path used in the attribute
+     */
+    public static File parseFile(Element parent, String attrName) {
+        if(StringUtils.hasText(parent.getAttribute(attrName))) {
+            return new File(parent.getAttribute(attrName));
+        }
+        return null;
+    }
+    
+    /**
+     * Return an attribute value as an {@link InetAddress}
+     * @param parent The element
+     * @param attrName The attribute name
+     * @return The attribute value parsed into a {@link InetAddress}
+     */
+    public static InetAddress parseInetAddress(Element parent, String attrName) {
+        if(StringUtils.hasText(parent.getAttribute(attrName))) {
+            try {
+                return InetAddress.getByName(parent.getAttribute(attrName));
+            } catch (UnknownHostException e) {
+                throw new FtpServerConfigurationException("Unknown host", e);
+            }
+        }
+        return null;
+    }
+
+}

Added: mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/UserManagerBeanDefinitionParser.java
URL: http://svn.apache.org/viewvc/mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/UserManagerBeanDefinitionParser.java?rev=665702&view=auto
==============================================================================
--- mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/UserManagerBeanDefinitionParser.java (added)
+++ mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/config/spring/UserManagerBeanDefinitionParser.java Mon Jun  9 07:29:09 2008
@@ -0,0 +1,52 @@
+package org.apache.ftpserver.config.spring;
+
+import org.apache.ftpserver.ftplet.UserManager;
+import org.apache.ftpserver.usermanager.DbUserManager;
+import org.apache.ftpserver.usermanager.PropertiesUserManager;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.util.StringUtils;
+import org.w3c.dom.Element;
+
+/**
+ * Parses the FtpServer "file-user-manager" or "db-user-manager" elements into a Spring
+ * bean graph
+ */
+public class UserManagerBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
+    
+    @Override
+    protected Class<? extends UserManager> getBeanClass(Element element) {
+        if(element.getLocalName().equals("file-user-manager")) {
+            return PropertiesUserManager.class;
+        } else {
+            return DbUserManager.class;
+        }
+    }
+
+    @Override
+    protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
+        if(getBeanClass(element) == PropertiesUserManager.class) {
+            builder.addPropertyValue("propFile", element.getAttribute("file"));
+            if(StringUtils.hasText(element.getAttribute("encrypt-passwords")) &&
+                    element.getAttribute("encrypt-passwords").equals("true")) {
+                builder.addPropertyValue("encryptPasswords", true);
+            }
+        } else {
+            Element dsElm = SpringUtil.getChildElement(element, 
+                    FtpServerNamespaceHandler.FTPSERVER_NS, "data-source");
+            
+            // schema ensure we get the right type of element
+            Element springElm = SpringUtil.getChildElement(dsElm, null, null);
+            Object o;
+            if("bean".equals(springElm.getLocalName())) {
+                o = parserContext.getDelegate().parseBeanDefinitionElement(springElm, builder.getBeanDefinition());
+            } else {
+                // ref
+                o = parserContext.getDelegate().parsePropertySubElement(springElm, builder.getBeanDefinition());
+
+            }
+            builder.addPropertyValue("dataSource", o);
+        }
+    }
+}

Modified: mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/interfaces/CommandFactory.java
URL: http://svn.apache.org/viewvc/mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/interfaces/CommandFactory.java?rev=665702&r1=665701&r2=665702&view=diff
==============================================================================
--- mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/interfaces/CommandFactory.java (original)
+++ mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/interfaces/CommandFactory.java Mon Jun  9 07:29:09 2008
@@ -19,6 +19,10 @@
 
 package org.apache.ftpserver.interfaces;
 
+import java.util.Map;
+
+import com.sun.org.apache.bcel.internal.generic.ISUB;
+
 
 /**
  * Command factory interface.
@@ -30,4 +34,41 @@
      * Get the command instance.
      */
     Command getCommand(String commandName);
+    
+    /**
+     * Get the registered SITE commands
+     * @return Active site commands, the key is 
+     *   the site command name, used in FTP 
+     *   sessions as SITE <command name>
+     */
+//    Map<String, Command> getSiteCommands();
+    
+    /**
+     * Register SITE commands. The map can replace or
+     * append to the default SITE commands provided
+     * by FtpServer depending on the value of
+     * {@see CommandFactory#isUseDefaultSiteCommands()}
+     * @param siteCommands Active site commands, the key is 
+     *   the site command name, used in FTP 
+     *   sessions as SITE <command name>. The value is the
+     *   command
+     */
+//    void setSiteCommands(Map<String, Command> siteCommands);
+
+    /**
+     * Should custom site commands append to or replace
+     * the default commands provided by FtpServer?. 
+     * The default is to append
+     * @return true if custom commands should append to the default,
+     *  false if they should replace
+     */
+//    boolean isUseDefaultSiteCommands();
+ 
+    /**
+     * Should custom site commands append to or replace
+     * the default commands provided by FtpServer?. 
+     * @param useDefaultSiteCommands true if custom commands should append to the default,
+     *  false if they should replace
+     */
+//    void setUseDefaultSiteCommands(boolean useDefaultSiteCommands);
 }

Added: mina/ftpserver/trunk/core/src/main/resources/META-INF/spring.handlers
URL: http://svn.apache.org/viewvc/mina/ftpserver/trunk/core/src/main/resources/META-INF/spring.handlers?rev=665702&view=auto
==============================================================================
--- mina/ftpserver/trunk/core/src/main/resources/META-INF/spring.handlers (added)
+++ mina/ftpserver/trunk/core/src/main/resources/META-INF/spring.handlers Mon Jun  9 07:29:09 2008
@@ -0,0 +1 @@
+http\://mina.apache.org/ftpserver/spring/v1=org.apache.ftpserver.config.spring.FtpServerNamespaceHandler
\ No newline at end of file

Added: mina/ftpserver/trunk/core/src/main/resources/META-INF/spring.schemas
URL: http://svn.apache.org/viewvc/mina/ftpserver/trunk/core/src/main/resources/META-INF/spring.schemas?rev=665702&view=auto
==============================================================================
--- mina/ftpserver/trunk/core/src/main/resources/META-INF/spring.schemas (added)
+++ mina/ftpserver/trunk/core/src/main/resources/META-INF/spring.schemas Mon Jun  9 07:29:09 2008
@@ -0,0 +1 @@
+http\://mina.apache.org/ftpserver/ftpserver-1.0.xsd=org/apache/ftpserver/config/spring/ftpserver-1.0.xsd
\ No newline at end of file

Added: mina/ftpserver/trunk/core/src/main/resources/org/apache/ftpserver/config/spring/ftpserver-1.0.xsd
URL: http://svn.apache.org/viewvc/mina/ftpserver/trunk/core/src/main/resources/org/apache/ftpserver/config/spring/ftpserver-1.0.xsd?rev=665702&view=auto
==============================================================================
--- mina/ftpserver/trunk/core/src/main/resources/org/apache/ftpserver/config/spring/ftpserver-1.0.xsd (added)
+++ mina/ftpserver/trunk/core/src/main/resources/org/apache/ftpserver/config/spring/ftpserver-1.0.xsd Mon Jun  9 07:29:09 2008
@@ -0,0 +1,223 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
+	targetNamespace="http://mina.apache.org/ftpserver/spring/v1"
+	xmlns="http://mina.apache.org/ftpserver/spring/v1"
+	xmlns:beans="http://www.springframework.org/schema/beans">
+
+	<!-- Import the Spring beans XML schema -->
+	<xs:import namespace="http://www.springframework.org/schema/beans"
+		schemaLocation="http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"/>
+
+	<!-- The main entry point, used for setting up an entire FTP server -->
+	<xs:element name="server">
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element minOccurs="0" name="listeners">
+					<xs:complexType>
+						<xs:choice minOccurs="1" maxOccurs="unbounded">
+							<xs:element ref="nio-listener"/>
+							<xs:element ref="listener"/>
+						</xs:choice>
+					</xs:complexType>
+				</xs:element>
+				<xs:element minOccurs="0" ref="ftplets"/>
+				<xs:choice minOccurs="0" maxOccurs="1">
+					<xs:element minOccurs="0" ref="file-user-manager"/>
+					<xs:element minOccurs="0" ref="db-user-manager"/>
+					<xs:element minOccurs="0" ref="user-manager"/>
+				</xs:choice>
+				<xs:choice minOccurs="0" maxOccurs="1">
+					<xs:element minOccurs="0" ref="native-filesystem"/>
+					<xs:element minOccurs="0" ref="filesystem"/>
+				</xs:choice>
+				<xs:element minOccurs="0" ref="commands"/>
+				<xs:element minOccurs="0" ref="messages"/>
+			</xs:sequence>
+			<xs:attribute name="id" type="xs:ID"/>
+
+		</xs:complexType>
+	</xs:element>
+
+	<!-- Reusable element for defining SSL properties -->
+	<xs:element name="ssl">
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element minOccurs="0" name="keystore">
+					<xs:complexType>
+						<xs:attribute name="file"/>
+						<xs:attribute name="password"/>
+						<xs:attribute name="type"/>
+						<xs:attribute name="algorithm"/>
+						<xs:attribute name="key-alias"/>
+						<xs:attribute name="key-password"/>
+					</xs:complexType>
+				</xs:element>
+				<xs:element minOccurs="0" name="truststore">
+					<xs:complexType>
+						<xs:attribute name="file"/>
+						<xs:attribute name="password"/>
+						<xs:attribute name="type"/>
+						<xs:attribute name="algorithm"/>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+			<xs:attribute name="client-authentication" type="xs:string"/>
+			<xs:attribute name="enabled-ciphersuites"/>
+		</xs:complexType>
+	</xs:element>
+
+	<!-- Element used to define the default, NIO based listener -->
+	<xs:element name="nio-listener">
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element minOccurs="0" ref="ssl"/>
+				<xs:element minOccurs="0" name="data-connection">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element minOccurs="0" ref="ssl"/>
+							<xs:element minOccurs="0" name="active">
+								<xs:complexType>
+									<xs:attribute name="enabled" type="xs:boolean"/>
+									<xs:attribute name="local-address"/>
+									<xs:attribute name="local-port" type="xs:int"/>
+									<xs:attribute name="ip-check" type="xs:boolean"/>
+								</xs:complexType>
+							</xs:element>
+							<xs:element minOccurs="0" name="passive">
+								<xs:complexType>
+									<xs:attribute name="address"/>
+									<xs:attribute name="external-address"/>
+									<xs:attribute name="ports"/>
+								</xs:complexType>
+							</xs:element>
+						</xs:sequence>
+						<xs:attribute name="idle-timeout" type="xs:int"/>
+					</xs:complexType>
+
+				</xs:element>
+				<xs:element minOccurs="0" name="blacklist" type="xs:string"/>
+			</xs:sequence>
+			<xs:attribute name="name" use="required" type="xs:string"/>
+			<xs:attribute name="local-address"/>
+			<xs:attribute name="port" type="xs:int"/>
+			<xs:attribute name="idle-timeout" type="xs:int"/>
+			<xs:attribute name="implicit-ssl" type="xs:boolean"/>
+		</xs:complexType>
+	</xs:element>
+	
+	<!-- Extension element used for defining a custom listener -->
+	<xs:element name="listener" type="spring-bean-or-ref-with-name"/>
+
+	<!-- Element used to configure Ftplets for used with the server -->
+	<xs:element name="ftplets">
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="ftplet">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:choice maxOccurs="unbounded">
+								<xs:element ref="beans:bean"/>
+								<xs:element ref="beans:ref"/>
+							</xs:choice>
+						</xs:sequence>
+						<xs:attribute name="name" use="required" type="xs:string"/>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+
+	<!-- Element used to configure a file based user manager -->
+	<xs:element name="file-user-manager">
+		<xs:complexType>
+			<xs:attribute name="file" use="required" type="xs:string"/>
+			<xs:attribute name="encrypt-passwords" type="xs:boolean"/>
+		</xs:complexType>
+	</xs:element>
+	
+	<!-- Element used to configure a database based user manager -->
+	<xs:element name="db-user-manager">
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="data-source" type="spring-bean-or-ref"/>
+				<xs:element name="statements">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="insert-user" type="xs:string"/>
+							<xs:element name="update-user" type="xs:string"/>
+							<xs:element name="delete-user" type="xs:string"/>
+							<xs:element name="select-user" type="xs:string"/>
+							<xs:element name="select-all-users" type="xs:string"/>
+							<xs:element name="is-admin" type="xs:string"/>
+							<xs:element name="authenticate" type="xs:string"/>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+
+	<!-- Extension element used for defining a custom user manager -->
+	<xs:element name="user-manager" type="spring-bean-or-ref"/>
+
+	<!-- Element used to configure the default file system -->
+	<xs:element name="native-filesystem">
+		<xs:complexType>
+			<xs:attribute name="case-insensitive" type="xs:boolean"/>
+			<xs:attribute name="create-home" type="xs:boolean"/>
+		</xs:complexType>
+	</xs:element>
+
+	<!-- Extension element used for defining a custom file system -->
+	<xs:element name="filesystem" type="spring-bean-or-ref"/>
+
+	<!-- Element used to provide custom command implementations -->
+	<xs:element name="commands">
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="command">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:choice maxOccurs="unbounded">
+								<xs:element ref="beans:bean"/>
+								<xs:element ref="beans:ref"/>
+							</xs:choice>
+						</xs:sequence>
+						<xs:attribute name="name" use="required"/>
+					</xs:complexType>
+
+				</xs:element>
+			</xs:sequence>
+			<xs:attribute name="use-default" type="xs:boolean"/>
+		</xs:complexType>
+	</xs:element>
+	
+	<!-- Element used to configure and localize messages -->
+	<xs:element name="messages">
+		<xs:complexType>
+			<xs:attribute name="languages"/>
+			<xs:attribute name="directory"/>
+		</xs:complexType>
+	</xs:element>
+
+	<!-- Reusable type used for extension elements -->
+	<xs:complexType name="spring-bean-or-ref">
+		<xs:choice>
+			<xs:element ref="beans:bean"/>
+			<xs:element ref="beans:ref"/>
+		</xs:choice>
+	</xs:complexType>
+	
+	<!-- Reusable type used for named extension elements -->
+	<xs:complexType name="spring-bean-or-ref-with-name">
+		<xs:sequence>
+			<xs:choice>
+				<xs:element ref="beans:bean"/>
+				<xs:element ref="beans:ref"/>
+			</xs:choice>
+			
+		</xs:sequence>
+		<xs:attribute name="name" use="required" type="xs:string"/>
+	</xs:complexType>
+	
+</xs:schema>

Added: mina/ftpserver/trunk/core/src/test/java/org/apache/ftpserver/config/spring/SpringConfigTest.java
URL: http://svn.apache.org/viewvc/mina/ftpserver/trunk/core/src/test/java/org/apache/ftpserver/config/spring/SpringConfigTest.java?rev=665702&view=auto
==============================================================================
--- mina/ftpserver/trunk/core/src/test/java/org/apache/ftpserver/config/spring/SpringConfigTest.java (added)
+++ mina/ftpserver/trunk/core/src/test/java/org/apache/ftpserver/config/spring/SpringConfigTest.java Mon Jun  9 07:29:09 2008
@@ -0,0 +1,61 @@
+package org.apache.ftpserver.config.spring;
+
+import java.net.InetAddress;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.apache.ftpserver.DefaultCommandFactory;
+import org.apache.ftpserver.FtpServer;
+import org.apache.ftpserver.command.HELP;
+import org.apache.ftpserver.listener.Listener;
+import org.apache.ftpserver.listener.mina.MinaListener;
+import org.apache.mina.filter.firewall.Subnet;
+import org.springframework.beans.factory.xml.XmlBeanFactory;
+import org.springframework.core.io.FileSystemResource;
+
+public class SpringConfigTest extends TestCase {
+
+    public void test() throws Throwable {
+        XmlBeanFactory factory = new XmlBeanFactory(new FileSystemResource("src/test/resources/spring-config/config-spring-1.xml"));
+
+        FtpServer server = (FtpServer) factory.getBean("server");
+        server.start();
+        
+        Map<String, Listener> listeners = server.getServerContext().getListeners(); 
+        assertEquals(3, listeners.size());
+        
+        Listener listener = listeners.get("listener0");
+        assertNotNull(listener);
+        assertTrue(listener instanceof MinaListener);
+        assertEquals(2222, ((MinaListener)listener).getPort());
+        
+        List<Subnet> subnets = ((MinaListener)listener).getBlockedSubnets();
+        assertEquals(3, subnets.size());
+        assertEquals(new Subnet(InetAddress.getByName("1.2.3.0"), 16), subnets.get(0));
+        assertEquals(new Subnet(InetAddress.getByName("1.2.4.0"), 16), subnets.get(1));
+        assertEquals(new Subnet(InetAddress.getByName("1.2.3.4"), 32), subnets.get(2));
+        
+        listener = listeners.get("listener1");
+        assertNotNull(listener);
+        assertTrue(listener instanceof MinaListener);
+        assertEquals(2223, ((MinaListener)listener).getPort());
+        
+        listener = listeners.get("listener2");
+        assertNotNull(listener);
+        assertTrue(listener instanceof MinaListener);
+        assertEquals(2224, ((MinaListener)listener).getPort());
+        
+        DefaultCommandFactory cf = (DefaultCommandFactory) server.getServerContext().getCommandFactory();
+        assertEquals(1, cf.getCommandMap().size());
+        assertTrue(cf.getCommand("FOO") instanceof HELP);
+        
+        String[] languages = server.getServerContext().getMessageResource().getAvailableLanguages();
+        
+        assertEquals(3, languages.length);
+        assertEquals("se", languages[0]);
+        assertEquals("no", languages[1]);
+        assertEquals("da", languages[2]);
+    }
+}

Added: mina/ftpserver/trunk/core/src/test/java/org/apache/ftpserver/config/spring/TestFtplet.java
URL: http://svn.apache.org/viewvc/mina/ftpserver/trunk/core/src/test/java/org/apache/ftpserver/config/spring/TestFtplet.java?rev=665702&view=auto
==============================================================================
--- mina/ftpserver/trunk/core/src/test/java/org/apache/ftpserver/config/spring/TestFtplet.java (added)
+++ mina/ftpserver/trunk/core/src/test/java/org/apache/ftpserver/config/spring/TestFtplet.java Mon Jun  9 07:29:09 2008
@@ -0,0 +1,17 @@
+package org.apache.ftpserver.config.spring;
+
+import org.apache.ftpserver.ftplet.DefaultFtplet;
+
+public class TestFtplet extends DefaultFtplet {
+
+    private int foo;
+
+    public int getFoo() {
+        return foo;
+    }
+
+    public void setFoo(int foo) {
+        this.foo = foo;
+    }
+    
+}

Added: mina/ftpserver/trunk/core/src/test/resources/spring-config/config-spring-1.xml
URL: http://svn.apache.org/viewvc/mina/ftpserver/trunk/core/src/test/resources/spring-config/config-spring-1.xml?rev=665702&view=auto
==============================================================================
--- mina/ftpserver/trunk/core/src/test/resources/spring-config/config-spring-1.xml (added)
+++ mina/ftpserver/trunk/core/src/test/resources/spring-config/config-spring-1.xml Mon Jun  9 07:29:09 2008
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans:beans xmlns="http://mina.apache.org/ftpserver/spring/v1"
+	xmlns:beans="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.5.xsd 
+	   http://mina.apache.org/ftpserver/spring/v1 http://mina.apache.org/ftpserver/ftpserver-1.0.xsd	
+	   ">
+
+	<beans:bean id="listener1" class="org.apache.ftpserver.listener.mina.MinaListener">
+		<beans:property name="port" value="2223"/>
+	</beans:bean>
+
+	<server id="server">
+		<listeners>
+			<nio-listener name="listener0" port="2222">
+				<data-connection>
+					<ssl>
+						<keystore file="/tmp/tmp.jks" password="secret"/>
+					</ssl>
+					<active enabled="true" local-address="1.2.3.4"/>
+					<passive ports="123-125"/>
+				</data-connection>
+				<blacklist>1.2.3.0/16, 1.2.4.0/16, 1.2.3.4</blacklist>				
+			</nio-listener>
+			<listener name="listener1">
+				<beans:ref bean="listener1"/>
+			</listener>
+			<listener name="listener2">
+				<beans:bean class="org.apache.ftpserver.listener.mina.MinaListener">
+					<beans:property name="port" value="2224"/>
+				</beans:bean>
+			</listener>
+		</listeners>
+		<ftplets>
+			<ftplet name="ftplet1">
+				<beans:bean class="org.apache.ftpserver.config.spring.TestFtplet">
+					<beans:property name="foo" value="123"/>
+				</beans:bean>
+				
+			</ftplet>
+		</ftplets>
+		<!--<file-user-manager file="/tmp/foo.users" encrypt-passwords="true" />-->
+		<user-manager>
+			<beans:bean class="org.apache.ftpserver.usermanager.PropertiesUserManager"/>
+		</user-manager>
+		<native-filesystem case-insensitive="false" />
+		<commands use-default="false">
+		  <command name="FOO">
+			  <beans:bean class="org.apache.ftpserver.command.HELP" />
+		  </command>
+		</commands>
+		<messages languages="se no ,da" />
+	</server>
+</beans:beans>