1ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair/*
2ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * Copyright 2008 the original author or authors.
3ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair *
4ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * Licensed under the Apache License, Version 2.0 (the "License");
5ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * you may not use this file except in compliance with the License.
6ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * You may obtain a copy of the License at
7ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair *
8ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair *      http://www.apache.org/licenses/LICENSE-2.0
9ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair *
10ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * Unless required by applicable law or agreed to in writing, software
11ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * distributed under the License is distributed on an "AS IS" BASIS,
12ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * See the License for the specific language governing permissions and
14ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * limitations under the License.
15ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair */
16ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismairpackage org.mockftpserver.fake;
17ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair
18ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismairimport org.mockftpserver.core.command.CommandHandler;
19ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismairimport org.mockftpserver.core.command.CommandNames;
20ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismairimport org.mockftpserver.core.server.AbstractFtpServer;
21ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismairimport org.mockftpserver.fake.command.*;
22ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismairimport org.mockftpserver.fake.filesystem.FileSystem;
23ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair
24ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismairimport java.util.HashMap;
25ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismairimport java.util.List;
26ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismairimport java.util.Map;
27ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair
28ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair/**
29ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * <b>FakeFtpServer</b> is the top-level class for a "fake" implementation of an FTP Server,
30ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * suitable for testing FTP client code or standing in for a live FTP server.
31ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * <p/>
32ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * <b>FakeFtpServer</b> provides a high-level abstraction for an FTP Server and is suitable
33ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * for most testing and simulation scenarios. You define a filesystem (internal, in-memory) containing
34ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * an arbitrary set of files and directories. These files and directories can (optionally) have
35ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * associated access permissions. You also configure a set of one or more user accounts that
36ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * control which users can login to the FTP server, and their home (default) directories. The
37ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * user account is also used when assigning file and directory ownership for new files.
38ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * <p> <b>FakeFtpServer</b> processes FTP client requests and responds with reply codes and
39ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * reply messages consistent with its configuration and the contents of its internal filesystem,
40ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * including file and directory permissions, if they have been configured.
41ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * <p/>
42ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * <b>FakeFtpServer</b> can be fully configured programmatically or within the
43ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * <b>Spring Framework</b> or other dependency-injection container.
44ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * <p/>
45ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * In general the steps for setting up and starting the <b>FakeFtpServer</b> are:
46ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * <ol>
47ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * <li>Create a new <b>FakeFtpServer</b> instance, and optionally set the server control port.</li>
48ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * <li>Create and configure a <b>FileSystem</b>, and attach to the <b>FakeFtpServer</b> instance.</li>
49ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * <li>Create and configure one or more <b>UserAccount</b> objects and attach to the <b>FakeFtpServer</b> instance.</li>
50ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * </ol>
51ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * <h4>Example Code</h4>
52ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * <pre><code>
53ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * FileSystem fileSystem = new WindowsFakeFileSystem();
54ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * DirectoryEntry directoryEntry1 = new DirectoryEntry("c:\\");
55ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * directoryEntry1.setPermissions(new Permissions("rwxrwx---"));
56ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * directoryEntry1.setOwner("joe");
57ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * directoryEntry1.setGroup("dev");
58ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * <p/>
59ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * DirectoryEntry directoryEntry2 = new DirectoryEntry("c:\\data");
60ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * directoryEntry2.setPermissions(Permissions.ALL);
61ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * directoryEntry2.setOwner("joe");
62ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * directoryEntry2.setGroup("dev");
63ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * <p/>
64ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * FileEntry fileEntry1 = new FileEntry("c:\\data\\file1.txt", "abcdef 1234567890");
65ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * fileEntry1.setPermissionsFromString("rw-rw-rw-");
66ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * fileEntry1.setOwner("joe");
67ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * fileEntry1.setGroup("dev");
68ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * <p/>
69ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * FileEntry fileEntry2 = new FileEntry("c:\\data\\run.exe");
70ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * fileEntry2.setPermissionsFromString("rwxrwx---");
71ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * fileEntry2.setOwner("mary");
72ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * fileEntry2.setGroup("dev");
73ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * <p/>
74ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * fileSystem.add(directoryEntry1);
75ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * fileSystem.add(directoryEntry2);
76ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * fileSystem.add(fileEntry1);
77ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * fileSystem.add(fileEntry2);
78ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * <p/>
79ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * FakeFtpServer fakeFtpServer = new FakeFtpServer();
80ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * fakeFtpServer.setFileSystem(fileSystem);
81ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * <p/>
82ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * UserAccount userAccount = new UserAccount();
83ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * userAccount.setUsername("joe");
84ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * userAccount.setPassword("joe123");
85ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * userAccount.setHomeDirectory("c:\\");
86ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * List userAccounts = Collections.singletonList(userAccount);
87ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * fakeFtpServer.setUserAccounts(userAccounts);
88ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * <p/>
89ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * fakeFtpServer.start();
90ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * </code></pre>
91ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * <p/>
92ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * <h4>FTP Command Reply Text ResourceBundle</h4>
93ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * <p/>
94ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * The default text asociated with each FTP command reply code is contained within the
95ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * "ReplyText.properties" ResourceBundle file. You can customize these messages by providing a
96ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * locale-specific ResourceBundle file on the CLASSPATH, according to the normal lookup rules of
97ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * the ResourceBundle class (e.g., "ReplyText_de.properties"). Alternatively, you can
98ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * completely replace the ResourceBundle file by calling the calling the
99ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * {@link #setReplyTextBaseName(String)} method.
100ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair *
101ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * @author Chris Mair
102ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair * @version $Revision: 143 $ - $Date: 2008-10-31 21:07:23 -0400 (Fri, 31 Oct 2008) $
103ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair */
104ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismairpublic class FakeFtpServer extends AbstractFtpServer implements ServerConfiguration {
105ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair
106ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    private FileSystem fileSystem;
107ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    private String systemName = "WINDOWS";
108ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    private Map helpText = new HashMap();
109ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    private Map userAccounts = new HashMap();
110ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair
111ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    public FileSystem getFileSystem() {
112ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        return fileSystem;
113ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    }
114ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair
115ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    public void setFileSystem(FileSystem fileSystem) {
116ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        this.fileSystem = fileSystem;
117ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    }
118ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair
119ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    public String getSystemName() {
120ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        return systemName;
121ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    }
122ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair
123ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    public void setSystemName(String systemName) {
124ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        this.systemName = systemName;
125ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    }
126ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair
127ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    public Map getHelpText() {
128ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        return helpText;
129ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    }
130ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair
131ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    public void setHelpText(Map helpText) {
132ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        this.helpText = helpText;
133ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    }
134ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair
135ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    public FakeFtpServer() {
136ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.ACCT, new AcctCommandHandler());
137ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.ABOR, new AborCommandHandler());
138ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.ALLO, new AlloCommandHandler());
139ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.APPE, new AppeCommandHandler());
140ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.CONNECT, new ConnectCommandHandler());
141ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.CWD, new CwdCommandHandler());
142ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.CDUP, new CdupCommandHandler());
143ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.DELE, new DeleCommandHandler());
144ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.HELP, new HelpCommandHandler());
145ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.LIST, new ListCommandHandler());
146ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.MKD, new MkdCommandHandler());
147ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.MODE, new ModeCommandHandler());
148ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.NLST, new NlstCommandHandler());
149ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.NOOP, new NoopCommandHandler());
150ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.PASS, new PassCommandHandler());
151ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.PASV, new PasvCommandHandler());
152ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.PWD, new PwdCommandHandler());
153ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.PORT, new PortCommandHandler());
154ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.QUIT, new QuitCommandHandler());
155ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.REIN, new ReinCommandHandler());
156ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.REST, new RestCommandHandler());
157ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.RETR, new RetrCommandHandler());
158ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.RMD, new RmdCommandHandler());
159ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.RNFR, new RnfrCommandHandler());
160ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.RNTO, new RntoCommandHandler());
161ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.SITE, new SiteCommandHandler());
162ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.STOR, new StorCommandHandler());
163ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.STOU, new StouCommandHandler());
164ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.STRU, new StruCommandHandler());
165ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.SYST, new SystCommandHandler());
166ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.TYPE, new TypeCommandHandler());
167ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.USER, new UserCommandHandler());
168ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        setCommandHandler(CommandNames.XPWD, new PwdCommandHandler());
169ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    }
170ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair
171ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    /**
172ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair     * Initialize a CommandHandler that has been registered to this server. If the CommandHandler implements
173ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair     * the <code>ServerConfigurationAware</code> interface, then set its <code>ServerConfiguration</code>
174ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair     * property to <code>this</code>.
175ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair     *
176ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair     * @param commandHandler - the CommandHandler to initialize
177ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair     */
178ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    protected void initializeCommandHandler(CommandHandler commandHandler) {
179ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        if (commandHandler instanceof ServerConfigurationAware) {
180ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair            ServerConfigurationAware sca = (ServerConfigurationAware) commandHandler;
181ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair            sca.setServerConfiguration(this);
182ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        }
183ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    }
184ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair
185ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    /**
186ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair     * @return the {@link UserAccount}        configured for this server for the specified user name
187ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair     */
188ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    public UserAccount getUserAccount(String username) {
189ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        return (UserAccount) userAccounts.get(username);
190ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    }
191ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair
192ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    /**
193ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair     * Return the help text for a command or the default help text if no command name is specified
194ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair     *
195ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair     * @param name - the command name; may be empty or null to indicate  a request for the default help text
196ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair     * @return the help text for the named command or the default help text if no name is supplied
197ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair     */
198ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    public String getHelpText(String name) {
199ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        String key = name == null ? "" : name;
200ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        return (String) helpText.get(key);
201ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    }
202ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair
203ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    /**
204ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair     * Add a single UserAccount. If an account with the same <code>username</code> already exists,
205ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair     * it will be replaced.
206ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair     *
207ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair     * @param userAccount - the UserAccount to add
208ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair     */
209ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    public void addUserAccount(UserAccount userAccount) {
210ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        userAccounts.put(userAccount.getUsername(), userAccount);
211ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    }
212ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair
213ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    /**
214ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair     * Add the UserAccount objects in the <code>userAccountList</code> to the set of UserAccounts.
215ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair     *
216ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair     * @param userAccountList - the List of UserAccount objects to add
217ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair     */
218ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    public void setUserAccounts(List userAccountList) {
219ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        for (int i = 0; i < userAccountList.size(); i++) {
220ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair            UserAccount userAccount = (UserAccount) userAccountList.get(i);
221ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair            userAccounts.put(userAccount.getUsername(), userAccount);
222ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair        }
223ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair    }
224ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair
225ad39334d4c363c6ada5863d0bb3184f5f4699d69chrismair}