diff --git a/year4/semester2/CT414/assignments/assignment1/code/src/client/ApplicationClient.java b/year4/semester2/CT414/assignments/assignment1/code/src/client/ApplicationClient.java index 30fdcfd2..a5e4dd8f 100644 --- a/year4/semester2/CT414/assignments/assignment1/code/src/client/ApplicationClient.java +++ b/year4/semester2/CT414/assignments/assignment1/code/src/client/ApplicationClient.java @@ -1,5 +1,7 @@ package client; +import exceptions.InvalidCredentialsException; +import exceptions.InvalidSessionIDException; import interfaces.ApplicationForm; import interfaces.ApplicationHandler; @@ -21,14 +23,22 @@ public class ApplicationClient { System.out.println("ApplicationHandler found in registry"); // login - System.out.printf("Enter your username\n> "); - String username = scanner.nextLine(); + long sessionID; + while (true) { + try { + System.out.printf("Enter your username\n> "); + String username = scanner.nextLine(); - System.out.printf("Enter your password\n> "); - String password = scanner.nextLine(); + System.out.printf("Enter your password\n> "); + String password = scanner.nextLine(); - long sessionID = handler.login(username, password); - System.out.println("Successfully logged in with session ID: " + sessionID); + sessionID = handler.login(username, password); + System.out.println("Successfully logged in with session ID: " + sessionID); + break; + } catch (Exception e) { + System.out.println("Username or password incorrect, try again."); + } + } // download application form ApplicationForm form = handler.downloadApplicationForm(sessionID); @@ -52,6 +62,8 @@ public class ApplicationClient { handler.submitApplicationForm(sessionID, form); System.out.println("Successfully submitted application form."); + } catch (InvalidSessionIDException e) { + System.out.println("Invalid session ID, exiting..."); } catch (Exception e) { e.printStackTrace(); } finally { diff --git a/year4/semester2/CT414/assignments/assignment1/code/src/exceptions/InvalidCredentialsException.java b/year4/semester2/CT414/assignments/assignment1/code/src/exceptions/InvalidCredentialsException.java index bec1d03d..97c3fc4a 100644 --- a/year4/semester2/CT414/assignments/assignment1/code/src/exceptions/InvalidCredentialsException.java +++ b/year4/semester2/CT414/assignments/assignment1/code/src/exceptions/InvalidCredentialsException.java @@ -2,7 +2,7 @@ package exceptions; import java.rmi.RemoteException; -public class InvalidCredentialsException extends RemoteException { +public class InvalidCredentialsException extends Exception { public InvalidCredentialsException() { super("Invalid username or password."); } diff --git a/year4/semester2/CT414/assignments/assignment1/code/src/exceptions/InvalidSessionIDException.java b/year4/semester2/CT414/assignments/assignment1/code/src/exceptions/InvalidSessionIDException.java index 2d60f8f9..10894ce4 100644 --- a/year4/semester2/CT414/assignments/assignment1/code/src/exceptions/InvalidSessionIDException.java +++ b/year4/semester2/CT414/assignments/assignment1/code/src/exceptions/InvalidSessionIDException.java @@ -2,7 +2,7 @@ package exceptions; import java.rmi.RemoteException; -public class InvalidSessionIDException extends RemoteException { +public class InvalidSessionIDException extends Exception { public InvalidSessionIDException() { super("Invalid or expired session ID."); } diff --git a/year4/semester2/CT414/assignments/assignment1/code/src/implementations/ApplicationHandlerImpl.java b/year4/semester2/CT414/assignments/assignment1/code/src/implementations/ApplicationHandlerImpl.java index 0a2bcba8..148e8df0 100644 --- a/year4/semester2/CT414/assignments/assignment1/code/src/implementations/ApplicationHandlerImpl.java +++ b/year4/semester2/CT414/assignments/assignment1/code/src/implementations/ApplicationHandlerImpl.java @@ -10,6 +10,13 @@ import java.io.*; public class ApplicationHandlerImpl implements ApplicationHandler { private ArrayList sessions = new ArrayList(); + // private method to validate session ids + private boolean isSessionIDValid(long sessionID) { + // check that session is valid and has not expired + // letting session ids expire after 60 seconds for easier testing, a more practical number would be something like 10 minutes + return sessions.contains(sessionID) && ((System.currentTimeMillis()) - sessionID < 6000); + } + @Override public long login(String username, String password) throws RemoteException, InvalidCredentialsException { // hardcoded username and password (great practice for security) @@ -21,13 +28,15 @@ public class ApplicationHandlerImpl implements ApplicationHandler { return sessionId; } else { + System.out.println("Login failed with user " + username + " and password " + password); throw new InvalidCredentialsException("Invalid username or password."); } } @Override public ApplicationForm downloadApplicationForm(long sessionID) throws RemoteException, InvalidSessionIDException { - if (sessions.contains(sessionID)) { + // check that session is valid and has not expired + if (isSessionIDValid(sessionID)) { System.out.println("Returning application form for session ID: " + sessionID); return new ApplicationFormV1(); } else { @@ -37,7 +46,7 @@ public class ApplicationHandlerImpl implements ApplicationHandler { @Override public void submitApplicationForm(long sessionID, ApplicationForm applicationForm) throws RemoteException, InvalidSessionIDException { - if (sessions.contains(sessionID)) { + if (isSessionIDValid(sessionID)) { String filename = applicationForm.getName().replaceAll("\\s", "_") + ".txt"; try (BufferedWriter writer = new BufferedWriter(new FileWriter(filename))) { diff --git a/year4/semester2/CT414/assignments/assignment1/code/src/run.sh b/year4/semester2/CT414/assignments/assignment1/code/src/run.sh index 287abd46..d18a62c1 100755 --- a/year4/semester2/CT414/assignments/assignment1/code/src/run.sh +++ b/year4/semester2/CT414/assignments/assignment1/code/src/run.sh @@ -14,4 +14,4 @@ $TERM -e java -cp $src_path -Djava.rmi.server.codebase=file:$src_path/ server.Ap sleep 1 # start client (in a new terminal) -$TERM -e java -cp $src_path -Djava.rmi.server.codebase=file:$src_path/ client.ApplicationClient +$TERM -e bash -c "java -cp $src_path -Djava.rmi.server.codebase=file:$src_path/ client.ApplicationClient ; zsh" diff --git a/year4/semester2/CT414/assignments/assignment1/latex/CT414-Assignment-01.pdf b/year4/semester2/CT414/assignments/assignment1/latex/CT414-Assignment-01.pdf index 4ba2e6e6..dbb991e4 100644 Binary files a/year4/semester2/CT414/assignments/assignment1/latex/CT414-Assignment-01.pdf and b/year4/semester2/CT414/assignments/assignment1/latex/CT414-Assignment-01.pdf differ diff --git a/year4/semester2/CT414/assignments/assignment1/latex/CT414-Assignment-01.tex b/year4/semester2/CT414/assignments/assignment1/latex/CT414-Assignment-01.tex index c9b87d5e..a0cebf46 100644 --- a/year4/semester2/CT414/assignments/assignment1/latex/CT414-Assignment-01.tex +++ b/year4/semester2/CT414/assignments/assignment1/latex/CT414-Assignment-01.tex @@ -71,7 +71,8 @@ Assignment 1: Java RMI \end{center} \hrule -\medskip + +\section{Testing} To run and test the code, I wrote a short shell script based off those provided in RMI Compute Server Example code provided on Canvas which compiles the code and launches three terminals: one running the \mintinline{shell}{rmiregistry}, one running the \mintinline{java}{ApplicationServer}, and one running the \mintinline{java}{ApplicationClient}. @@ -97,5 +98,25 @@ The details entered were saved into a file called \verb|Michael_D_Higgins.txt|, The output file contained all the questions and answers from the application form, as expected. +\subsection{\mintinline{java}{InvalidCredentialsException}} +To test that an appropriate exception was thrown when a user attempted to login with invalid credentials, I tried a few invalid logins. +The desired behaviour, as can be seen in the output screenshot below, was that the \mintinline{java}{ApplicationHandlerImpl} class would throw an \mintinline{java}{InvalidCredentialsException} when the \mintinline{java}{ApplicationClient} invoked its \mintinline{java}{ApplicationHandler.login()} method. +The \mintinline{java}{ApplicationClient} would then handle this exception gracefully, prompting the user to re-enter their login details until they entered valid details. + +\begin{figure}[H] + \centering + \includegraphics[width=\textwidth]{./images/inalidcred.png} + \caption{Failed logins with invalid credentials, handled gracefully } +\end{figure} + +\subsection{\mintinline{java}{InvalidSessionIDException}} +Since my \mintinline{java}{ApplicationHandlerImpl} class would reject session IDs older than 60 seconds (the low value being chosen for testing purposes, a more practical value would be, say, 10 minutes), I simply waited 60 seconds after logging in to answer the very last question, ensuring that the form submission method would be invoked with an expired session ID, the desired behaviour (as can be seen in the output below) being that the client would receive an \mintinline{java}{InvalidSessionIDException}, and gracefully terminate the program. + +\begin{figure}[H] + \centering + \includegraphics[width=\textwidth]{./images/invalidsessionid.png} + \caption{Session ID expiring after 60 seconds} +\end{figure} + \end{document} diff --git a/year4/semester2/CT414/assignments/assignment1/latex/images/inalidcred.png b/year4/semester2/CT414/assignments/assignment1/latex/images/inalidcred.png new file mode 100644 index 00000000..3b214f59 Binary files /dev/null and b/year4/semester2/CT414/assignments/assignment1/latex/images/inalidcred.png differ diff --git a/year4/semester2/CT414/assignments/assignment1/latex/images/invalidsessionid.png b/year4/semester2/CT414/assignments/assignment1/latex/images/invalidsessionid.png new file mode 100644 index 00000000..802b21b4 Binary files /dev/null and b/year4/semester2/CT414/assignments/assignment1/latex/images/invalidsessionid.png differ