/*
* OrderList.java
*
* Copyright � 1998-2011 Research In Motion Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Note: For the sake of simplicity, this sample application may not leverage
* resource bundles and resource strings. However, it is STRONGLY recommended
* that application developers make use of the localization features available
* within the BlackBerry development platform to ensure a seamless application
* experience across a variety of languages and geographies. For more information
* on localizing your application, please refer to the BlackBerry Java Development
* Environment Development Guide associated with this release.
*/
package com.rim.samples.device.memorydemo;
import java.util.Date;
import java.util.Vector;
import net.rim.device.api.lowmemory.LowMemoryManager;
import net.rim.device.api.system.ObjectGroup;
import net.rim.device.api.system.PersistentObject;
import net.rim.device.api.system.PersistentStore;
import net.rim.device.api.util.Comparator;
import net.rim.device.api.util.SimpleSortingVector;
/**
* Represents a list of order records for a fictional business.
*/
public final class OrderList {
// Members
// -------------------------------------------------------------------------------------
private final PersistentObject _persist;
private Vector _orderRecords;
// Statics
// -------------------------------------------------------------------------------------
private static OrderList _instance;
// Constants
// -----------------------------------------------------------------------------------
private static final long PERSIST = 0x53fd5dae400aaccL; // com.rim.samples.device.memorydemo
private static final int MAX_NUM_ORDERED = 100;
/**
* This constructor ensures that a persistent object is in place to store
* order records.
*/
public OrderList() {
_persist = PersistentStore.getPersistentObject(PERSIST);
_orderRecords = (Vector) _persist.getContents();
if (_orderRecords == null) {
_orderRecords = new Vector();
_persist.setContents(_orderRecords);
_persist.commit();
}
}
/**
* Retrieves the single instance of the order list.
*
* @return The order list.
*/
static OrderList getInstance() {
if (_instance == null) {
_instance = new OrderList();
}
return _instance;
}
/**
* Retrieves the number of order records stored in the order list.
*
* @return The number of order records.
*/
int getNumOrderRecords() {
return _orderRecords.size();
}
/**
* Retrieves the order record at the specified index.
*
* @param index
* The index of the order record to retrieve.
* @return The retrieved order record.
*/
OrderRecord getOrderRecordAt(final int index) {
return (OrderRecord) _orderRecords.elementAt(index);
}
/**
* Deletes an order record from the list.
*
* @param orderRecord
* The order record to delete.
*/
synchronized void deleteOrderRecord(final OrderRecord orderRecord) {
_orderRecords.removeElement(orderRecord);
}
/**
* Deletes all order records from the list.
*/
synchronized void deleteAllOrderRecords() {
_orderRecords = new Vector();
_persist.setContents(_orderRecords);
}
/**
* Replaces an order record at a specified index with a new order record.
* The new order record is first encoded into an object group so that it
* only occupies one persistent object handle, no matter how many objects it
* actually refers to.
*
* @param index
* The index of the order record to replace.
* @param newOrderRecord
* The new order record.
*/
synchronized void replaceOrderRecordAt(final int index,
final OrderRecord newOrderRecord) {
ObjectGroup.createGroup(newOrderRecord);
_orderRecords.setElementAt(newOrderRecord, index);
}
/**
* Removes all orders that occurred before 'before', and notifies the low
* memory manager that their storage can be reclaimed.
*
* @param before
* The cutoff date for deleting order records.
* @return True if any records are deleted; false otherwise.
*/
synchronized boolean removeStaleOrderRecords(final long before) {
if (_orderRecords.size() == 0) {
return false;
}
// Sort the order records
_orderRecords = sortVector(_orderRecords); // Make sure records are in
// order by date.
boolean freedData = false;
final Vector orderRecords = _orderRecords;
int i = 0;
while (((OrderRecord) orderRecords.elementAt(i)).getDate() < before) // Skip
// over
// all
// stale
// records.
{
++i;
}
if (i > 0) {
final int numRecordsKept = orderRecords.size() - i;
_orderRecords = new Vector();
_persist.setContents(_orderRecords);
for (int j = 0; j < numRecordsKept; ++j) {
_orderRecords.addElement(orderRecords.elementAt(j + i));
}
LowMemoryManager.markAsRecoverable(orderRecords);
freedData = true;
commit();
}
return freedData;
}
/**
* Sorts a Vector of order records.
*
* @param records
* The Vector to be sorted.
* @return The sorted Vector.
*/
private Vector sortVector(final Vector records) {
final SortableVector sortableVector = new SortableVector();
for (int i = 0; i < records.size(); ++i) {
sortableVector.addElement(records.elementAt(i));
}
sortableVector.reSort(); // Make sure records are in order by date.
for (int i = 0; i < sortableVector.size(); ++i) {
records.setElementAt(sortableVector.elementAt(i), i);
}
return records;
}
/**
* Commits the order records to the persistent store.
*/
synchronized void commit() {
_persist.commit();
}
/**
* Populates this order list with order records, each consisting of a random
* company, product, and number of products ordered.
*
* @param totalRecords
* The number of records that should be in the list upon
* completion of this method.
* @param listener
* Object that listens for counting and sorting updates.
*/
synchronized void populate(final int totalRecords,
final CountAndSortListener listener) {
final int numRecordsToAdd = totalRecords - _orderRecords.size();
for (int i = 0; i < numRecordsToAdd; ++i) {
listener.counterUpdated(i);
final long today = new Date().getTime();
final long date = MemoryDemo.randomLongBetween(0, today);
final String company = MemoryDemo.randomString();
final String product = MemoryDemo.randomString();
final int numOrdered =
MemoryDemo.randomIntBetween(1, MAX_NUM_ORDERED);
final OrderRecord orderRecord =
new OrderRecord(date, company, product, numOrdered);
addOrderRecord(orderRecord);
}
listener.sortingStarted();
_orderRecords = sortVector(_orderRecords);
// Vector sorting is done.
listener.sortingFinished();
}
/**
* Retrieves the number of records to be added to the order list.
*
*/
int getNumRecordsToAdd(final int totalRecords) {
return totalRecords - _orderRecords.size();
}
/**
* Helper method to add a new order record to the list. The order record is
* first encoded into an object group so that it only occupies one
* persistent object handle, no matter how many objects it actually refers
* to.
*
* @param orderRecord
* The order record to add.
*/
private void addOrderRecord(final OrderRecord orderRecord) {
ObjectGroup.createGroup(orderRecord);
_orderRecords.addElement(orderRecord);
}
/**
* Implements a sortable vector which sorts based on chronological order.
*/
final static class SortableVector extends SimpleSortingVector {
/**
* Creates a new SortableVector object
*/
public SortableVector() {
setSortComparator(new Comparator() {
public int compare(final Object o1, final Object o2) {
final OrderRecord r1 = (OrderRecord) o1;
final OrderRecord r2 = (OrderRecord) o2;
if (r1.getDate() < r2.getDate()) {
return -1;
}
if (r1.getDate() > r2.getDate()) {
return 1;
}
return 0;
}
});
}
}
}