Java Guild course · The starter code
Workspace · the exercise
The Solirius project exactly as supplied. Every defect discussed in the course is visible here.
Start with README.md for the brief, then Library.java for
the IOException problem, then the exceptions/ package —
and note that nothing anywhere imports it. See the
defect inventory for the full list.
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# IDEA files
*.iml
.idea/
# MVN files
target/*
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*
This repository contains a Java challenge designed to assess the skills of a Java Guild candidate. The challenge includes problem-solving, coding, and demonstrating knowledge of Java fundamentals and best practices.
# Build a Library Management System
## Objective:
Create a simplified Library Management System (LMS) using Java that allows users to perform basic operations like adding books, borrowing books, and viewing available books.
# Requirements
## Book Class (visibility at candidate discretion)
Represents a book in the library.
### Attributes (visibility at candidate discretion)
* String title
* String author
* boolean isBorrowed
### Methods (visibility at candidate discretion)
* Book(String title, String author) - Constructor to initialise a book.
* boolean borrowBook() - Marks the book as borrowed if it's not already borrowed.
* boolean returnBook() - Marks the book as returned.
* String toString() - Returns a string representation of the book (e.g., "Title by Author (Available/Borrowed)").
## Library Class (visibility at candidate discretion)
Manages a collection of books.
### Attributes (visibility at candidate discretion)
* ArrayList<Book> books
### Methods (visibility at candidate discretion)
* void addBook(Book book) - Adds a new book to the collection.
* List<Book> viewAvailableBooks() - Returns a list of books that are not borrowed.
* Book searchBook(String title) - Searches for a book by title.
* boolean borrowBook(String title) - Allows a user to borrow a book by title.
* boolean returnBook(String title) - Allows a user to return a book by title.
## Main Class (visibility at candidate discretion)
Provides a menu-driven interface for the user to interact with the Library Management System.
Options include:
* Add a new book.
* View available books.
* Search for a book.
* Borrow a book.
* Return a book.
* Exit the application.
## Incremental role-based extra features (eg. an intermediate is expected to build Graduate+Intermediate)
* Graduate
* Unit Tests: Write test cases for Book and Library classes.
* Intermediate
* Exception Handling: Handle scenarios where a book is already borrowed, does not exist, or cannot be returned.
* Persistence: Save the library state to a file and reload it upon application restart.
* Advanced roles
* Persistence: Save the library state to a portable file-based database.
* Search: Find a book by title or author
* Sorting: Provide an option to view books sorted by title or author.
## Instructions for Submission
Create a zip file (.7z or .zip) containing the code and any other files for your project.
Include:
* The complete Java source code.
* A README.md file with instructions on how to run the program.
* A brief description of the approach taken and any additional features implemented.
* Email the zip file to your talent acquisition contact as an attachment when completed.
## Evaluation Criteria
* Code readability and organisation.
* Proper use of object-oriented programming principles.
* Handling edge cases and exceptions.
* Implementation of bonus features (if any).
* Clarity and thoroughness of the README file.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>groupId</groupId>
<artifactId>java-guild-candidate-test</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.47.2.0</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.15.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.6.0</version>
<reportSets>
<reportSet>
<reports>
<report>checkstyle</report>
</reports>
</reportSet>
</reportSets>
</plugin>
</plugins>
</reporting>
</project>
package com.solirius.intermediate.library;
/**
* Represents a book in the library.
*/
public class Book {
/**
* The book's title.
*/
private final String title;
/**
* The book's author.
*/
private final String author;
/**
* Defines whether the book has been borrowed.
*/
private boolean isBorrowed;
/**
* Creates a book with a title and author.
* The book is initially not borrowed.
*
* @param theTitle the title of the book
* @param theAuthor the author of the book
*/
public Book(final String theTitle, final String theAuthor) {
this.title = theTitle;
this.author = theAuthor;
this.isBorrowed = false;
}
/**
* Borrows the book if it's not already borrowed.
*
* @return true if the book is successfully borrowed, otherwise false
*/
public boolean borrowBook() {
if (!isBorrowed) {
isBorrowed = true;
return true;
}
return false;
}
/**
* Returns the book if it's currently borrowed.
*
* @return true if the book is successfully returned, otherwise false
*/
public boolean returnBook() {
if (isBorrowed) {
isBorrowed = false;
return true;
}
return false;
}
/**
* Helps printing a book's features.
* @return a string representation of the book.
*/
@Override
public String toString() {
return title + " by " + author
+ " (" + (isBorrowed ? "Borrowed" : "Available") + ")";
}
/**
* Gets the title of the book.
*
* @return the title of the book
*/
public String getTitle() {
return title;
}
/**
* Checks if the book is borrowed.
*
* @return true if the book is borrowed, otherwise false
*/
public boolean isBorrowed() {
return isBorrowed;
}
/**
* Gets the author of the book.
*
* @return the author of the book
*/
public String getAuthor() {
return author;
}
}
package com.solirius.intermediate.library;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* Represents a library that holds a collection of books.
*/
public class Library {
/**
* Library Books.
*/
private final List<Book> books;
/**
* Creates an empty library.
*/
public Library() {
this.books = new ArrayList<>();
}
/**
* Adds a book to the library.
*
* @param book the book to add
*/
public void addBook(final Book book) {
books.add(book);
}
/**
* Gets a list of available books.
*
* @return a list of books that are not borrowed
*/
public List<Book> viewAvailableBooks() {
List<Book> availableBooks = new ArrayList<>();
for (Book book : books) {
if (!book.isBorrowed()) {
availableBooks.add(book);
}
}
return availableBooks;
}
/**
* Searches for a book by its title.
*
* @param title the title of the book to search
* @return the book if found, otherwise null
*/
public Book searchBook(final String title) {
for (Book book : books) {
if (book.getTitle().equalsIgnoreCase(title)) {
return book;
}
}
return null;
}
/**
* Borrows a book by its title.
*
* @param title the title of the book to borrow
* @return true if the book is successfully borrowed, otherwise false
*/
public boolean borrowBook(final String title) throws IOException {
Book book = searchBook(title);
if (book == null || !book.borrowBook()) {
throw new IOException("Book not found: " + title);
}
return true;
}
/**
* Returns a book by its title.
*
* @param title the title of the book to return
* @return true if the book is successfully returned, otherwise false
*/
public boolean returnBook(final String title) throws IOException {
Book book = searchBook(title);
if (book == null || !book.returnBook()) {
throw new IOException("Book not found or not borrowed: " + title);
}
return true;
}
/**
* Saves the state of the library to a file.
*
* @param filePath the path to save the file
* @throws IOException if an I/O error occurs
*/
public void saveLibraryState(final String filePath) throws IOException {
try (BufferedWriter writer =
new BufferedWriter(new FileWriter(filePath))) {
for (Book book : books) {
writer.write(book.getTitle() + ";"
+ book.getAuthor() + ";"
+ book.isBorrowed());
writer.newLine();
}
}
}
/**
* Loads the state of the library from a file.
*
* @param filePath the path to load the file
* @throws IOException if an I/O error occurs
*/
public void loadLibraryState(final String filePath) throws IOException {
books.clear();
try (BufferedReader reader = new BufferedReader(
new FileReader(filePath))) {
String line;
while ((line = reader.readLine()) != null) {
String[] parts = line.split(";");
String title = parts[0];
String author = parts[1];
boolean isBorrowed = Boolean.parseBoolean(parts[2]);
Book book = new Book(title, author);
if (isBorrowed) {
book.borrowBook();
}
books.add(book);
}
}
}
}
package com.solirius.intermediate.library;
import java.io.IOException;
import java.util.Scanner;
public final class Main {
/**
* The main menu.
*/
public static final String MENU = "\nMenu:"
+ "\n1. Add a new book"
+ "\n2. View available books"
+ "\n3. Search for a book"
+ "\n4. Borrow a book"
+ "\n5. Return a book"
+ "\n6. Exit"
+ "\nEnter your choice: ";
/**
* Option to add a Book.
*/
public static final int ADD_A_BOOK_OPTION = 1;
/**
* Option to list available Books.
*/
public static final int LIST_AVAILABLE_BOOKS = 2;
/**
* Option to search a Book.
*/
public static final int SEARCH_BOOK_OPTION = 3;
/**
* Option to search a Book.
*/
public static final int BORROW_BOOK_OPTION = 4;
/**
* Option to return a Book.
*/
public static final int RETURN_BOOK_OPTION = 5;
/**
* Option to terminate the program.
*/
public static final int EXIT_OPTION = 6;
private Main() {
}
/**
* Initialises the LMS program.
* @param args from the command line.
*/
public static void main(final String[] args) {
Library library = new Library();
String filePath = "libraryState.txt";
// Load library state
try {
library.loadLibraryState(filePath);
System.out.println("Library state loaded successfully.");
} catch (IOException e) {
System.out.println("Could not load library state. Starting fresh.");
}
Scanner scanner = new Scanner(System.in);
boolean running = true;
System.out.println("Welcome to the Library Management System!");
while (running) {
System.out.println(MENU);
int choice = scanner.nextInt();
scanner.nextLine(); // Consume newline
switch (choice) {
case ADD_A_BOOK_OPTION:
System.out.print("Enter book title: ");
String title = scanner.nextLine();
System.out.print("Enter book author: ");
String author = scanner.nextLine();
library.addBook(new Book(title, author));
System.out.println("Book added successfully!");
break;
case LIST_AVAILABLE_BOOKS:
System.out.println("Available books:");
for (Book book : library.viewAvailableBooks()) {
System.out.println(book);
}
break;
case SEARCH_BOOK_OPTION:
System.out.print("Enter the title of the book to search: ");
title = scanner.nextLine();
Book foundBook = library.searchBook(title);
System.out.println(foundBook != null
? foundBook : "Book not found.");
break;
case BORROW_BOOK_OPTION:
System.out.print("Enter the title of the book to borrow: ");
title = scanner.nextLine();
try {
library.borrowBook(title);
System.out.println("Book borrowed successfully!");
} catch (IOException e) {
throw new RuntimeException(e);
}
break;
case RETURN_BOOK_OPTION:
System.out.print("Enter the title of the book to return: ");
title = scanner.nextLine();
try {
library.returnBook(title);
System.out.println("Book returned successfully!");
} catch (IOException e) {
throw new RuntimeException(e);
}
break;
case EXIT_OPTION:
System.out.println("Saving library state...");
try {
library.saveLibraryState(filePath);
System.out.println("Library state saved successfully.");
} catch (IOException e) {
System.out.println(e.getMessage());
}
running = false;
System.out.println("Thank you for using "
+ "the Library Management System!");
break;
default:
System.out.println("Invalid choice. Please try again.");
}
}
scanner.close();
}
}
package com.solirius.intermediate.library.exceptions;
/**
* Exception thrown when attempting to borrow a book that is already borrowed.
*/
public class AlreadyBorrowedException extends Exception {
/**
* Constructs a new AlreadyBorrowedException with the specified message.
*
* @param message the detail message
*/
public AlreadyBorrowedException(final String message) {
super(message);
}
}
package com.solirius.intermediate.library.exceptions;
/**
* Exception thrown when a book is not found in the library.
*/
public class BookNotFoundException extends Exception {
/**
* Constructs a new BookNotFoundException with the specified message.
*
* @param message the detail message
*/
public BookNotFoundException(final String message) {
super(message);
}
}
package com.solirius.intermediate.library.exceptions;
/**
* Exception thrown when attempting to return a book that was not borrowed.
*/
public class NotBorrowedException extends Exception {
/**
* Constructs a new NotBorrowedException with the specified message.
*
* @param message the detail message
*/
public NotBorrowedException(final String message) {
super(message);
}
}
/**
* This package contains custom exceptions used in
* the Library Management System.
*
* <ul>
* <li>{@link
* com.solirius.intermediate.library.exceptions.AlreadyBorrowedException} -
* Thrown when attempting to borrow a book that is already borrowed.</li>
* <li>{@link
* com.solirius.intermediate.library.exceptions.BookNotFoundException} -
* Thrown when a requested book is not found in the library.</li>
* <li>{@link
* com.solirius.intermediate.library.exceptions.NotBorrowedException} -
* Thrown when attempting to return a book that was not borrowed.</li>
* </ul>
*/
package com.solirius.intermediate.library.exceptions;
/**
* Provides the classes and interfaces for managing
* a library system.
* <p>
* This package includes functionalities for:
* </p>
* <ul>
* <li>Managing books (adding, removing, and updating
* book information).</li>
* <li>Handling user operations such as registration,
* borrowing, and
* returning books.</li>
* </ul>
* <p>
* The core components of this package are:
* </p>
* <ul>
* <li>{@code Book}: Represents a book entity with details
* like title,
* author, ISBN, and availability status.</li>
* <li>{@code Library}: Handles the main operations of the
* library, acting
* as the controller of the system.</li>
* </ul>
* <p>
* Example usage:
* </p>
* <pre>
* Library library = new Library();
* Book book = new Book("The Great Gatsby",
* "F. Scott Fitzgerald");
* library.addBook(book);
* book.borrowBook();
* </pre>
*
* @since 1.0
* @author Antonio Cucchiara (Solirius Consulting Ltd.)
*/
package com.solirius.intermediate.library;