BankExampleWithDatabase.java
package examples;
import java.io.*;
import java.util.*;
import sos.db.*;
public class BankExampleWithDatabase
{
private static final int NUM_ACCOUNTS = 10;
private static final int NUM_REPORTS = 10;
private static final int NUM_DEPOSITS = 10;
private static final int NUM_TRANSFERS = 10;
private static final int NUM_DEPOSIT_THREADS = 5;
private static final int NUM_TRANSFER_THREADS = 5;
private static final int NUM_REPORT_THREADS = 10;
private static final int INITIAL_BALANCE = 100;
private static final int AMOUNT_TO_DEPOSIT = 10;
private static final int AMOUNT_TO_TRANSFER = 20;
private Database db;
private Map accounts;
public BankExampleWithDatabase() throws IOException
{
db = new FileDatabase( "Account Database", "test\\accts.db" );
db.create( new HashMap() );
db.open( false );
accounts = (Map)db.getRoot();
db.startTransaction();
for( int i = 0; i < NUM_ACCOUNTS; i++ )
openAccount( i, INITIAL_BALANCE );
db.commitTransaction( null );
}
private Thread createDepositThread( final double depositAmount )
{
Thread thread = new Thread( new Runnable() {
public void run()
{
for( int acctNumber = 0; acctNumber < NUM_ACCOUNTS; acctNumber++ )
{
Account acct = (Account)lookupAccount( acctNumber );
for( int i = 0; i < NUM_DEPOSITS; i++ )
{
deposit( acct, depositAmount ); }
}
}
} );
return thread;
}
private Thread createReportThread()
{
Thread thread = new Thread( new Runnable() {
public void run()
{
for( int i = 0; i < NUM_REPORTS; i++ )
{
generateReport(); }
}
} );
return thread;
}
private Thread createTransferThread( final double transferAmount )
{
Thread thread = new Thread( new Runnable() {
public void run()
{
for( int acctNumber = 0; acctNumber < NUM_ACCOUNTS; acctNumber++ )
{
Account fromAcct = lookupAccount( acctNumber );
Account toAcct = lookupAccount( ( acctNumber + 1 ) % NUM_ACCOUNTS );
for( int i = 0; i < NUM_TRANSFERS; i++ )
{
transfer( fromAcct, toAcct, transferAmount ); }
}
}
} );
return thread;
}
private void deposit( Account acct, double amount )
{
db.startTransaction();
double balance = acct.getBalance(); balance += amount; acct.setBalance( balance ); db.commitTransaction( null );
}
private void generateReport()
{
db.startTransaction();
int numAccounts = accounts.size(); double total = 0;
Collection values = accounts.values();
Iterator acctIterator = values.iterator();
while( acctIterator.hasNext() )
{
Account account = (Account)acctIterator.next();
double balance = account.getBalance(); total += balance; }
db.commitTransaction( null );
System.err.println( total + " for " + numAccounts + " accounts " );
}
private Account lookupAccount( int accountNumber )
{
Object key = new Integer( accountNumber );
return (Account)accounts.get( key ); }
public static void main(String[] args) throws InterruptedException, IOException, NoSuchMethodException
{
ReadOnlyManager.setMethodStatus( Account.class, "getBalance",
null, ReadOnlyManager.READ_ONLY );
BankExampleWithDatabase example = new BankExampleWithDatabase();
example.run();
}
private Account openAccount( int accountNumber, double initialBalance )
{
db.startTransaction();
Account account = new DefaultAccount();
account = (Account)db.addObject( account );
Object key = new Integer( accountNumber );
accounts.put( key, account );
account.setBalance( initialBalance );
db.commitTransaction( null );
return account;
}
public void run() throws InterruptedException, IOException
{
int numThreads = NUM_DEPOSIT_THREADS + NUM_TRANSFER_THREADS + NUM_REPORT_THREADS;
Thread[] threads = new Thread[numThreads];
int index = 0;
for( int i = 0; i < NUM_DEPOSIT_THREADS; i++ )
threads[index++] = createDepositThread( AMOUNT_TO_DEPOSIT );
for( int i = 0; i < NUM_TRANSFER_THREADS; i++ )
threads[index++] = createTransferThread( AMOUNT_TO_TRANSFER );
for( int i = 0; i < NUM_REPORT_THREADS; i++ )
threads[index++] = createReportThread();
for( int i = 0; i < threads.length; i++ )
threads[i].start();
for( int i = 0; i < threads.length; i++ )
threads[i].join();
double expectedBalance = INITIAL_BALANCE + NUM_DEPOSIT_THREADS * NUM_DEPOSITS * AMOUNT_TO_DEPOSIT;
for( int i = 0; i < NUM_ACCOUNTS; i++ )
{
Account acct = lookupAccount( i );
double balance = acct.getBalance();
assert balance == expectedBalance : "Incorrect balance for account " + i + ": " + balance;
}
db.close();
}
private void transfer( Account fromAcct, Account toAcct, double amount )
{
db.startTransaction();
deposit( fromAcct, -amount ); deposit( toAcct, amount ); db.commitTransaction( null );
}
}