177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair/* 277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Copyright 2008 the original author or authors. 377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * 477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Licensed under the Apache License, Version 2.0 (the "License"); 577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * you may not use this file except in compliance with the License. 677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * You may obtain a copy of the License at 777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * 877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * http://www.apache.org/licenses/LICENSE-2.0 977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * 1077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Unless required by applicable law or agreed to in writing, software 1177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * distributed under the License is distributed on an "AS IS" BASIS, 1277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * See the License for the specific language governing permissions and 1477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * limitations under the License. 1577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */ 1677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairpackage org.mockftpserver.fake.command; 1777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 1877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport org.mockftpserver.core.CommandSyntaxException; 1977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport org.mockftpserver.core.IllegalStateException; 2077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport org.mockftpserver.core.NotLoggedInException; 2177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport org.mockftpserver.core.command.AbstractCommandHandler; 2277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport org.mockftpserver.core.command.Command; 2377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport org.mockftpserver.core.command.ReplyCodes; 2477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport org.mockftpserver.core.session.Session; 2577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport org.mockftpserver.core.session.SessionKeys; 2677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport org.mockftpserver.core.util.Assert; 2777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport org.mockftpserver.fake.ServerConfiguration; 2877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport org.mockftpserver.fake.ServerConfigurationAware; 2977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport org.mockftpserver.fake.UserAccount; 3077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport org.mockftpserver.fake.filesystem.FileSystem; 3177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport org.mockftpserver.fake.filesystem.FileSystemEntry; 3277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport org.mockftpserver.fake.filesystem.FileSystemException; 3377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport org.mockftpserver.fake.filesystem.InvalidFilenameException; 3477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 3577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport java.text.MessageFormat; 3677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport java.util.ArrayList; 3777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport java.util.Collections; 3877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport java.util.List; 3977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport java.util.MissingResourceException; 4077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 4177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair/** 4277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Abstract superclass for CommandHandler classes for the "Fake" server. 4377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * 4477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @author Chris Mair 4577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @version $Revision$ - $Date$ 4677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */ 4777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairpublic abstract class AbstractFakeCommandHandler extends AbstractCommandHandler implements ServerConfigurationAware { 4877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 4977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair protected static final String INTERNAL_ERROR_KEY = "internalError"; 5077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 5177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair private ServerConfiguration serverConfiguration; 5277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 5377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair /** 5477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Reply code sent back when a FileSystemException is caught by the {@link #handleCommand(Command, Session)} 5577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * This defaults to ReplyCodes.EXISTING_FILE_ERROR (550). 5677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */ 5777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair protected int replyCodeForFileSystemException = ReplyCodes.READ_FILE_ERROR; 5877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 5977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair public ServerConfiguration getServerConfiguration() { 6077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair return serverConfiguration; 6177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 6277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 6377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair public void setServerConfiguration(ServerConfiguration serverConfiguration) { 6477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair this.serverConfiguration = serverConfiguration; 6577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 6677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 6777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair /** 6877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Use template method to centralize and ensure common validation 6977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */ 7077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair public void handleCommand(Command command, Session session) { 7177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair Assert.notNull(serverConfiguration, "serverConfiguration"); 7277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair Assert.notNull(command, "command"); 7377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair Assert.notNull(session, "session"); 7477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 7577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair try { 7677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair handle(command, session); 7777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 7877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair catch (CommandSyntaxException e) { 7977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair handleException(command, session, e, ReplyCodes.COMMAND_SYNTAX_ERROR); 8077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 8177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair catch (IllegalStateException e) { 8277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair handleException(command, session, e, ReplyCodes.ILLEGAL_STATE); 8377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 8477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair catch (NotLoggedInException e) { 8577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair handleException(command, session, e, ReplyCodes.NOT_LOGGED_IN); 8677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 8777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair catch (InvalidFilenameException e) { 8877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair handleFileSystemException(command, session, e, ReplyCodes.FILENAME_NOT_VALID, e.getPath()); 8977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 9077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair catch (FileSystemException e) { 9177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair handleFileSystemException(command, session, e, replyCodeForFileSystemException, e.getPath()); 9277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 9377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 9477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 9577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair /** 9677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Convenience method to return the FileSystem stored in the ServerConfiguration 9777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * 9877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @return the FileSystem 9977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */ 10077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair protected FileSystem getFileSystem() { 10177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair return serverConfiguration.getFileSystem(); 10277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 10377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 10477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair /** 10577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Handle the specified command for the session. All checked exceptions are expected to be wrapped or handled 10677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * by the caller. 10777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * 10877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param command - the Command to be handled 10977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param session - the session on which the Command was submitted 11077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */ 11177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair protected abstract void handle(Command command, Session session); 11277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 11377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair // ------------------------------------------------------------------------- 11477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair // Utility methods for subclasses 11577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair // ------------------------------------------------------------------------- 11677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 11777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair /** 11877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Send a reply for this command on the control connection. 11977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * <p/> 12077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * The reply code is designated by the <code>replyCode</code> property, and the reply text 12177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * is retrieved from the <code>replyText</code> ResourceBundle, using the specified messageKey. 12277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * 12377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param session - the Session 12477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param replyCode - the reply code 12577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param messageKey - the resource bundle key for the reply text 12677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @throws AssertionError - if session is null 12777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @see MessageFormat 12877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */ 12977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair protected void sendReply(Session session, int replyCode, String messageKey) { 13077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair sendReply(session, replyCode, messageKey, Collections.EMPTY_LIST); 13177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 13277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 13377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair /** 13477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Send a reply for this command on the control connection. 13577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * <p/> 13677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * The reply code is designated by the <code>replyCode</code> property, and the reply text 13777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * is retrieved from the <code>replyText</code> ResourceBundle, using the specified messageKey. 13877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * 13977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param session - the Session 14077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param replyCode - the reply code 14177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param messageKey - the resource bundle key for the reply text 14277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param args - the optional message arguments; defaults to [] 14377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @throws AssertionError - if session is null 14477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @see MessageFormat 14577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */ 14677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair protected void sendReply(Session session, int replyCode, String messageKey, List args) { 14777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair Assert.notNull(session, "session"); 14877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair assertValidReplyCode(replyCode); 14977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 15077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair String text = getTextForKey(messageKey); 15177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair String replyText = (args != null && !args.isEmpty()) ? MessageFormat.format(text, args.toArray()) : text; 15277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 15377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair String replyTextToLog = (replyText == null) ? "" : " " + replyText; 15477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair String argsToLog = (args != null && !args.isEmpty()) ? (" args=" + args) : ""; 15577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair LOG.info("Sending reply [" + replyCode + replyTextToLog + "]" + argsToLog); 15677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair session.sendReply(replyCode, replyText); 15777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 15877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 15977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair /** 16077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Send a reply for this command on the control connection. 16177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * <p/> 16277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * The reply code is designated by the <code>replyCode</code> property, and the reply text 16377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * is retrieved from the <code>replyText</code> ResourceBundle, using the reply code as the key. 16477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * 16577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param session - the Session 16677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param replyCode - the reply code 16777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @throws AssertionError - if session is null 16877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @see MessageFormat 16977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */ 17077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair protected void sendReply(Session session, int replyCode) { 17177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair sendReply(session, replyCode, Collections.EMPTY_LIST); 17277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 17377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 17477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair /** 17577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Send a reply for this command on the control connection. 17677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * <p/> 17777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * The reply code is designated by the <code>replyCode</code> property, and the reply text 17877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * is retrieved from the <code>replyText</code> ResourceBundle, using the reply code as the key. 17977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * 18077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param session - the Session 18177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param replyCode - the reply code 18277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param args - the optional message arguments; defaults to [] 18377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @throws AssertionError - if session is null 18477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @see MessageFormat 18577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */ 18677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair protected void sendReply(Session session, int replyCode, List args) { 18777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair sendReply(session, replyCode, Integer.toString(replyCode), args); 18877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 18977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 19077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair /** 19177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Handle the exception caught during handleCommand() 19277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * 19377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param command - the Command 19477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param session - the Session 19577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param exception - the caught exception 19677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param replyCode - the reply code that should be sent back 19777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */ 19877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair private void handleException(Command command, Session session, Throwable exception, int replyCode) { 19977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair LOG.warn("Error handling command: " + command + "; " + exception, exception); 20077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair sendReply(session, replyCode); 20177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 20277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 20377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair /** 20477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Handle the exception caught during handleCommand() 20577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * 20677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param command - the Command 20777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param session - the Session 20877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param exception - the caught exception 20977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param replyCode - the reply code that should be sent back 21077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param arg - the arg for the reply (message) 21177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */ 21277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair private void handleFileSystemException(Command command, Session session, FileSystemException exception, int replyCode, Object arg) { 21377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair LOG.warn("Error handling command: " + command + "; " + exception, exception); 21477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair sendReply(session, replyCode, exception.getMessageKey(), Collections.singletonList(arg)); 21577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 21677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 21777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair /** 21877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Return the value of the named attribute within the session. 21977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * 22077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param session - the Session 22177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param name - the name of the session attribute to retrieve 22277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @return the value of the named session attribute 22377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @throws IllegalStateException - if the Session does not contain the named attribute 22477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */ 22577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair protected Object getRequiredSessionAttribute(Session session, String name) { 22677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair Object value = session.getAttribute(name); 22777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair if (value == null) { 22877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair throw new IllegalStateException("Session missing required attribute [" + name + "]"); 22977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 23077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair return value; 23177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 23277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 23377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair /** 23477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Verify that the current user (if any) has already logged in successfully. 23577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * 23677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param session - the Session 23777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */ 23877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair protected void verifyLoggedIn(Session session) { 23977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair if (getUserAccount(session) == null) { 24077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair throw new NotLoggedInException("User has not logged in"); 24177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 24277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 24377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 24477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair /** 24577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param session - the Session 24677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @return the UserAccount stored in the specified session; may be null 24777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */ 24877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair protected UserAccount getUserAccount(Session session) { 24977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair return (UserAccount) session.getAttribute(SessionKeys.USER_ACCOUNT); 25077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 25177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 25277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair /** 25377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Verify that the specified condition related to the file system is true, 25477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * otherwise throw a FileSystemException. 25577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * 25677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param condition - the condition that must be true 25777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param path - the path involved in the operation; this will be included in the 25877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * error message if the condition is not true. 25977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param messageKey - the message key for the exception message 26077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @throws FileSystemException - if the condition is not true 26177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */ 26277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair protected void verifyFileSystemCondition(boolean condition, String path, String messageKey) { 26377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair if (!condition) { 26477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair throw new FileSystemException(path, messageKey); 26577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 26677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 26777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 26877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair /** 26977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Verify that the current user has execute permission to the specified path 27077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * 27177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param session - the Session 27277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param path - the file system path 27377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @throws FileSystemException - if the condition is not true 27477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */ 27577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair protected void verifyExecutePermission(Session session, String path) { 27677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair UserAccount userAccount = getUserAccount(session); 27777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair FileSystemEntry entry = getFileSystem().getEntry(path); 27877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair verifyFileSystemCondition(userAccount.canExecute(entry), path, "filesystem.cannotExecute"); 27977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 28077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 28177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair /** 28277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Verify that the current user has write permission to the specified path 28377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * 28477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param session - the Session 28577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param path - the file system path 28677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @throws FileSystemException - if the condition is not true 28777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */ 28877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair protected void verifyWritePermission(Session session, String path) { 28977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair UserAccount userAccount = getUserAccount(session); 29077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair FileSystemEntry entry = getFileSystem().getEntry(path); 29177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair verifyFileSystemCondition(userAccount.canWrite(entry), path, "filesystem.cannotWrite"); 29277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 29377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 29477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair /** 29577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Verify that the current user has read permission to the specified path 29677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * 29777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param session - the Session 29877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param path - the file system path 29977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @throws FileSystemException - if the condition is not true 30077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */ 30177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair protected void verifyReadPermission(Session session, String path) { 30277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair UserAccount userAccount = getUserAccount(session); 30377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair FileSystemEntry entry = getFileSystem().getEntry(path); 30477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair verifyFileSystemCondition(userAccount.canRead(entry), path, "filesystem.cannotRead"); 30577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 30677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 30777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair /** 30877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Return the full, absolute path for the specified abstract pathname. 30977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * If path is null, return the current directory (stored in the session). If 31077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * path represents an absolute path, then return path as is. Otherwise, path 31177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * is relative, so assemble the full path from the current directory 31277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * and the specified relative path. 31377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * 31477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param session - the Session 31577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param path - the abstract pathname; may be null 31677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @return the resulting full, absolute path 31777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */ 31877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair protected String getRealPath(Session session, String path) { 31977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair String currentDirectory = (String) session.getAttribute(SessionKeys.CURRENT_DIRECTORY); 32077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair if (path == null) { 32177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair return currentDirectory; 32277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 32377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair if (getFileSystem().isAbsolute(path)) { 32477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair return path; 32577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 32677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair return getFileSystem().path(currentDirectory, path); 32777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 32877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 32977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair /** 33077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Return the end-of-line character(s) used when building multi-line responses 33177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * 33277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @return "\r\n" 33377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */ 33477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair protected String endOfLine() { 33577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair return "\r\n"; 33677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 33777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 33877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair private String getTextForKey(String key) { 33977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair String msgKey = (key != null) ? key : INTERNAL_ERROR_KEY; 34077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair try { 34177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair return getReplyTextBundle().getString(msgKey); 34277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 34377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair catch (MissingResourceException e) { 34477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair // No reply text is mapped for the specified key 34577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair LOG.warn("No reply text defined for key [" + msgKey + "]"); 34677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair return null; 34777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 34877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 34977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 35077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair // ------------------------------------------------------------------------- 35177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair // Login Support (used by USER and PASS commands) 35277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair // ------------------------------------------------------------------------- 35377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 35477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair /** 35577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Validate the UserAccount for the specified username. If valid, return true. If the UserAccount does 35677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * not exist or is invalid, log an error message, send back a reply code of 530 with an appropriate 35777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * error message, and return false. A UserAccount is considered invalid if the homeDirectory property 35877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * is not set or is set to a non-existent directory. 35977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * 36077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param username - the username 36177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param session - the session; used to send back an error reply if necessary 36277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @return true only if the UserAccount for the named user is valid 36377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */ 36477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair protected boolean validateUserAccount(String username, Session session) { 36577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair UserAccount userAccount = serverConfiguration.getUserAccount(username); 36677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair if (userAccount == null || !userAccount.isValid()) { 36777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair LOG.error("UserAccount missing or not valid for username [" + username + "]: " + userAccount); 36877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair sendReply(session, ReplyCodes.USER_ACCOUNT_NOT_VALID, "login.userAccountNotValid", list(username)); 36977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair return false; 37077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 37177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 37277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair String home = userAccount.getHomeDirectory(); 37377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair if (!getFileSystem().isDirectory(home)) { 37477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair LOG.error("Home directory configured for username [" + username + "] is not valid: " + home); 37577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair sendReply(session, ReplyCodes.USER_ACCOUNT_NOT_VALID, "login.homeDirectoryNotValid", list(username, home)); 37677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair return false; 37777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 37877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 37977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair return true; 38077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 38177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 38277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair /** 38377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Log in the specified user for the current session. Send back a reply of 230 with a message indicated 38477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * by the replyMessageKey and set the UserAccount and current directory (homeDirectory) in the session. 38577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * 38677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param userAccount - the userAccount for the user to be logged in 38777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param session - the session 38877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param replyCode - the reply code to send 38977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param replyMessageKey - the message key for the reply text 39077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */ 39177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair protected void login(UserAccount userAccount, Session session, int replyCode, String replyMessageKey) { 39277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair sendReply(session, replyCode, replyMessageKey); 39377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair session.setAttribute(SessionKeys.USER_ACCOUNT, userAccount); 39477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair session.setAttribute(SessionKeys.CURRENT_DIRECTORY, userAccount.getHomeDirectory()); 39577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 39677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 39777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair /** 39877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Convenience method to return a List with the specified single item 39977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * 40077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param item - the single item in the returned List 40177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @return a new List with that single item 40277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */ 40377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair protected List list(Object item) { 40477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair return Collections.singletonList(item); 40577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 40677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 40777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair /** 40877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Convenience method to return a List with the specified two items 40977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * 41077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param item1 - the first item in the returned List 41177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param item2 - the second item in the returned List 41277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @return a new List with the specified items 41377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */ 41477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair protected List list(Object item1, Object item2) { 41577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair List list = new ArrayList(2); 41677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair list.add(item1); 41777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair list.add(item2); 41877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair return list; 41977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 42077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 42177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair /** 42277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Return true if the specified string is null or empty 42377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * 42477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param string - the String to check; may be null 42577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @return true only if the specified String is null or empyt 42677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */ 42777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair protected boolean notNullOrEmpty(String string) { 42877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair return string != null && string.length() > 0; 42977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 43077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 43177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair /** 43277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Return the string unless it is null or empty, in which case return the defaultString. 43377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * 43477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param string - the String to check; may be null 43577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @param defaultString - the value to return if string is null or empty 43677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @return string if not null and not empty; otherwise return defaultString 43777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */ 43877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair protected String defaultIfNullOrEmpty(String string, String defaultString) { 43977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair return (notNullOrEmpty(string) ? string : defaultString); 44077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair } 44177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair 44277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair}