/**************************************************************************************************
* Program Name : File IO
* Author : Terry Weiss
* Date : March 4, 2016
* Course/Section : CSC264 - 001
* Program Description: This program allows the user to input usernames and passwords from a file,
* and allows users to login and logout of the system. Also, once a user is logged in, they
* are able to change their password. Only 1 user may be logged in at any time. Before
* shutting the program down, write to a file all of the usernames that were logged in. The
* program menu allows users to login, logout, change the password, or quit the program. The
* user must enter their current password before they're able to change it. If the old
* password is incorrect, they will receive an error. When the user changes their password,
* the file is updated. If the user tries to log in while a user is already logged in, they
* also get an error. All logins are logged in a separate file.
*
* Methods:
* -------
* Main - Runs the transcript program
* Menu Prompt - Displays menu and prompts option
* Prompt Filename - Prompts for a filename
* Check File Exists - Checks if a file already exists
**************************************************************************************************/
import java.util.ArrayList;
import java.util.Date;
import java.io.File;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.io.IOException;
public class FileIOTTW
{
/**********************************************************************************************
*============================================================================================*
*| Class variables |*
*============================================================================================*
**********************************************************************************************/
/**********************************************************************************************
*============================================================================================*
*| Class methods |*
*============================================================================================*
**********************************************************************************************/
/**********************************************************************************************
* Method Name : FileIO - Main
* Author : Terry Weiss
* Date : March 4, 2016
* Course/Section : CSC264 - 001
* Program Description: This method asks the user for the filenames of their id/password file
* and log file. They are then given a menu to login, logout, change their password or
* exit.
*
* BEGIN Main
* Dispaly title for file setup
* Prompt login file
* WHILE (login file doesn't exist)
* Display error that file doesn't exist
* Prompt login file
* END WHILE
* Load login file
* Prompt log file
* Init login info to an empty username and password
* Clear screen
* Get menu option
* WHILE (option isn't to exit)
* SWITCH (option)
* CASE login: If no login, set login info to result of attempted log in
* IF (no one is already logged in) THEN
* Set login info to result of attempted login
* ELSE
* Display message that no one's logged in
* END IF
* CASE password: Run change password method
* CASE logout: Set username and password to empty strings and announce logout
* DEFAULT: Throw unsupported operation exception
* END SWITCH
* Get new menu option
* IF (new menu option is to exit) THEN
* Save all password changes to the logins file and update log file
* END IF
* END WHILE
* END Main
**********************************************************************************************/
public static void main(String[] args) throws IOException
{
//Local constants
final int FILENAME_PROMPT_PAD = 21; //Character padding for filename prompts
final int PROMPT_PAD = 18; //Character padding for menu prompt
final int MENU_OPTION_LOGIN = 1; //Menu option for logging in
final int MENU_OPTION_PASSWD = 2; //Menu option for changing password
final int MENU_OPTION_LOGOUT = 3; //Menu option for logging out
final int MENU_OPTION_EXIT = 4; //Menu option for exiting
final int LOGIN_USERNAME = 0; //Username value in login info
final int LOGIN_PASSWORD = 1; //Password value in login info
//Local variables
String loginsFilename; //File name of login info file
String logFilename; //File name of log file
int menuOption; //Menu option selected
String[] loginInfo; //Username and password of current login
ArrayList<String[]> loginPairs; //List of ID and password pairs
ArrayList<String> loginLog; //Log of all successful logins
Library64 clear = new Library64(); //Library utility that clears the screen
/********************************** Start Main Method ***********************************/
//Dispaly title for file setup
System.out.println("\n" + Console.center("File Setup") + "\n");
//Prompt login file
loginsFilename = promptFilename(FILENAME_PROMPT_PAD, "Enter login info file name: ");
//WHILE (login file doesn't exist)
while (!fileExists(loginsFilename))
{
//Display error that file doesn't exist
System.out.println(Console.padLeft(FILENAME_PROMPT_PAD, "!! FILE DOESN'T EXIST !!"));
//Prompt login file
loginsFilename = promptFilename(FILENAME_PROMPT_PAD, "Enter login info file name: ");
}//end while
//Load login file
loginPairs = readLogins(loginsFilename);
System.out.println("\n" + Console.padLeft(FILENAME_PROMPT_PAD, "Loaded login info.\n"));
//Prompt log file
logFilename = promptFilename(FILENAME_PROMPT_PAD, "Enter log file name: ");
//Init login log to empty array list
loginLog = new ArrayList<String>();
//Init login info to an empty username and password
loginInfo = new String[2];
//Clear screen
clear.clrscr();
//Get menu option
menuOption = menuPrompt();
//WHILE (option isn't to exit)
while (menuOption != MENU_OPTION_EXIT)
{
//SWITCH (option)
switch (menuOption)
{
//CASE login: If no one's logged in, set login info to result of attempted login
case MENU_OPTION_LOGIN:
//IF (no one is already logged in) THEN
if (loginInfo[LOGIN_USERNAME] == null || loginInfo[LOGIN_USERNAME].isEmpty())
{
//Set login info to result of attempted login
loginInfo = attemptLogin(loginPairs, loginLog);
}
//ELSE (someone is logged in)
else
{
//Display someone is already logged in
System.out.println(Console.padLeft(PROMPT_PAD,
loginInfo[LOGIN_USERNAME] + " is already logged in!"));
}//end if anyone's logged in
break;
//CASE password: Run change password method
case MENU_OPTION_PASSWD:
changePassword(loginPairs, loginInfo);
break;
//CASE logout: Set username and password to empty strings and announce logout
case MENU_OPTION_LOGOUT:
//IF (no one is logged in) THEN
if (loginInfo[LOGIN_USERNAME] == null || loginInfo[LOGIN_USERNAME].isEmpty())
{
System.out.println(Console.padLeft(PROMPT_PAD, "No one's logged in!"));
}
//ELSE (someone's logged in)
else
{
//Set all login info to empty strings
loginInfo[LOGIN_USERNAME] = "";
loginInfo[LOGIN_PASSWORD] = "";
//Display success message
System.out.println("\nYou have successfully logged out.\n");
}//end if anyone's logged in
break;
default:
throw new UnsupportedOperationException("Unsupported menu option was selected.");
}//END SWITCH
//Get new menu option
menuOption = menuPrompt();
//IF (new menu option was to exit) THEN
if (menuOption == MENU_OPTION_EXIT)
{
//Save all password changes to the logins file and update log file
exit(loginsFilename, loginPairs, logFilename, loginLog);
}
}//END WHILE
}//end class main
/**********************************************************************************************
* Method Name : FileIO - Read Logins
* Author : Terry Weiss
* Date : March 4, 2016
* Course/Section : CSC264 - 001
* Program Description: This method loads all the usernames and passwords from a file. This
* method does not verify if the file exists or if it's formatted correctly. All login
* info should be formatted as `NAME PASSWORD` with one space between. There should only
* one ID/password pair per line.
*
* BEGIN Read Logins
* Init logins to empty array list
* Open the input stream for reading logins file
* WHILE (there are more lines in the file)
* Add the line to the list, splitting the username and password
* END WHILE
* Close file reader
* Return logins
* END Read Logins
**********************************************************************************************/
private static ArrayList<String[]> readLogins(String filename) throws IOException
{
//Local constants
//Local variables
ArrayList<String[]> logins; //List of username and password pairs
BufferedReader bFile; //File reader reading the logins file
String loginLine; //Current line being read from the file
/******************************* Start Read Logins Method *******************************/
//Init logins to empty array list
logins = new ArrayList<String[]>();
//Open the input stream for reading logins file
bFile = new BufferedReader(new FileReader(filename));
//Get first line of logins file
loginLine = bFile.readLine();
//WHILE (there are more lines in the file)
while (loginLine != null)
{
//Add the line to the list, splitting the username and password
logins.add(loginLine.split(" "));
//Get the next line from the logins file
loginLine = bFile.readLine();
}//end while there are more lines
//Close file reader
bFile.close();
//Return success
return logins;
}//end method Read Logins
/**********************************************************************************************
* Method Name : FileIO - Menu Prompt
* Author : Terry Weiss
* Date : March 4, 2016
* Course/Section : CSC264 - 001
* Program Description: This method displays the menu options and prompts the user for their
* menu option.
*
* BEGIN Menu Prompt
* Display menu title
* Display menu options
* Prompt user for option
* WHILE (option is out of range)
* Display error message about out of range
* Prompt user for option
* END WHILE
* Return menu option
* END Menu Prompt
**********************************************************************************************/
private static int menuPrompt()
{
//Local constants
final int OPTION_PAD = 31; //Character padding for menu options
final int PROMPT_PAD = 18; //Character padding for menu prompt
final int FIRST_OPTION = 1; //Value of first menu option
final int LAST_OPTION = 4; //Value of last menu option
//Local variables
int option; //User's selected menu option
Library64 clear = new Library64(); //Library utility that clears the screen
/******************************* Start Menu Prompt Method *******************************/
//Display menu title
System.out.println("\n" + Console.center("Login System") + "\n");
//Display menu options
System.out.println(Console.padLeft(OPTION_PAD, "1. Log in"));
System.out.println(Console.padLeft(OPTION_PAD, "2. Change password"));
System.out.println(Console.padLeft(OPTION_PAD, "3. Log out"));
System.out.println(Console.padLeft(OPTION_PAD, "4. Exit"));
//Prompt user for option
System.out.print(Console.padLeft(PROMPT_PAD, "Please choose a menu option: "));
option = Keyboard.readInt();
//WHILE (option is out of range)
while (option < FIRST_OPTION || option > LAST_OPTION)
{
//Display error message about out of range
System.out.print("Invalid option. ");
//Prompt user for option
System.out.print("Choose a menu option: ");
option = Keyboard.readInt();
}//end while (option is out of range)
//return menu option
return option;
}//end class menu prompt
/**********************************************************************************************
* Method Name : FileIO - Prompt Filename
* Author : Terry Weiss
* Date : March 4, 2016
* Course/Section : CSC264 - 001
* Program Description: This method prompts for a filename. If the original filename is empty
* or just spaces, they are given an error message and prompted again. After the first
* time, the trailing whitespace of the prompt message is removed to avoid overflowing the
* line as easily with the error message.
*
* BEGIN Prompt Filename
* Prompt user for a filename
* WHILE (filename is empty)
* Display error message about invalid filename
* Prompt user for a filename
* END WHILE
* Return filename
* END Prompt Filename
**********************************************************************************************/
private static String promptFilename(int pad, String prompt)
{
//Local constants
//Local variables
String filename; //New filename
/***************************** Start Prompt Filename Method *****************************/
//Prompt user for a filename
System.out.print(Console.padLeft(pad, prompt));
filename = Keyboard.readString().trim();
//WHILE (filename is empty)
while (filename.isEmpty())
{
//Display error message about invalid filename
System.out.print(Console.padLeft(pad, "Invalid filename. "));
//Prompt user for a filename
System.out.print(prompt.trim() + " "); //Replaces original trailing space with 1 space
filename = Keyboard.readString();
}
//Return filename
return filename;
}//end method prompt filename
/**********************************************************************************************
* Method Name : FileIO - File Exists
* Author : Terry Weiss
* Date : March 4, 2016
* Course/Section : CSC264 - 001
* Program Description: This method confirms if a file exists.
*
* BEGIN File Exists
* Create new file object and check if it exists
* END File Exists
**********************************************************************************************/
private static boolean fileExists(String filename)
{
//Local constants
//Local variables
/******************************* Start File Exists Method *******************************/
//Create new file object and check if it exists
return (new File(filename).exists());
}//end method file exists
/**********************************************************************************************
* Method Name : FileIO - Attempt Login
* Author : Terry Weiss
* Date : March 4, 2016
* Course/Section : CSC264 - 001
* Program Description: This method attempts to log in a user. The user is prompted for a
* username and password. If the username isn't found, the login fails. Otherwise, the
* user is prompted for their password. If the password doesn't match the username's
* password, the login also fails. If the login fails, a login array with an empty
* username and password is returned. Otherwise, a login array with the matching username
* and password is returned, and the login is written to the log file. If the login is
* successful, the username and time stamp will be added to the given log ArrayList.
*
* BEGIN Attempt Login
* Init index to 0
* Prompt username
* WHILE (username is empty)
* Display invalid username and reprompt
* END WHILE
* WHILE (the username doesn't match AND there are more login pairs) //find username's index
* Increment index
* END WHILE
* IF (username was found) THEN
* Init attempts to 0
* Prompt password
* WHILE (more attempts are left AND password doesn't match)
* Increment attempt
* Display error message and reprompt
* END WHILE
* IF (password attempt matches real password) THEN
* Set login's password to password
* Set login's username to username
* Add username to log
* Display successful login
* END IF
* ELSE
* Display username doesn't exist
* END IF
* END Attempt Login
**********************************************************************************************/
private static String[] attemptLogin(ArrayList<String[]> pairs, ArrayList<String> log)
{
//Local constants
final int LOGIN_FIELDS = 2; //Number of fields returned (currently id & passwd)
final int LOGIN_USERNAME = 0; //Username index in login info
final int LOGIN_PASSWORD = 1; //Password index in login info
final int MAX_ATTEMPTS = 2; //Additional attempts after initial password failure
final int PROMPT_PAD = 30; //Character pad for prompt
//Local variables
int index; //Current index of login pair
int attempts; //Number of additional attempts for correct password
String username; //User's username
String passwordAttempt; //User's password attempt
String password; //Username's real password
String[] login; //User's login info
String logLine; //Read username and password
/****************************** Start Attempt Login Method ******************************/
//Init index to 0
index = 0;
//Init login to an empty username and password
login = new String[LOGIN_FIELDS];
login[LOGIN_USERNAME] = "";
login[LOGIN_USERNAME] = "";
//Prompt for a username
System.out.print(Console.padLeft(PROMPT_PAD, "Enter your username: "));
username = Keyboard.readString().trim();
//WHILE (username is empty)
while (username.isEmpty())
{
//Display invalid username and reprompt
System.out.print(Console.padLeft(PROMPT_PAD, "Invalid username. Enter your username: "));
username = Keyboard.readString().trim();
}
/*
* This is to find the username's index if it exists. If it doesn't exist, index will end
* up equaling the array list's size.
*/
//WHILE (there are more login pairs AND the username doesn't match)
while (index < pairs.size() && !pairs.get(index)[LOGIN_USERNAME].equalsIgnoreCase(username))
{
//Increment index
index++;
}
//IF (username was found) THEN
if (index < pairs.size())
{
//Init attempts to 0
attempts = 0;
//Prompt password
System.out.print(Console.padLeft(PROMPT_PAD, "Enter your password: "));
password = Keyboard.readString();
//WHILE (more attempts are left AND password doesn't match)
while (!pairs.get(index)[LOGIN_PASSWORD].equals(password) && attempts < MAX_ATTEMPTS)
{
//Increment attempt
attempts++;
//Display error message and reprompt
System.out.print(Console.padLeft(PROMPT_PAD,
"Invalid password. Please enter your password: "));
password = Keyboard.readString();
}//end while
//IF (password attempt matches real password) THEN
if (pairs.get(index)[LOGIN_PASSWORD].equals(password))
{
//Set login's password to password
login[LOGIN_USERNAME] = username;
//Set login's username to username
login[LOGIN_PASSWORD] = password;
//Add username to log
log.add(String.format("%-20s %s", username, new Date()));
//Display successful login
System.out.println("\n" + Console.center("Welcome back, " + username + "!"));
}//end if password matches
}//end if username was found
//ELSE (username wasn't found)
else
{
//Display message that username wasn't found.
System.out.println(Console.padLeft(PROMPT_PAD, "Username doesn't exist!"));
}
//Return login
return login;
}//end method attempt login
/**********************************************************************************************
* Method Name : FileIO - Change Password
* Author : Terry Weiss
* Date : March 4, 2016
* Course/Section : CSC264 - 001
* Program Description: This method changes the password of the current login if someone is
* currently logged in. A success or failure message is printed to the console based on
* if anyone is logged in. Passwords must have at least 5 characters to be valid. A user
* must confirm their current password before being able to change their password.
*
* BEGIN Change Password
* IF (no one is logged in) THEN
* Display error message
* ELSE
* Prompt for current password
* IF (password doesn't match) THEN
* Display error
* ELSE
* Store index of current login info
* Prompt for new password
* WHILE (password is too short)
* Reprompt for new password
* END WHILE
* Set login info's password to entered password
* Replace index with new login info
* Display success message
* END IF
* END IF
* END Change Password
**********************************************************************************************/
public static void changePassword(ArrayList<String[]> loginPairs, String[] loginInfo)
{
//Local constants
final boolean APPEND = true; //Append to a file when writing
final int LOGIN_USERNAME = 0; //Username index in login info
final int LOGIN_PASSWORD = 1; //Password index in login info
final int PAD = 18; //Character padding for output
final int MIN_LENGTH = 5; //Minimum password length
//Local variables
BufferedWriter writer; //Utility object writes to file writer
boolean confirmed; //Whether current password was confirmed
int index; //Index of login
String passwordAttempt; //User's attempt to confirm password
String newPassword; //User's new password
/***************************** Start Change Password Method *****************************/
//IF (no one is logged in) THEN
if (loginInfo[LOGIN_USERNAME] == null || loginInfo[LOGIN_USERNAME].isEmpty())
{
//Display error message
System.out.println(Console.padLeft(PAD, "Please log in to change your password.\n"));
}
//ELSE (someone is logged in)
else
{
//Prompt for current password
System.out.print(Console.padLeft(PAD, "Enter current password: "));
passwordAttempt = Keyboard.readString();
//IF (password doesn't match) THEN
if (!passwordAttempt.equals(loginInfo[LOGIN_PASSWORD]))
{
//Display error
System.out.println(Console.padLeft(PAD, "Incorrect password.\n"));
}
//ELSE (password matches)
else
{
//Store index of current login info
index = getIndex(loginPairs, loginInfo);
//Prompt for new password
System.out.print(Console.padLeft(PAD, "Enter new password: "));
newPassword = Keyboard.readString();
//WHILE (password is too short)
while (newPassword.length() < MIN_LENGTH)
{
//Reprompt for new password
System.out.print(Console.padLeft(PAD, "Enter new password (min "
+ MIN_LENGTH + " characters): "));
newPassword = Keyboard.readString();
}//end while password is too short
//Set login info's password to entered password
loginInfo[LOGIN_PASSWORD] = newPassword;
//Replace index with new login info
loginPairs.set(index, loginInfo);
//Display success message
System.out.println(Console.padLeft(PAD, "Password changed successfully!\n"));
}//end if password matches
}//end if someone is logged in
}//end method change password
/**********************************************************************************************
* Method Name : FileIO - Get Index
* Author : Terry Weiss
* Date : March 4, 2016
* Course/Section : CSC264 - 001
* Program Description: This method gets the index of a given login in the login list. A
* login matches with a case insensitive username and case sensitive password.
*
* BEGIN Get Index
* Init found to false
* Init index to 0
* WHILE (there are more logins AND login wasn't found)
* IF (username/password matches current pair's username/password)
* Set found to true
* ELSE
* Increment index
* END IF
* END WHILE
* IF (login wasn't found) THEN
* Set index to not found
* END IF
* Return index
* END Get Index
**********************************************************************************************/
private static int getIndex(ArrayList<String[]> loginPairs, String[] loginInfo)
{
//Local constants
final int LOGIN_USERNAME = 0; //Username index in login info
final int LOGIN_PASSWORD = 1; //Password index in login info
final int NOT_FOUND = -1; //Index if login wasn't found
//Local variables
boolean found; //Whether login was found
int index; //Index of login
/******************************* Start File Exists Method *******************************/
//Init found to false
found = false;
//Init index to 0
index = 0;
//WHILE (there are more logins AND login wasn't found)
while (index < loginPairs.size() && !found)
{
//IF (username/password matches current pair's username/password)
if (loginPairs.get(index)[LOGIN_USERNAME].equalsIgnoreCase(loginInfo[LOGIN_USERNAME])
&& loginPairs.get(index)[LOGIN_PASSWORD].equals(loginInfo[LOGIN_PASSWORD]))
{
//Set found to true
found = true;
}
//ELSE username/passwords don't match
else
{
//Increment index
index++;
}//end if username/password matches
}//end while more logins and not found
//IF (login wasn't found) THEN
if (!found)
{
//Set index to not found
index = NOT_FOUND;
}
//Return index
return index;
}//end method file exists
/**********************************************************************************************
* Method Name : FileIO - Exit
* Author : Terry Weiss
* Date : March 4, 2016
* Course/Section : CSC264 - 001
* Program Description: This method saves the new login info and log to their files before
* the program exits.
*
* BEGIN Exit
* Init empty writer
* TRY to write the pairs
* Open writer to write logins info back to file
* FOR (each login pair)
* Write username and password to the file with a space between them
* END FOR
* CATCH (IO exception)
* Display unable to write to logins file
* FINALLY
* Flush writer
* Close writer
* END TRY-CATCH-FINALLY
* TRY to write the log
* IF (log file exists) THEN
* Open writer to append log back to file
* ELSE
* Open writer to write log back to file
* END IF
* FOR (each log entry)
* Write the log entry to log file
* END FOR
* CATCH (IO Exception)
* Display unable to write to log file
* FINALLY
* Flush writer
* Close writer
* END TRY-CATCH-FINALLY
* END Exit
**********************************************************************************************/
private static void exit(String loginsFilename, ArrayList<String[]> pairs, String logFilename,
ArrayList<String> log)
throws IOException
{
//Local constants
final boolean APPEND = true; //Append to a file when writing
final int LOGIN_USERNAME = 0; //Username index in login info
final int LOGIN_PASSWORD = 1; //Password index in login info
final int PAD = 18; //Character padding for output
//Local variables
BufferedWriter writer; //Utility object writes to file writer
/********************************** Start Exit Method ***********************************/
//Init empty writer
writer = null;
//TRY to write the pairs
try
{
//Open writer to write logins info back to file
writer = new BufferedWriter(new FileWriter(loginsFilename));
//FOR (each login pair)
for (String[] pair : pairs)
{
//Write username and password to the file with a space between them
writer.write(pair[LOGIN_USERNAME] + " " + pair[LOGIN_PASSWORD] + "\n");
}
}
//CATCH (IO exception)
catch (IOException e)
{
//Display unable to write to logins file
System.out.println(Console.center("!! UNABLE TO WRITE TO LOGINS FILE !!"));
}
//FINALLY
finally
{
//Flush writer
writer.flush();
//Close writer
writer.close();
}//end try-catch-finally writing to logins info file
//TRY to write the log
try
{
//IF (log file exists) THEN
if (fileExists(logFilename))
{
//Open writer to append log back to file
writer = new BufferedWriter(new FileWriter(logFilename, APPEND));
}
//ELSE (log file doesn't exist)
else
{
//Open writer to write log back to file
writer = new BufferedWriter(new FileWriter(logFilename));
}//end if log file exists
//FOR (each log entry)
for (String entry : log)
{
//Write the log entry to log file
writer.write(entry + "\n");
}//end for each log entry
}
//CATCH (IO Exception)
catch (IOException e)
{
//Display unable to write to log file
System.out.println(Console.center("!! UNABLE TO WRITE TO LOG FILE !!"));
}
//FINALLY
finally
{
//Flush writer
writer.flush();
//Close writer
writer.close();
}//end try-catch-finally writing to log file
}//end method exit
}//end class File IO
Comments