一、前言
通过apache的ftpserver-core包(1.0.6)中关于org.apache.ftpserver.command.Command基于命令模式实现(如下图),其中ftp的cwd、dele、type、list等常用的操作命令基于AbstractCommand定义接口,再注入到DefaultCommandFactory工厂类中。
二、源码说明
1.Command接口
package org.apache.ftpserver.command;@b@@b@import java.io.IOException;@b@import org.apache.ftpserver.ftplet.FtpException;@b@import org.apache.ftpserver.ftplet.FtpRequest;@b@import org.apache.ftpserver.impl.FtpIoSession;@b@import org.apache.ftpserver.impl.FtpServerContext;@b@@b@public abstract interface Command@b@{@b@ public abstract void execute(FtpIoSession paramFtpIoSession, FtpServerContext paramFtpServerContext, FtpRequest paramFtpRequest)@b@ throws IOException, FtpException;@b@}
2.LIST实现类
package org.apache.ftpserver.command.impl;@b@@b@import java.io.IOException;@b@import java.net.InetAddress;@b@import java.net.SocketException;@b@import org.apache.ftpserver.command.AbstractCommand;@b@import org.apache.ftpserver.command.impl.listing.DirectoryLister;@b@import org.apache.ftpserver.command.impl.listing.LISTFileFormater;@b@import org.apache.ftpserver.command.impl.listing.ListArgument;@b@import org.apache.ftpserver.command.impl.listing.ListArgumentParser;@b@import org.apache.ftpserver.ftplet.DataConnection;@b@import org.apache.ftpserver.ftplet.DataConnectionFactory;@b@import org.apache.ftpserver.ftplet.DefaultFtpReply;@b@import org.apache.ftpserver.ftplet.FileSystemView;@b@import org.apache.ftpserver.ftplet.FtpException;@b@import org.apache.ftpserver.ftplet.FtpFile;@b@import org.apache.ftpserver.ftplet.FtpRequest;@b@import org.apache.ftpserver.impl.FtpIoSession;@b@import org.apache.ftpserver.impl.FtpServerContext;@b@import org.apache.ftpserver.impl.IODataConnectionFactory;@b@import org.apache.ftpserver.impl.LocalizedFtpReply;@b@import org.apache.ftpserver.impl.ServerDataConnectionFactory;@b@import org.slf4j.Logger;@b@import org.slf4j.LoggerFactory;@b@@b@public class LIST extends AbstractCommand@b@{@b@ private final Logger LOG;@b@ private static final LISTFileFormater LIST_FILE_FORMATER = new LISTFileFormater();@b@ private DirectoryLister directoryLister;@b@@b@ public LIST()@b@ {@b@ this.LOG = LoggerFactory.getLogger(LIST.class);@b@@b@ this.directoryLister = new DirectoryLister();@b@ }@b@@b@ public void execute(FtpIoSession session, FtpServerContext context, FtpRequest request)@b@ throws IOException, FtpException@b@ {@b@ try@b@ {@b@ DataConnection dataConnection;@b@ session.resetState();@b@@b@ ListArgument parsedArg = ListArgumentParser.parse(request.getArgument());@b@@b@ FtpFile file = session.getFileSystemView().getFile(parsedArg.getFile());@b@@b@ if (!(file.doesExist())) {@b@ this.LOG.debug("Listing on a non-existing file");@b@ session.write(LocalizedFtpReply.translate(session, request, context, 450, "LIST", null));@b@@b@ return;@b@ }@b@ DataConnectionFactory connFactory = session.getDataConnection();@b@ if (connFactory instanceof IODataConnectionFactory) {@b@ InetAddress address = ((IODataConnectionFactory)connFactory).getInetAddress();@b@@b@ if (address == null) {@b@ session.write(new DefaultFtpReply(503, "PORT or PASV must be issued first"));@b@@b@ return;@b@ }@b@ }@b@ session.write(LocalizedFtpReply.translate(session, request, context, 150, "LIST", null));@b@ try@b@ {@b@ dataConnection = session.getDataConnection().openConnection();@b@ } catch (Exception e) {@b@ this.LOG.debug("Exception getting the output data stream", e);@b@ session.write(LocalizedFtpReply.translate(session, request, context, 425, "LIST", null));@b@@b@ session.getDataConnection().closeDataConnection(); return;@b@ }@b@ boolean failure = false;@b@ try@b@ {@b@ dataConnection.transferToClient(session.getFtpletSession(), this.directoryLister.listFiles(parsedArg, session.getFileSystemView(), LIST_FILE_FORMATER));@b@ }@b@ catch (SocketException ex)@b@ {@b@ this.LOG.debug("Socket exception during list transfer", ex);@b@ failure = true;@b@ session.write(LocalizedFtpReply.translate(session, request, context, 426, "LIST", null));@b@ }@b@ catch (IOException ex)@b@ {@b@ this.LOG.debug("IOException during list transfer", ex);@b@ failure = true;@b@ session.write(LocalizedFtpReply.translate(session, request, context, 551, "LIST", null));@b@ }@b@ catch (IllegalArgumentException e)@b@ {@b@ this.LOG.debug("Illegal list syntax: " + request.getArgument(), e);@b@@b@ session.write(LocalizedFtpReply.translate(session, request, context, 501, "LIST", null));@b@ }@b@@b@ if (!(failure))@b@ session.write(LocalizedFtpReply.translate(session, request, context, 226, "LIST", null));@b@@b@ }@b@ finally@b@ {@b@ session.getDataConnection().closeDataConnection();@b@ }@b@ }@b@}
3.CommandFactory工厂接口类
package org.apache.ftpserver.command;@b@@b@public abstract interface CommandFactory@b@{@b@ public abstract Command getCommand(String paramString);@b@}
4.DefaultCommandFactory默认工厂实现类
package org.apache.ftpserver.command.impl;@b@@b@import java.util.HashMap;@b@import java.util.Map;@b@import org.apache.ftpserver.command.Command;@b@import org.apache.ftpserver.command.CommandFactory;@b@@b@public class DefaultCommandFactory@b@ implements CommandFactory@b@{@b@ private Map<String, Command> commandMap = new HashMap();@b@@b@ public DefaultCommandFactory(Map<String, Command> commandMap)@b@ {@b@ this.commandMap = commandMap;@b@ }@b@@b@ public Command getCommand(String cmdName)@b@ {@b@ if ((cmdName == null) || (cmdName.equals("")))@b@ return null;@b@@b@ String upperCaseCmdName = cmdName.toUpperCase();@b@ return ((Command)this.commandMap.get(upperCaseCmdName));@b@ }@b@}