package edu.pdx.cs410J.di; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import com.google.inject.Inject; import javax.xml.bind.JAXBException; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlRootElement; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * Stores {@link CreditCard}s in an XML file */ public class CreditCardDatabase extends JaxbDatabase { private final Map<CreditCard, Double> balances; @Inject public CreditCardDatabase(@DataDirectory File directory) throws JAXBException, IOException { this( directory, "CreditCards.xml"); } CreditCardDatabase( File directory, String fileName ) throws IOException, JAXBException { super( directory, fileName, XmlCreditCardDatabase.class, XmlCreditCardDatabase.CreditCardBalance.class, CreditCard.class ); XmlCreditCardDatabase xml = (XmlCreditCardDatabase) readFile(); if (xml != null) { this.balances = xml.getMap(); } else { this.balances = Maps.newHashMap(); } } synchronized void setBalance(CreditCard card, double balance) { this.balances.put(card, balance); writeDatabase(); } public synchronized void debit(CreditCard card, double amount) { double balance = balances.get(card); balance -= amount; this.balances.put(card, balance); writeDatabase(); } private void writeDatabase() { writeXml( new XmlCreditCardDatabase( this.balances) ); } public ImmutableMap<CreditCard, Double> getBalances() { return ImmutableMap.copyOf( this.balances ); } /** * JAXB can't marshall a <code>HashMap</code>, so we need to use this stupid class to represent a CreditCard database. */ @XmlRootElement(name="CreditCard-database") private static class XmlCreditCardDatabase { @XmlElementWrapper(name="CreditCards") private List<CreditCardBalance> balances; /** * For unmarshalling */ public XmlCreditCardDatabase() { } public XmlCreditCardDatabase( Map<CreditCard, Double> inventory ) { balances = new ArrayList<CreditCardBalance>(inventory.size()); for (Map.Entry<CreditCard, Double> count : inventory.entrySet()) { balances.add(new CreditCardBalance(count.getKey(), count.getValue())); } } public Map<CreditCard, Double> getMap() { Map<CreditCard, Double> map = Maps.newHashMap(); for ( CreditCardBalance balance : balances ) { map.put(balance.getCard(), balance.getBalance()); } return map; } @XmlRootElement(name="balance") private static class CreditCardBalance { @XmlElement private CreditCard card; @XmlAttribute private double balance; /** * For unmarshalling */ public CreditCardBalance() { } public CreditCardBalance( CreditCard card, Double balance ) { this.card = card; this.balance = balance; } public CreditCard getCard() { return card; } public double getBalance() { return balance; } } } }