Apache Financial ServicesSimple BankThe Simple Bank implementation aims to establish a minimal implementation - unsecured, very simplistic, but functional. Block DirectiveBank has no service dependencies (after all, its a rather simple implementation). The block.xml simply establishes the Bank instance ready to handle account creation and removal requests. <container name="banking"> <component name="bank" class="org.apache.bank.impl.BankProvider" activation="startup"/> </container> Bank ImplementationBankProvider is a simple component with dependencies on the supplied runtime context. It uses the supplied context to retrieve a working directory from which it can internalise and externalise a serializable set of accounts. With an established set of accounts, the Bank can handle requests for new account creation and account removal. Bank.java package org.apache.bank.impl; import java.io.File; import java.io.InputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import org.apache.avalon.framework.logger.AbstractLogEnabled; import org.apache.avalon.framework.context.Contextualizable; import org.apache.avalon.framework.context.Context; import org.apache.avalon.framework.context.ContextException; import org.apache.avalon.framework.activity.Initializable; import org.apache.avalon.framework.activity.Disposable; import org.apache.bank.Bank; import org.apache.bank.Account; import org.apache.bank.PolicyException; import org.apache.bank.NoSuchAccountException; public class BankProvider extends AbstractLogEnabled implements Contextualizable, Initializable, Disposable, Bank { private File m_home = null; /** * The persistant account registry. */ private Accounts m_accounts; /** * Supply of the runtime context to the component by the container. The * component uses the supplied home directory to store accounts. * @param context the runtime context * @exception ContextException if the container does not supply the * home directory under the "urn:avalon:home" key. */ public void contextualize( Context context ) throws ContextException { m_home = (File) context.get( "urn:avalon:home" ); getLogger().info( "setting home directory: " + m_home ); } /** * Initialization of the component by the container. * @exception if an initialization error occurs */ public void initialize() throws Exception { File file = new File( m_home, "accounts.ser" ); getLogger().info( "initialization" ); if( file.exists() ) { getLogger().info( "loading store: " + file ); InputStream stream = new FileInputStream( file ); final ObjectInputStream ois = new ObjectInputStream( stream ); m_accounts = (Accounts) ois.readObject(); getLogger().info( "accounts established: " + m_accounts.accounts() ); } else { getLogger().info( "creating new account registry" ); m_accounts = new Accounts(); } } /** * Disposal of the bank by the container. */ public void dispose() { getLogger().info( "initiating bank disposal" ); try { File file = new File( m_home, "accounts.ser" ); File parent = file.getParentFile(); parent.mkdirs(); file.createNewFile(); FileOutputStream stream = new FileOutputStream( file ); final ObjectOutputStream output = new ObjectOutputStream( stream ); output.writeObject( m_accounts ); output.flush(); getLogger().info( "accounts saved to " + file ); } catch( Throwable e ) { final String error = "Unable to write accounts to file."; getLogger().error( error, e ); } } /** * Get the number of accounts managed by the bank. * @return the number of accounts */ public int accounts() { return m_accounts.accounts(); } /** * Create, register and return a new account. * @param name the name of the account holder * @return Account the account */ public Account createAccount( String name ) { Account account = m_accounts.createAccount( name ); getLogger().info( "created new account for: " + name + " with id: " + account.getID() ); return account; } /** * Close an account. * @param id the account number */ public void closeAccount( int id ) throws PolicyException, NoSuchAccountException { getLogger().info( "closing account: " + id ); m_accounts.closeAccount( id ); } /** * Returns an account based on a supplied account number. * @param id the account number * @return Account the bank account */ public Account getAccount( int id ) throws NoSuchAccountException { Account account = m_accounts.getAccount( id ); getLogger().info( "retrieving account: " + id + " for " + account.getName() ); return account; } } Bank ImplementationThe DefaultAccount implementation provides support for functional operations including the deposit and withdrawal of funds and provision of the standing account balance. Bank.java package org.apache.bank.impl; import java.io.Serializable; import org.apache.bank.Account; import org.apache.bank.InsufficientFundsException; public class DefaultAccount implements Account, Serializable { private int m_id; private String m_name; private float m_balance; public DefaultAccount( String name, int id ) { m_id = id; m_name = name; } /** * Deposit funds into the account. * @param amount the amount of funds to deposit */ public synchronized void deposit( float amount ) { m_balance = m_balance + amount; } /** * Withdraw funds from the account. * @param amount the amount of funds to withdraw */ public synchronized void withdraw( float amount ) throws InsufficientFundsException { if( amount > m_balance ) { final String message = "Request withdrawl of " + amount + " exceeds balance of " + m_balance + "."; throw new InsufficientFundsException( message ); } m_balance = m_balance - amount; } /** * Get the account balance. * @return the account balance */ public float getBalance() { return m_balance; } /** * Get the account name. * @return the account name */ public String getName() { return m_name; } /** * Get the account number. * @return the account number */ public int getID() { return m_id; } public int hashcode() { return getID(); } } |