1fba2635c088b01af59300e8a02611bb788ee3bffchrismair/*
2fba2635c088b01af59300e8a02611bb788ee3bffchrismair * Copyright 2008 the original author or authors.
3fba2635c088b01af59300e8a02611bb788ee3bffchrismair *
4fba2635c088b01af59300e8a02611bb788ee3bffchrismair * Licensed under the Apache License, Version 2.0 (the "License");
5fba2635c088b01af59300e8a02611bb788ee3bffchrismair * you may not use this file except in compliance with the License.
6fba2635c088b01af59300e8a02611bb788ee3bffchrismair * You may obtain a copy of the License at
7fba2635c088b01af59300e8a02611bb788ee3bffchrismair *
8fba2635c088b01af59300e8a02611bb788ee3bffchrismair *      http://www.apache.org/licenses/LICENSE-2.0
9fba2635c088b01af59300e8a02611bb788ee3bffchrismair *
10fba2635c088b01af59300e8a02611bb788ee3bffchrismair * Unless required by applicable law or agreed to in writing, software
11fba2635c088b01af59300e8a02611bb788ee3bffchrismair * distributed under the License is distributed on an "AS IS" BASIS,
12fba2635c088b01af59300e8a02611bb788ee3bffchrismair * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fba2635c088b01af59300e8a02611bb788ee3bffchrismair * See the License for the specific language governing permissions and
14fba2635c088b01af59300e8a02611bb788ee3bffchrismair * limitations under the License.
15fba2635c088b01af59300e8a02611bb788ee3bffchrismair */
16fba2635c088b01af59300e8a02611bb788ee3bffchrismairpackage org.mockftpserver.fake;
17fba2635c088b01af59300e8a02611bb788ee3bffchrismair
18fba2635c088b01af59300e8a02611bb788ee3bffchrismairimport org.mockftpserver.core.command.CommandHandler;
19fba2635c088b01af59300e8a02611bb788ee3bffchrismairimport org.mockftpserver.core.command.CommandNames;
20fba2635c088b01af59300e8a02611bb788ee3bffchrismairimport org.mockftpserver.core.command.ConnectCommandHandler;
21fba2635c088b01af59300e8a02611bb788ee3bffchrismairimport org.mockftpserver.core.command.ReplyTextBundleUtil;
22fba2635c088b01af59300e8a02611bb788ee3bffchrismairimport org.mockftpserver.core.command.UnsupportedCommandHandler;
23fba2635c088b01af59300e8a02611bb788ee3bffchrismairimport org.mockftpserver.core.server.AbstractFtpServer;
24fba2635c088b01af59300e8a02611bb788ee3bffchrismairimport org.mockftpserver.fake.command.*;
25fba2635c088b01af59300e8a02611bb788ee3bffchrismairimport org.mockftpserver.fake.filesystem.FileSystem;
26fba2635c088b01af59300e8a02611bb788ee3bffchrismair
27fba2635c088b01af59300e8a02611bb788ee3bffchrismairimport java.util.HashMap;
28fba2635c088b01af59300e8a02611bb788ee3bffchrismairimport java.util.List;
29fba2635c088b01af59300e8a02611bb788ee3bffchrismairimport java.util.Map;
30fba2635c088b01af59300e8a02611bb788ee3bffchrismair
31fba2635c088b01af59300e8a02611bb788ee3bffchrismair/**
32fba2635c088b01af59300e8a02611bb788ee3bffchrismair * <b>FakeFtpServer</b> is the top-level class for a "fake" implementation of an FTP Server,
33fba2635c088b01af59300e8a02611bb788ee3bffchrismair * suitable for testing FTP client code or standing in for a live FTP server.
34fba2635c088b01af59300e8a02611bb788ee3bffchrismair * <p/>
35fba2635c088b01af59300e8a02611bb788ee3bffchrismair * <b>FakeFtpServer</b> provides a high-level abstraction for an FTP Server and is suitable
36fba2635c088b01af59300e8a02611bb788ee3bffchrismair * for most testing and simulation scenarios. You define a filesystem (internal, in-memory) containing
37fba2635c088b01af59300e8a02611bb788ee3bffchrismair * an arbitrary set of files and directories. These files and directories can (optionally) have
38fba2635c088b01af59300e8a02611bb788ee3bffchrismair * associated access permissions. You also configure a set of one or more user accounts that
39fba2635c088b01af59300e8a02611bb788ee3bffchrismair * control which users can login to the FTP server, and their home (default) directories. The
40fba2635c088b01af59300e8a02611bb788ee3bffchrismair * user account is also used when assigning file and directory ownership for new files.
41fba2635c088b01af59300e8a02611bb788ee3bffchrismair * <p> <b>FakeFtpServer</b> processes FTP client requests and responds with reply codes and
42fba2635c088b01af59300e8a02611bb788ee3bffchrismair * reply messages consistent with its configuration and the contents of its internal filesystem,
43fba2635c088b01af59300e8a02611bb788ee3bffchrismair * including file and directory permissions, if they have been configured.
44fba2635c088b01af59300e8a02611bb788ee3bffchrismair * <p/>
45fba2635c088b01af59300e8a02611bb788ee3bffchrismair * <b>FakeFtpServer</b> can be fully configured programmatically or within the
46fba2635c088b01af59300e8a02611bb788ee3bffchrismair * <a href="http://www.springframework.org/">Spring Framework</a> or other dependency-injection container.
47fba2635c088b01af59300e8a02611bb788ee3bffchrismair * <p/>
48fba2635c088b01af59300e8a02611bb788ee3bffchrismair * In general the steps for setting up and starting the <b>FakeFtpServer</b> are:
49fba2635c088b01af59300e8a02611bb788ee3bffchrismair * <ol>
50fba2635c088b01af59300e8a02611bb788ee3bffchrismair * <li>Create a new <b>FakeFtpServer</b> instance, and optionally set the server control port.</li>
51fba2635c088b01af59300e8a02611bb788ee3bffchrismair * <li>Create and configure a <b>FileSystem</b>, and attach to the <b>FakeFtpServer</b> instance.</li>
52fba2635c088b01af59300e8a02611bb788ee3bffchrismair * <li>Create and configure one or more <b>UserAccount</b> objects and attach to the <b>FakeFtpServer</b> instance.</li>
53fba2635c088b01af59300e8a02611bb788ee3bffchrismair * <li>Start the <b>FakeFtpServer</b> instance.</li>
54fba2635c088b01af59300e8a02611bb788ee3bffchrismair * </ol>
55fba2635c088b01af59300e8a02611bb788ee3bffchrismair * <h4>Example Code</h4>
56fba2635c088b01af59300e8a02611bb788ee3bffchrismair * <pre><code>
57fba2635c088b01af59300e8a02611bb788ee3bffchrismair * FakeFtpServer fakeFtpServer = new FakeFtpServer();
58fba2635c088b01af59300e8a02611bb788ee3bffchrismair *
59fba2635c088b01af59300e8a02611bb788ee3bffchrismair * FileSystem fileSystem = new WindowsFakeFileSystem();
60fba2635c088b01af59300e8a02611bb788ee3bffchrismair * fileSystem.add(new DirectoryEntry("c:\\"));
61fba2635c088b01af59300e8a02611bb788ee3bffchrismair * fileSystem.add(new DirectoryEntry("c:\\data"));
62fba2635c088b01af59300e8a02611bb788ee3bffchrismair * fileSystem.add(new FileEntry("c:\\data\\file1.txt", "abcdef 1234567890"));
63fba2635c088b01af59300e8a02611bb788ee3bffchrismair * fileSystem.add(new FileEntry("c:\\data\\run.exe"));
64fba2635c088b01af59300e8a02611bb788ee3bffchrismair * fakeFtpServer.setFileSystem(fileSystem);
65fba2635c088b01af59300e8a02611bb788ee3bffchrismair *
66fba2635c088b01af59300e8a02611bb788ee3bffchrismair * // Create UserAccount with username, password, home-directory
67fba2635c088b01af59300e8a02611bb788ee3bffchrismair * UserAccount userAccount = new UserAccount("joe", "joe123", "c:\\");
68fba2635c088b01af59300e8a02611bb788ee3bffchrismair * fakeFtpServer.addUserAccounts(userAccount);
69fba2635c088b01af59300e8a02611bb788ee3bffchrismair *
70fba2635c088b01af59300e8a02611bb788ee3bffchrismair * fakeFtpServer.start();
71fba2635c088b01af59300e8a02611bb788ee3bffchrismair * </code></pre>
72fba2635c088b01af59300e8a02611bb788ee3bffchrismair *
73fba2635c088b01af59300e8a02611bb788ee3bffchrismair * <h4>Example Code with Permissions</h4>
74fba2635c088b01af59300e8a02611bb788ee3bffchrismair * You can optionally set the permissions and owner/group for each file and directory, as in the following example.
75fba2635c088b01af59300e8a02611bb788ee3bffchrismair * <pre><code>
76fba2635c088b01af59300e8a02611bb788ee3bffchrismair * FileSystem fileSystem = new UnixFakeFileSystem();
77fba2635c088b01af59300e8a02611bb788ee3bffchrismair * DirectoryEntry directoryEntry1 = new DirectoryEntry("/");
78fba2635c088b01af59300e8a02611bb788ee3bffchrismair * directoryEntry1.setPermissions(new Permissions("rwxrwx---"));
79fba2635c088b01af59300e8a02611bb788ee3bffchrismair * directoryEntry1.setOwner("joe");
80fba2635c088b01af59300e8a02611bb788ee3bffchrismair * directoryEntry1.setGroup("dev");
81fba2635c088b01af59300e8a02611bb788ee3bffchrismair *
82fba2635c088b01af59300e8a02611bb788ee3bffchrismair * DirectoryEntry directoryEntry2 = new DirectoryEntry("/data");
83fba2635c088b01af59300e8a02611bb788ee3bffchrismair * directoryEntry2.setPermissions(Permissions.ALL);
84fba2635c088b01af59300e8a02611bb788ee3bffchrismair * directoryEntry2.setOwner("joe");
85fba2635c088b01af59300e8a02611bb788ee3bffchrismair * directoryEntry2.setGroup("dev");
86fba2635c088b01af59300e8a02611bb788ee3bffchrismair *
87fba2635c088b01af59300e8a02611bb788ee3bffchrismair * FileEntry fileEntry1 = new FileEntry("/data/file1.txt", "abcdef 1234567890");
88fba2635c088b01af59300e8a02611bb788ee3bffchrismair * fileEntry1.setPermissionsFromString("rw-rw-rw-");
89fba2635c088b01af59300e8a02611bb788ee3bffchrismair * fileEntry1.setOwner("joe");
90fba2635c088b01af59300e8a02611bb788ee3bffchrismair * fileEntry1.setGroup("dev");
91fba2635c088b01af59300e8a02611bb788ee3bffchrismair *
92fba2635c088b01af59300e8a02611bb788ee3bffchrismair * FileEntry fileEntry2 = new FileEntry("/data/run.exe");
93fba2635c088b01af59300e8a02611bb788ee3bffchrismair * fileEntry2.setPermissionsFromString("rwxrwx---");
94fba2635c088b01af59300e8a02611bb788ee3bffchrismair * fileEntry2.setOwner("mary");
95fba2635c088b01af59300e8a02611bb788ee3bffchrismair * fileEntry2.setGroup("dev");
96fba2635c088b01af59300e8a02611bb788ee3bffchrismair *
97fba2635c088b01af59300e8a02611bb788ee3bffchrismair * fileSystem.add(directoryEntry1);
98fba2635c088b01af59300e8a02611bb788ee3bffchrismair * fileSystem.add(directoryEntry2);
99fba2635c088b01af59300e8a02611bb788ee3bffchrismair * fileSystem.add(fileEntry1);
100fba2635c088b01af59300e8a02611bb788ee3bffchrismair * fileSystem.add(fileEntry2);
101fba2635c088b01af59300e8a02611bb788ee3bffchrismair *
102fba2635c088b01af59300e8a02611bb788ee3bffchrismair * FakeFtpServer fakeFtpServer = new FakeFtpServer();
103fba2635c088b01af59300e8a02611bb788ee3bffchrismair * fakeFtpServer.setFileSystem(fileSystem);
104fba2635c088b01af59300e8a02611bb788ee3bffchrismair *
105fba2635c088b01af59300e8a02611bb788ee3bffchrismair * // Create UserAccount with username, password, home-directory
106fba2635c088b01af59300e8a02611bb788ee3bffchrismair * UserAccount userAccount = new UserAccount("joe", "joe123", "/");
107fba2635c088b01af59300e8a02611bb788ee3bffchrismair * fakeFtpServer.addUserAccounts(userAccount);
108fba2635c088b01af59300e8a02611bb788ee3bffchrismair *
109fba2635c088b01af59300e8a02611bb788ee3bffchrismair * fakeFtpServer.start();
110fba2635c088b01af59300e8a02611bb788ee3bffchrismair * </code></pre>
111fba2635c088b01af59300e8a02611bb788ee3bffchrismair *
112fba2635c088b01af59300e8a02611bb788ee3bffchrismair * <h4>FTP Server Control Port</h4>
113fba2635c088b01af59300e8a02611bb788ee3bffchrismair * By default, <b>FakeFtpServer</b> binds to the server control port of 21. You can use a different server control
114fba2635c088b01af59300e8a02611bb788ee3bffchrismair * port by setting the <code>serverControlPort</code> property. If you specify a value of <code>0</code>,
115fba2635c088b01af59300e8a02611bb788ee3bffchrismair * then a free port number will be chosen automatically; call <code>getServerControlPort()</code> AFTER
116fba2635c088b01af59300e8a02611bb788ee3bffchrismair * <code>start()</code> has been called to determine the actual port number being used. Using a non-default
117fba2635c088b01af59300e8a02611bb788ee3bffchrismair * port number is usually necessary when running on Unix or some other system where that port number is
118fba2635c088b01af59300e8a02611bb788ee3bffchrismair * already in use or cannot be bound from a user process.
119fba2635c088b01af59300e8a02611bb788ee3bffchrismair *
120fba2635c088b01af59300e8a02611bb788ee3bffchrismair * <h4>Other Configuration</h4>
121fba2635c088b01af59300e8a02611bb788ee3bffchrismair * The <code>systemName</code> property specifies the value returned by the <code>SYST</code>
122fba2635c088b01af59300e8a02611bb788ee3bffchrismair * command. Note that this is typically used by an FTP client to determine how to parse
123fba2635c088b01af59300e8a02611bb788ee3bffchrismair * system-dependent reply text, such as directory listings. This value defaults to <code>"WINDOWS"</code>.
124fba2635c088b01af59300e8a02611bb788ee3bffchrismair * <p/>
125fba2635c088b01af59300e8a02611bb788ee3bffchrismair * The <code>helpText</code> property specifies a <i>Map</i> of help text replies sent by the
126fba2635c088b01af59300e8a02611bb788ee3bffchrismair * <code>HELP</code> command. The keys in that <i>Map</i> correspond to the command names passed as
127fba2635c088b01af59300e8a02611bb788ee3bffchrismair * parameters to the <code>HELP</code> command. An entry with the key of an empty string ("") indicates the
128fba2635c088b01af59300e8a02611bb788ee3bffchrismair * text used as the default help text when no command name parameter is specified for the <code>HELP</code> command.
129fba2635c088b01af59300e8a02611bb788ee3bffchrismair *
130fba2635c088b01af59300e8a02611bb788ee3bffchrismair * <h4>FTP Command Reply Text ResourceBundle</h4>
131fba2635c088b01af59300e8a02611bb788ee3bffchrismair * The default text asociated with each FTP command reply code is contained within the
132fba2635c088b01af59300e8a02611bb788ee3bffchrismair * "ReplyText.properties" ResourceBundle file. You can customize these messages by providing a
133fba2635c088b01af59300e8a02611bb788ee3bffchrismair * locale-specific ResourceBundle file on the CLASSPATH, according to the normal lookup rules of
134fba2635c088b01af59300e8a02611bb788ee3bffchrismair * the ResourceBundle class (e.g., "ReplyText_de.properties"). Alternatively, you can
135fba2635c088b01af59300e8a02611bb788ee3bffchrismair * completely replace the ResourceBundle file by calling the calling the
136fba2635c088b01af59300e8a02611bb788ee3bffchrismair * {@link #setReplyTextBaseName(String)} method.
137fba2635c088b01af59300e8a02611bb788ee3bffchrismair *
138fba2635c088b01af59300e8a02611bb788ee3bffchrismair * @author Chris Mair
139fba2635c088b01af59300e8a02611bb788ee3bffchrismair * @version $Revision$ - $Date$
140fba2635c088b01af59300e8a02611bb788ee3bffchrismair */
141fba2635c088b01af59300e8a02611bb788ee3bffchrismairpublic class FakeFtpServer extends AbstractFtpServer implements ServerConfiguration {
142fba2635c088b01af59300e8a02611bb788ee3bffchrismair
143fba2635c088b01af59300e8a02611bb788ee3bffchrismair    private FileSystem fileSystem;
144fba2635c088b01af59300e8a02611bb788ee3bffchrismair    private String systemName = "WINDOWS";
145fba2635c088b01af59300e8a02611bb788ee3bffchrismair    private String systemStatus = "Connected";
146fba2635c088b01af59300e8a02611bb788ee3bffchrismair    private Map helpText = new HashMap();
147fba2635c088b01af59300e8a02611bb788ee3bffchrismair    private Map userAccounts = new HashMap();
148fba2635c088b01af59300e8a02611bb788ee3bffchrismair
149fba2635c088b01af59300e8a02611bb788ee3bffchrismair    public FileSystem getFileSystem() {
150fba2635c088b01af59300e8a02611bb788ee3bffchrismair        return fileSystem;
151fba2635c088b01af59300e8a02611bb788ee3bffchrismair    }
152fba2635c088b01af59300e8a02611bb788ee3bffchrismair
153fba2635c088b01af59300e8a02611bb788ee3bffchrismair    public void setFileSystem(FileSystem fileSystem) {
154fba2635c088b01af59300e8a02611bb788ee3bffchrismair        this.fileSystem = fileSystem;
155fba2635c088b01af59300e8a02611bb788ee3bffchrismair    }
156fba2635c088b01af59300e8a02611bb788ee3bffchrismair
157fba2635c088b01af59300e8a02611bb788ee3bffchrismair    public String getSystemName() {
158fba2635c088b01af59300e8a02611bb788ee3bffchrismair        return systemName;
159fba2635c088b01af59300e8a02611bb788ee3bffchrismair    }
160fba2635c088b01af59300e8a02611bb788ee3bffchrismair
161fba2635c088b01af59300e8a02611bb788ee3bffchrismair    public void setSystemName(String systemName) {
162fba2635c088b01af59300e8a02611bb788ee3bffchrismair        this.systemName = systemName;
163fba2635c088b01af59300e8a02611bb788ee3bffchrismair    }
164fba2635c088b01af59300e8a02611bb788ee3bffchrismair
165fba2635c088b01af59300e8a02611bb788ee3bffchrismair    public Map getHelpText() {
166fba2635c088b01af59300e8a02611bb788ee3bffchrismair        return helpText;
167fba2635c088b01af59300e8a02611bb788ee3bffchrismair    }
168fba2635c088b01af59300e8a02611bb788ee3bffchrismair
169fba2635c088b01af59300e8a02611bb788ee3bffchrismair    public void setHelpText(Map helpText) {
170fba2635c088b01af59300e8a02611bb788ee3bffchrismair        this.helpText = helpText;
171fba2635c088b01af59300e8a02611bb788ee3bffchrismair    }
172fba2635c088b01af59300e8a02611bb788ee3bffchrismair
173fba2635c088b01af59300e8a02611bb788ee3bffchrismair    public FakeFtpServer() {
174fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.ACCT, new AcctCommandHandler());
175fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.ABOR, new AborCommandHandler());
176fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.ALLO, new AlloCommandHandler());
177fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.APPE, new AppeCommandHandler());
178fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.CWD, new CwdCommandHandler());
179fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.CDUP, new CdupCommandHandler());
180fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.DELE, new DeleCommandHandler());
181fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.EPRT, new EprtCommandHandler());
182fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.EPSV, new EpsvCommandHandler());
183fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.HELP, new HelpCommandHandler());
184fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.LIST, new ListCommandHandler());
185fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.MKD, new MkdCommandHandler());
186fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.MODE, new ModeCommandHandler());
187fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.NLST, new NlstCommandHandler());
188fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.NOOP, new NoopCommandHandler());
189fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.PASS, new PassCommandHandler());
190fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.PASV, new PasvCommandHandler());
191fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.PWD, new PwdCommandHandler());
192fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.PORT, new PortCommandHandler());
193fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.QUIT, new QuitCommandHandler());
194fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.REIN, new ReinCommandHandler());
195fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.REST, new RestCommandHandler());
196fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.RETR, new RetrCommandHandler());
197fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.RMD, new RmdCommandHandler());
198fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.RNFR, new RnfrCommandHandler());
199fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.RNTO, new RntoCommandHandler());
200fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.SITE, new SiteCommandHandler());
201fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.SMNT, new SmntCommandHandler());
202fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.STAT, new StatCommandHandler());
203fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.STOR, new StorCommandHandler());
204fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.STOU, new StouCommandHandler());
205fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.STRU, new StruCommandHandler());
206fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.SYST, new SystCommandHandler());
207fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.TYPE, new TypeCommandHandler());
208fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.USER, new UserCommandHandler());
209fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.XPWD, new PwdCommandHandler());
210fba2635c088b01af59300e8a02611bb788ee3bffchrismair
211fba2635c088b01af59300e8a02611bb788ee3bffchrismair        // "Special" Command Handlers
212fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.CONNECT, new ConnectCommandHandler());
213fba2635c088b01af59300e8a02611bb788ee3bffchrismair        setCommandHandler(CommandNames.UNSUPPORTED, new UnsupportedCommandHandler());
214fba2635c088b01af59300e8a02611bb788ee3bffchrismair    }
215fba2635c088b01af59300e8a02611bb788ee3bffchrismair
216fba2635c088b01af59300e8a02611bb788ee3bffchrismair    /**
217fba2635c088b01af59300e8a02611bb788ee3bffchrismair     * Initialize a CommandHandler that has been registered to this server.
218fba2635c088b01af59300e8a02611bb788ee3bffchrismair     *
219fba2635c088b01af59300e8a02611bb788ee3bffchrismair     * If the CommandHandler implements the <code>ServerConfigurationAware</code> interface, then set its
220fba2635c088b01af59300e8a02611bb788ee3bffchrismair     * <code>ServerConfiguration</code> property to <code>this</code>.
221fba2635c088b01af59300e8a02611bb788ee3bffchrismair     *
222fba2635c088b01af59300e8a02611bb788ee3bffchrismair     * If the CommandHandler implements the <code>ReplyTextBundleAware</code> interface, then set its
223fba2635c088b01af59300e8a02611bb788ee3bffchrismair     * <code>replyTextBundle</code> property using the reply text bundle for this server.
224fba2635c088b01af59300e8a02611bb788ee3bffchrismair     *
225fba2635c088b01af59300e8a02611bb788ee3bffchrismair     * @param commandHandler - the CommandHandler to initialize
226fba2635c088b01af59300e8a02611bb788ee3bffchrismair     */
227fba2635c088b01af59300e8a02611bb788ee3bffchrismair    protected void initializeCommandHandler(CommandHandler commandHandler) {
228fba2635c088b01af59300e8a02611bb788ee3bffchrismair        if (commandHandler instanceof ServerConfigurationAware) {
229fba2635c088b01af59300e8a02611bb788ee3bffchrismair            ServerConfigurationAware sca = (ServerConfigurationAware) commandHandler;
230fba2635c088b01af59300e8a02611bb788ee3bffchrismair            sca.setServerConfiguration(this);
231fba2635c088b01af59300e8a02611bb788ee3bffchrismair        }
232fba2635c088b01af59300e8a02611bb788ee3bffchrismair
233fba2635c088b01af59300e8a02611bb788ee3bffchrismair        ReplyTextBundleUtil.setReplyTextBundleIfAppropriate(commandHandler, getReplyTextBundle());
234fba2635c088b01af59300e8a02611bb788ee3bffchrismair    }
235fba2635c088b01af59300e8a02611bb788ee3bffchrismair
236fba2635c088b01af59300e8a02611bb788ee3bffchrismair    /**
237fba2635c088b01af59300e8a02611bb788ee3bffchrismair     * @return the {@link UserAccount}        configured for this server for the specified user name
238fba2635c088b01af59300e8a02611bb788ee3bffchrismair     */
239fba2635c088b01af59300e8a02611bb788ee3bffchrismair    public UserAccount getUserAccount(String username) {
240fba2635c088b01af59300e8a02611bb788ee3bffchrismair        return (UserAccount) userAccounts.get(username);
241fba2635c088b01af59300e8a02611bb788ee3bffchrismair    }
242fba2635c088b01af59300e8a02611bb788ee3bffchrismair
243fba2635c088b01af59300e8a02611bb788ee3bffchrismair    /**
244fba2635c088b01af59300e8a02611bb788ee3bffchrismair     * Return the help text for a command or the default help text if no command name is specified
245fba2635c088b01af59300e8a02611bb788ee3bffchrismair     *
246fba2635c088b01af59300e8a02611bb788ee3bffchrismair     * @param name - the command name; may be empty or null to indicate  a request for the default help text
247fba2635c088b01af59300e8a02611bb788ee3bffchrismair     * @return the help text for the named command or the default help text if no name is supplied
248fba2635c088b01af59300e8a02611bb788ee3bffchrismair     */
249fba2635c088b01af59300e8a02611bb788ee3bffchrismair    public String getHelpText(String name) {
250fba2635c088b01af59300e8a02611bb788ee3bffchrismair        String key = name == null ? "" : name;
251fba2635c088b01af59300e8a02611bb788ee3bffchrismair        return (String) helpText.get(key);
252fba2635c088b01af59300e8a02611bb788ee3bffchrismair    }
253fba2635c088b01af59300e8a02611bb788ee3bffchrismair
254fba2635c088b01af59300e8a02611bb788ee3bffchrismair    /**
255fba2635c088b01af59300e8a02611bb788ee3bffchrismair     * Add a single UserAccount. If an account with the same <code>username</code> already exists,
256fba2635c088b01af59300e8a02611bb788ee3bffchrismair     * it will be replaced.
257fba2635c088b01af59300e8a02611bb788ee3bffchrismair     *
258fba2635c088b01af59300e8a02611bb788ee3bffchrismair     * @param userAccount - the UserAccount to add
259fba2635c088b01af59300e8a02611bb788ee3bffchrismair     */
260fba2635c088b01af59300e8a02611bb788ee3bffchrismair    public void addUserAccount(UserAccount userAccount) {
261fba2635c088b01af59300e8a02611bb788ee3bffchrismair        userAccounts.put(userAccount.getUsername(), userAccount);
262fba2635c088b01af59300e8a02611bb788ee3bffchrismair    }
263fba2635c088b01af59300e8a02611bb788ee3bffchrismair
264fba2635c088b01af59300e8a02611bb788ee3bffchrismair    /**
265fba2635c088b01af59300e8a02611bb788ee3bffchrismair     * Add the UserAccount objects in the <code>userAccountList</code> to the set of UserAccounts.
266fba2635c088b01af59300e8a02611bb788ee3bffchrismair     *
267fba2635c088b01af59300e8a02611bb788ee3bffchrismair     * @param userAccountList - the List of UserAccount objects to add
268fba2635c088b01af59300e8a02611bb788ee3bffchrismair     */
269fba2635c088b01af59300e8a02611bb788ee3bffchrismair    public void setUserAccounts(List userAccountList) {
270fba2635c088b01af59300e8a02611bb788ee3bffchrismair        for (int i = 0; i < userAccountList.size(); i++) {
271fba2635c088b01af59300e8a02611bb788ee3bffchrismair            UserAccount userAccount = (UserAccount) userAccountList.get(i);
272fba2635c088b01af59300e8a02611bb788ee3bffchrismair            userAccounts.put(userAccount.getUsername(), userAccount);
273fba2635c088b01af59300e8a02611bb788ee3bffchrismair        }
274fba2635c088b01af59300e8a02611bb788ee3bffchrismair    }
275fba2635c088b01af59300e8a02611bb788ee3bffchrismair
276fba2635c088b01af59300e8a02611bb788ee3bffchrismair    /**
277fba2635c088b01af59300e8a02611bb788ee3bffchrismair     * Return the system status description
278fba2635c088b01af59300e8a02611bb788ee3bffchrismair     *
279fba2635c088b01af59300e8a02611bb788ee3bffchrismair     * @return the system status
280fba2635c088b01af59300e8a02611bb788ee3bffchrismair     */
281fba2635c088b01af59300e8a02611bb788ee3bffchrismair    public String getSystemStatus() {
282fba2635c088b01af59300e8a02611bb788ee3bffchrismair        return systemStatus;
283fba2635c088b01af59300e8a02611bb788ee3bffchrismair    }
284fba2635c088b01af59300e8a02611bb788ee3bffchrismair
285fba2635c088b01af59300e8a02611bb788ee3bffchrismair    /**
286fba2635c088b01af59300e8a02611bb788ee3bffchrismair     * Set the system status description text, used by the STAT command handler.
287fba2635c088b01af59300e8a02611bb788ee3bffchrismair     *
288fba2635c088b01af59300e8a02611bb788ee3bffchrismair     * @param systemStatus - the system status description text
289fba2635c088b01af59300e8a02611bb788ee3bffchrismair     */
290fba2635c088b01af59300e8a02611bb788ee3bffchrismair    public void setSystemStatus(String systemStatus) {
291fba2635c088b01af59300e8a02611bb788ee3bffchrismair        this.systemStatus = systemStatus;
292fba2635c088b01af59300e8a02611bb788ee3bffchrismair    }
293fba2635c088b01af59300e8a02611bb788ee3bffchrismair
294fba2635c088b01af59300e8a02611bb788ee3bffchrismair}