Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/example/DevDatabaseInitializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ public static void start() {
}
}
}
// klar
200 changes: 193 additions & 7 deletions src/main/java/com/example/Main.java
Original file line number Diff line number Diff line change
@@ -1,36 +1,222 @@
package com.example;

import com.example.datasource.SimpleDriverManagerDataSource;
import com.example.model.Account;
import com.example.model.MoonMission;
import com.example.repository.AccountRepository;
import com.example.repository.JdbcAccountRepository;
import com.example.repository.JdbcMoonMissionRepository;
import com.example.repository.MoonMissionRepository;
import org.testcontainers.shaded.org.checkerframework.checker.units.qual.A;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLOutput;
Comment on lines +10 to +16
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Remove unused imports.

Several imports are not used and should be removed:

  • Line 10: org.testcontainers.shaded.org.checkerframework.checker.units.qual.A
  • Line 16: java.sql.SQLOutput
 import com.example.repository.JdbcMoonMissionRepository;
 import com.example.repository.MoonMissionRepository;
-import org.testcontainers.shaded.org.checkerframework.checker.units.qual.A;
 
 import javax.sql.DataSource;
 import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.SQLException;
-import java.sql.SQLOutput;
 import java.util.Arrays;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import org.testcontainers.shaded.org.checkerframework.checker.units.qual.A;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLOutput;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
🤖 Prompt for AI Agents
In src/main/java/com/example/Main.java around lines 10 to 16, the imports
org.testcontainers.shaded.org.checkerframework.checker.units.qual.A (line 10)
and java.sql.SQLOutput (line 16) are unused; remove those two import lines from
the top of the file and leave the remaining imports as-is (optionally
reformat/sort imports) then recompile to ensure no unused-import warnings
remain.

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Scanner;

public class Main {
private final AccountRepository accountRepository;
private final MoonMissionRepository missionRepository;
private final Scanner scanner;

public Main(AccountRepository accountRepository, MoonMissionRepository missionRepository) {
this.accountRepository = accountRepository;
this.missionRepository = missionRepository;
this.scanner = new Scanner(System.in);
}
public static void main(String[] args) {

static void main(String[] args) {
if (isDevMode(args)) {
DevDatabaseInitializer.start();
}
new Main().run();
}

public void run() {
// Resolve DB settings with precedence: System properties -> Environment variables
public Main() {
String jdbcUrl = resolveConfig("APP_JDBC_URL", "APP_JDBC_URL");
String dbUser = resolveConfig("APP_DB_USER", "APP_DB_USER");
String dbPass = resolveConfig("APP_DB_PASS", "APP_DB_PASS");

if (jdbcUrl == null || dbUser == null || dbPass == null) {
throw new IllegalStateException(
"Missing DB configuration. Provide APP_JDBC_URL, APP_DB_USER, APP_DB_PASS " +
"as system properties (-Dkey=value) or environment variables.");
"Missing DB configuration. Provide APP_JDBC_URL, APP_DB_USER, APP_DB_PASS \" +\n" +
"\"as system properties (-Dkey=value) or environment variables.\"");
}
Comment on lines 46 to 49
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Malformed exception message with literal \n.

The string concatenation creates a malformed message with a literal \n appearing in the output instead of an actual newline.

         if (jdbcUrl == null || dbUser == null || dbPass == null) {
             throw new IllegalStateException(
-                    "Missing DB configuration. Provide APP_JDBC_URL, APP_DB_USER, APP_DB_PASS \" +\n" +
-                            "\"as system properties (-Dkey=value) or environment variables.\"");
+                    "Missing DB configuration. Provide APP_JDBC_URL, APP_DB_USER, APP_DB_PASS " +
+                            "as system properties (-Dkey=value) or environment variables.");
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
throw new IllegalStateException(
"Missing DB configuration. Provide APP_JDBC_URL, APP_DB_USER, APP_DB_PASS " +
"as system properties (-Dkey=value) or environment variables.");
"Missing DB configuration. Provide APP_JDBC_URL, APP_DB_USER, APP_DB_PASS \" +\n" +
"\"as system properties (-Dkey=value) or environment variables.\"");
}
throw new IllegalStateException(
"Missing DB configuration. Provide APP_JDBC_URL, APP_DB_USER, APP_DB_PASS " +
"as system properties (-Dkey=value) or environment variables.");
}
🤖 Prompt for AI Agents
In src/main/java/com/example/Main.java around lines 46 to 49, the
IllegalStateException message is built with a string containing a literal "\n"
and an awkward concatenation that causes the backslash-n to appear in the
output; replace the concatenation and escaped sequence with a properly formatted
string (either a single string literal containing a real newline using
System.lineSeparator() or by using two concatenated string literals without the
escaped backslash) so the message reads with an actual newline (or explicit
separator) and clear wording for the required APP_JDBC_URL, APP_DB_USER,
APP_DB_PASS configuration.


try (Connection connection = DriverManager.getConnection(jdbcUrl, dbUser, dbPass)) {
System.out.println("✓ Database connection successful!");
} catch (SQLException e) {
throw new RuntimeException(e);
throw new RuntimeException("Failed to connect to database. Check your configuration.", e);
}

DataSource dataSource = new SimpleDriverManagerDataSource(jdbcUrl, dbUser, dbPass);

this.accountRepository = new JdbcAccountRepository(dataSource);
this.missionRepository = new JdbcMoonMissionRepository(dataSource);
this.scanner = new Scanner(System.in);
}

public void run() {
System.out.println("=== Moon Mission Database === \n");

if (!login()) {
System.out.println("Login invalid. Exiting...");
return;
}
boolean running = true;
while (running) {
printMenu();
int choice = getIntInput();

switch (choice) {
case 1 -> listMoonMissions();
case 2 -> getMissionById();
case 3 -> countMissionsByYear();
case 4 -> createAccount();
case 5 -> updateAccountPassword();
case 6 -> deleteAccount();
case 0 -> {
running = false;
System.out.println("Goodbye!");
}
default -> System.out.println("Invalid option!");
}
}
scanner.close();
}

private boolean login() {
System.out.print("Username: ");
String username = scanner.nextLine().trim();

System.out.print("Password: ");
String password = scanner.nextLine().trim();

Optional<Account> accountOpt = accountRepository.findByUsernameAndPassword(username, password);

if (accountOpt.isPresent()) {
Account account = accountOpt.get();
System.out.println("✓ Login successful! Welcome, " + account.name() + "\n");
return true;
} else {
System.out.println("Invalid username or password.");
return false;
}
}

private void printMenu() {
System.out.println("\n=== 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 option: ");
}

private void listMoonMissions () {
System.out.println("\n --- Moon Missions ---");

List<String> spacecrafts = missionRepository.findAllSpaceCraftNames();
spacecrafts.forEach(System.out::println);
}

private void getMissionById() {
System.out.print("Enter mission_id: ");
int missionId = getIntInput();

Optional<MoonMission> missionOpt = missionRepository.findById(missionId);

if (missionOpt.isPresent()) {
MoonMission mission = missionOpt.get();
System.out.println("\n--- Mission Details ---");
System.out.println("Mission ID: " + mission.missionId());
System.out.println("Spacecraft: " + mission.spacecraft());
System.out.println("Launch Date: " + mission.launchDate());
System.out.println("Carrier Rocket: " + mission.carrierRocket());
System.out.println("Operator: " + mission.operator());
System.out.println("Mission Type: " + mission.missionType());
System.out.println("Outcome: " + mission.outcome());
} else {
System.out.println("Mission not found.");
}
}

private void countMissionsByYear() {
System.out.print("Enter year: ");
int year = getIntInput();

int count = missionRepository.countByYear(year);
System.out.println("Missions launched in " + year + ": " + count);
}

private void createAccount() {
System.out.print("First name: ");
String firstName = scanner.nextLine().trim();

System.out.print("Last name: ");
String lastName = scanner.nextLine().trim();

System.out.print("SSN: ");
String ssn = scanner.nextLine().trim();

System.out.print("Password: ");
String password = scanner.nextLine().trim();

int userId = accountRepository.create(firstName, lastName, ssn, password);

if (userId > 0) {
System.out.println("✓ Account created successfully! User ID: " + userId);
} else {
System.out.println("Failed to create account.");
}
}

private void updateAccountPassword() {
System.out.print("Enter user_id: ");
int userId = getIntInput();

System.out.print("Enter new password: ");
String newPassword = scanner.nextLine().trim();

boolean success = accountRepository.updatePassword(userId, newPassword);

if (success) {
System.out.println("✓ Password updated successfully!");
} else {
System.out.println("User not found.");
}
}

private void deleteAccount() {
System.out.print("Enter user_id: ");
int userId = getIntInput();

boolean success = accountRepository.delete(userId);

if (success) {
System.out.println("✓ Account deleted successfully!");
} else {
System.out.println("User not found.");
}
}

private int getIntInput() {
while(true) {
try {
String input = scanner.nextLine().trim();
return Integer.parseInt(input);
} catch (NumberFormatException e) {
System.out.println("Invalid number. Try again: ");
}
}
//Todo: Starting point for your code
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.example.datasource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
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() throws SQLException {
return DriverManager.getConnection(url, username, password);
}

@Override
public Connection getConnection(String username, String password) throws SQLException {
return DriverManager.getConnection(url, username, password);
}

@Override
public java.io.PrintWriter getLogWriter() { return null; }

@Override
public void setLogWriter(java.io.PrintWriter out) {}

@Override
public void setLoginTimeout(int seconds) {}

@Override
public int getLoginTimeout() { return 0; }

@Override
public Logger getParentLogger() { return null; }

@Override
public <T> T unwrap(Class<T> iface) { return null; }

@Override
public boolean isWrapperFor(Class<?> iface) { return false; }
}
20 changes: 20 additions & 0 deletions src/main/java/com/example/model/Account.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.example.model;

public record Account(
int userID,
String name,
String ssn,
String password
) {
public Account {
if(name == null || name.isBlank()) {
throw new IllegalArgumentException("Name cannot be blank");
}
if (ssn == null || ssn.isBlank()) {
throw new IllegalArgumentException("SSN cannot be blank");
}
if (password == null || password.isBlank()) {
throw new IllegalArgumentException("Password cannot be blank");
}
}
}
22 changes: 22 additions & 0 deletions src/main/java/com/example/model/MoonMission.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.example.model;

import java.time.LocalDate;

public record MoonMission(
int missionId,
String spacecraft,
LocalDate launchDate,
String carrierRocket,
String operator,
String missionType,
String outcome
) {
public MoonMission {
if (spacecraft == null || spacecraft.isBlank()) {
throw new IllegalArgumentException("Spacecraft cannot be blank");
}
if (launchDate == null) {
throw new IllegalArgumentException("Launch date cannot be null");
}
}
}
16 changes: 16 additions & 0 deletions src/main/java/com/example/repository/AccountRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.example.repository;

import com.example.model.Account;

import java.util.Optional;

public interface AccountRepository {

Optional<Account> findByUsernameAndPassword (String username, String password);

int create (String firstName, String lastName, String ssn, String password);

boolean updatePassword(int userId, String newPassword);

boolean delete(int userId);
}
Loading
Loading