This is an automated email from the ASF dual-hosted git repository. elecharny pushed a commit to branch 1.2.X in repository https://gitbox.apache.org/repos/asf/mina-ftpserver.git
The following commit(s) were added to refs/heads/1.2.X by this push: new 081801d6 - Code refactoring - Javadoc addition - Minor cosmetic changes 081801d6 is described below commit 081801d6969425ac19cbf3b71c0498192803cc10 Author: emmanuel lecharny <elecha...@apache.org> AuthorDate: Tue Jul 4 00:47:00 2023 +0200 - Code refactoring - Javadoc addition - Minor cosmetic changes --- .../java/org/apache/ftpserver/command/Command.java | 11 +- .../apache/ftpserver/command/CommandFactory.java | 36 ------ .../ftpserver/command/CommandFactoryFactory.java | 138 ++++++++++++--------- .../command/impl/DefaultCommandFactory.java | 13 +- .../org/apache/ftpserver/command/impl/HELP.java | 10 +- .../apache/ftpserver/impl/DefaultFtpRequest.java | 21 ++-- .../apache/ftpserver/impl/DefaultFtpServer.java | 1 + .../ftpserver/impl/DefaultFtpServerContext.java | 7 +- .../apache/ftpserver/impl/FtpReplyTranslator.java | 8 +- .../ftpserver/message/MessageResourceFactory.java | 3 +- .../message/impl/DefaultMessageResource.java | 117 +++++++++-------- .../usermanager/DbUserManagerFactory.java | 7 ++ .../usermanager/PropertiesUserManagerFactory.java | 14 +-- .../usermanager/impl/PropertiesUserManager.java | 3 +- .../org/apache/ftpserver/util/PasswordUtil.java | 26 ++-- 15 files changed, 217 insertions(+), 198 deletions(-) diff --git a/core/src/main/java/org/apache/ftpserver/command/Command.java b/core/src/main/java/org/apache/ftpserver/command/Command.java index a0fb8035..7dd7f53f 100644 --- a/core/src/main/java/org/apache/ftpserver/command/Command.java +++ b/core/src/main/java/org/apache/ftpserver/command/Command.java @@ -32,19 +32,14 @@ import org.apache.ftpserver.impl.FtpServerContext; * @author <a href="http://mina.apache.org">Apache MINA Project</a> */ public interface Command { - /** * Execute command. * - * @param session - * The current {@link FtpIoSession} - * @param context - * The current {@link FtpServerContext} + * @param session The current {@link FtpIoSession} + * @param context The current {@link FtpServerContext} * @param request The current {@link FtpRequest} * @throws IOException * @throws FtpException */ - void execute(FtpIoSession session, FtpServerContext context, - FtpRequest request) throws IOException, FtpException; - + void execute(FtpIoSession session, FtpServerContext context, FtpRequest request) throws IOException, FtpException; } diff --git a/core/src/main/java/org/apache/ftpserver/command/CommandFactory.java b/core/src/main/java/org/apache/ftpserver/command/CommandFactory.java index 5c987b46..d9823fdb 100644 --- a/core/src/main/java/org/apache/ftpserver/command/CommandFactory.java +++ b/core/src/main/java/org/apache/ftpserver/command/CommandFactory.java @@ -33,40 +33,4 @@ public interface CommandFactory { * null if no such command exists. */ 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); } diff --git a/core/src/main/java/org/apache/ftpserver/command/CommandFactoryFactory.java b/core/src/main/java/org/apache/ftpserver/command/CommandFactoryFactory.java index d2149110..3291aaa9 100644 --- a/core/src/main/java/org/apache/ftpserver/command/CommandFactoryFactory.java +++ b/core/src/main/java/org/apache/ftpserver/command/CommandFactoryFactory.java @@ -86,62 +86,82 @@ public class CommandFactoryFactory { static { // first populate the default command list - DEFAULT_COMMAND_MAP.put("ABOR", new ABOR()); - DEFAULT_COMMAND_MAP.put("ACCT", new ACCT()); - DEFAULT_COMMAND_MAP.put("APPE", new APPE()); - DEFAULT_COMMAND_MAP.put("AUTH", new AUTH()); - DEFAULT_COMMAND_MAP.put("CDUP", new CDUP()); - DEFAULT_COMMAND_MAP.put("CWD", new CWD()); - DEFAULT_COMMAND_MAP.put("DELE", new DELE()); - DEFAULT_COMMAND_MAP.put("EPRT", new EPRT()); - DEFAULT_COMMAND_MAP.put("EPSV", new EPSV()); - DEFAULT_COMMAND_MAP.put("FEAT", new FEAT()); - DEFAULT_COMMAND_MAP.put("HELP", new HELP()); - DEFAULT_COMMAND_MAP.put("LANG", new LANG()); - DEFAULT_COMMAND_MAP.put("LIST", new LIST()); - DEFAULT_COMMAND_MAP.put(MD5.MD5, new MD5()); - DEFAULT_COMMAND_MAP.put("MFMT", new MFMT()); - DEFAULT_COMMAND_MAP.put(MD5.MMD5, new MD5()); - DEFAULT_COMMAND_MAP.put("MDTM", new MDTM()); - DEFAULT_COMMAND_MAP.put("MLST", new MLST()); - DEFAULT_COMMAND_MAP.put("MKD", new MKD()); - DEFAULT_COMMAND_MAP.put("MLSD", new MLSD()); - DEFAULT_COMMAND_MAP.put("MODE", new MODE()); - DEFAULT_COMMAND_MAP.put("NLST", new NLST()); - DEFAULT_COMMAND_MAP.put("NOOP", new NOOP()); - DEFAULT_COMMAND_MAP.put("OPTS", new OPTS()); - DEFAULT_COMMAND_MAP.put("PASS", new PASS()); - DEFAULT_COMMAND_MAP.put("PASV", new PASV()); - DEFAULT_COMMAND_MAP.put("PBSZ", new PBSZ()); - DEFAULT_COMMAND_MAP.put("PORT", new PORT()); - DEFAULT_COMMAND_MAP.put("PROT", new PROT()); - DEFAULT_COMMAND_MAP.put("PWD", new PWD()); - DEFAULT_COMMAND_MAP.put("QUIT", new QUIT()); - DEFAULT_COMMAND_MAP.put("REIN", new REIN()); - DEFAULT_COMMAND_MAP.put("REST", new REST()); - DEFAULT_COMMAND_MAP.put("RETR", new RETR()); - DEFAULT_COMMAND_MAP.put("RMD", new RMD()); - DEFAULT_COMMAND_MAP.put("RNFR", new RNFR()); - DEFAULT_COMMAND_MAP.put("RNTO", new RNTO()); - DEFAULT_COMMAND_MAP.put("SITE", new SITE()); - DEFAULT_COMMAND_MAP.put("SIZE", new SIZE()); - DEFAULT_COMMAND_MAP.put("SITE_DESCUSER", new SITE_DESCUSER()); - DEFAULT_COMMAND_MAP.put("SITE_HELP", new SITE_HELP()); - DEFAULT_COMMAND_MAP.put("SITE_STAT", new SITE_STAT()); - DEFAULT_COMMAND_MAP.put("SITE_WHO", new SITE_WHO()); - DEFAULT_COMMAND_MAP.put("SITE_ZONE", new SITE_ZONE()); - - DEFAULT_COMMAND_MAP.put("STAT", new STAT()); - DEFAULT_COMMAND_MAP.put("STOR", new STOR()); - DEFAULT_COMMAND_MAP.put("STOU", new STOU()); - DEFAULT_COMMAND_MAP.put("STRU", new STRU()); - DEFAULT_COMMAND_MAP.put("SYST", new SYST()); - DEFAULT_COMMAND_MAP.put("TYPE", new TYPE()); - DEFAULT_COMMAND_MAP.put("USER", new USER()); + DEFAULT_COMMAND_MAP.put("ABOR", new ABOR()); // rfc959, 4.1.3 + DEFAULT_COMMAND_MAP.put("ACCT", new ACCT()); // rfc959, 4.1.1 + // ADAT, rfc2228, 3? + // ALLO, rfc959? + DEFAULT_COMMAND_MAP.put("APPE", new APPE()); // rfc959, 4.1.3 + DEFAULT_COMMAND_MAP.put("AUTH", new AUTH()); // rfc2228, 3 + //AVBL, draft-peterson-streamlined-ftp-command-extensions? + // CCC, rfc2228, 3? + DEFAULT_COMMAND_MAP.put("CDUP", new CDUP()); // rfc959, 4.1.1 + // CONF, rfc2228, 3? + // CSID, draft-peterson-streamlined-ftp-command-extensions? + DEFAULT_COMMAND_MAP.put("CWD", new CWD()); // rfc959, 4.1.1 + DEFAULT_COMMAND_MAP.put("DELE", new DELE()); // rfc959, 4.1.3 + // DSIZ, draft-peterson-streamlined-ftp-command-extensions? + // ENC, rfc2228, 3? + DEFAULT_COMMAND_MAP.put("EPRT", new EPRT()); // rfc2428, 2 + DEFAULT_COMMAND_MAP.put("EPSV", new EPSV()); // rfc2428, 3 + DEFAULT_COMMAND_MAP.put("FEAT", new FEAT()); // rfc2389, 3 + DEFAULT_COMMAND_MAP.put("HELP", new HELP()); // rfc959, 4.1.3 + // HOST, rfc7151? + DEFAULT_COMMAND_MAP.put("LANG", new LANG()); // rfc2640, 4.1 + DEFAULT_COMMAND_MAP.put("LIST", new LIST()); // rfc959, 4.1.3 + // LPRT, rfc1639 2? + // LPSV, rfc1639 2? + DEFAULT_COMMAND_MAP.put(MD5.MD5, new MD5()); // draft-twine-ftpmd5-00.txt, 3.1 + // MIC, rfc2228, 3? + DEFAULT_COMMAND_MAP.put(MD5.MMD5, new MD5()); // draft-twine-ftpmd5-00.txt , 3.2 + DEFAULT_COMMAND_MAP.put("MDTM", new MDTM()); // rfc3659, 3 + // "MFCT, draft-somers-ftp-mfxx, 4 + // "MFF, draft-somers-ftp-mfxx, 5 + DEFAULT_COMMAND_MAP.put("MFMT", new MFMT()); // draft-somers-ftp-mfxx, 3 + DEFAULT_COMMAND_MAP.put("MKD", new MKD()); // rfc959, 4.1.3 + DEFAULT_COMMAND_MAP.put("MLSD", new MLSD()); // rfc3659, 7 + DEFAULT_COMMAND_MAP.put("MLST", new MLST()); // rfc3659, 7 + DEFAULT_COMMAND_MAP.put("MODE", new MODE()); // rfc959, 4.1.2 + DEFAULT_COMMAND_MAP.put("NLST", new NLST()); // rfc959, 4.1.3 + DEFAULT_COMMAND_MAP.put("NOOP", new NOOP()); // rfc959, 4.1.3 + DEFAULT_COMMAND_MAP.put("OPTS", new OPTS()); // rfc2389, 4 + DEFAULT_COMMAND_MAP.put("PASS", new PASS()); // rfc959, 4.1.1 + DEFAULT_COMMAND_MAP.put("PASV", new PASV()); // rfc959, 4.1.2 + DEFAULT_COMMAND_MAP.put("PBSZ", new PBSZ()); // rfc2228, 3 + DEFAULT_COMMAND_MAP.put("PORT", new PORT()); // rfc959, 4.1.2 + DEFAULT_COMMAND_MAP.put("PROT", new PROT()); // rfc2228, 3 + DEFAULT_COMMAND_MAP.put("PWD", new PWD()); // rfc959, 4.1.3 + DEFAULT_COMMAND_MAP.put("QUIT", new QUIT()); // rfc959, 4.1.1 + DEFAULT_COMMAND_MAP.put("REIN", new REIN()); // rfc959, 4.1.1 + DEFAULT_COMMAND_MAP.put("REST", new REST()); // rfc959, 4.1.3, rfc3659, 5 + DEFAULT_COMMAND_MAP.put("RETR", new RETR()); // rfc959, 4.1.3 + DEFAULT_COMMAND_MAP.put("RMD", new RMD()); // rfc959, 4.1.3 + // RMDA, draft-peterson-streamlined-ftp-command-extensions? + DEFAULT_COMMAND_MAP.put("RNFR", new RNFR()); // rfc959, 4.1.3 + DEFAULT_COMMAND_MAP.put("RNTO", new RNTO()); // rfc959, 4.1.3 + DEFAULT_COMMAND_MAP.put("SITE", new SITE()); // rfc959, 4.1.3 + DEFAULT_COMMAND_MAP.put("SITE_DESCUSER", new SITE_DESCUSER()); // rfc959, 4.1.3 + DEFAULT_COMMAND_MAP.put("SITE_HELP", new SITE_HELP()); // rfc959, 4.1.3 + DEFAULT_COMMAND_MAP.put("SITE_STAT", new SITE_STAT()); // rfc959, 4.1.3 + DEFAULT_COMMAND_MAP.put("SITE_WHO", new SITE_WHO()); // rfc959, 4.1.3 + DEFAULT_COMMAND_MAP.put("SITE_ZONE", new SITE_ZONE()); // rfc959, 4.1.3 + DEFAULT_COMMAND_MAP.put("SIZE", new SIZE()); // rfc3659, 4 + // SMNT, rfc959? + // SPSV, draft-rosenau-ftp-single-port + DEFAULT_COMMAND_MAP.put("STAT", new STAT()); // rfc959, 4.1.3 + DEFAULT_COMMAND_MAP.put("STOR", new STOR()); // rfc959, 4.1.3 + DEFAULT_COMMAND_MAP.put("STOU", new STOU()); // rfc959, 4.1.3 + DEFAULT_COMMAND_MAP.put("STRU", new STRU()); // rfc959, 4.1.2 + DEFAULT_COMMAND_MAP.put("SYST", new SYST()); // rfc959, 4.1.3 + // THMB, draft-peterson-streamlined-ftp-command-extensions + DEFAULT_COMMAND_MAP.put("TYPE", new TYPE()); // rfc959, 4.1.2 + // TVFS, rfc3659, 6? + DEFAULT_COMMAND_MAP.put("USER", new USER()); // rfc959, 4.1.1 } + /** The commands map */ private Map<String, Command> commandMap = new HashMap<String, Command>(); + /** A flag indicating of we have non-default commands */ private boolean useDefaultCommands = true; /** @@ -151,7 +171,8 @@ public class CommandFactoryFactory { public CommandFactory createCommandFactory() { Map<String, Command> mergedCommands = new HashMap<String, Command>(); - if(useDefaultCommands) { + + if (useDefaultCommands) { mergedCommands.putAll(DEFAULT_COMMAND_MAP); } @@ -172,8 +193,7 @@ public class CommandFactoryFactory { /** * Sets whether the default commands will be used. * - * @param useDefaultCommands - * true if default commands should be used + * @param useDefaultCommands <code>true</code> if default commands should be used */ public void setUseDefaultCommands(final boolean useDefaultCommands) { this.useDefaultCommands = useDefaultCommands; @@ -194,10 +214,11 @@ public class CommandFactoryFactory { * @param command The command */ public void addCommand(String commandName, Command command) { - if(commandName == null) { + if (commandName == null) { throw new NullPointerException("commandName can not be null"); } - if(command == null) { + + if (command == null) { throw new NullPointerException("command can not be null"); } @@ -207,8 +228,7 @@ public class CommandFactoryFactory { /** * Set commands to add or override to the default commands * - * @param commandMap - * The map of commands, the key will be used to map to requests. + * @param commandMap The map of commands, the key will be used to map to requests. */ public void setCommandMap(final Map<String, Command> commandMap) { if (commandMap == null) { diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/DefaultCommandFactory.java b/core/src/main/java/org/apache/ftpserver/command/impl/DefaultCommandFactory.java index 8b0fd476..24bad29e 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/DefaultCommandFactory.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/DefaultCommandFactory.java @@ -37,7 +37,10 @@ import org.apache.ftpserver.command.CommandFactoryFactory; * @author <a href="http://mina.apache.org">Apache MINA Project</a> */ public class DefaultCommandFactory implements CommandFactory { + /** The list of supported commands */ + private final Map<String, Command> commandMap; + /** Internal constructor, use {@link CommandFactoryFactory} instead */ public DefaultCommandFactory() { this(new HashMap<String, Command>()); } @@ -49,16 +52,16 @@ public class DefaultCommandFactory implements CommandFactory { this.commandMap = commandMap; } - private final Map<String, Command> commandMap; /** - * Get command. Returns null if not found. + * {@inheritDoc} */ + @Override public Command getCommand(final String cmdName) { - if (cmdName == null || cmdName.equals("")) { + if (cmdName == null || (cmdName.length() == 0)) { return null; } - String upperCaseCmdName = cmdName.toUpperCase(); - return commandMap.get(upperCaseCmdName); + + return commandMap.get(cmdName.toUpperCase()); } } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/HELP.java b/core/src/main/java/org/apache/ftpserver/command/impl/HELP.java index f5607908..885c186b 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/HELP.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/HELP.java @@ -32,17 +32,18 @@ import org.apache.ftpserver.message.MessageResource; /** * <strong>Internal class, do not use directly.</strong> * - * <code>HELP [<SP> <string>] <CRLF></code><br> + * <code>HELP [<SP> <string>] <CRLF></code><br> * * This command shall cause the server to send helpful information regarding its * implementation status over the control connection to the user. The command * may take an argument (e.g., any command name) and return more specific * information as a response. + * <br> + * Defined in RFC 959 * * @author <a href="http://mina.apache.org">Apache MINA Project</a> */ public class HELP extends AbstractCommand { - /** * Execute command. */ @@ -63,10 +64,11 @@ public class HELP extends AbstractCommand { // print command specific help if available String ftpCmd = request.getArgument().toUpperCase(); MessageResource resource = context.getMessageResource(); - if (resource.getMessage(FtpReply.REPLY_214_HELP_MESSAGE, ftpCmd, - session.getLanguage()) == null) { + + if (resource.getMessage(FtpReply.REPLY_214_HELP_MESSAGE, ftpCmd, session.getLanguage()) == null) { ftpCmd = null; } + session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_214_HELP_MESSAGE, ftpCmd, null)); } diff --git a/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpRequest.java b/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpRequest.java index 6f8f9192..c75d7055 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpRequest.java +++ b/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpRequest.java @@ -29,20 +29,22 @@ import org.apache.ftpserver.ftplet.FtpRequest; * @author <a href="http://mina.apache.org">Apache MINA Project</a> */ public class DefaultFtpRequest implements FtpRequest { - + /** The request line */ private final String line; + /** The FTP command */ private final String command; + /** The FTP argument */ private final String argument; - /** - * timestamp when this request was received - */ + /** timestamp when this request was received */ private final long receivedTime; /** * Default constructor. + * + * @param requestLine The request line */ public DefaultFtpRequest(final String requestLine) { //Assuming we create the request as soon as we receive the command from @@ -50,7 +52,7 @@ public class DefaultFtpRequest implements FtpRequest { //bunch of things after we receive the command from the client and //before constructing this FtpRequest object, then this method is not //going to be accurate and need to look for an alternative solution. - this.receivedTime = System.currentTimeMillis(); + receivedTime = System.currentTimeMillis(); line = requestLine.trim(); int spInd = line.indexOf(' '); command = parseCmd(line, spInd); @@ -62,14 +64,17 @@ public class DefaultFtpRequest implements FtpRequest { */ private String parseCmd(final String lineToParse, int spInd) { String cmd = null; + if (spInd != -1) { cmd = line.substring(0, spInd).toUpperCase(); } else { cmd = line.toUpperCase(); } + if ((cmd.length() > 0) && (cmd.charAt(0) == 'X')) { cmd = cmd.substring(1); } + return cmd; } @@ -77,10 +82,12 @@ public class DefaultFtpRequest implements FtpRequest { String arg = null; if (spInd != -1) { arg = line.substring(spInd + 1); + if (arg.equals("")) { arg = null; } } + return arg; } @@ -109,7 +116,7 @@ public class DefaultFtpRequest implements FtpRequest { * Has argument. */ public boolean hasArgument() { - return getArgument() != null; + return argument != null; } public long getReceivedTime() { @@ -123,6 +130,6 @@ public class DefaultFtpRequest implements FtpRequest { */ @Override public String toString() { - return getRequestLine(); + return line; } } diff --git a/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpServer.java b/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpServer.java index 680bd19a..d6197c7b 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpServer.java +++ b/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpServer.java @@ -76,6 +76,7 @@ public class DefaultFtpServer implements FtpServer { try { Map<String, Listener> listeners = serverContext.getListeners(); + for (Listener listener : listeners.values()) { listener.start(serverContext); startedListeners.add(listener); diff --git a/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpServerContext.java b/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpServerContext.java index 731b0f58..c9ee1270 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpServerContext.java +++ b/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpServerContext.java @@ -63,6 +63,7 @@ public class DefaultFtpServerContext implements FtpServerContext { private final Logger LOG = LoggerFactory .getLogger(DefaultFtpServerContext.class); + /** The FTP messages per language */ private MessageResource messageResource = new MessageResourceFactory().createMessageResource(); private UserManager userManager = new PropertiesUserManagerFactory().createUserManager(); @@ -101,7 +102,11 @@ public class DefaultFtpServerContext implements FtpServerContext { } /** - * Create default users. + * Create default users: + * <ul> + * <li>Admin</li> + * <li>Anonymous</ul> + * </ul> */ public void createDefaultUsers() throws Exception { UserManager userManager = getUserManager(); diff --git a/core/src/main/java/org/apache/ftpserver/impl/FtpReplyTranslator.java b/core/src/main/java/org/apache/ftpserver/impl/FtpReplyTranslator.java index dc53f5d1..cd63f3f7 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/FtpReplyTranslator.java +++ b/core/src/main/java/org/apache/ftpserver/impl/FtpReplyTranslator.java @@ -113,19 +113,21 @@ public class FtpReplyTranslator { * the basic message * @return the translated message */ - public static String translateMessage(FtpIoSession session, - FtpRequest request, FtpServerContext context, int code, String subId, - String basicMsg) { + public static String translateMessage(FtpIoSession session, FtpRequest request, FtpServerContext context, + int code, String subId, String basicMsg) { MessageResource resource = context.getMessageResource(); String lang = session.getLanguage(); String msg = null; + if (resource != null) { msg = resource.getMessage(code, subId, lang); } + if (msg == null) { msg = ""; } + msg = replaceVariables(session, request, context, code, basicMsg, msg); return msg; diff --git a/core/src/main/java/org/apache/ftpserver/message/MessageResourceFactory.java b/core/src/main/java/org/apache/ftpserver/message/MessageResourceFactory.java index a55c7d3b..66fb1044 100644 --- a/core/src/main/java/org/apache/ftpserver/message/MessageResourceFactory.java +++ b/core/src/main/java/org/apache/ftpserver/message/MessageResourceFactory.java @@ -30,9 +30,10 @@ import org.apache.ftpserver.message.impl.DefaultMessageResource; * @author <a href="http://mina.apache.org">Apache MINA Project</a> */ public class MessageResourceFactory { - + /** The supported languages */ private List<String> languages; + /** The directory where the message are stored */ private File customMessageDirectory; /** diff --git a/core/src/main/java/org/apache/ftpserver/message/impl/DefaultMessageResource.java b/core/src/main/java/org/apache/ftpserver/message/impl/DefaultMessageResource.java index 67caaf4b..c473b248 100644 --- a/core/src/main/java/org/apache/ftpserver/message/impl/DefaultMessageResource.java +++ b/core/src/main/java/org/apache/ftpserver/message/impl/DefaultMessageResource.java @@ -21,11 +21,9 @@ package org.apache.ftpserver.message.impl; import java.io.File; import java.io.FileInputStream; -import java.io.IOException; import java.io.InputStream; import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; @@ -33,40 +31,41 @@ import java.util.Properties; import org.apache.ftpserver.FtpServerConfigurationException; import org.apache.ftpserver.message.MessageResource; import org.apache.ftpserver.message.MessageResourceFactory; -import org.apache.ftpserver.util.IoUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * <strong>Internal class, do not use directly.</strong> - * - * Class to get FtpServer reply messages. This supports i18n. Basic message - * search path is: - * - * <strong><strong>Internal class, do not use directly.</strong></strong> + * <br> + * Class to get FtpServer reply messages. This supports i18n. + * <br> + * Basic message search path is: * * Custom Language Specific Messages -> Default Language Specific Messages -> * Custom Common Messages -> Default Common Messages -> null (not found) + * <br> + * <strong>Internal class, do not use directly.</strong> * * @author <a href="http://mina.apache.org">Apache MINA Project</a> */ public class DefaultMessageResource implements MessageResource { + /** A logger for this class */ + private final Logger LOG = LoggerFactory.getLogger(DefaultMessageResource.class); - private final Logger LOG = LoggerFactory - .getLogger(DefaultMessageResource.class); - + /** The default path for the message root */ private final static String RESOURCE_PATH = "org/apache/ftpserver/message/"; + /** The requested languages. Default to none, ie EN */ private final List<String> languages; + /** The <language, properties> list of messages */ private final Map<String, PropertiesPair> messages; /** * Internal constructor, do not use directly. Use {@link MessageResourceFactory} instead. */ - public DefaultMessageResource(List<String> languages, - File customMessageDirectory) { - if(languages != null) { + public DefaultMessageResource(List<String> languages, File customMessageDirectory) { + if (languages != null) { this.languages = Collections.unmodifiableList(languages); } else { this.languages = null; @@ -74,77 +73,76 @@ public class DefaultMessageResource implements MessageResource { // populate different properties messages = new HashMap<String, PropertiesPair>(); + if (languages != null) { for (String language : languages) { PropertiesPair pair = createPropertiesPair(language, customMessageDirectory); messages.put(language, pair); } } + + // The default property pair PropertiesPair pair = createPropertiesPair(null, customMessageDirectory); messages.put(null, pair); } + /** + * Define a pair of default and custom properties. + * + * @author <a href="mailto:d...@directory.apache.org">Apache Directory Project</a> + */ private static class PropertiesPair { + /** The default properties */ public Properties defaultProperties = new Properties(); + /** The custom properties */ public Properties customProperties = new Properties(); } /** * Create Properties pair object. It stores the default and the custom * messages. + * The default file to read will be stored in <em>org/apache/ftpserver/message/FtpStatus.properties</em> + * or <em>org/apache/ftpserver/message/FtpStatus_<lang>.properties</em> if a language is provided. + * The custom file to read will be stored in <em>org/apache/ftpserver/message/FtpStatus.gen</em> + * or <em>org/apache/ftpserver/message/FtpStatus_<lang>.gen</em> if a language is provided. */ private PropertiesPair createPropertiesPair(String lang, File customMessageDirectory) { PropertiesPair pair = new PropertiesPair(); // load default resource String defaultResourceName; + if (lang == null) { defaultResourceName = RESOURCE_PATH + "FtpStatus.properties"; } else { - defaultResourceName = RESOURCE_PATH + "FtpStatus_" + lang - + ".properties"; + defaultResourceName = RESOURCE_PATH + "FtpStatus_" + lang + ".properties"; } - InputStream in = null; - try { - in = getClass().getClassLoader().getResourceAsStream( - defaultResourceName); - if (in != null) { - try { - pair.defaultProperties.load(in); - } catch (IOException e) { - throw new FtpServerConfigurationException( - "Failed to load messages from \"" + defaultResourceName + "\", file not found in classpath"); - } - } else { - throw new FtpServerConfigurationException( - "Failed to load messages from \"" + defaultResourceName + "\", file not found in classpath"); - } - } finally { - IoUtils.close(in); + + try (InputStream in = getClass().getClassLoader().getResourceAsStream(defaultResourceName)) { + pair.defaultProperties.load(in); + } catch (Exception ex){ + throw new FtpServerConfigurationException( + "Failed to load messages from \"" + defaultResourceName + "\", file not found in classpath"); } // load custom resource File resourceFile = null; + if (lang == null) { resourceFile = new File(customMessageDirectory, "FtpStatus.gen"); } else { - resourceFile = new File(customMessageDirectory, "FtpStatus_" + lang - + ".gen"); + resourceFile = new File(customMessageDirectory, "FtpStatus_" + lang + ".gen"); } - in = null; - try { - if (resourceFile.exists()) { - in = new FileInputStream(resourceFile); + + if (resourceFile.exists()) { + try (InputStream in = new FileInputStream(resourceFile)) { pair.customProperties.load(in); + } catch (Exception ex) { + LOG.warn("MessageResourceImpl.createPropertiesPair()", ex); + throw new FtpServerConfigurationException("MessageResourceImpl.createPropertiesPair()", ex); } - } catch (Exception ex) { - LOG.warn("MessageResourceImpl.createPropertiesPair()", ex); - throw new FtpServerConfigurationException( - "MessageResourceImpl.createPropertiesPair()", ex); - } finally { - IoUtils.close(in); } return pair; @@ -152,6 +150,8 @@ public class DefaultMessageResource implements MessageResource { /** * Get all the available languages. + * + * @return The list of available languages */ public List<String> getAvailableLanguages() { if (languages == null) { @@ -163,22 +163,32 @@ public class DefaultMessageResource implements MessageResource { /** * Get the message. If the message not found, it will return null. + * + * @param code The FTP code for which we want the message + * @param subId The FTP command for this code + * @param language The language to use + * @return The message for this code and command */ public String getMessage(int code, String subId, String language) { // find the message key String key = String.valueOf(code); + if (subId != null) { key = key + '.' + subId; } // get language specific value String value = null; + PropertiesPair pair = null; + if (language != null) { language = language.toLowerCase(); pair = messages.get(language); + if (pair != null) { value = pair.customProperties.getProperty(key); + if (value == null) { value = pair.defaultProperties.getProperty(key); } @@ -188,8 +198,10 @@ public class DefaultMessageResource implements MessageResource { // if not available get the default value if (value == null) { pair = messages.get(null); + if (pair != null) { value = pair.customProperties.getProperty(key); + if (value == null) { value = pair.defaultProperties.getProperty(key); } @@ -200,7 +212,10 @@ public class DefaultMessageResource implements MessageResource { } /** - * Get all messages. + * Get all messages for a specific language. + * + * @param language The language we are interested in. If <code>null</code>, we will use the default properties. + * @return The resulting messages */ public Map<String, String> getMessages(String language) { Properties messages = new Properties(); @@ -208,13 +223,16 @@ public class DefaultMessageResource implements MessageResource { // load properties sequentially // (default,custom,default language,custom language) PropertiesPair pair = this.messages.get(null); + if (pair != null) { messages.putAll(pair.defaultProperties); messages.putAll(pair.customProperties); } + if (language != null) { language = language.toLowerCase(); pair = this.messages.get(language); + if (pair != null) { messages.putAll(pair.defaultProperties); messages.putAll(pair.customProperties); @@ -222,6 +240,7 @@ public class DefaultMessageResource implements MessageResource { } Map<String, String> result = new HashMap<String, String>(); + for(Object key : messages.keySet()) { result.put(key.toString(), messages.getProperty(key.toString())); } @@ -233,13 +252,13 @@ public class DefaultMessageResource implements MessageResource { * Dispose component - clear all maps. */ public void dispose() { - Iterator<String> it = messages.keySet().iterator(); - while (it.hasNext()) { - String language = it.next(); + + for (String language : messages.keySet()) { PropertiesPair pair = messages.get(language); pair.customProperties.clear(); pair.defaultProperties.clear(); } + messages.clear(); } } diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/DbUserManagerFactory.java b/core/src/main/java/org/apache/ftpserver/usermanager/DbUserManagerFactory.java index e64823d1..ff068d24 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/DbUserManagerFactory.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/DbUserManagerFactory.java @@ -57,30 +57,37 @@ public class DbUserManagerFactory implements UserManagerFactory { throw new FtpServerConfigurationException( "Required data source not provided"); } + if (insertUserStmt == null) { throw new FtpServerConfigurationException( "Required insert user SQL statement not provided"); } + if (updateUserStmt == null) { throw new FtpServerConfigurationException( "Required update user SQL statement not provided"); } + if (deleteUserStmt == null) { throw new FtpServerConfigurationException( "Required delete user SQL statement not provided"); } + if (selectUserStmt == null) { throw new FtpServerConfigurationException( "Required select user SQL statement not provided"); } + if (selectAllStmt == null) { throw new FtpServerConfigurationException( "Required select all users SQL statement not provided"); } + if (isAdminStmt == null) { throw new FtpServerConfigurationException( "Required is admin user SQL statement not provided"); } + if (authenticateStmt == null) { throw new FtpServerConfigurationException( "Required authenticate user SQL statement not provided"); diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/PropertiesUserManagerFactory.java b/core/src/main/java/org/apache/ftpserver/usermanager/PropertiesUserManagerFactory.java index b3ddc7e6..985efa7e 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/PropertiesUserManagerFactory.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/PropertiesUserManagerFactory.java @@ -31,13 +31,14 @@ import org.apache.ftpserver.usermanager.impl.PropertiesUserManager; * @author <a href="http://mina.apache.org">Apache MINA Project</a> */ public class PropertiesUserManagerFactory implements UserManagerFactory { - + /** The default admin name */ private String adminName = "admin"; private File userDataFile; private URL userDataURL; + /** The default password encryption method*/ private PasswordEncryptor passwordEncryptor = new Md5PasswordEncryptor(); /** @@ -45,17 +46,15 @@ public class PropertiesUserManagerFactory implements UserManagerFactory { */ public UserManager createUserManager() { if (userDataURL != null) { - return new PropertiesUserManager(passwordEncryptor, userDataURL, - adminName); + return new PropertiesUserManager(passwordEncryptor, userDataURL, adminName); } else { - - return new PropertiesUserManager(passwordEncryptor, userDataFile, - adminName); + return new PropertiesUserManager(passwordEncryptor, userDataFile, adminName); } } /** * Get the admin name. + * * @return The admin user name */ public String getAdminName() { @@ -66,8 +65,7 @@ public class PropertiesUserManagerFactory implements UserManagerFactory { * Set the name to use as the administrator of the server. The default value * is "admin". * - * @param adminName - * The administrator user name + * @param adminName The administrator user name */ public void setAdminName(String adminName) { this.adminName = adminName; diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/impl/PropertiesUserManager.java b/core/src/main/java/org/apache/ftpserver/usermanager/impl/PropertiesUserManager.java index 8faf5f3d..a896019e 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/impl/PropertiesUserManager.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/impl/PropertiesUserManager.java @@ -140,8 +140,7 @@ public class PropertiesUserManager extends AbstractUserManager { /** * Internal constructor, do not use directly. Use {@link PropertiesUserManagerFactory} instead. */ - public PropertiesUserManager(PasswordEncryptor passwordEncryptor, - URL userDataPath, String adminName) { + public PropertiesUserManager(PasswordEncryptor passwordEncryptor, URL userDataPath, String adminName) { super(adminName, passwordEncryptor); loadFromUrl(userDataPath); diff --git a/core/src/main/java/org/apache/ftpserver/util/PasswordUtil.java b/core/src/main/java/org/apache/ftpserver/util/PasswordUtil.java index cf65046e..198e8fda 100644 --- a/core/src/main/java/org/apache/ftpserver/util/PasswordUtil.java +++ b/core/src/main/java/org/apache/ftpserver/util/PasswordUtil.java @@ -24,16 +24,11 @@ public class PasswordUtil { * Securely compares two strings up to a maximum number of characters in a way * that obscures the password length from timing attacks * - * @param input - * user input - * @param password - * correct password - * @param loops - * number of characters to compare; must be larger than password - * length; 1024 is a good number + * @param input user input + * @param password correct password + * @param loops number of characters to compare; must be larger than password length; 1024 is a good number * - * @throws IllegalArgumentException - * when the limit is less than the password length + * @throws IllegalArgumentException when the limit is less than the password length * * @return true if the passwords match */ @@ -41,11 +36,13 @@ public class PasswordUtil { if (loops < password.length()) { throw new IllegalArgumentException("loops must be equal or greater than the password length"); } + /* * Set the default result based on the string lengths; if the lengths do not * match then we know that this comparison should always fail. */ int result = (input.length() ^ password.length()); + /* * Cycle through all of the characters up to the limit value * @@ -66,12 +63,9 @@ public class PasswordUtil { * Securely compares two strings forcing the number of loops equal to password length * thereby obscuring the password length based on user input * - * @param input - * user input - * @param password - * correct password - * @throws IllegalArgumentException - * when the limit is less than the password length + * @param input user input + * @param password correct password + * @throws IllegalArgumentException when the limit is less than the password length * * @return true if the passwords match */ @@ -80,11 +74,13 @@ public class PasswordUtil { * the number of compare loops */ int loops = password.length(); + /* * Set the default result based on the string lengths; if the lengths do not * match then we know that this comparison should always fail. */ int result = (input.length() ^ password.length()); + /* * Cycle through all of the characters up to the limit value *