package net.sf.colossus.webcommon;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.sf.colossus.webserver.WebServerClient;
public class UserDB
{
private static final Logger LOGGER = Logger.getLogger(UserDB.class
.getName());
private final int maxUsers;
private final String usersFile;
private final HashMap<String, User> userMap = new HashMap<String, User>();
private final HashMap<String, User> loggedInUserMap = new HashMap<String, User>();
private final HashMap<String, User> pendingRegistrations = new HashMap<String, User>();
private long highestExistingId;
public UserDB(String filename, int maxUsersVal)
{
maxUsers = maxUsersVal;
usersFile = filename;
if (usersFile != null)
{
readUsersFromFile();
}
}
public int getUserCount()
{
synchronized (userMap)
{
return userMap.size();
}
}
public void updateLoggedinStatus(User u, WebServerClient wsc)
{
String username = u.getName();
synchronized (loggedInUserMap)
{
if (wsc == null)
{
if (loggedInUserMap.containsKey(username))
{
loggedInUserMap.remove(username);
}
}
else
{
loggedInUserMap.put(username, u);
}
}
}
public boolean isUserOnline(User u)
{
synchronized (loggedInUserMap)
{
return loggedInUserMap.containsKey(u.getName());
}
}
public Collection<User> getLoggedInUsers()
{
synchronized (loggedInUserMap)
{
Collection<User> c = new LinkedList<User>();
c.addAll(loggedInUserMap.values());
return c;
}
}
public User findUserByName(String name)
{
synchronized (userMap)
{
String nameAllLower = name.toLowerCase();
return userMap.get(nameAllLower);
}
}
public String getLoggedInNamesAsString(String useSeparator)
{
String names = "<none>";
String separator = "";
synchronized (loggedInUserMap)
{
if (!loggedInUserMap.isEmpty())
{
StringBuilder list = new StringBuilder("");
for (String key : loggedInUserMap.keySet())
{
list.append(separator);
list.append(key);
separator = useSeparator;
}
names = list.toString();
}
}
return names;
}
// still dummy
public int getDeadCount()
{
return 0;
}
// still dummy
public int getEnrolledCount()
{
return 0;
}
// still dummy
public int getPlayingCount()
{
return 0;
}
public int getLoggedInCount()
{
synchronized (loggedInUserMap)
{
return loggedInUserMap.size();
}
}
public Collection<User> getAllUsers()
{
synchronized (userMap)
{
Collection<User> c = new LinkedList<User>();
c.addAll(userMap.values());
return c;
}
}
/**
* Given a username and password, verifies that the user
* is allowed to login with that password.
* @param username
* @param password
* @return reasonLoginFailed (String), null if login ok
**/
public String verifyLogin(String username, String password)
{
String reasonLoginFailed = null;
User user = findUserByName(username);
if (user == null)
{
reasonLoginFailed = "Invalid username";
}
else if (password != null && user.isCorrectPassword(password))
{
// ok, return null to indicate all is fine
}
else
{
reasonLoginFailed = "Invalid username/password";
}
return reasonLoginFailed;
}
public String registerUser(String username, String password, String email,
IColossusMail mailObject)
{
boolean isAdmin = false;
String usernameAllLc = username;
usernameAllLc = usernameAllLc.toLowerCase();
if (usernameAllLc.startsWith("guest")
|| usernameAllLc.startsWith("anonym"))
{
String problem = "Usernames starting with 'guest' or 'anonym' "
+ " are reserved for special purposes!";
return problem;
}
User alreadyExisting = findUserByName(username);
if (alreadyExisting != null)
{
String problem = "User " + username + " does already exist.";
return problem;
}
else if (getUserCount() >= maxUsers)
{
String problem = "Maximum number of accounts )" + maxUsers
+ ") reached - no more registrations possible,"
+ " until some administrator checks the situation.";
return problem;
}
else
{
highestExistingId++;
User u = new User(highestExistingId, username, password, email,
isAdmin, null, null, null, 0);
String cCode = u.getLastConfirmationCode();
User.LOGGER.fine("Confirmation code for user " + username
+ " is: " + cCode);
String reason = sendConfirmationMail(username, email, cCode,
mailObject);
if (reason != null)
{
// mail sending failed, for some reason. Let user know it.
return reason;
}
pendingRegistrations.put(username, u);
// so far everything fine. Now client shall request the conf. code
reason = User.PROVIDE_CONFCODE;
return reason;
}
}
public String sendConfirmationMail(String username, String email,
String confCode, IColossusMail mailObject)
{
// this is in webcommon package:
return mailObject.sendConfirmationMail(username, email, confCode);
}
public String confirmRegistration(String username, String confirmationCode)
{
String reason = "";
if (confirmationCode == null || confirmationCode.equals("null")
|| confirmationCode.equals(""))
{
reason = "Missing confirmation code";
return reason;
}
String msg = "User " + username + " attempts confirmation "
+ "with code '" + confirmationCode + "'.";
User.LOGGER.fine(msg);
reason = confirmIfCorrectCode(username, confirmationCode);
return reason;
}
private String confirmIfCorrectCode(String username,
String tryConfirmationCode)
{
User u = pendingRegistrations.get(username);
if (u == null)
{
return "No confirmation pending for this username";
}
if (!u.getLastConfirmationCode().equals(tryConfirmationCode))
{
return User.WRONG_CONFCODE;
}
User.LOGGER.info("Registration confirmed for user '" + username
+ "', email '" + u.getEmail() + "'.");
pendingRegistrations.remove(username);
storeUser(u);
storeUsersToFile();
return null;
}
public String changeProperties(String username, String oldPW,
String newPW, String email, Boolean isAdmin)
{
String reason;
User u = findUserByName(username);
if (u == null)
{
reason = "User does not exist";
return reason;
}
else if ((reason = verifyLogin(username, oldPW)) != null)
{
return reason;
}
else
{
u.setProperties(newPW, email, isAdmin);
storeUsersToFile();
return null;
}
}
private void readUsersFromFile()
{
long maxId = 0;
try
{
BufferedReader users = new BufferedReader(new InputStreamReader(
new FileInputStream(usersFile)));
String line = null;
while ((line = users.readLine()) != null)
{
if (line.startsWith("#"))
{
// ignore comment line
}
else if (line.matches("\\s*"))
{
// ignore empty line
}
else
{
User u = User.makeUserFromUserLine(line);
if (u != null)
{
storeUser(u);
if (u.getId() > maxId)
{
maxId = u.getId();
}
}
}
}
this.highestExistingId = maxId;
users.close();
}
catch (FileNotFoundException e)
{
LOGGER.log(Level.SEVERE,
"Users file " + usersFile + " not found!", e);
System.exit(1);
}
catch (IOException e)
{
LOGGER.log(Level.SEVERE, "IOException while reading users file "
+ usersFile + "!", e);
System.exit(1);
}
}
public void storeUsersToFile()
{
if (usersFile == null)
{
User.LOGGER.log(Level.SEVERE, "UsersFile name is null!");
System.exit(1);
}
// LOGGER.log(Level.FINE, "Storing users back to file " + filename);
PrintWriter out = null;
try
{
out = new PrintWriter(new FileOutputStream(usersFile));
Collection<User> users = new LinkedList<User>();
users.addAll(getAllUsers());
for (User user : users)
{
String line = user.makeLine();
out.println(line);
}
out.close();
}
catch (FileNotFoundException e)
{
User.LOGGER.log(Level.SEVERE, "Writing users file " + usersFile
+ "failed: FileNotFoundException: ", e);
System.exit(1);
}
}
private void storeUser(User u)
{
String name = u.getName();
String nameAllLower = name.toLowerCase();
synchronized (userMap)
{
userMap.put(nameAllLower, u);
}
}
public void cleanup()
{
synchronized (userMap)
{
userMap.clear();
}
synchronized (loggedInUserMap)
{
loggedInUserMap.clear();
}
}
}