Everything the library needs already exists: you wrote it, one class per module, and the workspace lists them and says which version it is using (a lesson you skipped contributes the reference version until you do it). They compile alongside your file, so Book, Member, Status, Policy, Fees, Checksum, Search, Isbn, Reports, and LibraryException are all in scope. Your job is the class that ties them together: Library.
Work in steps: get books and members in first, then borrowing, then returning with fees, then the reports. When a check fails, its message says what it expected. If a part misbehaves, fix it in its own lesson; the project uses the new version on the next run.
Library lib = new Library();
lib.addBook(new Book("Dune", "Frank Herbert", "0441172717"));
lib.addMember(new Member("Ada", "1234567895"));
lib.checkout("0441172717", "1234567895", 1);
int fee = lib.returnBook("0441172717", 20); // 5 days late at 25 cents: 125Your task
Write class Library with these methods. void addBook(Book book) throws LibraryException: refuse an ISBN that fails Isbn.isValid (message invalid ISBN). void addMember(Member member) throws LibraryException: refuse a card unless Checksum.digitSum of the card number (parse it with Long.parseLong) is a multiple of 10 (message invalid card). Status statusOf(String isbn) throws LibraryException: LOST for a book marked lost, ON_LOAN while it is out, AVAILABLE otherwise, and message unknown book for an ISBN that was never added.
void checkout(String isbn, String card, int day) throws LibraryException: messages unknown book, unknown member, and not available in that order of checking; on success the book is no longer available and the loan is due on day + Policy.LOAN_DAYS. int returnBook(String isbn, int day) throws LibraryException: message not on loan when it is not out; otherwise the book becomes available again and the method returns Fees.lateFee(day - dueDay, Policy.DAILY_FEE_CENTS). void markLost(String isbn) throws LibraryException (unknown book); a lost book is not available either.
Reports: int indexOf(String title) returns the position of the title among the books in the order added, using Search.indexOf on an array of the titles; List<String> overdue(int today) returns the titles of the books on loan whose due day is before today, sorted alphabetically; Map<String, Long> booksPerAuthor() uses Reports.countByAuthor on the authors of all books.
This is the final project. It is built from the 10 parts you made along the way; the workspace lists them and which version it is using.
Hint 1
A private helper that finds a Book by ISBN (loop over books, compare getIsbn with equals) and throws new LibraryException("unknown book") when there is none keeps every method short. The same idea for members by card.
Hint 2
checkout: find the book, find the member, then if (!book.isAvailable() || lost.contains(isbn)) throw not available; book.setAvailable(false); loans.put(isbn, new Loan(isbn, card, day + Policy.LOAN_DAYS)). returnBook: Loan loan = loans.remove(isbn) (null means not on loan), book.setAvailable(true), return Fees.lateFee(day - loan.dueDay(), Policy.DAILY_FEE_CENTS). overdue: collect titles of loans with dueDay() < today, then Collections.sort.
Show the solution
import java.util.*;
public class Main {
public static void main(String[] args) throws LibraryException {
Library lib = new Library();
lib.addBook(new Book("Dune", "Frank Herbert", "0441172717"));
lib.addMember(new Member("Ada", "1234567895"));
lib.checkout("0441172717", "1234567895", 1);
System.out.println(lib.statusOf("0441172717") + " " + lib.returnBook("0441172717", 20));
}
}
record Loan(String isbn, String card, int dueDay) {}
class Library {
private List<Book> books = new ArrayList<>();
private List<Member> members = new ArrayList<>();
private Map<String, Loan> loans = new HashMap<>();
private Set<String> lost = new HashSet<>();
private Book find(String isbn) throws LibraryException {
for (Book b : books) {
if (b.getIsbn().equals(isbn)) {
return b;
}
}
throw new LibraryException("unknown book");
}
private Member findMember(String card) throws LibraryException {
for (Member m : members) {
if (m.card().equals(card)) {
return m;
}
}
throw new LibraryException("unknown member");
}
void addBook(Book book) throws LibraryException {
if (!Isbn.isValid(book.getIsbn())) {
throw new LibraryException("invalid ISBN");
}
books.add(book);
}
void addMember(Member member) throws LibraryException {
if (Checksum.digitSum(Long.parseLong(member.card())) % 10 != 0) {
throw new LibraryException("invalid card");
}
members.add(member);
}
Status statusOf(String isbn) throws LibraryException {
Book book = find(isbn);
if (lost.contains(isbn)) {
return Status.LOST;
}
return book.isAvailable() ? Status.AVAILABLE : Status.ON_LOAN;
}
void checkout(String isbn, String card, int day) throws LibraryException {
Book book = find(isbn);
findMember(card);
if (!book.isAvailable() || lost.contains(isbn)) {
throw new LibraryException("not available");
}
book.setAvailable(false);
loans.put(isbn, new Loan(isbn, card, day + Policy.LOAN_DAYS));
}
int returnBook(String isbn, int day) throws LibraryException {
Book book = find(isbn);
Loan loan = loans.remove(isbn);
if (loan == null) {
throw new LibraryException("not on loan");
}
book.setAvailable(true);
return Fees.lateFee(day - loan.dueDay(), Policy.DAILY_FEE_CENTS);
}
void markLost(String isbn) throws LibraryException {
Book book = find(isbn);
book.setAvailable(false);
lost.add(isbn);
}
int indexOf(String title) {
String[] titles = new String[books.size()];
for (int i = 0; i < books.size(); i++) {
titles[i] = books.get(i).getTitle();
}
return Search.indexOf(titles, title);
}
List<String> overdue(int today) {
List<String> titles = new ArrayList<>();
for (Loan loan : loans.values()) {
if (loan.dueDay() < today) {
try {
titles.add(find(loan.isbn()).getTitle());
} catch (LibraryException e) {
// a loan always refers to a known book
}
}
}
Collections.sort(titles);
return titles;
}
Map<String, Long> booksPerAuthor() {
List<String> authors = new ArrayList<>();
for (Book b : books) {
authors.add(b.getAuthor());
}
return Reports.countByAuthor(authors);
}
}