Skip to content

Commit

Permalink
final stage 4 completed
Browse files Browse the repository at this point in the history
  • Loading branch information
wisskirchenj committed Aug 18, 2023
1 parent 6e85dfd commit 057efa2
Show file tree
Hide file tree
Showing 17 changed files with 420 additions and 108 deletions.
1 change: 0 additions & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ rent out their cars and find customers.

## Project completion

[//]: # (Project was completed on 14.05.23.)
Project was completed on 18.08.23.

## Repository Contents

Expand All @@ -39,3 +39,7 @@ provided as bean. The CommandLineRunner uses a service to connect (query / inser

17.08.23 Stage 3 completed. Add second entity `Car` with JPA-Repository and Service, connect it via `@ManyToOne` and
`@JoinColumn` to the `Company`-table to generate a foreign key. Expand the menu structure (a bit weird requirements).

17.08.23 Final Stage 4 completed. Third entity `Customer` was needed, that got its repository and service too. It has a
nullable `@OneToOne` connection to the `Car` entity. Used generic AbstractMenuController to reduce menu flow
complexity. Also a JQL-`@Query` with `LEFT JOIN` was needed to query available cars without altering the tables.
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package de.cofinpro.cars.controller;


import de.cofinpro.cars.io.ConsolePrinter;
import de.cofinpro.cars.io.NamedItem;

import java.util.List;
import java.util.Scanner;

/**
* Abstract controller class for menu looping over enum based menu actions, that takes the enum E as type parameter.
* Since this class provides methods for handling integer-choice based menus including the action loop and calling
* the menu item's action, new menus can be added very easily. The customization is done by abstract framework methods.
*/
abstract class AbstractMenuController<E extends Enum<E>> {

protected final ConsolePrinter printer;
protected final Scanner scanner;

protected AbstractMenuController(ConsolePrinter consolePrinter, Scanner scanner) {
this.printer = consolePrinter;
this.scanner = scanner;
}

/**
* abstract getter to implement in subclass.
* @return the menu text to display when prompting for a user choice
*/
protected abstract String getMenuText();

/**
* abstract action getter for choice to implement in subclass.
* @param choice user's choice as enum constant of type parameter E
* @return the action to run for the user's choice
*/
protected abstract Runnable getMenuAction(E choice);

/**
* abstract getter with which subclasses must tell this controller, which is the menu option to leave the menu
*/
protected abstract E getExitChoice();

/**
* entry point method doing the menu loop and triggering the actions chosen.
*/
public void run() {
var choice = getMenuChoice();
while (choice != getExitChoice()) {
getMenuAction(choice).run();
choice = getMenuChoice();
}
}

protected int chooseFromList(List<? extends NamedItem> items, String itemType) {
if (items.isEmpty()) {
printer.printInfo("The {} list is empty!\n", itemType);
return 0;
}
printItemsMenu(items, itemType);
var choice = Integer.parseInt(scanner.nextLine());
printer.printInfo("");
return choice;
}

private void printItemsMenu(List<? extends NamedItem> items, String itemType) {
printer.printInfo("Choose a {}:", itemType);
printer.printEnumeratedList(items);
printer.printInfo("0. Back");
}

/**
* user interaction method, that displays the menu and prompts for the users integer choice.
* @return the choice as enum constant of the enum type parameter.
*/
private E getMenuChoice() {
printer.printInfo(getMenuText());
var menuOptions = getExitChoice().getDeclaringClass().getEnumConstants();
var choice = menuOptions[Integer.parseInt(scanner.nextLine())];
printer.printInfo("");
return choice;
}
}
58 changes: 31 additions & 27 deletions src/main/java/de/cofinpro/cars/controller/CompanyMenu.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,42 @@
import lombok.Setter;
import org.springframework.stereotype.Controller;

import java.util.Map;
import java.util.Scanner;

@Controller
public class CompanyMenu {
public class CompanyMenu extends AbstractMenuController<CompanyMenu.Choice> {

private final CarService carService;
private final Scanner scanner;
private final ConsolePrinter printer;
@Setter
private Company company;

public CompanyMenu(CarService carService,
Scanner scanner,
ConsolePrinter printer) {
public CompanyMenu(Scanner scanner,
ConsolePrinter printer,
CarService carService) {
super(printer, scanner);
this.carService = carService;
this.scanner = scanner;
this.printer = printer;
}

public void run() {
printMenu();
var choice = Integer.parseInt(scanner.nextLine());
while (choice != 0) {
switch (choice) {
case 1 -> listCars();
case 2 -> createCar();
default -> throw new IllegalStateException("invalid choice");
}
printMenu();
choice = Integer.parseInt(scanner.nextLine());
}
@Override
protected String getMenuText() {
return """
1. Car list
2. Create a car
0. Back""";
}

@Override
protected Runnable getMenuAction(Choice choice) {
return Map.<Choice, Runnable>of(
Choice.LIST_CARS, this::listCars,
Choice.CREATE_CAR, this::createCar
).get(choice);
}

@Override
protected Choice getExitChoice() {
return Choice.EXIT;
}

private void createCar() {
Expand All @@ -47,15 +52,14 @@ private void createCar() {
}

private void listCars() {
var cars = carService.listCars(company.getId());
var cars = carService.getCars(company.getId());
printer.printCarList(cars);
printer.printInfo("");
}

private void printMenu() {
printer.printInfo("""
1. Car list
2. Create a car
0. Back
""");
protected enum Choice {
EXIT,
LIST_CARS,
CREATE_CAR
}
}
102 changes: 102 additions & 0 deletions src/main/java/de/cofinpro/cars/controller/CustomerMenu.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package de.cofinpro.cars.controller;

import de.cofinpro.cars.io.ConsolePrinter;
import de.cofinpro.cars.persistence.Customer;
import de.cofinpro.cars.service.CarService;
import de.cofinpro.cars.service.CompanyService;
import de.cofinpro.cars.service.CustomerService;
import lombok.Setter;
import org.springframework.stereotype.Controller;

import java.util.Map;
import java.util.Objects;
import java.util.Scanner;

@Controller
public class CustomerMenu extends AbstractMenuController<CustomerMenu.Choice> {

public static final String NO_CAR_RENT = "You didn't rent a car!\n";
private final CustomerService customerService;
private final CompanyService companyService;
private final CarService carService;
@Setter
private Customer customer;

protected CustomerMenu(ConsolePrinter consolePrinter,
Scanner scanner,
CustomerService customerService,
CompanyService companyService,
CarService carService) {
super(consolePrinter, scanner);
this.customerService = customerService;
this.companyService = companyService;
this.carService = carService;
}

@Override
protected String getMenuText() {
return """
1. Rent a car
2. Return a rented car
3. My rented car
0. Back""";
}

@Override
protected Runnable getMenuAction(Choice choice) {
return Map.<Choice, Runnable>of(
Choice.RENT, this::rentCar,
Choice.RETURN, this::returnCar,
Choice.SHOW, this::showCar
).get(choice);
}

@Override
protected Choice getExitChoice() {
return Choice.EXIT;
}

private void rentCar() {
if (Objects.nonNull(customer.getRentedCar())) {
printer.printInfo("You've already rented a car!\n");
return;
}
var companies = companyService.getCompanies();
var index = chooseFromList(companies, "company");
var companySelected = companies.get(index - 1);
var cars = carService.getAvailableCars(companySelected.getId());
index = chooseFromList(cars, "car");
if (index > 0) {
var car = cars.get(index - 1);
customerService.rentCar(customer, car);
printer.printInfo("You rented '{}'\n", car.getName());
}
}

private void returnCar() {
if (Objects.isNull(customer.getRentedCar())) {
printer.printInfo(NO_CAR_RENT);
return;
}
customerService.returnCar(customer);
printer.printInfo("You've returned a rented car!\n");
}

private void showCar() {
if (Objects.isNull(customer.getRentedCar())) {
printer.printInfo(NO_CAR_RENT);
return;
}
printer.printInfo("Your rented car:");
printer.printInfo(customer.getRentedCar().getName());
printer.printInfo("Company:");
printer.printInfo("{}\n", customer.getRentedCar().getCompany().getName());
}

protected enum Choice {
EXIT,
RENT,
RETURN,
SHOW
}
}
Loading

0 comments on commit 057efa2

Please sign in to comment.