From 24e6376d9d84c0adc8f26e8b269295ffc734b622 Mon Sep 17 00:00:00 2001 From: "github-classroom[bot]" <66690702+github-classroom[bot]@users.noreply.github.com> Date: Thu, 27 Nov 2025 12:07:01 +0000 Subject: [PATCH 01/17] add deadline --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d20aaf9..7071577 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +[![Review Assignment Due Date](https://classroom.github.com/assets/deadline-readme-button-22041afd0340ce965d47ae6ef1cefeee28c7c493a6346c4f15d667ab976d596c.svg)](https://classroom.github.com/a/339Lr3BJ) ### How the tests work (and Docker requirement) This project ships with an end‑to‑end CLI integration test suite that uses Testcontainers to spin up a temporary MySQL database. From 643768b6dc241f200e43a3c9a9e1ca4056f87e93 Mon Sep 17 00:00:00 2001 From: Annika Holmqvist Date: Tue, 2 Dec 2025 12:33:08 +0100 Subject: [PATCH 02/17] Add initial repository interfaces and JDBC implementations --- .../java/com/example/AccountRepository.java | 12 +++++++ .../com/example/JdbcAccountRepository.java | 35 +++++++++++++++++++ .../example/JdbcMoonMissionRepository.java | 4 +++ .../com/example/MoonMissionRepository.java | 17 +++++++++ 4 files changed, 68 insertions(+) create mode 100644 src/main/java/com/example/AccountRepository.java create mode 100644 src/main/java/com/example/JdbcAccountRepository.java create mode 100644 src/main/java/com/example/JdbcMoonMissionRepository.java create mode 100644 src/main/java/com/example/MoonMissionRepository.java diff --git a/src/main/java/com/example/AccountRepository.java b/src/main/java/com/example/AccountRepository.java new file mode 100644 index 0000000..5da19a5 --- /dev/null +++ b/src/main/java/com/example/AccountRepository.java @@ -0,0 +1,12 @@ +package com.example; + +public interface AccountRepository { + + boolean isValidLogin(String username, String password); + + boolean createAccount(String firstName, String lastName, String ssn, String password); + + boolean updatePassword(long userId, String newPassword); + + boolean deleteAccount(long userId); +} diff --git a/src/main/java/com/example/JdbcAccountRepository.java b/src/main/java/com/example/JdbcAccountRepository.java new file mode 100644 index 0000000..5d04111 --- /dev/null +++ b/src/main/java/com/example/JdbcAccountRepository.java @@ -0,0 +1,35 @@ +package com.example; + +public class JdbcAccountRepository implements AccountRepository{ + + private final String jdbcUrl; + private final String dbUser; + private final String dbPass; + + public JdbcAccountRepository(String jdbcUrl, String dbUser, String dbPass){ + this.jdbcUrl=jdbcUrl; + this.dbUser=dbUser; + this.dbPass=dbPass; + } + + + @Override + public boolean isValidLogin(String username, String password) { + return false; + } + + @Override + public boolean createAccount(String firstName, String lastName, String ssn, String password) { + return false; + } + + @Override + public boolean updatePassword(long userId, String newPassword) { + return false; + } + + @Override + public boolean deleteAccount(long userId) { + return false; + } +} diff --git a/src/main/java/com/example/JdbcMoonMissionRepository.java b/src/main/java/com/example/JdbcMoonMissionRepository.java new file mode 100644 index 0000000..24e3ab7 --- /dev/null +++ b/src/main/java/com/example/JdbcMoonMissionRepository.java @@ -0,0 +1,4 @@ +package com.example; + +public class JdbcMoonMissionRepository { +} diff --git a/src/main/java/com/example/MoonMissionRepository.java b/src/main/java/com/example/MoonMissionRepository.java new file mode 100644 index 0000000..760553e --- /dev/null +++ b/src/main/java/com/example/MoonMissionRepository.java @@ -0,0 +1,17 @@ +package com.example; + +import java.util.List; + +public interface MoonMissionRepository { + + // List of all names: + List findAllSpacecraftNames(); + + //Fetch assignment from ID: + OptionalfindById(long missionId); + + //Number of assignments per year: + int countByYear(int year); + + +} From 82e1be09a70e8a1360d0edbe8839c3cab6cfc96d Mon Sep 17 00:00:00 2001 From: Annika Holmqvist Date: Tue, 2 Dec 2025 12:49:08 +0100 Subject: [PATCH 03/17] Implement SQL-based login validation in JdbcAccountRepository --- .../com/example/JdbcAccountRepository.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/main/java/com/example/JdbcAccountRepository.java b/src/main/java/com/example/JdbcAccountRepository.java index 5d04111..eca8c02 100644 --- a/src/main/java/com/example/JdbcAccountRepository.java +++ b/src/main/java/com/example/JdbcAccountRepository.java @@ -1,5 +1,7 @@ package com.example; +import java.sql.*; + public class JdbcAccountRepository implements AccountRepository{ private final String jdbcUrl; @@ -15,7 +17,27 @@ public JdbcAccountRepository(String jdbcUrl, String dbUser, String dbPass){ @Override public boolean isValidLogin(String username, String password) { + String sql = "SELECT COUNT(*) FROM account WHERE name = ? AND password = ?"; + + try( + Connection connection= DriverManager.getConnection(jdbcUrl,dbUser,dbPass); + PreparedStatement ps= connection.prepareStatement(sql); + ) { + ps.setString(1, username); + ps.setString(2, password); + + try(ResultSet rs = ps.executeQuery()) { + if (rs.next()){ + return rs.getInt(1)>0; + } + } + + } catch (SQLException e){ + return false; + } + return false; + } @Override From b161192651323122672e942db13643b812f4bd79 Mon Sep 17 00:00:00 2001 From: Annika Holmqvist Date: Tue, 2 Dec 2025 15:03:01 +0100 Subject: [PATCH 04/17] Add SQL-based account creation to JdbcAccountRepository --- .../java/com/example/JdbcAccountRepository.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/JdbcAccountRepository.java b/src/main/java/com/example/JdbcAccountRepository.java index eca8c02..8842fe2 100644 --- a/src/main/java/com/example/JdbcAccountRepository.java +++ b/src/main/java/com/example/JdbcAccountRepository.java @@ -42,7 +42,22 @@ public boolean isValidLogin(String username, String password) { @Override public boolean createAccount(String firstName, String lastName, String ssn, String password) { - return false; + String sql= "INSERT INTO account (first_name, last_name, ssn, password) VALUES (?, ?, ?, ?)"; + + try(Connection connection= DriverManager.getConnection(jdbcUrl,dbUser,dbPass); + PreparedStatement ps= connection.prepareStatement(sql)){ + + ps.setString(1, firstName); + ps.setString(2, lastName); + ps.setString(3, ssn); + ps.setString(4, password); + + int rowsAffected= ps.executeUpdate(); + return rowsAffected>0; + } catch (SQLException e){ + System.err.println("Could not create account: " + e.getMessage()); + return false; + } } @Override From ffb31be3c7115011a21760bdaa0dfef596d5292d Mon Sep 17 00:00:00 2001 From: Annika Holmqvist Date: Tue, 2 Dec 2025 15:12:56 +0100 Subject: [PATCH 05/17] Implement SQL-based password update in JdbcAccountRepository --- .../java/com/example/JdbcAccountRepository.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/JdbcAccountRepository.java b/src/main/java/com/example/JdbcAccountRepository.java index 8842fe2..a196837 100644 --- a/src/main/java/com/example/JdbcAccountRepository.java +++ b/src/main/java/com/example/JdbcAccountRepository.java @@ -62,7 +62,21 @@ public boolean createAccount(String firstName, String lastName, String ssn, Stri @Override public boolean updatePassword(long userId, String newPassword) { - return false; + String sql= "UPDATE account SET password = ? WHERE user_id = ?"; + + try(Connection connection= DriverManager.getConnection(jdbcUrl,dbUser,dbPass); + PreparedStatement ps=connection.prepareStatement(sql)){ + + ps.setString(1, newPassword); + ps.setLong(2, userId); + + int rowsAffected=ps.executeUpdate(); + return rowsAffected>0; + + }catch (SQLException e){ + System.err.println(" Could not update password: " + e.getMessage()); + return false; + } } @Override From 004c36a89f9623a053994e70d6bdedf1f794cfe3 Mon Sep 17 00:00:00 2001 From: Annika Holmqvist Date: Tue, 2 Dec 2025 15:27:23 +0100 Subject: [PATCH 06/17] Implement SQL-based account deletion in JdbcAccountRepository --- .../java/com/example/JdbcAccountRepository.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/JdbcAccountRepository.java b/src/main/java/com/example/JdbcAccountRepository.java index a196837..ccfc1d9 100644 --- a/src/main/java/com/example/JdbcAccountRepository.java +++ b/src/main/java/com/example/JdbcAccountRepository.java @@ -81,6 +81,21 @@ public boolean updatePassword(long userId, String newPassword) { @Override public boolean deleteAccount(long userId) { - return false; + String sql= " DELETE FROM account WHERE user_id = ?"; + + try(Connection connection= DriverManager.getConnection(jdbcUrl,dbUser,dbPass); + PreparedStatement ps=connection.prepareStatement(sql)){ + + ps.setLong(1, userId); + + int rowsAffected=ps.executeUpdate(); + return rowsAffected>0; + + }catch (SQLException e){ + System.err.println(" Could not delete account: " + e.getMessage()); + return false; + } + + } } From d62076c8410e35aa21ddceb00f67d6849ae491fa Mon Sep 17 00:00:00 2001 From: Annika Holmqvist Date: Tue, 2 Dec 2025 16:01:44 +0100 Subject: [PATCH 07/17] Add SQL-based MoonMission repository with initial methods --- .../example/JdbcMoonMissionRepository.java | 74 ++++++++++++++++++- src/main/java/com/example/MoonMission.java | 8 ++ .../com/example/MoonMissionRepository.java | 3 +- 3 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/example/MoonMission.java diff --git a/src/main/java/com/example/JdbcMoonMissionRepository.java b/src/main/java/com/example/JdbcMoonMissionRepository.java index 24e3ab7..ed6fe01 100644 --- a/src/main/java/com/example/JdbcMoonMissionRepository.java +++ b/src/main/java/com/example/JdbcMoonMissionRepository.java @@ -1,4 +1,76 @@ package com.example; -public class JdbcMoonMissionRepository { +import java.sql.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public class JdbcMoonMissionRepository implements MoonMissionRepository{ + + + private final String jdbcUrl; + private final String dbUser; + private final String dbPass; + + + public JdbcMoonMissionRepository(String jdbcUrl, String dbUser, String dbPass) { + this.jdbcUrl = jdbcUrl; + this.dbUser = dbUser; + this.dbPass = dbPass; + } + + @Override + public List findAllSpacecraftNames() { + List names = new ArrayList<>(); + + String sql= "SELECT spacecraft_name FROM moon_mission ORDER BY launch_year"; + + try( Connection connection= DriverManager.getConnection(jdbcUrl,dbUser,dbPass); + Statement statement= connection.createStatement(); + ResultSet rs= statement.executeQuery(sql)) { + + while (rs.next()){ + names.add(rs.getString("spacecraft_name")); + + } + } catch (SQLException e){ + System.err.println(" Failure to find names: " +e.getMessage()); + + } + + return names; + } + + @Override + public Optional findById(long missionId) { + String sql = "SELECT mission_id, spacecraft_name, launchYear, description FROM moon_mission WHERE mission_id = ?"; + + try( Connection connection= DriverManager.getConnection(jdbcUrl,dbUser,dbPass); + PreparedStatement ps= connection.prepareStatement(sql)){ + + ps.setLong(1, missionId); + + try(ResultSet rs = ps.executeQuery()){ + if(rs.next()){ + //Map to MoonMission object: + MoonMission mission= new MoonMission( + rs.getLong("mission_id"), + rs.getString("spacecraft_name"), + rs.getInt("launch_year"), + rs.getString("description") + ); + + return Optional.of(mission); + } + } + }catch (SQLException e){ + System.err.println(" Failure in receiving mission per ID: " + e.getMessage()); + } + return Optional.empty(); + } + + @Override + public int countByYear(int year) { + return 0; + } } diff --git a/src/main/java/com/example/MoonMission.java b/src/main/java/com/example/MoonMission.java new file mode 100644 index 0000000..13a5c9f --- /dev/null +++ b/src/main/java/com/example/MoonMission.java @@ -0,0 +1,8 @@ +package com.example; + +public record MoonMission( + long missionId, + String spacecraftName, + int launchYear, + String description +) { } diff --git a/src/main/java/com/example/MoonMissionRepository.java b/src/main/java/com/example/MoonMissionRepository.java index 760553e..37a5045 100644 --- a/src/main/java/com/example/MoonMissionRepository.java +++ b/src/main/java/com/example/MoonMissionRepository.java @@ -1,6 +1,7 @@ package com.example; import java.util.List; +import java.util.Optional; public interface MoonMissionRepository { @@ -8,7 +9,7 @@ public interface MoonMissionRepository { List findAllSpacecraftNames(); //Fetch assignment from ID: - OptionalfindById(long missionId); + Optional findById(long missionId); //Number of assignments per year: int countByYear(int year); From d94ebdfd17f2dce9aa0b6e3616298b5fca97a815 Mon Sep 17 00:00:00 2001 From: Annika Holmqvist Date: Tue, 2 Dec 2025 16:10:16 +0100 Subject: [PATCH 08/17] Implement SQL-based mission counting by year in JdbcMoonMissionRepository --- .../com/example/JdbcMoonMissionRepository.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/main/java/com/example/JdbcMoonMissionRepository.java b/src/main/java/com/example/JdbcMoonMissionRepository.java index ed6fe01..d142487 100644 --- a/src/main/java/com/example/JdbcMoonMissionRepository.java +++ b/src/main/java/com/example/JdbcMoonMissionRepository.java @@ -71,6 +71,23 @@ public Optional findById(long missionId) { @Override public int countByYear(int year) { + String sql = "SELECT COUNT(*) FROM moon_mission WHERE launch_year = ?"; + + try( Connection connection=DriverManager.getConnection(jdbcUrl,dbUser,dbPass); + PreparedStatement ps=connection.prepareStatement(sql)){ + + ps.setInt(1, year); + + try(ResultSet rs=ps.executeQuery()){ + if(rs.next()){ + //Result is COUNT(*) column 1: + return rs.getInt(1); + } + } + } catch (SQLException e ){ + System.err.println(" Failure in counting missions per year: " + e.getMessage()); + } + //returnera 0 om inga resultat finns: return 0; } } From b5582c1168d8da7585e4dff573179f48fefd8e52 Mon Sep 17 00:00:00 2001 From: Annika Holmqvist Date: Tue, 2 Dec 2025 16:51:49 +0100 Subject: [PATCH 09/17] Add user login handling and initialization of repositories in Main class --- src/main/java/com/example/Main.java | 37 +++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/main/java/com/example/Main.java b/src/main/java/com/example/Main.java index 6dc6fbd..0731b3b 100644 --- a/src/main/java/com/example/Main.java +++ b/src/main/java/com/example/Main.java @@ -4,9 +4,15 @@ import java.sql.DriverManager; import java.sql.SQLException; import java.util.Arrays; +import java.util.Scanner; public class Main { + private AccountRepository accountRepository; + private MoonMissionRepository missionRepository; + private Scanner scanner; + + static void main(String[] args) { if (isDevMode(args)) { DevDatabaseInitializer.start(); @@ -31,6 +37,37 @@ public void run() { throw new RuntimeException(e); } //Todo: Starting point for your code + this.accountRepository=new JdbcAccountRepository(jdbcUrl, dbUser, dbPass); + this.missionRepository=new JdbcMoonMissionRepository(jdbcUrl,dbUser,dbPass); + this.scanner=new Scanner(System.in); + + if(handleLogin()){ + showMainMenu(); + } + + scanner.close(); + } + + private boolean handleLogin() { + boolean loggedIn=false; + while(!loggedIn){ + System.out.println("Username: "); + String username=scanner.nextLine(); + System.out.println("Password: "); + String password= scanner.nextLine(); + + if (accountRepository.isValidLogin(username, password)){ + System.out.println("login successful! "); + loggedIn=true; + } else{ + System.out.println(" Login invalid. Enter 0 to exit, or any other key to try again. "); + String choice= scanner.nextLine().trim(); + if (choice.equals("0")){ + return false; + } + } + } + return true; } /** From eb4ec2bde302bb801d4ad3cfe7dfb247c42e1c33 Mon Sep 17 00:00:00 2001 From: Annika Holmqvist Date: Tue, 2 Dec 2025 17:07:52 +0100 Subject: [PATCH 10/17] Add main menu and moon mission listing/retrieval methods to Main class --- src/main/java/com/example/Main.java | 73 ++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/Main.java b/src/main/java/com/example/Main.java index 0731b3b..393d264 100644 --- a/src/main/java/com/example/Main.java +++ b/src/main/java/com/example/Main.java @@ -4,6 +4,8 @@ import java.sql.DriverManager; import java.sql.SQLException; import java.util.Arrays; +import java.util.List; +import java.util.Optional; import java.util.Scanner; public class Main { @@ -48,6 +50,8 @@ public void run() { scanner.close(); } + + private boolean handleLogin() { boolean loggedIn=false; while(!loggedIn){ @@ -57,7 +61,7 @@ private boolean handleLogin() { String password= scanner.nextLine(); if (accountRepository.isValidLogin(username, password)){ - System.out.println("login successful! "); + System.out.println("Login successful! "); loggedIn=true; } else{ System.out.println(" Login invalid. Enter 0 to exit, or any other key to try again. "); @@ -70,6 +74,73 @@ private boolean handleLogin() { return true; } + private void showMainMenu() { + boolean running= true; + while (running){ + System.out.println("\n--- Main Menu ---"); + System.out.println("1) List moon missions"); + System.out.println("2) Get a moon mission by mission_id"); + System.out.println("3) Count missions for a given year"); + System.out.println("4) Create an account"); + System.out.println("5) Update an account password"); + System.out.println("6) Delete an account"); + System.out.println("0) Exit"); + System.out.print("Choose an option: "); + + String choice=scanner.nextLine(); + + try{ + switch(choice){ + case "1": listMoonMissions(); break; + case "2": getMissionById(); break; + case "3": countMissionsByYear(); break; + case "4": createAccount(); break; + case "5": updateAccountPassword(); break; + case "6": deleteAccount(); break; + case "0": running = false; break; + default: System.out.println("Invalid option. Please try again."); break; + + } + } catch (Exception e){ + //to avoid numberFormat exceptions. + System.err.println(" An error occurred: " + e.getMessage()); + scanner.nextLine(); + } + + } + } + + + + private void listMoonMissions() { + System.out.println("\n--- Spacecraft Names ---"); + List names = missionRepository.findAllSpacecraftNames(); + names.forEach(name-> System.out.println("- " + name)); + } + + private void getMissionById() { + System.out.println("Enter Mission ID: "); + try{ + long id = Long.parseLong(scanner.nextLine()); + Optional mission = missionRepository.findById(id); + + if (mission.isPresent()){ + MoonMission m=mission.get(); + + System.out.println("\nMission details for ID " + m.missionId() + ":"); + System.out.println(" Name: " + m.spacecraftName()); + System.out.println(" Year: " + m.launchYear()); + System.out.println(" Description: " + m.description()); + } else{ + System.out.println("Mission not found."); + } + + + } catch(NumberFormatException e){ + System.out.println("Invalid ID format."); + } + } + /** * Determines if the application is running in development mode based on system properties, * environment variables, or command-line arguments. From 78ff8b9df936995eb4bec7282e6e862a522b35d4 Mon Sep 17 00:00:00 2001 From: Annika Holmqvist Date: Tue, 2 Dec 2025 17:25:41 +0100 Subject: [PATCH 11/17] Add method to count missions by year in Main class --- src/main/java/com/example/Main.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/com/example/Main.java b/src/main/java/com/example/Main.java index 393d264..5694c18 100644 --- a/src/main/java/com/example/Main.java +++ b/src/main/java/com/example/Main.java @@ -112,6 +112,7 @@ private void showMainMenu() { + private void listMoonMissions() { System.out.println("\n--- Spacecraft Names ---"); List names = missionRepository.findAllSpacecraftNames(); @@ -141,6 +142,19 @@ private void getMissionById() { } } + private void countMissionsByYear() { + System.out.println(" Enter launch year: "); + + try{ + int year= Integer.parseInt(scanner.nextLine()); + int count= missionRepository.countByYear(year); + + System.out.println(" There were " + count + " missions launched in " + year + "."); + } catch(NumberFormatException e){ + System.out.println(" Invalid year format."); + } + } + /** * Determines if the application is running in development mode based on system properties, * environment variables, or command-line arguments. From 9da5060e6805c337d7112aff6ffe7c84a4d0533c Mon Sep 17 00:00:00 2001 From: Annika Holmqvist Date: Tue, 2 Dec 2025 17:35:11 +0100 Subject: [PATCH 12/17] Add account creation, password update, and deletion methods to Main class --- src/main/java/com/example/Main.java | 58 +++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/main/java/com/example/Main.java b/src/main/java/com/example/Main.java index 5694c18..a84ff90 100644 --- a/src/main/java/com/example/Main.java +++ b/src/main/java/com/example/Main.java @@ -155,6 +155,64 @@ private void countMissionsByYear() { } } + private void createAccount(){ + System.out.println("\n--- Create Account ---"); + System.out.print("Enter first name: "); + String firstName = scanner.nextLine(); + System.out.print("Enter last name: "); + String lastName = scanner.nextLine(); + System.out.print("Enter SSN: "); + String ssn = scanner.nextLine(); + System.out.print("Enter password: "); + String password = scanner.nextLine(); + + if(accountRepository.createAccount(firstName,lastName,ssn,password)){ + System.out.println(" Account created successfully!"); + } else{ + System.out.println("failed to create account."); + } + + } + + private void updateAccountPassword(){ + System.out.println("Enter user ID to update: "); + + try{ + long userId=Long.parseLong(scanner.nextLine()); + System.out.println("Enter password: "); + String newPassword= scanner.nextLine(); + + + if (accountRepository.updatePassword(userId,newPassword)){ + System.out.println("Password updated successfully!"); + } else{ + System.out.println("failed to update password."); + } + } catch(NumberFormatException e ){ + System.out.println("Invalid User ID format."); + } + + } + + private void deleteAccount(){ + System.out.println(" Enter User ID to delete: "); + + try{ + long userId=Long.parseLong(scanner.nextLine()); + + if (accountRepository.deleteAccount(userId)){ + System.out.println("Account deleted successfully!"); + }else{ + System.out.println("failed to delete account. User id not found."); + } + + } catch (NumberFormatException e){ + System.out.println("Invalid User ID format."); + } + + + } + /** * Determines if the application is running in development mode based on system properties, * environment variables, or command-line arguments. From bb9f1e2c4337e51b9f229b2e0a633d00344dacb4 Mon Sep 17 00:00:00 2001 From: Annika Holmqvist Date: Tue, 2 Dec 2025 18:13:37 +0100 Subject: [PATCH 13/17] Refactor MoonMission model and repository to include detailed attributes; update Main class methods accordingly --- .../com/example/JdbcMoonMissionRepository.java | 18 +++++++++++------- src/main/java/com/example/Main.java | 13 ++++++++----- src/main/java/com/example/MoonMission.java | 11 ++++++++--- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/example/JdbcMoonMissionRepository.java b/src/main/java/com/example/JdbcMoonMissionRepository.java index d142487..065a888 100644 --- a/src/main/java/com/example/JdbcMoonMissionRepository.java +++ b/src/main/java/com/example/JdbcMoonMissionRepository.java @@ -1,6 +1,7 @@ package com.example; import java.sql.*; +import java.time.LocalDate; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -23,14 +24,14 @@ public JdbcMoonMissionRepository(String jdbcUrl, String dbUser, String dbPass) { public List findAllSpacecraftNames() { List names = new ArrayList<>(); - String sql= "SELECT spacecraft_name FROM moon_mission ORDER BY launch_year"; + String sql= "SELECT spacecraft FROM moon_mission ORDER BY launch_date"; try( Connection connection= DriverManager.getConnection(jdbcUrl,dbUser,dbPass); Statement statement= connection.createStatement(); ResultSet rs= statement.executeQuery(sql)) { while (rs.next()){ - names.add(rs.getString("spacecraft_name")); + names.add(rs.getString("spacecraft")); } } catch (SQLException e){ @@ -43,7 +44,7 @@ public List findAllSpacecraftNames() { @Override public Optional findById(long missionId) { - String sql = "SELECT mission_id, spacecraft_name, launchYear, description FROM moon_mission WHERE mission_id = ?"; + String sql = "SELECT mission_id, spacecraft, launch_date, carrier_rocket, operator, mission_type, outcome FROM moon_mission WHERE mission_id = ?"; try( Connection connection= DriverManager.getConnection(jdbcUrl,dbUser,dbPass); PreparedStatement ps= connection.prepareStatement(sql)){ @@ -55,9 +56,12 @@ public Optional findById(long missionId) { //Map to MoonMission object: MoonMission mission= new MoonMission( rs.getLong("mission_id"), - rs.getString("spacecraft_name"), - rs.getInt("launch_year"), - rs.getString("description") + rs.getString("spacecraft"), + rs.getObject("launch_date", LocalDate.class), + rs.getString("outcome"), + rs.getString("carrier_rocket"), + rs.getString("operator"), + rs.getString("mission_type") ); return Optional.of(mission); @@ -71,7 +75,7 @@ public Optional findById(long missionId) { @Override public int countByYear(int year) { - String sql = "SELECT COUNT(*) FROM moon_mission WHERE launch_year = ?"; + String sql = "SELECT COUNT(*) FROM moon_mission WHERE YEAR(launch_date) = ?"; try( Connection connection=DriverManager.getConnection(jdbcUrl,dbUser,dbPass); PreparedStatement ps=connection.prepareStatement(sql)){ diff --git a/src/main/java/com/example/Main.java b/src/main/java/com/example/Main.java index a84ff90..ab6e49a 100644 --- a/src/main/java/com/example/Main.java +++ b/src/main/java/com/example/Main.java @@ -64,7 +64,7 @@ private boolean handleLogin() { System.out.println("Login successful! "); loggedIn=true; } else{ - System.out.println(" Login invalid. Enter 0 to exit, or any other key to try again. "); + System.out.println(" Invalid username or password. "); String choice= scanner.nextLine().trim(); if (choice.equals("0")){ return false; @@ -114,7 +114,7 @@ private void showMainMenu() { private void listMoonMissions() { - System.out.println("\n--- Spacecraft Names ---"); + List names = missionRepository.findAllSpacecraftNames(); names.forEach(name-> System.out.println("- " + name)); } @@ -129,9 +129,12 @@ private void getMissionById() { MoonMission m=mission.get(); System.out.println("\nMission details for ID " + m.missionId() + ":"); - System.out.println(" Name: " + m.spacecraftName()); - System.out.println(" Year: " + m.launchYear()); - System.out.println(" Description: " + m.description()); + System.out.println(" Name: " + m.spacecraft()); + System.out.println(" Year: " + m.launch_date()); + System.out.println(" Outcome: " + m.outcome()); + System.out.println(" Carrier: " + m.carrier_rocket()); + System.out.println(" Operator: " + m.operator()); + System.out.println(" Mission type: " + m.mission_type()); } else{ System.out.println("Mission not found."); } diff --git a/src/main/java/com/example/MoonMission.java b/src/main/java/com/example/MoonMission.java index 13a5c9f..4fbec23 100644 --- a/src/main/java/com/example/MoonMission.java +++ b/src/main/java/com/example/MoonMission.java @@ -1,8 +1,13 @@ package com.example; +import java.time.LocalDate; + public record MoonMission( long missionId, - String spacecraftName, - int launchYear, - String description + String spacecraft, + LocalDate launch_date, + String carrier_rocket, + String operator, + String mission_type, + String outcome ) { } From 30091393a63981067ff58ad8286cc2f2a9bb2466 Mon Sep 17 00:00:00 2001 From: Annika Holmqvist Date: Wed, 3 Dec 2025 15:10:25 +0100 Subject: [PATCH 14/17] Refactor repositories to use `DataSource` abstraction; centralize connection handling with `SimpleDriverManagerDataSource` implementation --- src/main/java/com/example/DataSource.java | 11 ++++++++ .../com/example/JdbcAccountRepository.java | 23 ++++++++-------- .../example/JdbcMoonMissionRepository.java | 21 +++++++-------- src/main/java/com/example/Main.java | 9 +++++-- .../SimpleDriverManagerDataSource.java | 27 +++++++++++++++++++ 5 files changed, 65 insertions(+), 26 deletions(-) create mode 100644 src/main/java/com/example/DataSource.java create mode 100644 src/main/java/com/example/SimpleDriverManagerDataSource.java diff --git a/src/main/java/com/example/DataSource.java b/src/main/java/com/example/DataSource.java new file mode 100644 index 0000000..de0437a --- /dev/null +++ b/src/main/java/com/example/DataSource.java @@ -0,0 +1,11 @@ +package com.example; + +import java.sql.Connection; +import java.sql.SQLException; + +// define a new standard method for connection +public interface DataSource { + + Connection getConnection() throws SQLException; + +} diff --git a/src/main/java/com/example/JdbcAccountRepository.java b/src/main/java/com/example/JdbcAccountRepository.java index ccfc1d9..f3fbc1d 100644 --- a/src/main/java/com/example/JdbcAccountRepository.java +++ b/src/main/java/com/example/JdbcAccountRepository.java @@ -4,14 +4,13 @@ public class JdbcAccountRepository implements AccountRepository{ - private final String jdbcUrl; - private final String dbUser; - private final String dbPass; - - public JdbcAccountRepository(String jdbcUrl, String dbUser, String dbPass){ - this.jdbcUrl=jdbcUrl; - this.dbUser=dbUser; - this.dbPass=dbPass; + //Fetching Datasource object + private final DataSource dataSource; + + + //injection the datasource object into the constructor: + public JdbcAccountRepository(DataSource dataSource){ + this.dataSource=dataSource; } @@ -20,7 +19,7 @@ public boolean isValidLogin(String username, String password) { String sql = "SELECT COUNT(*) FROM account WHERE name = ? AND password = ?"; try( - Connection connection= DriverManager.getConnection(jdbcUrl,dbUser,dbPass); + Connection connection= dataSource.getConnection(); PreparedStatement ps= connection.prepareStatement(sql); ) { ps.setString(1, username); @@ -44,7 +43,7 @@ public boolean isValidLogin(String username, String password) { public boolean createAccount(String firstName, String lastName, String ssn, String password) { String sql= "INSERT INTO account (first_name, last_name, ssn, password) VALUES (?, ?, ?, ?)"; - try(Connection connection= DriverManager.getConnection(jdbcUrl,dbUser,dbPass); + try(Connection connection= dataSource.getConnection(); PreparedStatement ps= connection.prepareStatement(sql)){ ps.setString(1, firstName); @@ -64,7 +63,7 @@ public boolean createAccount(String firstName, String lastName, String ssn, Stri public boolean updatePassword(long userId, String newPassword) { String sql= "UPDATE account SET password = ? WHERE user_id = ?"; - try(Connection connection= DriverManager.getConnection(jdbcUrl,dbUser,dbPass); + try(Connection connection= dataSource.getConnection(); PreparedStatement ps=connection.prepareStatement(sql)){ ps.setString(1, newPassword); @@ -83,7 +82,7 @@ public boolean updatePassword(long userId, String newPassword) { public boolean deleteAccount(long userId) { String sql= " DELETE FROM account WHERE user_id = ?"; - try(Connection connection= DriverManager.getConnection(jdbcUrl,dbUser,dbPass); + try(Connection connection= dataSource.getConnection(); PreparedStatement ps=connection.prepareStatement(sql)){ ps.setLong(1, userId); diff --git a/src/main/java/com/example/JdbcMoonMissionRepository.java b/src/main/java/com/example/JdbcMoonMissionRepository.java index 065a888..80a030e 100644 --- a/src/main/java/com/example/JdbcMoonMissionRepository.java +++ b/src/main/java/com/example/JdbcMoonMissionRepository.java @@ -8,16 +8,13 @@ public class JdbcMoonMissionRepository implements MoonMissionRepository{ + //declare datasource object + private final DataSource dataSource; - private final String jdbcUrl; - private final String dbUser; - private final String dbPass; - - public JdbcMoonMissionRepository(String jdbcUrl, String dbUser, String dbPass) { - this.jdbcUrl = jdbcUrl; - this.dbUser = dbUser; - this.dbPass = dbPass; +// inject into contructor: + public JdbcMoonMissionRepository(DataSource dataSource){ + this.dataSource=dataSource; } @Override @@ -26,7 +23,7 @@ public List findAllSpacecraftNames() { String sql= "SELECT spacecraft FROM moon_mission ORDER BY launch_date"; - try( Connection connection= DriverManager.getConnection(jdbcUrl,dbUser,dbPass); + try( Connection connection= dataSource.getConnection(); Statement statement= connection.createStatement(); ResultSet rs= statement.executeQuery(sql)) { @@ -46,7 +43,7 @@ public List findAllSpacecraftNames() { public Optional findById(long missionId) { String sql = "SELECT mission_id, spacecraft, launch_date, carrier_rocket, operator, mission_type, outcome FROM moon_mission WHERE mission_id = ?"; - try( Connection connection= DriverManager.getConnection(jdbcUrl,dbUser,dbPass); + try( Connection connection= dataSource.getConnection(); PreparedStatement ps= connection.prepareStatement(sql)){ ps.setLong(1, missionId); @@ -77,7 +74,7 @@ public Optional findById(long missionId) { public int countByYear(int year) { String sql = "SELECT COUNT(*) FROM moon_mission WHERE YEAR(launch_date) = ?"; - try( Connection connection=DriverManager.getConnection(jdbcUrl,dbUser,dbPass); + try( Connection connection=dataSource.getConnection(); PreparedStatement ps=connection.prepareStatement(sql)){ ps.setInt(1, year); @@ -91,7 +88,7 @@ public int countByYear(int year) { } catch (SQLException e ){ System.err.println(" Failure in counting missions per year: " + e.getMessage()); } - //returnera 0 om inga resultat finns: + //return 0 if no results are found: return 0; } } diff --git a/src/main/java/com/example/Main.java b/src/main/java/com/example/Main.java index ab6e49a..48dcbe3 100644 --- a/src/main/java/com/example/Main.java +++ b/src/main/java/com/example/Main.java @@ -39,8 +39,13 @@ public void run() { throw new RuntimeException(e); } //Todo: Starting point for your code - this.accountRepository=new JdbcAccountRepository(jdbcUrl, dbUser, dbPass); - this.missionRepository=new JdbcMoonMissionRepository(jdbcUrl,dbUser,dbPass); + + //create datasource: + DataSource dataSource=new SimpleDriverManagerDataSource(jdbcUrl,dbUser,dbPass); + + //create Repositories by injecting datasource instead of jdbcUrl, dbUser, dbPass. + this.accountRepository=new JdbcAccountRepository(dataSource); + this.missionRepository=new JdbcMoonMissionRepository(dataSource); this.scanner=new Scanner(System.in); if(handleLogin()){ diff --git a/src/main/java/com/example/SimpleDriverManagerDataSource.java b/src/main/java/com/example/SimpleDriverManagerDataSource.java new file mode 100644 index 0000000..68d9b88 --- /dev/null +++ b/src/main/java/com/example/SimpleDriverManagerDataSource.java @@ -0,0 +1,27 @@ +package com.example; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +public class SimpleDriverManagerDataSource implements DataSource { + + private final String url; + private final String user; + private final String password; + + public SimpleDriverManagerDataSource(String url, String user, String password) { + this.url = url; + this.user = user; + this.password = password; + } + + + @Override + public Connection getConnection() throws SQLException { + + //We want the connection inside Datasource and not the Repository + return DriverManager.getConnection(url, user, password); + + } +} From fac4064c879451f214a13af04a52bcdcba352e44 Mon Sep 17 00:00:00 2001 From: Annika Holmqvist Date: Wed, 3 Dec 2025 15:24:42 +0100 Subject: [PATCH 15/17] Refactor repositories to use `DataSource` abstraction; centralize connection handling with `SimpleDriverManagerDataSource` implementation --- src/main/java/com/example/DataSource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/example/DataSource.java b/src/main/java/com/example/DataSource.java index de0437a..b96b0c9 100644 --- a/src/main/java/com/example/DataSource.java +++ b/src/main/java/com/example/DataSource.java @@ -8,4 +8,4 @@ public interface DataSource { Connection getConnection() throws SQLException; -} +} \ No newline at end of file From ec2d55f907ee063e04647dff553a293251b03438 Mon Sep 17 00:00:00 2001 From: Annika Holmqvist Date: Fri, 5 Dec 2025 15:12:06 +0100 Subject: [PATCH 16/17] Generate username during account creation, fix JdbcMoonMissionRepository mapping --- src/main/java/com/example/JdbcAccountRepository.java | 11 +++++++++-- .../java/com/example/JdbcMoonMissionRepository.java | 6 +++--- src/main/java/com/example/Main.java | 6 ++---- .../com/example/SimpleDriverManagerDataSource.java | 3 +++ 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/example/JdbcAccountRepository.java b/src/main/java/com/example/JdbcAccountRepository.java index f3fbc1d..0b4963b 100644 --- a/src/main/java/com/example/JdbcAccountRepository.java +++ b/src/main/java/com/example/JdbcAccountRepository.java @@ -20,7 +20,7 @@ public boolean isValidLogin(String username, String password) { try( Connection connection= dataSource.getConnection(); - PreparedStatement ps= connection.prepareStatement(sql); + PreparedStatement ps= connection.prepareStatement(sql) ) { ps.setString(1, username); ps.setString(2, password); @@ -32,6 +32,7 @@ public boolean isValidLogin(String username, String password) { } } catch (SQLException e){ + System.err.println("Database error during login validation: " + e.getMessage()); return false; } @@ -41,7 +42,12 @@ public boolean isValidLogin(String username, String password) { @Override public boolean createAccount(String firstName, String lastName, String ssn, String password) { - String sql= "INSERT INTO account (first_name, last_name, ssn, password) VALUES (?, ?, ?, ?)"; + + // concatenation of firstname and lastname to create username (name column in sql) for proper usage of the app. + String username = firstName.substring(0, Math.min(firstName.length(), 3)) + + lastName.substring(0, Math.min(lastName.length(), 3)); + + String sql= "INSERT INTO account (first_name, last_name, ssn, password, name) VALUES (?, ?, ?, ?, ?)"; try(Connection connection= dataSource.getConnection(); PreparedStatement ps= connection.prepareStatement(sql)){ @@ -50,6 +56,7 @@ public boolean createAccount(String firstName, String lastName, String ssn, Stri ps.setString(2, lastName); ps.setString(3, ssn); ps.setString(4, password); + ps.setString(5, username); int rowsAffected= ps.executeUpdate(); return rowsAffected>0; diff --git a/src/main/java/com/example/JdbcMoonMissionRepository.java b/src/main/java/com/example/JdbcMoonMissionRepository.java index 80a030e..da91a7b 100644 --- a/src/main/java/com/example/JdbcMoonMissionRepository.java +++ b/src/main/java/com/example/JdbcMoonMissionRepository.java @@ -52,13 +52,13 @@ public Optional findById(long missionId) { if(rs.next()){ //Map to MoonMission object: MoonMission mission= new MoonMission( - rs.getLong("mission_id"), + rs.getInt("mission_id"), rs.getString("spacecraft"), rs.getObject("launch_date", LocalDate.class), - rs.getString("outcome"), rs.getString("carrier_rocket"), rs.getString("operator"), - rs.getString("mission_type") + rs.getString("mission_type"), + rs.getString("outcome") ); return Optional.of(mission); diff --git a/src/main/java/com/example/Main.java b/src/main/java/com/example/Main.java index 48dcbe3..0a3594f 100644 --- a/src/main/java/com/example/Main.java +++ b/src/main/java/com/example/Main.java @@ -69,7 +69,7 @@ private boolean handleLogin() { System.out.println("Login successful! "); loggedIn=true; } else{ - System.out.println(" Invalid username or password. "); + System.out.println(" Invalid username or password. Press 0 to exit or any other key to keep trying. "); String choice= scanner.nextLine().trim(); if (choice.equals("0")){ return false; @@ -109,15 +109,13 @@ private void showMainMenu() { } catch (Exception e){ //to avoid numberFormat exceptions. System.err.println(" An error occurred: " + e.getMessage()); - scanner.nextLine(); + } } } - - private void listMoonMissions() { List names = missionRepository.findAllSpacecraftNames(); diff --git a/src/main/java/com/example/SimpleDriverManagerDataSource.java b/src/main/java/com/example/SimpleDriverManagerDataSource.java index 68d9b88..c61d544 100644 --- a/src/main/java/com/example/SimpleDriverManagerDataSource.java +++ b/src/main/java/com/example/SimpleDriverManagerDataSource.java @@ -1,5 +1,7 @@ package com.example; + + import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; @@ -10,6 +12,7 @@ public class SimpleDriverManagerDataSource implements DataSource { private final String user; private final String password; + public SimpleDriverManagerDataSource(String url, String user, String password) { this.url = url; this.user = user; From 1e06b64ff4f4b28e949d96b211bdbbbe43bca4c3 Mon Sep 17 00:00:00 2001 From: Annika Holmqvist Date: Mon, 8 Dec 2025 15:49:40 +0100 Subject: [PATCH 17/17] Fix mission ID type in JdbcMoonMissionRepository; update label in Main class mission details output --- src/main/java/com/example/JdbcMoonMissionRepository.java | 2 +- src/main/java/com/example/Main.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/JdbcMoonMissionRepository.java b/src/main/java/com/example/JdbcMoonMissionRepository.java index da91a7b..fd91279 100644 --- a/src/main/java/com/example/JdbcMoonMissionRepository.java +++ b/src/main/java/com/example/JdbcMoonMissionRepository.java @@ -52,7 +52,7 @@ public Optional findById(long missionId) { if(rs.next()){ //Map to MoonMission object: MoonMission mission= new MoonMission( - rs.getInt("mission_id"), + rs.getLong("mission_id"), rs.getString("spacecraft"), rs.getObject("launch_date", LocalDate.class), rs.getString("carrier_rocket"), diff --git a/src/main/java/com/example/Main.java b/src/main/java/com/example/Main.java index 0a3594f..5047f94 100644 --- a/src/main/java/com/example/Main.java +++ b/src/main/java/com/example/Main.java @@ -133,7 +133,7 @@ private void getMissionById() { System.out.println("\nMission details for ID " + m.missionId() + ":"); System.out.println(" Name: " + m.spacecraft()); - System.out.println(" Year: " + m.launch_date()); + System.out.println(" Date: " + m.launch_date()); System.out.println(" Outcome: " + m.outcome()); System.out.println(" Carrier: " + m.carrier_rocket()); System.out.println(" Operator: " + m.operator());