// DataIOManager
package org.javamoney.examples.ez.money.model;
import static org.javamoney.examples.ez.money.ApplicationProperties.UI_CURRENCY_SYMBOL;
import static org.javamoney.examples.ez.money.model.DataManager.getAccounts;
import static org.javamoney.examples.ez.money.model.DataManager.getExpenses;
import static org.javamoney.examples.ez.money.model.DataManager.getIncome;
import static org.javamoney.examples.ez.money.model.DataManager.getPayees;
import static org.javamoney.examples.ez.money.model.DataManager.getReminders;
import static org.javamoney.examples.ez.money.model.persisted.account.AccountTypeKeys.CASH;
import static org.javamoney.examples.ez.money.model.persisted.account.AccountTypeKeys.CREDIT;
import static org.javamoney.examples.ez.money.model.persisted.account.AccountTypeKeys.DEPOSIT;
import static org.javamoney.examples.ez.money.utility.CryptoHelper.getDecryptionCipher;
import static org.javamoney.examples.ez.money.utility.CryptoHelper.getEncryptionCipher;
import static org.javamoney.examples.ez.money.utility.DialogHelper.error;
import static org.javamoney.examples.ez.money.utility.PasswordHelper.readPassword;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import org.javamoney.examples.ez.money.locale.CurrencyFormat;
import org.javamoney.examples.ez.money.locale.CurrencyFormatKeys;
import org.javamoney.examples.ez.money.model.persisted.account.Account;
import org.javamoney.examples.ez.money.model.persisted.account.AccountTypeKeys;
import org.javamoney.examples.ez.money.model.persisted.category.Category;
import org.javamoney.examples.ez.money.model.persisted.category.CategoryCollection;
import org.javamoney.examples.ez.money.model.persisted.payee.Payee;
import org.javamoney.examples.ez.money.model.persisted.reminder.Reminder;
import org.javamoney.examples.ez.money.model.persisted.transaction.LabelKeys;
import org.javamoney.examples.ez.money.model.persisted.transaction.Transaction;
import org.javamoney.examples.ez.common.utility.I18NHelper;
import org.javamoney.moneta.Money;
/**
* This class facilitates reading and writing the persisted data. All methods in
* this class are static.
*/
public final class DataIOManager {
/**
* This method reads all the data and then returns the success of the
* operation.
* <p>
* <b>Note:</b> This method expects the file to be in a specific format.
*
* @param file
* The file to have the data read from.
* @param showError
* Whether or not to show an error message on failure.
* @param decrypt
* Whether or not the data needs to be decrypted.
*
* @return true or false.
*/
protected static boolean read(File file, boolean showError, boolean decrypt) {
boolean result = false;
try {
BufferedReader reader = createReader(file, decrypt);
String line = "";
while ((line = reader.readLine()) != null) {
if (line.equals(HEADER_ACCOUNTS) == true) {
readAccounts(reader);
} else if (line.equals(HEADER_EXPENSES) == true) {
readCategoryCollection(getExpenses(), reader);
} else if (line.equals(HEADER_INCOME) == true) {
readCategoryCollection(getIncome(), reader);
} else if (line.equals(HEADER_PAYEES) == true) {
readPayees(reader);
} else if (line.equals(HEADER_REMINDERS) == true) {
readReminders(reader);
} else if (line.equals(HEADER_TRANSACTIONS) == true) {
readTransactions(reader);
}
}
reader.close();
result = true;
} catch (Exception exception) {
if (showError == true) {
error(getProperty("read.title"),
getProperty("read.description") + "<br><br><b>" + file
+ "</b>");
}
}
return result;
}
/**
* This method writes all the data and then returns the success of the
* operation.
*
* @param file
* The file to have the data written to.
* @param showError
* Whether or not to show an error message on failure.
* @param encrypt
* Whether or not the data needs to be encrypted.
*
* @return true or false.
*/
protected static boolean write(File file, boolean showError, boolean encrypt) {
boolean result = false;
try {
PrintStream stream = createPrintStream(file, encrypt);
writeAccounts(stream);
writeCategoryCollection(getExpenses(), stream);
writeCategoryCollection(getIncome(), stream);
writePayess(stream);
writeReminders(stream);
writeTransactions(stream);
stream.close();
result = true;
} catch (Exception exception) {
if (showError == true) {
error(getProperty("write.title"),
getProperty("write.description") + "<br><br><b>" + file
+ "</b>");
}
}
return result;
}
// ////////////////////////////////////////////////////////////////////////////
// Start of private methods.
// ////////////////////////////////////////////////////////////////////////////
private static PrintStream createPrintStream(File file, boolean encrypt)
throws Exception {
FileOutputStream fStream = new FileOutputStream(file);
PrintStream pStream = null;
if (encrypt == true) {
Cipher cipher = getEncryptionCipher(readPassword());
// TODO try with resource (Java7)
pStream = new PrintStream(new CipherOutputStream(fStream, cipher));
} else {
pStream = new PrintStream(fStream);
}
return pStream;
}
private static BufferedReader createReader(File file, boolean decrypt)
throws Exception {
FileInputStream fStream = new FileInputStream(file);
InputStreamReader reader = null;
if (decrypt == true) {
Cipher cipher = getDecryptionCipher(readPassword());
CipherInputStream cStream = new CipherInputStream(fStream, cipher);
reader = new InputStreamReader(cStream);
} else {
reader = new InputStreamReader(fStream);
}
return new BufferedReader(reader);
}
private static String getProperty(String key) {
return I18NHelper.getProperty("DataIOManager." + key);
}
private static boolean parseBoolean(String value) {
return Boolean.parseBoolean(value);
}
private static void readAccounts(BufferedReader stream) throws Exception {
Account account = new Account(DEPOSIT, "");
String line = "";
char key;
while ((line = stream.readLine()) != null) {
key = Character.toUpperCase(line.charAt(0));
// Remove the key from the line.
line = line.substring(1);
if (key == END_OF_COLLECTION) {
break;
} else if (key == END_OF_ENTRY) {
getAccounts().add(account);
} else if (key == ACCOUNT_ACTIVE) {
account.setIsActive(parseBoolean(line));
} else if (key == ACCOUNT_BALANCE) {
account.setBalance(Money.of(US_DOLLAR.parse(line),
UI_CURRENCY_SYMBOL.getCurrency()));
} else if (key == ACCOUNT_KEY) {
if (line.equals(AccountTypeKeys.CASH.name()) == true) {
account = new Account(CASH, "");
} else if (line.equals(AccountTypeKeys.CREDIT.name()) == true) {
account = new Account(CREDIT, "");
} else {
account = new Account(DEPOSIT, "");
}
} else if (key == UID) {
account.setIdentifier(line);
}
}
}
private static void readCategoryCollection(CategoryCollection collection,
BufferedReader stream) throws Exception {
Category category = new Category("");
Category group = null;
String line = "";
char key;
while ((line = stream.readLine()) != null) {
key = Character.toUpperCase(line.charAt(0));
// Remove the key from the line.
line = line.substring(1);
if (key == END_OF_COLLECTION) {
break;
} else if (key == END_OF_ENTRY) {
if (group != null) {
collection.addToGroup(group, category);
} else {
collection.add(category);
}
} else if (key == CATEGORY_BUDGET) {
category.setBudget(Integer.parseInt(line));
category.setIsBudgeted(true);
} else if (key == CATEGORY_DATE) {
category.setRolloverStartDate(DATE_FORMAT.parse(line));
} else if (key == CATEGORY_GROUP) {
group = collection.getCategoryFromQIF(line);
} else if (key == CATEGORY_ROLLOVER) {
category.setHasRolloverBudget(parseBoolean(line));
} else if (key == UID) {
category = new Category(line);
}
}
}
private static void readPayees(BufferedReader stream) throws Exception {
Payee payee = new Payee("");
String line = "";
char key;
while ((line = stream.readLine()) != null) {
key = Character.toUpperCase(line.charAt(0));
// Remove the key from the line.
line = line.substring(1);
if (key == END_OF_COLLECTION) {
break;
} else if (key == END_OF_ENTRY) {
getPayees().add(payee);
} else if (key == UID) {
payee = new Payee(line);
}
}
}
private static void readReminders(BufferedReader stream) throws Exception {
Reminder reminder = new Reminder("");
String line = "";
char key;
while ((line = stream.readLine()) != null) {
key = Character.toUpperCase(line.charAt(0));
// Remove the key from the line.
line = line.substring(1);
if (key == END_OF_COLLECTION) {
break;
} else if (key == END_OF_ENTRY) {
getReminders().add(reminder);
} else if (key == REMINDER_COMPLETE) {
reminder.setIsComplete(parseBoolean(line));
} else if (key == REMINDER_DAYS_TO_ALARM) {
reminder.setDaysToAlarm(Integer.parseInt(line));
} else if (key == REMINDER_DUE_BY) {
reminder.setDueBy(DATE_FORMAT.parse(line));
} else if (key == UID) {
reminder = new Reminder(line);
}
}
}
private static void readTransactions(BufferedReader stream)
throws Exception {
Account account = new Account(DEPOSIT, "");
String amount = "";
String category = "";
String date = "";
String label = LabelKeys.NONE.name();
String line = "";
String notes = "";
String number = "";
String payee = "";
String reconciled = "false";
char key;
while ((line = stream.readLine()) != null) {
key = Character.toUpperCase(line.charAt(0));
// Remove the key from the line.
line = line.substring(1);
if (key == END_OF_COLLECTION) {
break;
} else if (key == END_OF_ENTRY) {
Transaction trans = new Transaction(number,
DATE_FORMAT.parse(date), payee, Money.of(
US_DOLLAR.parse(amount),
UI_CURRENCY_SYMBOL.getCurrency()), category,
notes);
trans.setIsReconciled(parseBoolean(reconciled));
trans.setLabel(LabelKeys.valueOf(label));
account.getTransactions().add(trans);
amount = "";
category = "";
date = "";
label = LabelKeys.NONE.name();
notes = "";
number = "";
payee = "";
reconciled = "false";
} else if (key == TRANS_ACCOUNT) {
account = (Account) getAccounts().get(line);
} else if (key == TRANS_AMOUNT) {
amount = line.substring(1);
} else if (key == TRANS_CATEGORY) {
category = line;
} else if (key == TRANS_CHECK_NUMBER) {
number = line;
} else if (key == TRANS_DATE) {
date = line;
} else if (key == TRANS_LABEL) {
label = line;
} else if (key == TRANS_NOTES) {
notes = line;
} else if (key == TRANS_PAYEE) {
payee = line;
} else if (key == TRANS_RECONCILED) {
reconciled = line;
}
}
}
private static void writeAccounts(PrintStream stream) {
stream.println(HEADER_ACCOUNTS);
for (DataElement element : getAccounts().getCollection()) {
Account account = (Account) element;
stream.println(ACCOUNT_KEY + account.getType().name());
stream.println(UID + account.getIdentifier());
stream.println(ACCOUNT_BALANCE
+ US_DOLLAR.format(account.getBalance().getNumber()
.doubleValue(), false));
stream.println(ACCOUNT_ACTIVE + String.valueOf(account.isActive()));
stream.println(END_OF_ENTRY);
}
stream.println(END_OF_COLLECTION);
}
private static void writeCategory(Category category, PrintStream stream) {
stream.println(UID + category.getIdentifier());
stream.println(CATEGORY_GROUP + category.getGroupName());
if (category.isBudgeted() == true) {
stream.println(CATEGORY_BUDGET
+ String.valueOf(category.getBudget()));
stream.println(CATEGORY_DATE
+ DATE_FORMAT.format(category.getRolloverStartDate()));
stream.println(CATEGORY_ROLLOVER
+ String.valueOf(category.hasRolloverBudget()));
}
stream.println(END_OF_ENTRY);
if (category.isGroup() == true) {
for (DataElement element : category.getSubcategories()) {
writeCategory((Category) element, stream);
}
}
}
private static void writeCategoryCollection(CategoryCollection collection,
PrintStream stream) {
if (collection == getExpenses()) {
stream.println(HEADER_EXPENSES);
} else {
stream.println(HEADER_INCOME);
}
for (DataElement element : collection.getCollection()) {
writeCategory((Category) element, stream);
}
stream.println(END_OF_COLLECTION);
}
private static void writePayess(PrintStream stream) {
stream.println(HEADER_PAYEES);
for (DataElement element : getPayees().getCollection()) {
stream.println(UID + element.getIdentifier());
stream.println(END_OF_ENTRY);
}
stream.println(END_OF_COLLECTION);
}
private static void writeReminders(PrintStream stream) {
stream.println(HEADER_REMINDERS);
for (DataElement element : getReminders().getCollection()) {
Reminder reminder = (Reminder) element;
stream.println(UID + reminder.getIdentifier());
stream.println(REMINDER_DUE_BY
+ DATE_FORMAT.format(reminder.getDueBy()));
stream.println(REMINDER_DAYS_TO_ALARM
+ String.valueOf(reminder.getDaysToAlarm()));
stream.println(REMINDER_COMPLETE
+ String.valueOf(reminder.isComplete()));
stream.println(END_OF_ENTRY);
}
stream.println(END_OF_COLLECTION);
}
private static void writeTransactions(PrintStream stream) {
stream.println(HEADER_TRANSACTIONS);
for (DataElement element : getAccounts().getCollection()) {
Account account = (Account) element;
for (Transaction trans : account.getTransactions()) {
stream.println(TRANS_ACCOUNT + account.getIdentifier());
stream.println(TRANS_AMOUNT
+ USD
+ US_DOLLAR.format(trans.getAmount().getNumber()
.doubleValue(), false));
stream.println(TRANS_CHECK_NUMBER + trans.getCheckNumber());
stream.println(TRANS_DATE + DATE_FORMAT.format(trans.getDate()));
stream.println(TRANS_CATEGORY + trans.getCategory());
stream.println(TRANS_LABEL + trans.getLabel().name());
stream.println(TRANS_NOTES + trans.getNotes());
stream.println(TRANS_PAYEE + trans.getPayee());
stream.println(TRANS_RECONCILED
+ String.valueOf(trans.isReconciled()));
stream.println(END_OF_ENTRY);
}
}
stream.println(END_OF_COLLECTION);
}
// ////////////////////////////////////////////////////////////////////////////
// Start of class members.
// ////////////////////////////////////////////////////////////////////////////
private static final String USD = "$";
private static final CurrencyFormat US_DOLLAR = CurrencyFormatKeys.US_DOLLAR
.getFormat();
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat(
"M/d/yyyy");
// Field keys.
private static final char ACCOUNT_ACTIVE = 'A';
private static final char ACCOUNT_BALANCE = 'B';
private static final char ACCOUNT_KEY = 'K';
private static final char CATEGORY_BUDGET = 'B';
private static final char CATEGORY_DATE = 'D';
private static final char CATEGORY_GROUP = 'G';
private static final char CATEGORY_ROLLOVER = 'R';
private static final char END_OF_COLLECTION = '*';
private static final char END_OF_ENTRY = '^';
private static final String HEADER_ACCOUNTS = "!Accounts";
private static final String HEADER_EXPENSES = "!Expenses";
private static final String HEADER_INCOME = "!Income";
private static final String HEADER_PAYEES = "!Payees";
private static final String HEADER_REMINDERS = "!Reminders";
private static final String HEADER_TRANSACTIONS = "!Transactions";
private static final char REMINDER_COMPLETE = 'C';
private static final char REMINDER_DAYS_TO_ALARM = 'A';
private static final char REMINDER_DUE_BY = 'D';
private static final char TRANS_ACCOUNT = '@';
private static final char TRANS_AMOUNT = '\u00A4';
private static final char TRANS_CHECK_NUMBER = '#';
private static final char TRANS_CATEGORY = 'G';
private static final char TRANS_DATE = 'D';
private static final char TRANS_LABEL = 'L';
private static final char TRANS_NOTES = 'N';
private static final char TRANS_PAYEE = 'P';
private static final char TRANS_RECONCILED = 'R';
private static final char UID = 'U';
}