Hi,

I have a couple of things I'm not too sure about how to go about implementing - Monitors and Atomic Transactions.

The system is a simple Java simulation of a Cash Machine just using the input stream, so eg: Press 1 for Enter card, enter your PIN, enter the amount you want to withdraw. That's basically it.

Now, the point of making it is to show real-time and concurrent processes and scenarios. So the scenario I am using is that the bank account might be a joint account, so I want to block it from being used by more than 1 user at the same time because otherwise they could both withdraw £1000 at the same time from a £1000 balance and end up with £2000 between them.

The way I have done it so far is to just add in a field to the account table in the DB called "locked" and set this to 1 when a user tries to withdraw some cash and to 0 when it finishes, obviously checking first to see if it is locked before any of that runs.

But that kind of seems to defeat the point of using a Monitor class. So could anyone explain to me how I might go about this? Because as far as I can see if you just used a class and didn't add that locked column into the DB surely if another user was using a different cash machine (different instance of Eclipse, so different objects) it wouldn't make any difference? :s


Also, I have two processes:

Update Balance
Dispense Cash

Now if there is an error dispensing the cash (Eg: run out of notes or just random error) then the update balance method shouldn't be committed. I could just do this easily by checking for an error in dispense cash and then just updating the balance again to the old value, but again it seems like i'm avoiding the atomic transaction.

So, could anyone explain how I might go about implementing these things? Or point me to some good examples/documentation?


Thanks.


If you need it, here is the source code for the Account class and the Interface class:

Java Code:
import java.sql.*;

public class Account {
	
	/* Set up some variables */
	
	private int accountNum;
	private int balance;
	private Conn myConn;
	
	/* Constructor */
	public Account(int n) throws SQLException
	{
		myConn = new Conn();
		accountNum = n;
		balance = getBalance();
		
	}
	
	/* Return account num */
	protected int getAccountNum()
	{
		return accountNum;
	}
	
	/* Return balance */
	protected int getBalance() throws SQLException
	{
		int b = -1;
		myConn.newConn();
		Connection dbConn = myConn.getConn();
		Statement s = dbConn.createStatement();
		String q = "SELECT balance FROM Accounts WHERE accountNum = " + accountNum;
		s.execute(q);
		
		ResultSet rs = s.getResultSet(); 
		if (rs != null) 
		{
		while ( rs.next() ) 
		{
		b = rs.getInt(1);
		}
		}
		s.close();
		dbConn.close();
		balance = b;
		return balance;

	}
		
	/* Set Balance */
	protected synchronized int updateBalance(int n) throws SQLException
	{
		int result = -1;
		try
		{
			if(getLockValue() == 1)
			{
				System.out.println("Error: Account Is Locked, Please Wait A Moment And Try Again...");
				return result;
			}
		
			lockAccount();
			
			if(n > 0 && n <= getBalance())
			{
			
		CashMachine newMachine = new CashMachine();
		myConn.newConn();
		Connection dbConn = myConn.getConn();
		Statement s = dbConn.createStatement();
		String q = "UPDATE Accounts SET balance = balance - "+ n +" WHERE accountNum = " + accountNum;
		s.execute(q);
		s.close();
		dbConn.close();
		
		System.out.println("Transaction Completed!\nNew Balance: " + getBalance() + "!");
		newMachine.dispenseCash(n);
		System.out.println("Your Card Has Now Been Ejected, Thank You For Using This Cash Machine!");
		result = n;
			}
			else
			{
				System.out.println("Error: You Do Not Have Enough Funds...");
			}
		
		}
		catch(Exception e)
		{
			System.out.println(e.toString());
			e.printStackTrace();		}
		
		unlockAccount();
		return result;
		
	}
	
	protected void lockAccount() throws SQLException
	{
		myConn.newConn();
		Connection dbConn = myConn.getConn();
		Statement s = dbConn.createStatement();
		String q = "UPDATE Accounts SET locked = 1 WHERE accountNum = " + accountNum;
		s.execute(q);
		s.close();
		dbConn.close();
	}
	
	protected void unlockAccount() throws SQLException
	{
		myConn.newConn();
		Connection dbConn = myConn.getConn();
		Statement s = dbConn.createStatement();
		String q = "UPDATE Accounts SET locked = 0 WHERE accountNum = " + accountNum;
		s.execute(q);
		s.close();
		dbConn.close();
	}
	
	protected int getLockValue() throws SQLException
	{
		int res = 0;
		myConn.newConn();
		Connection dbConn = myConn.getConn();
		Statement s = dbConn.createStatement();
		String q = "SELECT locked FROM Accounts WHERE accountNum = " + accountNum;
		s.execute(q);
		
		ResultSet rs = s.getResultSet(); 
		
		if (rs != null) 
		{
		while ( rs.next() ) 
		{
		res = rs.getInt(1);
		}
		}
		s.close();
		dbConn.close();
		return res;
	}
	
	protected void resetBalance()
	{
		try
		{
		CashMachine newMachine = new CashMachine();
		myConn.newConn();
		Connection dbConn = myConn.getConn();
		Statement s = dbConn.createStatement();
		String q = "UPDATE Accounts SET balance = 1000 WHERE accountNum = " + accountNum;
		s.execute(q);
		s.close();
		dbConn.close();
		}
			catch(Exception e)
			{
			System.out.println(e.toString());
			e.printStackTrace();		
			}
		
	
	}
}
Java Code:
import java.sql.SQLException;

public class Interface {
	
	public static void main (String[] args) throws SQLException {
		
		/* Create InputOutput Object to deal with user input */
		InputOutput myVar = new InputOutput();
		CashMachine myMachine = new CashMachine();
		
		/* Set Up Result Variable */
		int resp = -1;
		
		/* * * * * * * * * * * * * * * * * 
		 * * * * * * * * * * * * * * * * * 
		 * Start The System - Enter Card *
		 * * * * * * * * * * * * * * * * * 
		 * * * * * * * * * * * * * * * * */
		
		while(resp < 0)
		{
		
		/* Display Options */
		myVar.write("Please choose from the following options and then press ENTER...\n1) Enter Your Card");
		
		/* Try and parse result as int */
		resp = tryIt(myVar);
		
		if(resp != -1 && resp != 1){System.out.println("Error: Please select a valid choice.");resp = -1;}
		
		}
		
		/* Print Success Message */
		myMachine.enterCard();
		
		
		
		/* Move onto next step of system */
		
		/* Reset resp variable */
		resp = -1;
		
		
		/* * * * * * * * * * * * * * * * * 
		 * * * * * * * * * * * * * * * * * 
		 * Next Step - Enter PIN Number  *
		 * * * * * * * * * * * * * * * * * 
		 * * * * * * * * * * * * * * * * */
		
		CardVerification myCard = new CardVerification();
		
		while(resp < 0)
		{
		
		/* Display Options */
		myVar.write("Please Enter Your Personal Identification Number (PIN)...");
		
		/* Try and parse result as int */
		resp = tryIt(myVar);
		
			if(resp != -1)
			{
				boolean c = myMachine.enterPin(resp);
				if(c == false){resp = -1;}
			}
		
		}
		
		/* Print Success Message */
		/* This was done in the enterPin() method */
		
		
		
		/* Move onto next step of system */
		
		/* Reset resp variable */
		resp = -1;
		
		
		/* * * * * * * * * * * * * * * * * 
		 * * * * * * * * * * * * * * * * * 
		 * Next Step - Request Money     *
		 * * * * * * * * * * * * * * * * * 
		 * * * * * * * * * * * * * * * * */
		
		Account myAccount = null;
		try {
			myAccount = new Account(myCard.getCustomerAccountNum());
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		myAccount.resetBalance();
		myVar.write("Welcome back " + myCard.getCustomerName() + "\nYour current balance is: £"+myAccount.getBalance());
				
		while(resp < 0)
		{
		
		/* Display Options */
		myVar.write("Please enter the amount you wish to withdraw from your account...");

		/* Try and parse result as int */
		resp = tryIt(myVar);

		
		if(resp != -1 && (resp <= 0)){System.out.println("Error: Please enter an amount greater than 0 and less than your total balance...");resp = -1;}
		else
		{
			
			/* Print Success Message */
			System.out.println("You have requested: £"+resp);
			
			/* Try To Complete Transaction */

			resp = myAccount.updateBalance(resp);
			
		}
			

		}
		
		
		
		
	}
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	public static int tryIt(InputOutput i)
	{
		/* Try and parse result as int */
		try
		{
			int resp = Integer.parseInt(i.getResponse());
			return resp;
		}
		catch( Exception e )
		{
			System.out.println("Error: Please enter a numeric value");
			int resp = -1;
			return resp;
		}
	}
	
}