We’ve added a new session, LoanDao. It essentially provides a few queries dealing with loans such as finding all overdue books or finding all patrons with overdue books.
LoanDao.java
package session;
import java.util.Date;
import java.util.List;
import javax.persistence.NoResultException;
import entity.Book;
import entity.Loan;
import entity.Patron;
/**
* Provide some basic queries focused around the Loan object. These queries
* could have been placed in either the PatronDao or BookDao. However, neither
* seemed like quite the right place so we created this new Dao.
*/
public class LoanDao extends BaseDao {
/**
* Given a book id, find the associated loan or return null if none found.
*
* @param bookId
* Id of book on loan
*
* @return Loan object that holds onto bookId
*/
public Loan getLoanFor(Long bookId) {
try {
return (Loan) getEm().createNamedQuery("Loan.byBookId")
.setParameter("bookId", bookId).getSingleResult();
} catch (NoResultException e) {
return null;
}
}
public void remove(final Loan l) {
getEm().remove(l);
}
/**
* Return books that are due after the compareDate.
*
* @param compareDate
* If a book's due date is after compareDate, then it is included
* in the list. Note that this named query uses projection. Have
* a look at Loan.java.
*
* @return a list of all the books that were due after this date.
*/
@SuppressWarnings("unchecked")
public List<Book> listAllOverdueBooks(final Date compareDate) {
return getEm().createNamedQuery("Loan.overdueBooks").setParameter(
"date", compareDate).getResultList();
}
/**
* Essentially the same query as listAllOverdueBooks but we return the
* Patrons instead of the books. This method uses a named query that uses
* projection.
*
* @param compareDate
* If a patron has at least one book that was due after the
* compare date, include them.
*
* @return A list of the patrons with at least one overdue book
*/
@SuppressWarnings("unchecked")
public List<Patron> listAllPatronsWithOverdueBooks(final Date compareDate) {
return getEm().createNamedQuery("Loan.patronsWithOverdueBooks")
.setParameter("date", compareDate).getResultList();
}
/**
* Return all books on loan to the provided patron id.
*
* @param patronId
* If patron id is invalid, this method will not notice it.
*
* @return Zero or more books on loan to the patron in question
*/
@SuppressWarnings("unchecked")
public List<Book> listBooksOnLoanTo(final Long patronId) {
return getEm().createNamedQuery("Loan.booksLoanedTo").setParameter(
"patronId", patronId).getResultList();
}
}
Library.java
package session;
import java.util.Date;
import java.util.List;
import javax.persistence.EntityNotFoundException;
import entity.Address;
import entity.Author;
import entity.Book;
import entity.Loan;
import entity.Patron;
import exception.BookAlreadyCheckedOut;
import exception.BookNotCheckedOut;
import exception.PatronHasFines;
/**
* This class provides a basic facade to the library system. If we had a user
* interface, it would interact with this object rather than dealing with all of
* the underlying Daos.
*/
public class Library {
private BookDao bookDao;
private PatronDao patronDao;
private LoanDao loanDao;
public BookDao getBookDao() {
return bookDao;
}
public void setBookDao(final BookDao bookDao) {
this.bookDao = bookDao;
}
public PatronDao getPatronDao() {
return patronDao;
}
public void setPatronDao(final PatronDao patronDao) {
this.patronDao = patronDao;
}
public LoanDao getLoanDao() {
return loanDao;
}
public void setLoanDao(final LoanDao loanDao) {
this.loanDao = loanDao;
}
public Book createBook(final String title, final String isbn,
final Date date, final Author a1, final Author a2) {
return getBookDao().create(title, isbn, date, a1, a2);
}
public List<Book> findBookByIsbn(String isbn) {
return getBookDao().findByIsbn(isbn);
}
public Patron createPatron(final String patronId, final String fname,
final String lname, final String phoneNumber, final Address a) {
return getPatronDao().createPatron(fname, lname, phoneNumber, a);
}
public Patron findPatronById(final Long id) {
final Patron p = getPatronDao().retrieve(id);
if (p == null) {
throw new EntityNotFoundException(String.format(
"Patron with id: %d does not exist", id));
}
return p;
}
public Book findBookById(Long id) {
final Book b = getBookDao().findById(id);
if (b == null) {
throw new EntityNotFoundException(String.format(
"Book with Id:%d does not exist", id));
}
return b;
}
public void returnBook(final Date checkinDate, final Long... bookIds) {
for (Long bookId : bookIds) {
final Loan l = getLoanDao().getLoanFor(bookId);
if (l == null) {
throw new BookNotCheckedOut(bookId);
}
l.checkin(checkinDate);
getLoanDao().remove(l);
}
}
public void checkout(final Long patronId, final Date checkoutDate,
final Long... bookIds) {
final Patron p = findPatronById(patronId);
double totalFines = p.calculateTotalFines();
if (totalFines > 0.0d) {
throw new PatronHasFines(totalFines);
}
for (Long id : bookIds) {
final Book b = findBookById(id);
if (b.isCheckedOut()) {
throw new BookAlreadyCheckedOut(id);
}
p.checkout(b, checkoutDate);
}
}
public List<Book> listBooksOnLoanTo(final Long patronId) {
return getLoanDao().listBooksOnLoanTo(patronId);
}
public List<Book> findAllOverdueBooks(final Date compareDate) {
return getLoanDao().listAllOverdueBooks(compareDate);
}
public List<Patron> findAllPatronsWithOverdueBooks(final Date compareDate) {
return getLoanDao().listAllPatronsWithOverdueBooks(compareDate);
}
public double calculateTotalFinesFor(final Long patronId) {
return getPatronDao().retrieve(patronId).calculateTotalFines();
}
public double tenderFine(final Long patronId, double amountTendered) {
final Patron p = getPatronDao().retrieve(patronId);
return p.pay(amountTendered);
}
}
Comments