package net.classicube.launcher; import java.util.Arrays; import java.util.HashMap; import java.util.logging.Level; import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; // Handles persistence/"remembering" of user account information for a given GameServiceType. // SessionManager creates an instance of AccountManager in SessionManager.selectService(). public final class AccountManager { private final Preferences store; private final HashMap<String, UserAccount> accounts = new HashMap<>(); private static final String ACCOUNTS_NODE_NAME = "Accounts"; // Creates a new account manager for specified service name // serviceName is used to separate storage of data from different services public AccountManager(final GameServiceType service) { final Preferences baseNode = Preferences.userNodeForPackage(getClass()); this.store = baseNode.node(service.name()).node(ACCOUNTS_NODE_NAME); } // Loads all accounts from preferences public void load() { if (!Prefs.getRememberUsers()) { return; } try { for (final String accountName : this.store.childrenNames()) { final Preferences accountNode = this.store.node(accountName); try { final UserAccount acct = new UserAccount(accountNode); if (acct.signInDate.getTime() == 0) { // AccountManager used to store all accounts as soon as [Sign In] button was // pressed. Now we only store after a successful sign-in. This avoids typos // from being saved forever. LogUtil.getLogger().log(Level.WARNING, "Skipping user account {0} (never signed into).", acct.signInUsername); accountNode.removeNode(); store.flush(); continue; } this.accounts.put(acct.signInUsername.toLowerCase(), acct); } catch (final IllegalArgumentException ex) { LogUtil.getLogger().log(Level.SEVERE, "Error loading an account", ex); accountNode.removeNode(); this.store.flush(); } } LogUtil.getLogger().log(Level.FINE, "Loaded {0} accounts", this.accounts.size()); } catch (BackingStoreException ex) { LogUtil.getLogger().log(Level.SEVERE, "Error loading accounts", ex); } } // Stores ALL remembered accounts public void storeAll() { LogUtil.getLogger().log(Level.FINE, "AccountManager.store"); this.clearStore(); if (!Prefs.getRememberUsers()) { return; } for (final UserAccount acct : this.accounts.values()) { acct.store(this.store.node(acct.signInUsername.toLowerCase())); } } // Stores given account public void store(final UserAccount acct) { if (!this.accounts.containsValue(acct)) { this.accounts.put(acct.signInUsername.toLowerCase(), acct); } acct.store(this.store.node(acct.signInUsername.toLowerCase())); } // Erases all accounts public void clear() { LogUtil.getLogger().log(Level.FINE, "AccountManager.clear"); this.accounts.clear(); this.clearStore(); } // Erases all accounts from memory and preferences store private void clearStore() { LogUtil.getLogger().log(Level.FINE, "AccountManager.clearStore"); try { for (final String accountName : this.store.childrenNames()) { this.store.node(accountName.toLowerCase()).removeNode(); } } catch (final BackingStoreException ex) { LogUtil.getLogger().log(Level.SEVERE, "Error clearing accounts", ex); } } // Clears passwords (sets them to empty string) for all accounts public void clearPasswords() { LogUtil.getLogger().log(Level.FINE, "AccountManager.clearPasswords"); for (final UserAccount account : this.accounts.values()) { account.password = ""; } this.storeAll(); } // Returns true if there is at least one account stored. public boolean hasAccounts() { return !this.accounts.isEmpty(); } // Returns true if at least one account has a password stored. public boolean hasPasswords() { for (final UserAccount account : this.accounts.values()) { if (!account.password.isEmpty()) { return true; } } return false; } // Tries to find stored UserAccount data for given sign-in name (case-insensitive) public UserAccount findAccount(final String signInName) { if (signInName == null) { throw new NullPointerException("signInName"); } return this.accounts.get(signInName.toLowerCase()); } // Gets a list of all accounts, ordered by sign-in date, most recent first public UserAccount[] getAccountsBySignInDate() { final UserAccount[] accountArray; accountArray = this.accounts.values().toArray(new UserAccount[this.accounts.size()]); Arrays.sort(accountArray, UserAccount.getUptimeComparator()); return accountArray; } // Either creates a new UserAccount or retrieves an existing UserAccount for given username. // Called from SignInScreen, right after [Sign In] button is pressed. public UserAccount onSignInBegin(final String username, final String password) { if (username == null) { throw new NullPointerException("username"); } if (password == null) { throw new NullPointerException("password"); } final UserAccount existingAccount = this.findAccount(username); if (existingAccount == null) { // new account! final UserAccount newAccount = new UserAccount(username, password); return newAccount; } else { existingAccount.signInUsername = username; existingAccount.password = password; return existingAccount; } } }