Ch08 code
From SCMAD Book
Contents |
Expense data access interface (Listing 8.1)
package com.scmadkit.ch08; import javax.microedition.rms.*; /** * This interface provides the API that must be implemented by the * DataAccessObject that would store/retrieve/delete records in the underlying * persistence system. * * @author Sathya.Srinivasan * @version 1.0 */ public interface IExpenseDAO { // ~ Methods -------------------------------------------------- /** * Adds a record into the record store. * * @param expense The expense to be added into the record store. * * @return The expense object containing newly-created ID in the record * store * * * @throws RecordStoreException If the record cannot be added for unexpected * reasons. * @throws RecordStoreNotOpenException If the record store cannot be * created. * @throws RecordStoreFullException If the record store does not have enough * space. */ public Expense add(Expense expense) throws RecordStoreException, RecordStoreNotOpenException, RecordStoreFullException; /** * Gets all the records in the record store. * * @return All the stored expenses as an array. * * @throws RecordStoreNotOpenException If the record store cannot be opened. * @throws RecordStoreException If the array cannot be created for any other * reason. */ public Expense[] allRecords() throws RecordStoreNotOpenException, RecordStoreException; /** * Deletes the passed record. * * @param expense The expense to be deleted. * * @throws RecordStoreException If the record cannot be deleted for * unexpected reasons. * @throws RecordStoreNotOpenException If the record store cannot be opened. * @throws InvalidRecordIDException If the expense passed contains an * invalid id. */ public void delete(Expense expense) throws RecordStoreException, RecordStoreNotOpenException, InvalidRecordIDException; /** * Gets the most expensive expenses. * * @param recordsToReturn The number of expenses to return. * * @return An array of most expensive expenses. If the number of records in * the record store is less than the records requested, all records * in the record store sorted by the expense amount in descending * order will be returned. * * @throws RecordStoreException If the records cannot be retrieved for * unexpected reasons. * @throws RecordStoreNotOpenException If the record store cannot be opened. */ public Expense[] mostExpensiveExpenses(int recordsToReturn) throws RecordStoreException, RecordStoreNotOpenException; /** * Gets the records based on a certain record type. * * @param type The type of expense to be used as a filter. * * @return An array of expenses that match the passed criteria. * * @throws RecordStoreException If the records cannot be retrieved for * unexpected reasons. * @throws RecordStoreNotOpenException If record store cannot be opened. */ public Expense[] recordsFor(ExpenseType type) throws RecordStoreException, RecordStoreNotOpenException; }
Expense data structure (Listing 8.2)
package com.scmadkit.ch08; /** * This class is a data structure that represents an Expense. * * @author Sathya.Srinivasan * @version 1.0 */ public class Expense { // ~ Instance fields ---------------------------------------------- private ExpenseType type; private double amount; private int id; private long date; private String description; // ~ Constructors ------------------------------------------------- /** * Creates a new Expense object. * * @param type Type of expense. * @param amount The amount incurred in this expense. * @param date The date when the expense happened. */ public Expense(ExpenseType type, double amount, long date) { this.setType(type); this.setAmount(amount); this.setDate(date); this.setDescription(description); } // ~ Methods ------------------------------------------------------ /** * Sets the amount for this expense. * * @param amount The amount incurred in this expense. */ public void setAmount(double amount) { this.amount = amount; } /** * Gets the amount for this expense. * * @return Amount incurred in this expense. */ public double getAmount() { return amount; } /** * Sets the date when this expense happened. * * @param date The date when this expense happened. */ public void setDate(long date) { this.date = date; } /** * Gets the date when this expense happened. * * @return Date when this expense happened. */ public long getDate() { return date; } /** * Sets the ID of this expense. * * @param id ID of this expense. */ public void setId(int id) { this.id = id; } /** * Gets the id for this expense. * * @return ID for this expense. */ public int getId() { return id; } /** * Sets the type of this expense. * * @param type Type of this expense. */ public void setType(ExpenseType type) { this.type = type; } /** * Gets the type of this expense. * * @return Type of this expense. */ public ExpenseType getType() { return type; } /** * Sets the description for this expense. * * @param description Description for this expense. */ public void setDescription(String description) { this.description = description; } /** * Gets the description for this expense. * * @return Description for this expense. */ public String getDescription() { return this.description; } /** * A readable version of this Expense. * * @return Readable version of this Expense. */ public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append(this.getDate()); buffer.append(','); buffer.append(this.getType().toString()); buffer.append(','); buffer.append(this.getDescription()); buffer.append(','); buffer.append(this.getAmount()); return buffer.toString(); } }
Expense Type enumeration (Listing 8.3)
package com.scmadkit.ch08; /** * This class represents an enumeration of the expense types used in this * application. * * @author Sathya.Srinivasan * @version 1.0 */ public class ExpenseType { // ~ Static fields/initializers ---------------------------------- /** Indicates a breakfast expense. */ public static final ExpenseType BREAKFAST = new ExpenseType(1, "Breakfast"); /** Indicates a lunch expense. */ public static final ExpenseType LUNCH = new ExpenseType(2, "Lunch"); /** Indicates a dinner expense. */ public static final ExpenseType DINNER = new ExpenseType(3, "Dinner"); /** Indicates a gas expense. */ public static final ExpenseType GAS = new ExpenseType(4, "Gas"); /** Indicates an entertainment expense. */ public static final ExpenseType ENTERTAINMENT = new ExpenseType(5, "Entertainment"); /** Indicates a miscellaneous expense. */ public static final ExpenseType MISCELLANEOUS = new ExpenseType(6, "Miscellaneous"); // ~ Instance fields --------------------------------------------- private String description; private int id; // ~ Constructors ------------------------------------------------- /** * Creates a new ExpenseType object. * * @param id ID for this instance. * @param description Description for this instance. */ public ExpenseType(int id, String description) { this.setId(id); this.setDescription(description); } // ~ Methods ------------------------------------------------------ /** * Sets the description for this instance. * * @param description Description for this instance. */ public void setDescription(String description) { this.description = description; } /** * Gets the id of this instance. * * @return ID of this instance. */ public int getId() { return id; } /** * Gets an instance of the ExpenseType class based on the passed id. This is * used to reconstruct the object when getting it from the database. * * @param id The id of the type. * * @return The instance representing the id. * * @throws IllegalArgumentException If the passed id is invalid. */ public static ExpenseType getInstance(int id) { switch (id) { case 1: return BREAKFAST; case 2: return LUNCH; case 3: return DINNER; case 4: return GAS; case 5: return ENTERTAINMENT; case 6: return MISCELLANEOUS; default: throw new IllegalArgumentException("Invalid ID " + id); } } /** * Provides a readable version of this instance. * * @return A human-readable version of this instance. */ public String toString() { return description; } /** * Sets the id for this instance. * * @param id ID for this instance. */ private void setId(int id) { this.id = id; } }
Expense DAO (Listing 8.4)
package com.scmadkit.ch08; import java.io.IOException; import java.util.Vector; import javax.microedition.rms.InvalidRecordIDException; import javax.microedition.rms.RecordEnumeration; import javax.microedition.rms.RecordStore; import javax.microedition.rms.RecordStoreException; import javax.microedition.rms.RecordStoreFullException; import javax.microedition.rms.RecordStoreNotFoundException; import javax.microedition.rms.RecordStoreNotOpenException; public class ExpenseDAO implements IExpenseDAO { private static final String STORE_NAME = "expenseTracker"; private ExpenseTypeFilter filter = new ExpenseTypeFilter(); private MostExpensiveComparator comparator = new MostExpensiveComparator(); public Expense add(Expense expense) throws RecordStoreException, RecordStoreNotOpenException, RecordStoreFullException { if (expense == null) { throw new IllegalArgumentException("Expense cannot be null"); } RecordStore store = RecordStore.openRecordStore(STORE_NAME, true); try { byte bytes[] = ExpenseUtility.convertToBytes(expense); int id = store.addRecord(bytes, 0, bytes.length); expense.setId(id); } catch (IOException e) { throw new RecordStoreException("Could not process record." + " REASON: " + e.getMessage()); } store.closeRecordStore(); return expense; } public void delete(Expense expense) throws RecordStoreException, RecordStoreNotFoundException, InvalidRecordIDException { if (expense == null) { throw new IllegalArgumentException("Expense cannot be null"); } int id = expense.getId(); RecordStore store = RecordStore.openRecordStore(STORE_NAME, false); store.deleteRecord(id); store.closeRecordStore(); } public Expense[] allRecords() throws RecordStoreNotOpenException, RecordStoreException { RecordStore store = RecordStore.openRecordStore(STORE_NAME, false); RecordEnumeration enumeration = store.enumerateRecords(null, null, false); int size = store.getNumRecords(); Expense expenses[] = new Expense[size]; int count = 0; try { while (enumeration.hasNextElement()) { int id = enumeration.nextRecordId(); byte record[] = store.getRecord(id); expenses[count++] = ExpenseUtility.convertToObject(record); } } catch (IOException e) { throw new RecordStoreException("Could not read records." + " REASON: " + e.getMessage()); } enumeration.destroy(); store.closeRecordStore(); return expenses; } /** * Gets records based on a certain record type. * * @param type The type of expense to be used as a filter. * * @return An array of expenses that match the passed criteria. * * @throws RecordStoreException If the records cannot be retrieved for * unexpected reasons. * @throws RecordStoreNotOpenException If the record store cannot be opened. */ public Expense[] recordsFor(ExpenseType type) throws RecordStoreException, RecordStoreNotOpenException { if (type == null) { throw new IllegalArgumentException("Expense cannot be null"); } filter.setExpenseType(type); RecordStore store = RecordStore.openRecordStore(STORE_NAME, false); RecordEnumeration enumeration = store.enumerateRecords(filter, null, false); Vector matchedRecords = new Vector(); try { while (enumeration.hasNextElement()) { int id = enumeration.nextRecordId(); byte record[] = store.getRecord(id); matchedRecords.add(ExpenseUtility.convertToObject(record)); } } catch (IOException e) { throw new RecordStoreException("Could not read records." + " REASON: " + e.getMessage()); } enumeration.destroy(); store.closeRecordStore(); Expense[] expenses = new Expense[matchedRecords.size()]; for (int i = 0; i < expenses.length; i++) { expenses[i] = (Expense) matchedRecords.elementAt(i); } return expenses; } /** * Gets the most expensive expenses. * * @param recordsToReturn The number of expenses to return. * * @return An array of most expensive expenses. If the number of records in * the record store is less than the records requested, all records * in the record store sorted by the expense amount in descending * order will be returned. * * @throws RecordStoreException If the records cannot be retrieved for * unexpected reasons. * @throws RecordStoreNotOpenException If the record store cannot be opened. */ public Expense[] mostExpensiveExpenses(int recordsToReturn) throws RecordStoreException, RecordStoreNotOpenException { if (recordsToReturn <= 0) { throw new IllegalArgumentException( "Records to return must be greater than 0."); } RecordStore store = RecordStore.openRecordStore(STORE_NAME, false); int totalRecords = store.getNumRecords(); Expense expenses[] = new Expense[(recordsToReturn < totalRecords) ? recordsToReturn : totalRecords]; RecordEnumeration enumeration = store.enumerateRecords(null, comparator, false); int count = 0; try { while (enumeration.hasNextElement()) { int id = enumeration.nextRecordId(); byte record[] = store.getRecord(id); expenses[count++] = ExpenseUtility.convertToObject(record); if (count == expenses.length) break; } } catch (IOException e) { throw new RecordStoreException("Could not read records. " + " REASON: " + e.getMessage()); } enumeration.destroy(); store.closeRecordStore(); return expenses; } }
Expense Utility class (Listing 8.5)
package com.scmadkit.ch08; import java.io.*; /** * This is an utility class that can perform some generic functions on an * Expense object. * * @author Sathya.Srinivasan * @version 1.0 */ public final class ExpenseUtility { /** * Converts an Expense object to a byte array. * * @param expense The expense object to be converted. * * @return An array of bytes representing the passed object. * * @throws IOException If the object cannot be converted. */ public static final byte[] convertToBytes(Expense expense) throws IOException { ByteArrayOutputStream bout = new ByteArrayOutputStream(); DataOutputStream out = new DataOutputStream(bout); out.writeInt(expense.getType().getId()); out.writeLong(expense.getDate()); out.writeUTF(expense.getDescription()); out.writeDouble(expense.getAmount()); return bout.toByteArray(); } /** * Converts a byte array into an Expense object. * * @param record The byte array to be used. * * @return An Expense object constructed from the passed byte array. * * @throws IOException If the object cannot be created from the byte array. */ public static final Expense convertToObject(byte record[]) throws IOException { ByteArrayInputStream bin = new ByteArrayInputStream(record); DataInputStream in = new DataInputStream(bin); ExpenseType type = ExpenseType.getInstance(in.readInt()); long date = in.readLong(); String description = in.readUTF(); double amount = in.readDouble(); Expense expense = new Expense(type, amount, date); expense.setDescription(description); return expense; } }
ExpenseType filter (Listing 8.9)
package com.scmadkit.ch08; import java.io.IOException; import javax.microedition.rms.RecordFilter; /** * Filters a record based on a given expense type. * * @author Sathya.Srinivasan * @version 1.0 */ public class ExpenseTypeFilter implements RecordFilter { // ~ Instance fields ---------------------------------------------- private ExpenseType expenseType; // ~ Methods ------------------------------------------------------ /** * Sets the expense type to be used in this filter. * * @param type The {@link ExpenseType} to be used in this filter. */ public void setExpenseType(ExpenseType type) { this.expenseType = type; } /** * Checks if the passed byte array matches the criteria. * * @param record The record to be checked if it meets the criteria. * * @return true if the record matches the criteria. false otherwise. */ public boolean matches(byte record[]) { try { Expense expense = ExpenseUtility.convertToObject(record); return (expense.getType() == expenseType); } catch (IOException e) { return false; } } }
MostExpensive comparator (Listing 8.10)
package com.scmadkit.ch08; import java.io.IOException; import javax.microedition.rms.RecordComparator; /** * Compares records and provides the order according to the amount in the * Expense in descending order. * * @author Sathya.Srinivasan * @version 1.0 */ public class MostExpensiveComparator implements RecordComparator { // ~ Methods ------------------------------------------------------ /** * Compares two expense records. * * @param record1 The first record to be compared. * @param record2 The second record to be compared. * * @return PRECEDES if the first record is more expensive than the second * record. FOLLOWS if the first records is less expensive than the * second record. EQUIVALENT if the expenses are the same. */ public int compare(byte record1[], byte record2[]) { Expense expense1 = null; Expense expense2 = null; try { expense1 = ExpenseUtility.convertToObject(record1); } catch (IOException e) { return FOLLOWS; } try { expense2 = ExpenseUtility.convertToObject(record2); } catch (IOException e) { return PRECEDES; } double amount1 = expense1.getAmount(); double amount2 = expense2.getAmount(); if (amount1 > amount2) { return PRECEDES; } else if (amount1 < amount2) { return FOLLOWS; } else { return EQUIVALENT; } } }
