edu.pdx.cs410J.di.BookDatabase Maven / Gradle / Ivy
The newest version!
package edu.pdx.cs410J.di;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.annotation.XmlAttribute;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlElementWrapper;
import jakarta.xml.bind.annotation.XmlRootElement;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
* An implementation of {@link BookInventory} that stores a database of books in a flat file
*/
@Singleton
public class BookDatabase extends JaxbDatabase implements BookInventory
{
private final Map inventory;
/**
* Creates a new database of books stored in a file named "books.xml"
*
* @param directory
* The directory in which the data file will reside
* @throws IOException
* If the data file cannot be created
* @throws JAXBException
* If we cannot create the XML context
*/
@Inject
public BookDatabase( @DataDirectory File directory ) throws JAXBException, IOException
{
this( directory, "books.xml" );
}
/**
* Creates a new database of books. This method is package-protected for testing purposes.
*
* @param directory
* The directory in which the data file will reside
* @param fileName
* The name of the file to store the book inventory
*
* @throws IOException
* If the data file cannot be created
* @throws JAXBException
* If we cannot create the XML context
*/
BookDatabase( File directory, String fileName ) throws IOException, JAXBException
{
super( directory, fileName, BookDatabase.XmlBookDatabase.class,
BookDatabase.XmlBookDatabase.BookCount.class, Book.class );
XmlBookDatabase xml = (XmlBookDatabase) readFile();
if (xml != null) {
this.inventory = xml.getMap();
} else {
this.inventory = new HashMap();
}
}
public synchronized void remove( Book book )
{
AtomicInteger count = inventory.get(book);
if (count == null || count.get() == 0) {
throw new IllegalStateException("We're out of " + book);
} else {
count.decrementAndGet();
writeInventory();
}
}
public synchronized void add(Book... books) {
for (Book book : books) {
AtomicInteger count = inventory.get(book);
if (count == null) {
count = new AtomicInteger( 0 );
inventory.put(book, count);
}
count.incrementAndGet();
}
writeInventory();
}
private synchronized void writeInventory()
{
writeXml( new XmlBookDatabase( this.inventory) );
}
public int getCopies( Book book )
{
AtomicInteger count = inventory.get(book);
if (count == null) {
return 0;
} else {
return count.get();
}
}
public Set getBooks()
{
return inventory.keySet();
}
/**
* JAXB can't marshall a HashMap
, so we need to use this stupid class to represent a book database.
*/
@XmlRootElement(name="book-database")
private static class XmlBookDatabase
{
@XmlElementWrapper(name="books")
private List counts;
/**
* For unmarshalling
*/
public XmlBookDatabase() {
}
public XmlBookDatabase( Map inventory )
{
counts = new ArrayList(inventory.size());
for (Map.Entry count : inventory.entrySet()) {
counts.add(new BookCount(count.getKey(), count.getValue()));
}
}
public Map getMap()
{
Map map = new HashMap(counts.size());
for (BookCount count : counts) {
Book book = count.getBook();
AtomicInteger ai = map.get(book);
if (ai == null) {
ai = new AtomicInteger( 0 );
map.put(book, ai);
}
ai.addAndGet( count.getCount() );
}
return map;
}
@XmlRootElement(name="count")
private static class BookCount
{
@XmlElement
private Book book;
@XmlAttribute
private int count;
/**
* For unmarshalling
*/
public BookCount() {
}
public BookCount( Book book, AtomicInteger count )
{
this.book = book;
this.count = count.get();
}
public Book getBook()
{
return book;
}
public int getCount()
{
return count;
}
}
}
}