flowchart direction TB id1{Borrow?} -- "YES" --> id2[User?] id2 -- "user@fakemail.com" -->id3[Unknown user, try again] id3 -- "Ask the user again" --> id2 id2 -- "john.smith@goodmail.com" --> id4[User exists:\n- Username: John Smith\n- User ID: XXX] id4 -- "Ask for a Book name" --> id5[Book?] id5 -- "Fake book" --> id6[Unknown book, try again] --> id5 id5 -- "Title of the book" --> id7[Title of the book exists, there are X available issues:\n- Book ID: 001\n- Book ID: 002\n...\n- Book ID: XXX] id7 --> id8{Proceed to\nborrow?} id8 -- "YES" --> id9[New borrow created:\n- Borrow ID: 001\n- Book: Title of the book Book ID: 001]
LAB#SE00-3: Maven Library model
javase
lab
Introduction
Basic understanding of Java programming language is required, as well as some familiarity with Maven or Gradle for managing dependencies and building the project. ssl encryption and is intended to run behind a Knowledge of algotighms and data structures to implement the required classes.
Describe the required models that might define the solution to a Library implementation. Create multiple classes in Java using the most convenient entity relationship between them to im.
Test these classes using JUnit.
- Create a new Maven or Gradle project and setting up the project structure
- Modify the project’s
pom.xml
orbuild.gradle
file to import necessary dependencies, including JUnit for testing - Implement the required classes in Java
- Implement two basic patter-designs: singleton and think about factory
- Write JUnit tests to verify that classes work as expected
- Allow the user to input data via the console, rather than using
hard-coded test data
in JUnit tests
Mock-up
User interface
A terminal menu will show the available options of the Library application
# The interface asks if the user wants to create a borrow
borrow? YES
# If answered YES, then proceed with the borrow
# The interface asks for the user identifier
User? user@mail.com
# If the user doesn't exist, then ask again for the user
Unknown user, try again. User? john.smith@goodmail.com
# If the user exists, then show info regarding that user
User exists
- Name: John Smith
- User id: XXX
# The interface asks for the title of the book to borrow
Book to borrow? "Fake book"
# If the book doesn't exist, then ask again for another book
Unknown book, try again. Book? "Title of the book"
# If the book exists, then show the available issues
Book exists, there are X available issues
- Book ID: 001
- Book ID: 002
{...}
- Book ID: 054
Proceed to borrow? YES
# Use the first available issue of that book and show the Borrow information
New borrow created:
- Borrow ID: 001
- Book: "Title of the book" (Book ID: 001)
- Initial Borrow: 2023-01-31
- Due Date: 2023-02-14
# Ask again if the user wants to borrow something new
borrow? NO
# If answered NO, then exit the program
BYE!
Domains
Core domain
Logic domain
User interface domain
UML
Core classes
Book
Person
User
Borrow
classDiagram class Book { } class User { <<Person>> -String userId } class Borrow { -Date initialBorrow -Date dueDate -Date returnDate -Book borrowedBook } Borrow "1..*" o-- "1" Book : lends Book "1" -- "1..*" Borrow : can be lent User "1" o-- "*" Borrow : can make
Management classes
BookManager
BookManager.java
package org.labse03part1.logic;
import com.github.javafaker.Faker;
import org.labse03part1.domain.Author;
import org.labse03part1.domain.Book;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.Scanner;
import java.util.stream.Stream;
import static org.labse03part1.utils.InterfaceUtils.askInt;
import static org.labse03part1.utils.InterfaceUtils.askString;
public class BookManager {
private static final HashMap<String, Book> books = new HashMap<>();
private enum bookOptionsEnum {
ADD_BOOK("Add book") {
@Override
void action(Scanner reader) {
addBook(reader);
}
void addBook(Scanner reader) {
// Create a book
String bookTitle = askString(reader, "[" + bookOptionsEnum.ADD_BOOK.getDescription() + "] Enter name of the new book ('Quit' to exit): ");
if (bookTitle.equals("Quit")) {
System.out.println("[" + bookOptionsEnum.ADD_BOOK.getDescription() + "] Add book cancelled");
return;
}
int bookYear = askInt(reader, "[" + bookOptionsEnum.ADD_BOOK.getDescription() + "] Enter year of the new book: ");
int bookPages = askInt(reader, "[" + bookOptionsEnum.ADD_BOOK.getDescription() + "] Enter number of pages of the book: ");
String bookISBN = askString(reader, "[" + bookOptionsEnum.ADD_BOOK.getDescription() + "] Enter book ISBN: ");
// The user selects one of the available authors
Author bookAuthor = AuthorManager.getAuthor(reader);
// Add the book into the system
Book newBook = new Book(bookTitle, bookPages, bookYear, bookISBN, bookAuthor, true);
books.put(newBook.getBookID(), newBook);
System.out.println("[" + bookOptionsEnum.ADD_BOOK.getDescription() + "] Book " + bookTitle + " added! ID: " + newBook.getBookID());
}
},
DELETE_BOOK("Delete book") {
@Override
void action(Scanner reader) {
deleteBook(reader);
}
void deleteBook(Scanner reader) {
// List the available books
bookOptionsEnum.LIST_BOOKS.action(reader);
String bookID = askString(reader, "[" + bookOptionsEnum.DELETE_BOOK.getDescription() + "] Enter ID of the book to delete ('Quit' to exit): ");
while (!books.containsKey(bookID)) {
if (bookID.equals("Quit")) {
System.out.println("[" + bookOptionsEnum.DELETE_BOOK.getDescription() + "] Delete book cancelled");
return;
}
System.out.println("[" + bookOptionsEnum.DELETE_BOOK.getDescription() + "] Book " + bookID + "doesn't exist in the system!");
bookID = askString(reader, "[" + bookOptionsEnum.DELETE_BOOK.getDescription() + "] Enter name of the book to delete ('Quit' to exit): ");
}
books.remove(bookID);
System.out.println("[" + bookOptionsEnum.DELETE_BOOK.getDescription() + "] Book " + bookID + " deleted!");
}
},
CHECK_BOOK("Check book") {
@Override
void action(Scanner reader) {
checkBook(reader);
}
void checkBook(Scanner reader) {
// List the available books
bookOptionsEnum.LIST_BOOKS.action(reader);
String bookID = askString(reader, "[" + bookOptionsEnum.CHECK_BOOK.getDescription() + "] Enter book ID ('Quit' to exit): ");
while (!books.containsKey(bookID)) {
if (bookID.equals("Quit")) {
System.out.println("[" + bookOptionsEnum.CHECK_BOOK.getDescription() + "] Check book cancelled");
return;
}
System.out.println("[" + bookOptionsEnum.CHECK_BOOK.getDescription() + "] Book " + bookID + "doesn't exist in the system!");
bookID = askString(reader, "[" + bookOptionsEnum.CHECK_BOOK.getDescription() + "] Enter book ID ('Quit' to exit): ");
}
// Print the book information
System.out.println(books.get(bookID));
}
},
LIST_BOOKS("List books") {
@Override
void action(Scanner reader) {
listBooks();
}
void listBooks() {
System.out.println("[" + bookOptionsEnum.LIST_BOOKS.getDescription() + "] Available books:");
books.forEach((bookID, book) -> System.out.println(bookID + ": " + book.getTitle()));
}
},
UPDATE_BOOK("Update book") {
@Override
void action(Scanner reader) {
updateBook(reader);
}
void updateBook(Scanner reader) {
// List the available books
bookOptionsEnum.LIST_BOOKS.action(reader);
String bookID = askString(reader, "[" + bookOptionsEnum.UPDATE_BOOK.getDescription() + "] Enter book ID to update ('Quit' to exit): ");
while (!books.containsKey(bookID)) {
if (bookID.equals("Quit")) {
System.out.println("[" + bookOptionsEnum.UPDATE_BOOK.getDescription() + "] Update book cancelled");
return;
}
System.out.println("[" + bookOptionsEnum.UPDATE_BOOK.getDescription() + "] Book " + bookID + " doesn't exist in the system!");
bookID = askString(reader, "[" + bookOptionsEnum.UPDATE_BOOK.getDescription() + "] Enter book ID to update ('Quit' to exit): ");
}
Book bookToUpdate = books.get(bookID);
System.out.println(bookToUpdate);
// Once book is found, ask for the parameter to change
String parameter = askString(reader, "[" + bookOptionsEnum.UPDATE_BOOK.getDescription() + "] Enter the parameter to modify ('Quit' to exit): ");
Object value;
while (!parameter.equals("Quit")) {
switch (parameter) {
case "title" -> {
value = askString(reader, "[" + bookOptionsEnum.UPDATE_BOOK.getDescription() + "] Enter the new title of the book: ");
bookToUpdate.setTitle(value.toString());
System.out.println("[" + bookOptionsEnum.UPDATE_BOOK.getDescription() + "] Title set to " + value);
}
case "pages" -> {
value = askInt(reader, "[" + bookOptionsEnum.UPDATE_BOOK.getDescription() + "] Enter the new pages of the book: ");
bookToUpdate.setPages((int) value);
System.out.println("[" + bookOptionsEnum.UPDATE_BOOK.getDescription() + "] Pages set to " + value);
}
case "year" -> {
value = askInt(reader, "[" + bookOptionsEnum.UPDATE_BOOK.getDescription() + "] Enter the new year of the book: ");
bookToUpdate.setYear((int) value);
System.out.println("[" + bookOptionsEnum.UPDATE_BOOK.getDescription() + "] Year set to " + value);
}
case "author" -> {
// Ask the user for a new author
Author newAuthor = AuthorManager.getAuthor(reader);
// Set the new author
bookToUpdate.setAuthor(newAuthor);
System.out.println("[" + bookOptionsEnum.UPDATE_BOOK.getDescription() + "] Author set to " + bookToUpdate.getAuthor().getFirstName() + " " + bookToUpdate.getAuthor().getLastName());
}
case "available" -> {
String newAvailable = askString(reader, "[" + bookOptionsEnum.UPDATE_BOOK.getDescription() + "] Enter new availability of the book (true or false)");
// Check that the input is a boolean
while (!Boolean.getBoolean(newAvailable)) {
newAvailable = askString(reader, "[" + bookOptionsEnum.UPDATE_BOOK.getDescription() + "] Invalid value. Enter new availability of the book (true or false)");
}
// Set the new boolean value
bookToUpdate.setAvailable(Boolean.getBoolean(newAvailable));
}
default -> System.out.println("[Manage books] " + parameter + " is a read-only parameter, choose another one");
}
parameter = askString(reader, "[" + bookOptionsEnum.UPDATE_BOOK.getDescription() + "] Insert the parameter to modify ('Quit' to exit): ");
}
}
};
abstract void action(Scanner reader);
private final String description;
bookOptionsEnum(String description) {
this.description = description;
}
private String getDescription() {
return this.description;
}
static void printOptions() {
// Print all the available Borrow options
System.out.println("[Manage books] Available options:");
bookOptionsEnum.stream()
.map(bookOptionsEnum::getDescription)
.forEach(System.out::println);
}
static bookOptionsEnum getOption(String action) {
for (bookOptionsEnum option : bookOptionsEnum.values()) {
if (option.getDescription().equals(action)) {
return option;
}
}
return null;
}
private static void executeOption(Scanner reader, String action) {
// compare the action with the available enum and see if it is a valid option
bookOptionsEnum option = getOption(action);
// execute the desired option
if (option != null) {
option.action(reader);
}
else {
System.out.println("[Manage books] Invalid option, try again");
}
}
public static Stream<bookOptionsEnum> stream() {
return Stream.of(bookOptionsEnum.values());
}
}
public static void initializeRandomBooks() {
if (books.isEmpty()) {
Random randomNum = new Random();
createFakeBooks(randomNum.nextInt(1, 10));
}
}
public static void start(Scanner reader) {
// Print the available options
bookOptionsEnum.printOptions();
String description = askString(reader, "[Manage books] - Select option: ");
while (!description.equals("Quit")) {
bookOptionsEnum.executeOption(reader, description);
System.out.println();
bookOptionsEnum.printOptions();
description = askString(reader, "[Manage books] - Select option: ");
}
}
// Private methods
private static void createFakeBooks(int number) {
Faker faker = new Faker();
// Initialize Random authors if the list is empty
AuthorManager.initializeRandomActors();
Book newBook;
// Create as many new Books as requested
for (int i = 0; i < number; i++) {
com.github.javafaker.Book fakeBook = faker.book();
newBook = new Book();
newBook.setTitle(fakeBook.title());
newBook.setPages(faker.number().numberBetween(10, 2000));
newBook.setYear(faker.number().numberBetween(0, 2023));
newBook.setISBN(faker.code().isbn13());
// Get a fake author
// Mandatory initialization of AuthorManager prior to this
newBook.setAuthor(AuthorManager.getRandomAuthor());
// Set a random availability status
newBook.setAvailable(faker.bool().bool());
// Put the fake book to the storage
books.put(newBook.getBookID(), newBook);
}
}
// Public methods
public static String getAvailableBookID(Scanner reader) {
//bookOptionsEnum.LIST_BOOKS.action(reader);
// List only the available books
System.out.println("[Book Manager] Available books:");
for (Map.Entry<String, Book> entry : books.entrySet()) {
Book book = entry.getValue();
if (book.isAvailable()) {
System.out.println(book.getBookID() + " - " + book.getTitle());
}
}
String bookID = askString(reader, "[Manage books] Enter book ID: ");
while (!books.containsKey(bookID)) {
bookID = askString(reader, "[Manage books] Invalid book ID. Enter book ID: ");
}
return bookID;
}
// TODO: Analyse if this method is correct compared to the enum approach
public static String getBookTitle(String bookID) {
return books.getOrDefault(bookID, null).getTitle();
}
public static void setBookAvailability(String bookID, boolean newAvailability) {
books.get(bookID).setAvailable(newAvailability);
}
}
StudentManager
BookManager.java
package org.labse03part1.logic;
import com.github.javafaker.Faker;
import org.labse03part1.domain.Book;
import org.labse03part1.domain.Student;
import java.util.*;
import java.util.stream.Stream;
import static org.labse03part1.utils.InterfaceUtils.askInt;
import static org.labse03part1.utils.InterfaceUtils.askString;
public class StudentManager {
private static final Map<String, Student> students = new HashMap<>();
public static void initializeRandomStudents() {
if (students.isEmpty()) {
Random randomNum = new Random();
createFakeStudents(randomNum.nextInt(1, 10));
}
}
private static void createFakeStudents(int number) {
Faker faker = new Faker();
Student newStudent;
// Create as many new Students as requested
for (int i = 0; i < number; i++) {
newStudent = new Student();
newStudent.setFirstName(faker.name().firstName());
newStudent.setLastName(faker.name().lastName());
newStudent.setAge(faker.number().numberBetween(10, 99));
newStudent.setUniversity(faker.university().name());
newStudent.setBooks(new ArrayList<>());
// Put the fake student into the storage
students.put(newStudent.getStudentID(), newStudent);
}
}
private enum studentOptionsEnum {
ADD_STUDENT("Add student") {
@Override
void action(Scanner reader) {
addStudent(reader);
}
private void addStudent(Scanner reader) {
while (true) {
// Ask for the student's details
String studentFirstName = askString(reader, "[" + studentOptionsEnum.ADD_STUDENT.getDescription() + "] Enter student's first name ('Quit' to exit): ");
if (studentFirstName.equals("Quit")) {
break;
}
// Ask for the rest of the student's information
String studentLastName = askString(reader, "[" + studentOptionsEnum.ADD_STUDENT.getDescription() + "] Enter student's last name ('Quit' to exit): ");
String studentFullName = studentFirstName + " " + studentLastName;
int studentAge = askInt(reader, "[" + studentOptionsEnum.ADD_STUDENT.getDescription() + "] Enter student's age ('Quit' to exit): ");
String studentUniversity = askString(reader, "[" + studentOptionsEnum.ADD_STUDENT.getDescription() + "] Enter student's university ('Quit' to exit): ");
List<Book> studentBooks = new ArrayList<>();
// Create the new student object
Student newStudent = new Student(studentFirstName, studentLastName, studentAge, studentUniversity, studentBooks);
// Check if the student already exists inside the students hashmap
if (!students.containsValue(newStudent)) {
// Insert the student into the storage - Key: studentID
students.put(newStudent.getStudentID(), newStudent);
System.out.println("[" + studentOptionsEnum.ADD_STUDENT.getDescription() + "] Student " + studentFullName + " added!");
break;
}
System.out.println("[" + studentOptionsEnum.ADD_STUDENT.getDescription() + "] Student " + studentFullName + " already exists! Enter a new one");
}
}
},
DELETE_STUDENT("Delete student") {
@Override
void action(Scanner reader) {
deleteStudent(reader);
}
private void deleteStudent(Scanner reader) {
studentOptionsEnum.LIST_STUDENTS.action(reader);
// Ask for the student ID
String studentID = askString(reader, "Enter the student ID: ");
while (!students.containsKey(studentID)) {
if (studentID.equals("Quit")) {
System.out.println("Delete student cancelled");
return;
}
studentID = askString(reader, "Incorrect ID. Enter the student ID: ");
}
Student deletedStudent = students.remove(studentID);
System.out.println("[" + studentOptionsEnum.DELETE_STUDENT.getDescription() + "] Student " + deletedStudent.getFirstName() + " " + deletedStudent.getLastName() + " deleted!");
}
},
CHECK_STUDENT("Check student") {
@Override
void action(Scanner reader) {
checkStudent(reader);
}
private void checkStudent(Scanner reader) {
studentOptionsEnum.LIST_STUDENTS.action(reader);
// Ask for the student ID
String studentID = askString(reader, "Enter the student ID: ");
System.out.println(students.get(studentID));
}
},
LIST_STUDENTS("List students") {
@Override
void action(Scanner reader) {
listStudents(reader);
}
private void listStudents(Scanner reader) {
System.out.println("[" + studentOptionsEnum.CHECK_STUDENT.getDescription() + "] Available students:");
students.forEach((studentID, student) -> System.out.println(studentID + ": " + student.getFirstName() + " " + student.getLastName()));
}
},
UPDATE_STUDENT("Update student") {
@Override
void action(Scanner reader) {
updateStudent(reader);
}
private void updateStudent(Scanner reader) {
// TODO: Ask for the student ID instead of the full name
// Ask for the student name
studentOptionsEnum.LIST_STUDENTS.action(reader);
//String studentFullName = getStudentFullName(reader);
String studentID = askString(reader, "Enter the student ID: ");
// Retrieve the student to update
Student studentToUpdate = students.get(studentID);
System.out.println(studentToUpdate);
// Once the student is found, ask for the parameter to change
String parameter = askString(reader, "[" + studentOptionsEnum.UPDATE_STUDENT.getDescription() + "] Enter the parameter to modify ('Quit' to exit): ");
// Define an Object variable to store the different types of answers
Object value;
while (!parameter.equals("Quit")) {
switch (parameter) {
case "firstName" -> {
value = askString(reader, "[" + studentOptionsEnum.UPDATE_STUDENT.getDescription() + "] Enter the student's new first name: ");
studentToUpdate.setFirstName(value.toString());
System.out.println("[" + studentOptionsEnum.UPDATE_STUDENT.getDescription() + "] First name set to " + value);
}
case "lastName" -> {
value = askString(reader, "[" + studentOptionsEnum.UPDATE_STUDENT.getDescription() + "] Enter the student's new last name: ");
studentToUpdate.setLastName(value.toString());
System.out.println("[" + studentOptionsEnum.UPDATE_STUDENT.getDescription() + "] Last name set to " + value);
}
case "age" -> {
value = askInt(reader, "[" + studentOptionsEnum.UPDATE_STUDENT.getDescription() + "] Enter the student's new age: ");
studentToUpdate.setAge((int) value);
System.out.println("[" + studentOptionsEnum.UPDATE_STUDENT.getDescription() + "] Age set to " + value);
}
case "university" -> {
value = askString(reader, "[" + studentOptionsEnum.UPDATE_STUDENT.getDescription() + "] Enter the student's new university: ");
studentToUpdate.setUniversity(value.toString());
System.out.println("[" + studentOptionsEnum.UPDATE_STUDENT.getDescription() + "] University set to " + value);
}
case "books" -> {
// TODO: Call a book manager for the student's list of books. Maybe a public static method in BookManager that accepts an ArrayList of Books?
System.out.println("Books Management coming soon!");
//value = askString(reader, "[" + studentOptionsEnum.UPDATE_STUDENT.getDescription() + "] Enter the student's new car: ");
// Some BookManager logic
//System.out.println("[" + studentOptionsEnum.UPDATE_STUDENT.getDescription() + "] Car set to " + value);
}
default -> System.out.println("[Manage students] " + parameter + " is a read-only parameter, choose another one");
}
}
}
};
abstract void action(Scanner reader);
private final String description;
studentOptionsEnum(String description) {
this.description = description;
}
private String getDescription() {
return this.description;
}
private static void printOptions() {
// Print all the available Student options
System.out.println("[Manage students] Available options:");
studentOptionsEnum.stream()
.map(studentOptionsEnum::getDescription)
.forEach(System.out::println);
}
private static studentOptionsEnum getOption(String action) {
for (studentOptionsEnum option : studentOptionsEnum.values()) {
if (option.getDescription().equals(action)) {
return option;
}
}
return null;
}
private static void executeOption(Scanner reader, String description) {
studentOptionsEnum option = getOption(description);
if (option != null) {
option.action(reader);
}
else {
System.out.println("[Manage students] Invalid option! Try again.");
}
}
private static Stream<studentOptionsEnum> stream() {
return Stream.of(studentOptionsEnum.values());
}
}
// Entrypoint of Student Manager
public static void start(Scanner reader) {
// Print available options
studentOptionsEnum.printOptions();
String description = askString(reader, "[Manage students] Select option ('Quit' to exit): ");
while (!description.equals("Quit")) {
studentOptionsEnum.executeOption(reader, description);
System.out.println();
studentOptionsEnum.printOptions();
description = askString(reader, "[Manage students] Select option ('Quit' to exit): ");
}
}
// StudentManager utilities
public static String getStudentID(Scanner reader) {
studentOptionsEnum.LIST_STUDENTS.action(reader);
String studentID = askString(reader, "- Enter student ID: ");
while (!students.containsKey(studentID)) {;
studentID = askString(reader, "- Invalid student ID! Enter student ID: ");
}
return studentID;
}
}
BorrowManager
BookManager.java
package org.labse03part1.logic;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import org.labse03part1.domain.Borrow;
import org.labse03part1.utils.InterfaceUtils;
import java.util.*;
import java.util.stream.Stream;
import static org.labse03part1.utils.InterfaceUtils.askString;
@Data
@Getter
@Setter
public class BorrowManager {
private static Map<String, Borrow> borrows = new HashMap<>();
private enum borrowOptionsEnum {
CREATE_BORROW("Create borrow") {
@Override
void action(Scanner reader) {
createBorrow(reader);
}
void createBorrow(Scanner reader) {
System.out.println("[" + borrowOptionsEnum.CREATE_BORROW.getDescription() + "] Creating new borrow...");
// Ask for the Student name through the StudentManager?
String studentID = StudentManager.getStudentID(reader);
// Ask for the Book name through the BookManager
// - Only show the available books
String bookID = BookManager.getAvailableBookID(reader);
// Create a borrow
Borrow newBorrow = new Borrow(studentID, bookID);
// Store the borrow
borrows.put(newBorrow.getBorrowID(), newBorrow);
System.out.println("[" + borrowOptionsEnum.CREATE_BORROW.getDescription() + "] New borrow created:");
System.out.println("- Borrow ID: " + newBorrow.getBorrowID());
System.out.println("- Borrow details: " + newBorrow);
// Set the book availability to false through the BookManager
BookManager.setBookAvailability(bookID, false);
}
},
DELETE_BORROW("Delete borrow") {
@Override
void action(Scanner reader) {
deleteBorrow(reader);
}
void deleteBorrow(Scanner reader) {
borrowOptionsEnum.LIST_BORROWS.action(reader);
// Option 1.- Ask for the borrow ID
String borrowID = InterfaceUtils.askString(reader, "[" + borrowOptionsEnum.DELETE_BORROW.getDescription() + "] Enter borrow ID ('Quit' to exit): ");
while (!borrows.containsKey(borrowID)) {
if (borrowID.equals("Quit")) {
System.out.println("[" + borrowOptionsEnum.DELETE_BORROW.getDescription() + "] Delete borrow cancelled.");
return;
}
borrowID = InterfaceUtils.askString(reader, "[" + borrowOptionsEnum.DELETE_BORROW.getDescription() + "] Unknown ID. Enter borrow ID ('Quit' to exit): ");
}
Borrow deletedBorrow = borrows.remove(borrowID);
// TODO: Set the book availability to true
BookManager.setBookAvailability(deletedBorrow.getBookID(), false);
System.out.println("[" + borrowOptionsEnum.DELETE_BORROW.getDescription() + "] Borrow " + deletedBorrow.getBorrowID() + " deleted!");
}
},
CHECK_BORROW("Check borrow") {
@Override
void action(Scanner reader) {
checkBorrow(reader);
}
void checkBorrow(Scanner reader) {
borrowOptionsEnum.LIST_BORROWS.action(reader);
// Option 1.- Ask for the borrow ID
String borrowID = InterfaceUtils.askString(reader, "[" + borrowOptionsEnum.CHECK_BORROW.getDescription() + "] Enter borrow ID ('Quit' to exit): ");
while (!borrows.containsKey(borrowID)) {
if (borrowID.equals("Quit")) {
System.out.println("[" + borrowOptionsEnum.CHECK_BORROW.getDescription() + "] Check borrow cancelled.");
return;
}
borrowID = InterfaceUtils.askString(reader, "[" + borrowOptionsEnum.CHECK_BORROW.getDescription() + "] Unknown ID. Enter borrow ID ('Quit' to exit): ");
}
// Print the borrow information
System.out.println(borrows.get(borrowID));
}
},
LIST_BORROWS("List borrows") {
@Override
void action(Scanner reader) {
listBorrows();
}
void listBorrows() {
System.out.println("[" + borrowOptionsEnum.LIST_BORROWS.getDescription() + "] Available 'In progress' borrows:");
// Print all the borrows in a defined format
borrows.entrySet().stream()
.filter(entry -> entry.getValue().getStatusDescription().equals("In progress"))
.map(x -> x.getKey() + ": " + x.getValue())
.forEach(x -> System.out.println(x));
}
},
UPDATE_BORROW("Update borrow") {
@Override
void action(Scanner reader) {
updateBorrow(reader);
}
void updateBorrow(Scanner reader) {
// Ask for the borrow id
borrowOptionsEnum.LIST_BORROWS.action(reader);
// Option 1. Ask for the borrow ID
/*
String borrowID = InterfaceUtils.askString(reader, "[" + borrowOptionsEnum.CHECK_BORROW.getDescription() + "] Enter borrow ID ('Quit' to exit): ");
while (!borrows.containsKey(borrowID)) {
if (borrowID.equals("Quit")) {
System.out.println("[" + borrowOptionsEnum.CHECK_BORROW.getDescription() + "] Check borrow cancelled.");
return;
}
borrowID = InterfaceUtils.askString(reader, "[" + borrowOptionsEnum.CHECK_BORROW.getDescription() + "] Unknown ID. Enter borrow ID ('Quit' to exit): ");
}
Borrow borrowToUpdate = borrows.get(borrowID);
*/
// Option 2. Invoke a borrow finding method
Borrow borrowToUpdate = findBorrow(reader);
if (borrowToUpdate == null) {
System.out.println("Error finding the borrow. Exiting...");
}
System.out.println(borrowToUpdate);
// Ask what field to change
// - Allowed fields to update: status, due date, return date, etc...
System.out.println("[" + borrowOptionsEnum.UPDATE_BORROW.getDescription() + "] Coming soon!");
String parameter = askString(reader, "[" + borrowOptionsEnum.UPDATE_BORROW.getDescription() + "] Enter the parameter to modify ('Quit' to exit): ");
Object value;
while (!parameter.equals("Quit")) {
switch(parameter) {
case "status" -> {
value = askString(reader, "[" + borrowOptionsEnum.UPDATE_BORROW.getDescription() + "] Change the status to 'In Progress', 'Late' or 'Closed': ");
borrowToUpdate.setStatus(String.valueOf(value));
// TODO: If status is set to "Closed", then book availability must be set to true
if (borrowToUpdate.getStatusDescription().equals("Closed")) {
BookManager.setBookAvailability(borrowToUpdate.getBookID(), true);
}
}
case "dueBorrowDate" -> {
// The due borrow date is updated to a later date
value = askString(reader, "[" + borrowOptionsEnum.UPDATE_BORROW.getDescription() + "] Enter the new due date in a YYYY/mm/dd format: ");
borrowToUpdate.setDueBorrowDate(String.valueOf(value));
//
}
default -> System.out.println("[" + borrowOptionsEnum.UPDATE_BORROW.getDescription() + "] " + parameter + "is a read-only parameter, choose another one");
}
parameter = askString(reader, "[" + borrowOptionsEnum.UPDATE_BORROW.getDescription() + "] Insert the parameter to modify ('Quit' to exit): ");
}
}
},
RETURN_BOOK("Return book") {
@Override
void action(Scanner reader) {
returnBook(reader);
}
private void returnBook(Scanner reader) {
// Find the borrow of the book
Borrow borrowToUpdate = findBorrow(reader);
if (borrowToUpdate == null) {
System.out.println("Error finding the borrow. Exiting...");
return;
}
// Set the borrow status to "Close"
borrowToUpdate.setStatus("Closed");
// Set the book availability to True
BookManager.setBookAvailability(borrowToUpdate.getBookID(), true);
System.out.println("[" + borrowOptionsEnum.RETURN_BOOK.getDescription() + "] Book " + BookManager.getBookTitle(borrowToUpdate.getBookID()));
}
};
abstract void action(Scanner reader);
private final String description;
borrowOptionsEnum(String action) {
this.description = action;
}
private String getDescription() {
return this.description;
}
private static void printOptions() {
// Print all the available Borrow options
System.out.println("[Manage borrows] Available options:");
borrowOptionsEnum.stream()
.map(borrowOptionsEnum::getDescription)
.forEach(System.out::println);
}
// Use private methods to manipulate borrows as they have sensitive data
private static borrowOptionsEnum getOption(String action) {
for (borrowOptionsEnum option : borrowOptionsEnum.values()) {
if (option.getDescription().equals(action)) {
return option;
}
}
return null;
}
private static void executeOption(Scanner reader, String action) {
// compare the action with the available enum and see if it is a valid option
borrowOptionsEnum option = getOption(action);
// execute the desired option
if (option != null) {
option.action(reader);
}
else {
System.out.println("[Manage borrows] Unknown option, try again");
}
}
public static Stream<borrowOptionsEnum> stream() {
return Stream.of(borrowOptionsEnum.values());
}
}
public static void start(Scanner reader) {
// Print the available options
borrowOptionsEnum.printOptions();
String action = InterfaceUtils.askString(reader, "[Manage borrows] Select option ('Quit' to exit): ");
while (!action.equals("Quit")) {
borrowOptionsEnum.executeOption(reader, action);
System.out.println();
borrowOptionsEnum.printOptions();
action = InterfaceUtils.askString(reader, "[Manage borrows] Select option ('Quit' to exit): ");
}
}
public static Borrow findBorrow(Scanner reader) {
String knownObject = askString(reader, "[Borrow Manager] Enter known object name ('Quit' to exit): ");
while (!knownObject.equals("book") && !knownObject.equals("user") && !knownObject.equals("borrow")) {
if (knownObject.equals("Quit")) {
System.out.println("Find Borrow cancelled");
return null;
}
knownObject = askString(reader, "[Borrow Manager] Unknown object. Enter known object name ('Quit' to exit): ");
}
String objectID = askString(reader, "[Book Manager] Enter " + knownObject + " ID: ");
switch(knownObject) {
case "book" -> {
return findBorrowByBookID(objectID);
}
case "user" -> {
return findBorrowByUserID(reader, objectID);
}
case "borrow" -> {
// Just return the borrow if it exists
return borrows.getOrDefault(objectID, null);
}
default -> {
return null;
}
}
}
public static Borrow findBorrowByBookID(String bookID) {
for (Map.Entry<String, Borrow> entry : borrows.entrySet()) {
Borrow borrow = entry.getValue();
if (borrow.getBookID().equals(bookID)) {
return borrow;
}
}
return null;
}
public static Borrow findBorrowByUserID(Scanner reader, String userID) {
// 1. Find all borrows of that user
List<Borrow> userBorrows = new ArrayList<>();
for (Map.Entry<String, Borrow> entry : borrows.entrySet()) {
Borrow borrow = entry.getValue();
if (borrow.getStudentID().equals(userID)) {
userBorrows.add(borrow);
}
}
// 2.- Text-only: show all available borrows
for (Borrow borrow : userBorrows) {
if (borrow.getStatusDescription().equals("In progress") || borrow.getStatusDescription().equals("Late")) {
System.out.println("Borrow ID: " + borrow.getBorrowID() + ", book: " + BookManager.getBookTitle(borrow.getBookID()) + ", status: " + borrow.getStatusDescription());
}
}
// 3. Let the user decide what borrow to get
String selectedBorrow = askString(reader, "[Borrow Manager] Enter the user's borrow ID: ");
while (!borrows.containsKey(selectedBorrow)) {
if (selectedBorrow.equals("Quit")) {
System.out.println("[Borrow Manager] Find borrow cancelled.");
return null;
}
selectedBorrow = askString(reader, "[Borrow Manager] Unknown ID. Enter the user's borrow ID: ");
}
// 4. Return the borrow
return borrows.get(selectedBorrow);
}
}
Storage classes
BookStorage
UserStorage
BorrowStorage
Object generation classes
Tests
Objects creation
CRUD operations
Integration tests
Borrow a book
Define the required steps to borrow a book:
- Create a User
- Create a Book
- Create a Borrow for that User and Book
Create an Input of Borrow by console
Define the required steps to replicate the Borrow test using an input from console.