diff --git a/README.md b/README.md
index d20aaf9..7071577 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
+[](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.
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..c1e2c6f
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,15 @@
+services:
+ mysql:
+ image: mysql:9.5.0
+ environment:
+ MYSQL_ROOT_PASSWORD: root
+ MYSQL_ROOT_HOST: "%"
+ MYSQL_DATABASE: testdb
+ MYSQL_USER: user
+ MYSQL_PASSWORD: pass
+ ports:
+ - "3306:3306"
+ volumes:
+ - mysql_data:/var/lib/mysql
+volumes:
+ mysql_data:
\ No newline at end of file
diff --git a/mvnw b/mvnw
old mode 100644
new mode 100755
diff --git a/pom.xml b/pom.xml
index 002ff66..5a38a0f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,6 +22,11 @@
9.5.0
runtime
+
+ org.slf4j
+ slf4j-api
+ 2.0.17
+
org.junit.jupiter
junit-jupiter
@@ -40,6 +45,11 @@
${mockito.version}
test
+
+ org.slf4j
+ slf4j-nop
+ 2.0.17
+
org.testcontainers
junit-jupiter
diff --git a/src/main/java/com/example/Account.java b/src/main/java/com/example/Account.java
new file mode 100644
index 0000000..573b461
--- /dev/null
+++ b/src/main/java/com/example/Account.java
@@ -0,0 +1,83 @@
+package com.example;
+
+public class Account {
+ private int user_id;
+ private String name, password, first_name, last_name, ssn;
+
+ public Account(int user_id, String name, String password, String first_name, String last_name, String ssn) {
+ this.user_id = user_id;
+ this.name = name;
+ this.password = password;
+ this.first_name = first_name;
+ this.last_name = last_name;
+ this.ssn = ssn;
+ }
+
+ public Account(String name, String password, String first_name, String last_name, String ssn) {
+ this.name = name;
+ this.password = password;
+ this.first_name = first_name;
+ this.last_name = last_name;
+ this.ssn = ssn;
+ }
+
+ public int getUser_id() {
+ return user_id;
+ }
+
+ public void setUser_id(int user_id) {
+ this.user_id = user_id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getFirst_name() {
+ return first_name;
+ }
+
+ public void setFirst_name(String first_name) {
+ this.first_name = first_name;
+ }
+
+ public String getLast_name() {
+ return last_name;
+ }
+
+ public void setLast_name(String last_name) {
+ this.last_name = last_name;
+ }
+
+ public String getSsn() {
+ return ssn;
+ }
+
+ public void setSsn(String ssn) {
+ this.ssn = ssn;
+ }
+
+ @Override
+ public String toString() {
+ return "Account{" +
+ "user_id=" + user_id +
+ ", name='" + name + '\'' +
+ ", password='" + password + '\'' +
+ ", first_name='" + first_name + '\'' +
+ ", last_name='" + last_name + '\'' +
+ ", ssn='" + ssn + '\'' +
+ '}';
+ }
+}
diff --git a/src/main/java/com/example/AccountRepository.java b/src/main/java/com/example/AccountRepository.java
new file mode 100644
index 0000000..73023d3
--- /dev/null
+++ b/src/main/java/com/example/AccountRepository.java
@@ -0,0 +1,15 @@
+package com.example;
+
+import java.util.List;
+import java.util.Optional;
+
+public interface AccountRepository {
+ List findUsernames();
+ List findPasswords();
+ Optional findByUsername(String username);
+ List findAccounts();
+ boolean createAccount(Account account);
+ int countAccounts();
+ boolean updatePassword(int id, String password);
+ boolean deleteAccount(int id);
+}
diff --git a/src/main/java/com/example/AccountRepositoryImpl.java b/src/main/java/com/example/AccountRepositoryImpl.java
new file mode 100644
index 0000000..5bd9137
--- /dev/null
+++ b/src/main/java/com/example/AccountRepositoryImpl.java
@@ -0,0 +1,176 @@
+package com.example;
+
+import javax.sql.DataSource;
+import java.sql.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+public class AccountRepositoryImpl implements AccountRepository {
+ private final DataSource dataSource;
+ Connection connection;
+
+ public AccountRepositoryImpl(DataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+
+
+ @Override
+ public List findUsernames() {
+ List usernames = new ArrayList<>();
+ String sql = "select * from account";
+ try {
+ connection = dataSource.getConnection();
+ PreparedStatement ps = connection.prepareStatement(sql);
+ ResultSet rs = ps.executeQuery();
+ while (rs.next()) {
+ usernames.add(rs.getString("name"));
+ }
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ return usernames;
+ }
+
+ @Override
+ public List findPasswords() {
+ List passwords = new ArrayList<>();
+ String sql = "select * from account";
+ try {
+ connection = dataSource.getConnection();
+ PreparedStatement ps = connection.prepareStatement(sql);
+ ResultSet rs = ps.executeQuery();
+ while (rs.next()) {
+ passwords.add(rs.getString("password"));
+ }
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ return passwords;
+ }
+
+ @Override
+ public Optional findByUsername(String username) {
+ String sql = "select * from account where name = ?";
+ try {
+ connection = dataSource.getConnection();
+ PreparedStatement ps = connection.prepareStatement(sql);
+ ps.setString(1, username);
+ ResultSet rs = ps.executeQuery();
+ if (rs.next()) {
+ Account account = new Account(
+ rs.getInt("user_id"),
+ rs.getString("name"),
+ rs.getString("password"),
+ rs.getString("first_name"),
+ rs.getString("last_name"),
+ rs.getString("ssn")
+ );
+ return Optional.of(account);
+ }
+ else return Optional.empty();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public List findAccounts() {
+ List accounts = new ArrayList<>();
+ String sql = "select * from account";
+ try {
+ connection = dataSource.getConnection();
+ PreparedStatement ps = connection.prepareStatement(sql);
+ ResultSet rs = ps.executeQuery();
+ while (rs.next()) {
+ Account a = new Account(
+ rs.getInt("user_id"),
+ rs.getString("name"),
+ rs.getString("password"),
+ rs.getString("first_name"),
+ rs.getString("last_name"),
+ rs.getString("ssn")
+ );
+ accounts.add(a);
+ }
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ return accounts;
+ }
+
+ @Override
+ public boolean createAccount(Account account) {
+ String sql = "insert into account(name, password, first_name, last_name, ssn) values (?, ?, ?, ?, ?)";
+ try {
+ connection = dataSource.getConnection();
+ PreparedStatement ps = connection.prepareStatement(sql);
+ ps.setString(1, account.getName());
+ ps.setString(2, account.getPassword());
+ ps.setString(3, account.getFirst_name());
+ ps.setString(4, account.getLast_name());
+ ps.setString(5, account.getSsn());
+ if (ps.executeUpdate() == 1) {
+ return true;
+ }
+
+
+ } catch (SQLException e) {
+ return false;
+ }
+ return false;
+ }
+
+ @Override
+ public int countAccounts() {
+ int count = 0;
+ try {
+ connection = dataSource.getConnection();
+ PreparedStatement ps = connection.prepareStatement("select count(*) from account");
+ ResultSet rs = ps.executeQuery();
+ while (rs.next()) {
+ count = rs.getInt(1);
+ }
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ return count;
+ }
+ @Override
+ public boolean updatePassword(int id, String password) {
+ String sql = "update account set password=? where user_id=?";
+ try {
+ connection = dataSource.getConnection();
+ PreparedStatement ps = connection.prepareStatement(sql);
+ ps.setString(1, password);
+ ps.setInt(2, id);
+ int rowsAffected = ps.executeUpdate();
+
+ if (rowsAffected > 0) {
+ return true;
+ }
+
+ } catch (SQLException e) {
+ return false;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean deleteAccount(int id) {
+ String sql = "delete from account where user_id=?";
+ try {
+ connection = dataSource.getConnection();
+ PreparedStatement ps = connection.prepareStatement(sql);
+ ps.setInt(1, id);
+ int rowsAffected = ps.executeUpdate();
+ if (rowsAffected > 0) {
+ return true;
+ }
+ } catch (SQLException e) {
+ return false;
+ }
+ return false;
+ }
+
+}
diff --git a/src/main/java/com/example/Main.java b/src/main/java/com/example/Main.java
index 6dc6fbd..4b12a6f 100644
--- a/src/main/java/com/example/Main.java
+++ b/src/main/java/com/example/Main.java
@@ -1,9 +1,10 @@
package com.example;
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.sql.SQLException;
+import javax.sql.DataSource;
import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.Scanner;
public class Main {
@@ -26,13 +27,152 @@ public void run() {
"as system properties (-Dkey=value) or environment variables.");
}
- try (Connection connection = DriverManager.getConnection(jdbcUrl, dbUser, dbPass)) {
- } catch (SQLException e) {
- throw new RuntimeException(e);
- }
//Todo: Starting point for your code
+
+ DataSource dataSource = new SimpleDriverManagerDataSource(jdbcUrl, dbUser, dbPass);
+ AccountRepository accountRepo = new AccountRepositoryImpl(dataSource);
+ MoonMissionRepository moonMissionRepo = new MoonMissionRepositoryImpl(dataSource);
+
+ Scanner scanner = new Scanner(System.in);
+
+ if (validateLogin(accountRepo, scanner)) return;
+
+ showMenu();
+ String choice = scanner.nextLine();
+ if (!choice.isEmpty()) {
+ switch (choice) {
+ case "1" -> showMissions(moonMissionRepo);
+ case "2" -> getMissionById(scanner, moonMissionRepo);
+ case "3" -> countMissionsForYear(scanner, moonMissionRepo);
+ case "4" -> createAccount(scanner, accountRepo);
+ case "5" -> updatePasswordById(scanner, accountRepo);
+ case "6" -> deleteAccountById(scanner, accountRepo);
+ case "0" -> System.out.println("Exiting...");
+ default -> System.out.println("Invalid choice.");
+ }
+ } else {
+ System.out.println("Choice cannot be empty.");
+ }
+
+// scanner.close();
+ }
+
+ private boolean validateLogin(AccountRepository accountRepo, Scanner scanner) {
+ Optional currentUser = login(accountRepo, scanner);
+
+ while (currentUser.isEmpty()) {
+ System.out.println("Enter 0 to exit or 1 to try again.");
+ String answer = scanner.nextLine().trim();
+ if (answer.equals("0")) {
+ System.out.println("Exiting...");
+ return true;
+ } else if (answer.equals("1")) {
+ currentUser = login(accountRepo, scanner);
+ }else
+ System.out.println("Invalid choice.");
+ }
+ return false;
+ }
+
+ private Optional login(AccountRepository accountRepo, Scanner sc) {
+ System.out.println("Username: ");
+ String user = sc.nextLine().trim();
+ System.out.println("Password: ");
+ String pass = sc.nextLine().trim();
+ if (user.isEmpty() || pass.isEmpty()) {
+ System.out.println("Username or password cannot be empty.");
+ return Optional.empty();
+ }
+
+ Optional maybeAccount = accountRepo.findByUsername(user);
+ if(maybeAccount.isEmpty() || !pass.equals(maybeAccount.get().getPassword())) {
+ System.out.println("Invalid username or password.");
+ return Optional.empty();
+ }
+ return maybeAccount;
+ }
+
+ private static void deleteAccountById(Scanner sc, AccountRepository accountRepo) {
+ System.out.println("Enter the user_id for the account you want to delete: ");
+ int userId = Integer.parseInt(sc.nextLine().trim());
+ if(accountRepo.deleteAccount(userId))
+ System.out.println("Account successfully deleted.");
+ else
+ System.out.println("Account could not be deleted.");
+ }
+
+ private static void updatePasswordById(Scanner sc, AccountRepository accountRepo) {
+ System.out.println("Enter a user_id to update the password for: ");
+ int userId = Integer.parseInt(sc.nextLine().trim());
+ System.out.println("Enter new password:");
+ String newPassword = sc.nextLine().trim();
+ while (newPassword.isEmpty()) {
+ System.out.println("Password cannot be empty.");
+ System.out.println("Enter new password:");
+ newPassword = sc.nextLine().trim();
+ }
+ if(accountRepo.updatePassword(userId, newPassword))
+ System.out.println("Password successfully updated.");
+ else
+ System.out.println("Password could not be updated.");
+ }
+
+ private static void createAccount(Scanner sc, AccountRepository accountRepo) {
+ String name, firstName, lastName, password, ssn;
+ System.out.println("Type in your username: ");
+ name = sc.nextLine().trim();
+ System.out.println("Type in your first name: ");
+ firstName = sc.nextLine().trim();
+ System.out.println("Type in your last name: ");
+ lastName = sc.nextLine().trim();
+ System.out.println("Type in your password: ");
+ password = sc.nextLine().trim();
+ System.out.println("Type in your ssn: ");
+ ssn = sc.nextLine().trim();
+ Account newAccount = new Account(name, password, firstName, lastName, ssn);
+ if (accountRepo.createAccount(newAccount)) {
+ System.out.println("Account successfully created.");
+ } else {
+ System.out.println("Account could not be created.");
+ }
+ }
+
+ private static void countMissionsForYear(Scanner sc, MoonMissionRepository moonMissionRepo) {
+ System.out.println("Enter a year for which you want number of missions listed: ");
+ int year = Integer.parseInt(sc.nextLine().trim());
+ System.out.println("In " + year + " there were " + moonMissionRepo.missionsCountByYear(year) + " missions.");
+ }
+
+ private static void getMissionById(Scanner sc, MoonMissionRepository moonMissionRepo) {
+ System.out.println("Provide a mission_id to get information: ");
+ String id = sc.nextLine().trim();
+ List missions = moonMissionRepo.getMoonMissionById(id);
+ if(missions.isEmpty())
+ System.out.println("Mission not found.");
+ else
+ System.out.println(missions);
+ }
+
+ private static void showMissions(MoonMissionRepository moonMissionRepo) {
+ System.out.println(moonMissionRepo.listMoonMissions());
+ }
+
+ private static void showMenu() {
+ System.out.println("Options: ");
+ String menu = """
+ 1) List moon missions (prints spacecraft names from `moon_mission`).
+ 2) Get a moon mission by mission_id (prints details for that mission).
+ 3) Count missions for a given year (prompts: year; prints the number of missions launched that year).
+ 4) Create an account (prompts: first name, last name, ssn, password; prints confirmation).
+ 5) Update an account password (prompts: user_id, new password; prints confirmation).
+ 6) Delete an account (prompts: user_id; prints confirmation).
+ 0) Exit.
+ """;
+ System.out.println(menu);
+ System.out.println("Enter your option (0-6): ");
}
+
/**
* Determines if the application is running in development mode based on system properties,
* environment variables, or command-line arguments.
diff --git a/src/main/java/com/example/MoonMission.java b/src/main/java/com/example/MoonMission.java
new file mode 100644
index 0000000..6e6596f
--- /dev/null
+++ b/src/main/java/com/example/MoonMission.java
@@ -0,0 +1,83 @@
+package com.example;
+
+import java.sql.Date;
+
+public class MoonMission {
+ private int mission_id;
+ private String spacecraft, carrier_rocket, operator, mission_type, outcome;
+ private Date launch_date;
+
+ public MoonMission(int mission_id, String spacecraft, Date launch_date, String carrier_rocket, String operator, String mission_type, String outcome) {
+ this.mission_id = mission_id;
+ this.spacecraft = spacecraft;
+ this.carrier_rocket = carrier_rocket;
+ this.operator = operator;
+ this.mission_type = mission_type;
+ this.outcome = outcome;
+ this.launch_date = launch_date;
+ }
+
+ public int getMission_id() {
+ return mission_id;
+ }
+
+ public void setMission_id(int mission_id) {
+ this.mission_id = mission_id;
+ }
+
+ public String getSpacecraft() {
+ return spacecraft;
+ }
+
+ public void setSpacecraft(String spacecraft) {
+ this.spacecraft = spacecraft;
+ }
+
+ public String getCarrier_rocket() {
+ return carrier_rocket;
+ }
+
+ public void setCarrier_rocket(String carrier_rocket) {
+ this.carrier_rocket = carrier_rocket;
+ }
+
+ public String getOperator() {
+ return operator;
+ }
+
+ public void setOperator(String operator) {
+ this.operator = operator;
+ }
+
+ public String getMission_type() {
+ return mission_type;
+ }
+
+ public void setMission_type(String mission_type) {
+ this.mission_type = mission_type;
+ }
+
+ public String getOutcome() {
+ return outcome;
+ }
+
+ public void setOutcome(String outcome) {
+ this.outcome = outcome;
+ }
+
+ public Date getLaunch_date() {
+ return launch_date;
+ }
+
+ public void setLaunch_date(Date launch_date) {
+ this.launch_date = launch_date;
+ }
+
+ @Override
+ public String toString() {
+ return String.format(
+ "ID: %s | Spacecraft: %s | Rocket: %s | Operator: %s | Type: %s | Outcome: %s | Launch date: %s",
+ mission_id, spacecraft, carrier_rocket, operator, mission_type, outcome, launch_date
+ );
+ }
+}
diff --git a/src/main/java/com/example/MoonMissionRepository.java b/src/main/java/com/example/MoonMissionRepository.java
new file mode 100644
index 0000000..49b90cd
--- /dev/null
+++ b/src/main/java/com/example/MoonMissionRepository.java
@@ -0,0 +1,9 @@
+package com.example;
+
+import java.util.List;
+
+public interface MoonMissionRepository {
+ List listMoonMissions();
+ List getMoonMissionById(String id);
+ int missionsCountByYear(int year);
+}
diff --git a/src/main/java/com/example/MoonMissionRepositoryImpl.java b/src/main/java/com/example/MoonMissionRepositoryImpl.java
new file mode 100644
index 0000000..0545799
--- /dev/null
+++ b/src/main/java/com/example/MoonMissionRepositoryImpl.java
@@ -0,0 +1,78 @@
+package com.example;
+
+import javax.sql.DataSource;
+import java.sql.*;
+import java.util.ArrayList;
+import java.util.List;
+
+public class MoonMissionRepositoryImpl implements MoonMissionRepository {
+ private final DataSource dataSource;
+ Connection connection;
+
+ public MoonMissionRepositoryImpl(DataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+
+
+ @Override
+ public List listMoonMissions() {
+ String sql = "select * from moon_mission";
+ List moonMissions = new ArrayList<>();
+ try {
+ connection = dataSource.getConnection();
+ PreparedStatement ps = connection.prepareStatement(sql);
+
+ ResultSet rs = ps.executeQuery();
+ while (rs.next()) {
+ moonMissions.add(rs.getString("spacecraft"));
+ }
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ return moonMissions;
+ }
+ @Override
+ public List getMoonMissionById(String id) {
+ List moonMissions = new ArrayList<>();
+ String sql = "select * from moon_mission where mission_id = ?";
+ try {
+ connection = dataSource.getConnection();
+ PreparedStatement ps = connection.prepareStatement(sql);
+ ps.setString(1,id);
+ ResultSet rs = ps.executeQuery();
+ while (rs.next()) {
+ MoonMission m = new MoonMission(
+ rs.getInt("mission_id"),
+ rs.getString("spacecraft"),
+ rs.getDate("launch_date"),
+ rs.getString("carrier_rocket"),
+ rs.getString("operator"),
+ rs.getString("mission_type"),
+ rs.getString("outcome"));
+ moonMissions.add(m);
+ }
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ return moonMissions;
+
+ }
+
+ @Override
+ public int missionsCountByYear(int year) {
+ int count= 0;
+ String sql = "select count(*) as mission_count from moon_mission where year(launch_date) = ?";
+ try {
+ connection = dataSource.getConnection();
+ PreparedStatement ps = connection.prepareStatement(sql);
+ ps.setInt(1, year);
+ ResultSet rs = ps.executeQuery();
+ while (rs.next()) {
+ count = rs.getInt("mission_count");
+ }
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ return count;
+ }
+}
diff --git a/src/main/java/com/example/SimpleDriverManagerDataSource.java b/src/main/java/com/example/SimpleDriverManagerDataSource.java
new file mode 100644
index 0000000..0eab497
--- /dev/null
+++ b/src/main/java/com/example/SimpleDriverManagerDataSource.java
@@ -0,0 +1,76 @@
+package com.example;
+
+import javax.sql.DataSource;
+import java.io.PrintWriter;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.logging.Logger;
+
+public class SimpleDriverManagerDataSource implements DataSource {
+
+ private final String url;
+ private final String username;
+ private final String password;
+
+
+ public SimpleDriverManagerDataSource(String url, String username, String password) {
+ this.url = url;
+ this.username = username;
+ this.password = password;
+ }
+
+ @Override
+ public Connection getConnection() {
+ try {
+ return DriverManager.getConnection(url, username, password);
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public Connection getConnection(String username, String password) {
+ try {
+ return DriverManager.getConnection(url, username, password);
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public PrintWriter getLogWriter() throws SQLException {
+ return null;
+ }
+
+ @Override
+ public void setLogWriter(PrintWriter out) throws SQLException {
+
+ }
+
+ @Override
+ public void setLoginTimeout(int seconds) throws SQLException {
+
+ }
+
+ @Override
+ public int getLoginTimeout() throws SQLException {
+ return 0;
+ }
+
+ @Override
+ public Logger getParentLogger() throws SQLFeatureNotSupportedException {
+ return null;
+ }
+
+ @Override
+ public T unwrap(Class iface) throws SQLException {
+ return null;
+ }
+
+ @Override
+ public boolean isWrapperFor(Class> iface) throws SQLException {
+ return false;
+ }
+}