46
ATM Simulation Code When this example was first developed (in 1996), the implementation was done in C++, using the curses package to produce a screen display that looks something like the machine being modelled. More recently (1997), it has been re-implemented using Java, with a full GUI interface. As noted in the initial page, minor changes were made to the overall design at that time as well. Both implementations are based on the same design, and except for the classes that model the components of the ATM, the code in both is very similar - in fact, much of the Java code is a straight translation of the corresponding C++ code. The following are the significant structural differences (see also the discussion of data type/prototype issues on the Operation Description Forms page ): 1. The Java constructor for class ATM has an additional parameter - a GUI container - that is not documented in the Class/Operation description forms. It uses this container to hold and display the various component parts of the ATM that it constructs. 2. The C++ implementation of the machine components in atmparts.cc uses quite a number of static variables plus an additional module (window.h/.cc) to simulate the machine on the screen using the curses pacakge. Most of the classes in the Java atmparts package have additional fields and methods needed to support the GUI that are not documented on the Class/Operation description form pages. and there are two additional classes in package

ATM Simulation Code

Embed Size (px)

Citation preview

Page 1: ATM Simulation Code

ATM Simulation Code

When this example was first developed (in 1996), the implementation was done in C++, using the curses package to produce a screen display that looks something like the machine being modelled. More recently (1997), it has been re-implemented using Java, with a full GUI interface. As noted in the initial page, minor changes were made to the overall design at that time as well. Both implementations are based on the same design, and except for the classes that model the components of the ATM, the code in both is very similar - in fact, much of the Java code is a straight translation of the corresponding C++ code. The following are the significant structural differences (see also the discussion of data type/prototype issues on the Operation Description Forms page ):

1. The Java constructor for class ATM has an additional parameter - a GUI container - that is not documented in the Class/Operation description forms. It uses this container to hold and display the various component parts of the ATM that it constructs.

2. The C++ implementation of the machine components in atmparts.cc uses quite a number of static variables plus an additional module (window.h/.cc) to simulate the machine on the screen using the curses pacakge. Most of the classes in the Java atmparts package have additional fields and methods needed to support the GUI that are not documented on the Class/Operation description form pages. and there are two additional classes in package (GUILayout, QuestionDialog) that contribute to the task as well.

3. The class Money has a different implementation in the two languages. In the C++ version, the operators +, -, +=, -=, ==, and < are overloaded for Money. Since operator overloading is not possible in Java, the Java version has methods named add (two versions), subtract (two versions), equals, and less. Also, the Java version has a set() method; in several places Money values are returned through the parameters of a method, which is done by assigning to a reference parameter in C++ and by setting the value of the object passed in Java.

Both implementations make use of two classes in addition to those that were developed during the early stages of the design. The need for these became evident when doing the detailed design of the individual classes. The class Money uses a class to implement money as an abstract data type. The class Status encapsulates status codes that indicate success or failure of various

Page 2: ATM Simulation Code

transactions. (This is basically an enum in C++, and a class that consists of static final int's in Java.)

C++ Implementation Java Implementation

[ Intro ] [ Requirements ] [ Domain Objects ] [ Use Cases ] [ State Diagram ] [ Interaction Diagram ] [ CRC Cards ] [ Class Diagram ] [ Class Desc. Forms ] [ Operation Desc. Forms ] [ Code ] [ Executable ]

Copyright © 1996, 1997, 1998 - Russell C. Bjork. Permission for non-commercial reproduction for educational use is hereby granted; all other rights are reserved.

C++ Implementation

The implementation of the ATM simulation in C++ consists of eight modules that declare and implement the various classes - most consisting of an interface (.h) file that contains the class declaration(s) and an implementation (.cc) file that implements the methods declared in the interface. (No implementation file is needed for the class Status, and no interface file is needed for the main program.) Most modules implement a single class, but all the component parts of the ATM are grouped together into a single atmparts module, and all types of transactions are grouped into a single transactions module.

The current version of these files has been compiled and run on both a VAX/VMS system and a Linux system, both using gnu C++. A complete downloadable package of the all the source code will eventually be available via anonymous ftp. The README file in that package contains information about system specific details.

Files that Implement the Various Classes, Plus Main Program

Interface Implementation Purposeatm.h atm.cc ATM itselfatmparts.h atmparts.cc Component parts of ATMsession.h session.cc Perform a customer sessiontransaction.h transaction.cc Perform a transactionbank.h bank.cc Manage communication with bankmoney.h money.cc Abstract data type Moneystatus.h (None) Status code values(None) main.cc Main program

Page 3: ATM Simulation Code

NOTE: The implementation file atmparts.cc contains very system-specific code for displaying some likeness of an ATM. Frankly, some of it is pretty ugly! This file also utilizes a windows module (windows.h/.cc) which builds a window class on top of the curses package.Likewise, the implementation of class Bank is very simple and also fairly ugly - ie card numbers and PINs are hardwired in, etc. It is intended that a more realistic implementation be left as an exercise to the student. For these reason, no links to these files are included above (though they will be included in the complete downloadable package.) Also, all of the implementation files include a file sysdep.h that incorporates system-dependent declarations. If you really _have_ to see these files, here are the links - but don't say I didn't warn you :-) !atmparts.cc bank.cc window.h window.cc sysdep.h

Java Implementation

The implementation of the ATM simulation in Java allows the simulation to be run either as a stand-alone application, or as an applet. It has the following package structure:

package atmo major classes: ATM, Bank, Sessiono package atmparts - individual component parts of the ATMo package transaction - class Transaction and its subclasseso package util - utility classes Money, Status

main class for standalone application: class ATMMain main class for applet: class ATMApplet

In keeping with standard Java practice, each class is implemented as a separate source file - except that the subclasses of Transaction are implemented in the same source file as class Transaction, since no class outside of Transaction needs explicit awareness of the individual subclasses. Of course, there is only one source file for each class - no separate interface and implementation as in C++. However, the standard java development tools include a program javadoc which creates an html document that describes the interface to a class by extracting the needed information from the source file. This has been created for all classes except the two main program classes. The links below allow access both to the javadoc-created interface documentation and to the actual source for each class. You can also view the complete javadoc documentation .

Please note that, at the time this example was created, the current version of Java was JDK 1.0.2, and the code below is based on the 1.0.2 API. When JDK 1.1 came out, I needed to change one class in order to get it to run under 1.1

Page 4: ATM Simulation Code

browsers - note that there are links to two versions of the applet on the Executables page. Though a JDK 1.1 or later compiler will complain about using deprecated API features, the code with the one changed class will compile and run. At some point in the near future, I hope to update the code to the 1.1/1.2 API. For now, if you wish to compile the code yourself, be sure to get the correct version of class QuestionDialog (see below).

Files that Implement the Various Classes, Plus Main Program/Applet

Documentation Source Purposeclass ATM ATM.java ATM itselfclass Bank Bank.java Manage communication with bankclass Session Session.java Perform a customer session

package atm.atmparts

CardReader.java CashDispenser.java Display.java EnvelopeAcceptor.java Keyboard.java OperatorPanel.java ReceiptPrinter.java

Component parts of ATM

package atm.transaction Transaction.java Perform a transactionclass Money Money.java  Abstract data type Moneyclass Status Status.java Status code values(None) ATMMain.java Main program - application version(None) ATMApplet.java Main program - applet version

NOTE: The implementation of class Bank is very simple and also fairly ugly - ie card numbers and PINs are hardwired in, etc. It is intended that a more realistic implementation be left as an exercise to the student. The atmparts package include two classes which are needed by the GUI, but are not otherwise documented in the design: class GUILayout and class QuestionDialog. For these reason, no links to these files are included above (though they will be included in the complete downloadable package.) If you really _have_ to see these files, here are the links - but don't say I didn't warn you :-)! Bank.java GUILayout.java QuestionDialog.java (1.0.2 version) QuestionDialog.java (1.1 version)

 //

Page 5: ATM Simulation Code

ATM Simulation Implementation - the ATM itself

/* * Example ATM simulation - file ATM.java * * This file implements the class that manages the ATM itself * * Copyright (c) 1997 - Russell C. Bjork * */

package atm; import java.awt.*; import atm.atmparts.*; import atm.util.Status; import atm.util.Money;

//

Class ATM

public class ATM

{ //

public ATM(int number, String location, Bank bank, Container container) { super(); _number = number; _location = location; _bank = bank; _cardReader = new CardReader(); _display = new Display(); _keyboard = new Keyboard(); _cashDispenser = new CashDispenser(); _envelopeAcceptor = new EnvelopeAcceptor(); _receiptPrinter = new ReceiptPrinter(); _operatorPanel = new OperatorPanel();

GUILayout.doLayout(container, _cardReader, _display, _keyboard, _cashDispenser, _envelopeAcceptor, _receiptPrinter, _operatorPanel); }

Page 6: ATM Simulation Code

//

public synchronized Money startupOperation() { // Wait for switch to be turned on. Message will blink on and off // to tell user what to do

while (! _operatorPanel.switchOn()) try { Thread.sleep(1000); } catch (InterruptedException e) { } _state = RUNNING; return _operatorPanel.getInitialCash(); }

//

public void serviceCustomers(Money initialCash) { _cashDispenser.setCash(initialCash);

while (_state == RUNNING) { int readerStatus = CardReader.NO_CARD; // Initialization needed only // to keep the compiler happy! _display.requestCard(); do { if (! _operatorPanel.switchOn()) _state = STOPPED; else readerStatus = _cardReader.checkForCardInserted(); } while (_state == RUNNING && readerStatus == CardReader.NO_CARD); _display.clearDisplay(); if (_state == RUNNING) switch (readerStatus) { case CardReader.CARD_HAS_BEEN_READ: { Session session = new Session(_cardReader.cardNumber(), this, _bank); session.doSessionUseCase(); break; }

Page 7: ATM Simulation Code

case CardReader.UNREADABLE_CARD:

_display.reportCardUnreadable(); _cardReader.ejectCard(); _display.clearDisplay(); } } }

//

public int getPIN() { _display.requestPIN(); int PIN = _keyboard.readPIN(_display); _display.clearDisplay(); return PIN; } //

public int getMenuChoice(String whatToChoose, int numItems, String items[]) { _display.displayMenu(whatToChoose, numItems, items); int choice = _keyboard.readMenuChoice(numItems); _display.clearDisplay(); return choice; } //

public Money getAmountEntry() { _display.requestAmountEntry(); Money amount = _keyboard.readAmountEntry(_display); _display.clearDisplay(); return amount; } //

public boolean checkIfCashAvailable(Money amount) { return ! _cashDispenser.currentCash().less(amount); } //

Page 8: ATM Simulation Code

public void dispenseCash(Money amount) { _cashDispenser.dispenseCash(amount); } //

public boolean acceptEnvelope() { return _envelopeAcceptor.acceptEnvelope(); } //

public void issueReceipt(int cardNumber, int serialNumber, String description, Money amount, Money balance, Money availableBalance) { _receiptPrinter.printReceipt(_number, _location, cardNumber, serialNumber, description, amount, balance, availableBalance);; } //

public int reEnterPIN() { _display.requestReEnterPIN(); int PIN = _keyboard.readPIN(_display); _display.clearDisplay(); return PIN; } //

public boolean reportTransactionFailure(String explanation) { _display.reportTransactionFailure(explanation); int response = _keyboard.readMenuChoice(2); _display.clearDisplay(); return response == 1; } //

Page 9: ATM Simulation Code

public void ejectCard() { _cardReader.ejectCard(); } //

public void retainCard() { _display.reportCardRetained(); _cardReader.retainCard(); _display.clearDisplay(); } //

public int number() { return _number; } //

// Private instance variables

private int _number; private String _location; private Bank _bank; // Values for _state instance variable

private static final int RUNNING = 0; private static final int STOPPED = 1; private int _state;

private CardReader _cardReader; private Display _display; private Keyboard _keyboard; private CashDispenser _cashDispenser; private EnvelopeAcceptor _envelopeAcceptor; private ReceiptPrinter _receiptPrinter; private OperatorPanel _operatorPanel; } //

 //

Page 10: ATM Simulation Code

ATM Simulation Implementation - Individual Sessions

/* * Example ATM simulation - file Session.java * * This file implements the class that represents a single customer session * with the ATM * * Copyright (c) 1997 - Russell C. Bjork * */

package atm; import atm.transaction.Transaction; import atm.util.Status; import atm.util.Money;

//

Class Session

public class Session {

//

public Session(int cardNumber, ATM atm, Bank bank) { _cardNumber = cardNumber; _atm = atm; _bank = bank; _state = RUNNING; _PIN = 0; _currentTransaction = null; } //

public void doSessionUseCase() { _PIN = _atm.getPIN(); do { String anotherMenu[] = { "Yes", "No" }; _currentTransaction = Transaction.chooseTransaction(this, _atm, _bank); int status = _currentTransaction.doTransactionUseCase();

Page 11: ATM Simulation Code

switch (status) { case Status.SUCCESS: if (1 != _atm.getMenuChoice ("Do you want to perform another transaction?",2,anotherMenu)) _state = FINISHED; break; case Status.INVALID_PIN: _state = ABORTED; break; default: boolean doAnother = doFailedTransactionExtension(status); if (! doAnother) _state = FINISHED; } } while (_state == RUNNING); if (_state != ABORTED) _atm.ejectCard(); }

//

public int doInvalidPINExtension() { int code; for (int i = 0; i < 3; i ++) { _PIN = _atm.reEnterPIN(); code = _currentTransaction.sendToBank(); if (code != Status.INVALID_PIN) return code; } _atm.retainCard(); _state = ABORTED; return Status.INVALID_PIN; } //

public boolean doFailedTransactionExtension(int reason) { switch(reason) { case Status.TOO_LITTLE_CASH:

Page 12: ATM Simulation Code

return _atm.reportTransactionFailure( "Sorry, there is not enough cash available to satisfy your request"); case Status.ENVELOPE_DEPOSIT_TIMED_OUT: return _atm.reportTransactionFailure( "Envelope not deposited - transaction cancelled"); default: return _atm.reportTransactionFailure( _bank.rejectionExplanation(reason)); } } //

public int cardNumber() { return _cardNumber; } //

public int PIN() { return _PIN; } //

// Possible values for _state instance variable

private static final int RUNNING = 0; private static final int FINISHED = 1; private static final int ABORTED = 2; // Instance variables private int _cardNumber; private ATM _atm; private Bank _bank; private int _state; private int _PIN; private Transaction _currentTransaction; } //

Page 13: ATM Simulation Code

 //

ATM Simulation Implementation - the Card Reader

/* * Example ATM simulation - file CardReader.java * * This file implements the class that manages the ATM's Card Reader * * Copyright (c) 1997 - Russell C. Bjork * */

package atm.atmparts; import java.awt.*;

//

Class CardReader

public class CardReader extends Button {

//

public CardReader() { super("Click to insert Card"); _status = NO_CARD; _originalBounds = null; // Must get this after GUI is all laid out } //

public void ejectCard() { // Animate card coming out of machine setLabel("Ejecting card"); Rectangle currentBounds = new Rectangle(_originalBounds.x + _originalBounds.width / 2, _originalBounds.y + _originalBounds.height / 2, _originalBounds.width / _originalBounds.height, 1);

Page 14: ATM Simulation Code

show(); while (currentBounds.height <= _originalBounds.height && currentBounds.width <= _originalBounds.width) { reshape(currentBounds.x, currentBounds.y, currentBounds.width, currentBounds.height); repaint(); try { Thread.sleep(100); } catch (InterruptedException e) { } currentBounds.height += 1; currentBounds.width = (_originalBounds.width * currentBounds.height) / _originalBounds.height; currentBounds.x = _originalBounds.x + (_originalBounds.width - currentBounds.width) / 2; currentBounds.y = _originalBounds.y + (_originalBounds.height - currentBounds.height) / 2; } hide(); _status = NO_CARD; } //

public void retainCard() { _status = NO_CARD; try { Thread.sleep(10 * 1000); } catch (InterruptedException e) { } } //

// These are the values that can be returned by checkForCardInserted() public static final int NO_CARD = 0; public static final int UNREADABLE_CARD = 1; public static final int CARD_HAS_BEEN_READ = 2; //

public synchronized int checkForCardInserted() {

Page 15: ATM Simulation Code

// Wait until user clicks the "Click To Insert Card" button, or operator // Turns the machine off. (The timeout in the wait ensures that we will // return periodically so that ATM can recheck the switch status.) if (_originalBounds == null) _originalBounds = bounds(); else reshape(_originalBounds.x, _originalBounds.y, _originalBounds.width, _originalBounds.height);

setLabel("Click to insert card"); show(); repaint(); requestFocus(); try { wait(1000); } catch (InterruptedException e) { } if (_status == NO_CARD) // This happens if we timeout { hide(); return NO_CARD; } // Animate card going into the machine

Rectangle currentBounds = new Rectangle(_originalBounds.x, _originalBounds.y, _originalBounds.width, _originalBounds.height); while (currentBounds.width > 0 && currentBounds.height > 0) { reshape(currentBounds.x, currentBounds.y, currentBounds.width, currentBounds.height); repaint(); try { Thread.sleep(100); } catch (InterruptedException e) { } currentBounds.height -= 1; currentBounds.width = (_originalBounds.width * currentBounds.height) / _originalBounds.height; currentBounds.x = _originalBounds.x + (_originalBounds.width - currentBounds.width) / 2; currentBounds.y = _originalBounds.y + (_originalBounds.height - currentBounds.height) / 2; } hide();

Page 16: ATM Simulation Code

// Since we don't have a magnetic stripe reader (or a literal card!), // pop up a dialog and ask user to enter the card number. QuestionDialog cardNumberDialog = new QuestionDialog("Enter card number:", this);

String answer = cardNumberDialog.answer(); // Extract the number typed. Typing a non-number simulates an unreadable // card. if (answer == null) _status = UNREADABLE_CARD; else { try { _cardNumberRead = Integer.parseInt(answer); _status = CARD_HAS_BEEN_READ; } catch (NumberFormatException e) { _status = UNREADABLE_CARD; } } return _status; }

//

public int cardNumber() { return _cardNumberRead; } //

// Instance variables private int _status; private int _cardNumberRead;

//

/* The following method and field are needed for the GUI */ public synchronized boolean action(Event e, Object arg) { if (e.target == this) { _status = CARD_HAS_BEEN_READ; notify(); return true; } else return false;

Page 17: ATM Simulation Code

} private Rectangle _originalBounds; }

//

 //

ATM Simulation Implementation - the Cash Dispenser

/* * Example ATM simulation - file CashDispenser.java * * This file implements the class that manages the ATM's cash dispenser * * Copyright (c) 1997 - Russell C. Bjork * */

package atm.atmparts; import java.awt.*; import atm.util.Money;

//

Class CashDispenser

public class CashDispenser extends Panel {

//

public CashDispenser() { setLayout(new GridLayout(1,1)); _label = new Label("$XXX", Label.CENTER); _label.setFont(new Font("Helvetica", Font.PLAIN, 24)); _label.setForeground(new Color(0, 64, 0)); add(_label); _label.hide(); _currentCash = new Money(0); }

//

Page 18: ATM Simulation Code

public void setCash(Money initialCash) { _currentCash = initialCash; }

//

public void dispenseCash(Money amount) { _label.setText("$" + amount.dollars()); for (int size = 3; size <= 24; size += 1) { _label.setFont(new Font("Helvetica", Font.PLAIN, size)); _label.show(); try { Thread.sleep(250); } catch (InterruptedException e) { } _label.hide(); } _currentCash.subtract(amount); } //

public Money currentCash() { return _currentCash; } //

// Instance variable private Money _currentCash;

//

// This field is needed for the GUI private Label _label; }

//

 //

Page 19: ATM Simulation Code

ATM Simulation Implementation - the Display

/* * Example ATM simulation - file Display.java * * This file implements the class that manages the ATM's display * * Copyright (c) 1997 - Russell C. Bjork * */

package atm.atmparts; import java.awt.*; import java.util.StringTokenizer;

//

Class Display

public class Display extends Panel {

//

public Display() { setLayout(new GridLayout(GUILayout.DISPLAYABLE_LINES, 1)); setBackground(new Color(0, 96, 0)); // Dark green setForeground(Color.white); _line = new Label[GUILayout.DISPLAYABLE_LINES]; for (int i = 0; i < GUILayout.DISPLAYABLE_LINES; i ++) { _line[i] = new Label(""); add(_line[i]); } _currentLine = 0; } //

public void requestCard() { write("Please insert your card to begin"); } //

public void requestPIN() { write( "Please enter your Personal Identification Number (PIN)\n" +

Page 20: ATM Simulation Code

"Press ENTER when finished or CLEAR to start over"); } //

public void displayMenu(String whatToChoose, int numItems, String items[]) { write(whatToChoose); for (int i = 0; i < numItems; i ++) write((i + 1) + ") " + items[i]); } //

public void requestAmountEntry() { write( "Please enter amount.\n" + "Press ENTER when finished or CLEAR to start over"); } //

public void requestDepositEnvelope() { write( "Please deposit an envelope in the slot"); } //

public void reportCardUnreadable() { write( "Sorry, your card was inserted incorrectly or\n" + "is unreadable.\n" + "Please try inserting your card again"); } //

public void reportTransactionFailure(String explanation) { write(explanation); write("\n" + "Do you want to perform another transaction\n" + "(1 = Yes, 2 = No)?"); } //

Page 21: ATM Simulation Code

public void requestReEnterPIN() { write( "Your PIN was entered incorrectly.\n" + "Please re-enter it"); } //

public void reportCardRetained() { write( "Your PIN was entered incorrectly.\n" + "Your card has been retained - please contact the bank"); try { Thread.sleep(10 * 1000); } catch (InterruptedException e) { } } //

public void echoInput(String echo) { _line[GUILayout.DISPLAYABLE_LINES - 1].setText(" " + echo); } //

public void clearDisplay() { for (int i = 0; i < GUILayout.DISPLAYABLE_LINES; i ++) _line[i].setText(""); _currentLine = 0; } //

// Private method and instance variables needed for GUI private void write(String s) // Write one or more lines; may contain multiple lines delimited by \n { StringTokenizer t = new StringTokenizer(s, "\n", false); while (t.hasMoreTokens()) { try { _line[_currentLine ++].setText(t.nextToken()); } catch (Exception e) { } } } private Label _line[]; private int _currentLine;

Page 22: ATM Simulation Code

}

//

 //

ATM Simulation Implementation - the Envelope Acceptor

/* * Example ATM simulation - file EnvelopeAcceptor.java * * This file implements the class that manages the ATM's envelope acceptor * * Copyright (c) 1997 - Russell C. Bjork * */

package atm.atmparts; import java.awt.*;

//

Class EnvelopeAcceptor

public class EnvelopeAcceptor extends Button {

//

public EnvelopeAcceptor() { super("Click to insert Envelope"); _originalBounds = null; // Must get this after GUI is all laid out } //

public synchronized boolean acceptEnvelope() { if (_originalBounds == null) _originalBounds = bounds(); else

Page 23: ATM Simulation Code

reshape(_originalBounds.x, _originalBounds.y, _originalBounds.width, _originalBounds.height);

show(); repaint(); requestFocus(); // Wait for user to simulate inserting envelope by clicking button. // If we wait 20 seconds and no envelope is entered, we time out

try { wait(20 * 1000); } catch(InterruptedException e) { }

if (! _inserted) { hide(); return _inserted; } // Animate envelope going into the machine Rectangle currentBounds = new Rectangle(_originalBounds.x, _originalBounds.y, _originalBounds.width, _originalBounds.height); while (currentBounds.width > 0 && currentBounds.height > 0) { reshape(currentBounds.x, currentBounds.y, currentBounds.width, currentBounds.height); repaint(); try { Thread.sleep(100); } catch (InterruptedException e) { } currentBounds.height -= 1; currentBounds.width = (_originalBounds.width * currentBounds.height) / _originalBounds.height; currentBounds.x = _originalBounds.x + (_originalBounds.width - currentBounds.width) / 2; currentBounds.y = _originalBounds.y + (_originalBounds.height - currentBounds.height) / 2; } hide(); return _inserted; } //

Page 24: ATM Simulation Code

// Method and private data needed for GUI

public synchronized boolean action(Event e, Object arg) { if (e.target == this) { _inserted = true; notify(); return true; } else return false; }

private Rectangle _originalBounds; private boolean _inserted; } //

 //

ATM Simulation Implementation - the Keyboard

/* * Example ATM simulation - file Keyboard.java * * This file implements the class that manages the ATM's keyboard * * Copyright (c) 1997 - Russell C. Bjork * */

package atm.atmparts; import java.awt.*; import atm.util.Money;

//

Class Keyboard

public class Keyboard extends Panel {

//

Page 25: ATM Simulation Code

public Keyboard() { super(); setLayout(new GridLayout(4,3)); _numberKey = new Button[10]; for (int i = 1; i < 10; i ++) { _numberKey[i] = new Button("" + i); add(_numberKey[i]); } _enterKey = new Button("Enter"); _enterKey.setForeground(Color.black); _enterKey.setBackground(new Color(128, 128, 255)); add(_enterKey); _numberKey[0] = new Button("0"); add(_numberKey[0]); _clearKey = new Button("Clear"); _clearKey.setForeground(Color.black); _clearKey.setBackground(new Color(255, 128, 128)); add(_clearKey); } //

public int readPIN(Display echoOn) { StringBuffer result = new StringBuffer(""); StringBuffer echo = new StringBuffer(""); int keyClicked; do { keyClicked = inKey(); switch (keyClicked) { case ENTER: // If a legitimate integer has been entered, return it; // otherwise fall through to clear case and make user // start over try { return Integer.parseInt(result.toString()); } catch (NumberFormatException e) { } case CLEAR: result.setLength(0); echo.setLength(0); break; default: result.append(keyClicked); echo.append('*'); } echoOn.echoInput(echo.toString()); } while (true); } //

Page 26: ATM Simulation Code

public int readMenuChoice(int numItems) { int key; do { key = inKey(); } while (key < 1 || key > numItems); return key; } //

public Money readAmountEntry(Display echoOn) { StringBuffer cents = new StringBuffer(" "), dollars = new StringBuffer(""); echoOn.echoInput(". "); int keyClicked; do { keyClicked = inKey(); switch (keyClicked) { case ENTER: // If a legitimate amout has been entered, return it; // otherwise fall through to clear case and make user // start over try { if (dollars.length() == 0) dollars.append('0'); if (cents.charAt(0) == ' ') cents.setCharAt(0, '0'); return new Money(Integer.parseInt(dollars.toString()), Integer.parseInt(cents.toString())); } catch (NumberFormatException e) { } case CLEAR: cents.setLength(0); cents.append(" "); dollars.setLength(0); break; default: if (cents.charAt(0) != ' ') dollars.append(cents.charAt(0)); cents.setCharAt(0, cents.charAt(1)); cents.setCharAt(1, Character.forDigit(keyClicked, 10)); } echoOn.echoInput(dollars.toString() + "." + cents.toString()); } while (true); }

Page 27: ATM Simulation Code

//

// Methods and private data needed for GUI private synchronized int inKey() { _buttonClicked = NONE; requestFocus(); do { try { wait(); } catch (InterruptedException e) { } } while (_buttonClicked == NONE); return _buttonClicked; } public synchronized boolean action(Event e, Object arg) { for (int i = 0; i < 10; i ++) if (e.target == _numberKey[i]) _buttonClicked = i; if (e.target == _enterKey) _buttonClicked = ENTER; if (e.target == _clearKey) _buttonClicked = CLEAR; if (_buttonClicked != NONE) { notify(); return true; } else return false; } // Each individual key is represented by a button private Button _numberKey[]; // _numberKey[i] represents digit i private Button _enterKey; private Button _clearKey; // Record the button clicked private int _buttonClicked; private static final int NONE = -1; private static final int ENTER = 10; private static final int CLEAR = 11; } //

 //

ATM Simulation Implementation - the Operator Panel

Page 28: ATM Simulation Code

/* * Example ATM simulation - file OperatorPanel.java * * This file implements the class that manages the ATM's operator panel * * Copyright (c) 1997 - Russell C. Bjork * */

package atm.atmparts; import java.awt.*; import atm.util.Money;

//

Class OperatorPanel

public class OperatorPanel extends Panel {

//

public OperatorPanel() { setLayout(new BorderLayout()); setBackground(new Color(128,128,255)); add("West", new Label("Operator Panel")); _message = new Label("Click ON button to turn ATM on"); add("Center", _message); CheckboxGroup group = new CheckboxGroup(); _offButton = new Checkbox("OFF", group, true); _onButton = new Checkbox("ON", group, false); Panel buttonPanel = new Panel(); buttonPanel.add(_offButton); buttonPanel.add(_onButton); add("East", buttonPanel); } //

public synchronized boolean switchOn() { // This will blink the "Click ON button ..." message when // the ATM is off boolean isOn = _onButton.getState(); if (! isOn) if (_message.isShowing()) _message.hide(); else _message.show(); else _message.hide();

Page 29: ATM Simulation Code

return isOn; } //

public Money getInitialCash() { int numberBills = -1; while (numberBills < 0) { QuestionDialog cashDialog = new QuestionDialog("How many $20 bills are in the cash dispenser?", this); String answer = cashDialog.answer(); if (answer != null) try { numberBills = Integer.parseInt(answer); } catch (NumberFormatException e) { } } return new Money(20 * numberBills); } //

// These fields are needed by the GUI private Label _message; private Checkbox _offButton; private Checkbox _onButton; }

//

 //

ATM Simulation Implementation - the Receipt Printer

/* * Example ATM simulation - file ReceiptPrinter.java * * This file implements the class that manages the ATM's receipt printer * * Copyright (c) 1997 - Russell C. Bjork * */

package atm.atmparts; import java.awt.*; import java.util.Date;

Page 30: ATM Simulation Code

import atm.util.Money;

//

Class ReceiptPrinter

public class ReceiptPrinter extends TextArea {

//

public ReceiptPrinter() { super(GUILayout.PRINTABLE_LINES, GUILayout.PRINTABLE_CHARS); setBackground(Color.white); setForeground(Color.black); setFont(new Font("Courier", Font.PLAIN, 12)); setEditable(false); } //

public void printReceipt(int theATMnumber, String theATMlocation, int cardNumber, int serialNumber, String description, Money amount, Money balance, Money availableBalance) { setText("");

// Set up the receipt String lines[] = new String[7]; int i = 0; lines[i ++] = new Date().toString() + "\n"; lines[i ++] = theATMnumber + " " + theATMlocation + "\n"; lines[i ++] = "CARD " + cardNumber + " TRANS " + serialNumber + "\n"; lines[i ++] = description + "\n"; if (amount.equals(new Money(0))) lines[i ++] = "\n"; else lines[i ++] = "AMOUNT: " + amount.dollars() + "." + ((amount.cents() >= 10) ? "" + amount.cents() : "0" + amount.cents()) + "\n"; lines[i ++] = "CURR BAL: " + balance.dollars() + "." + ((balance.cents() >= 10) ? "" + balance.cents() : "0" + balance.cents()) + "\n";

Page 31: ATM Simulation Code

lines[i ++] = "AVAILABLE: " + availableBalance.dollars() + "." + ((availableBalance.cents() >= 10) ? "" + availableBalance.cents() : "0" + availableBalance.cents()) + "\n"; // Animate it for (i = 0; i < 7; i ++) { appendText(lines[i]); try { Thread.sleep(1 * 1000); } catch (InterruptedException e) { } } } }

//

 //

ATM Simulation - Implementation of a Representation for Money

/* * Example ATM simulation - file Money.java * * This file implements the class used to represent money, * * Copyright (c) 1997 - Russell C. Bjork * */

package atm.util;

public class Money { public Money() { _cents = 0; } public Money(int dollars) { _cents = 100L * dollars; }

Page 32: ATM Simulation Code

public Money(int dollars, long cents) { _cents = 100L * dollars + cents; } public void set(Money value) { _cents = value._cents; } static public Money add(Money first, Money second) { return new Money(0, first._cents + second._cents); } static public Money subtract(Money minuend, Money subtrahend) { return new Money(0, minuend._cents - subtrahend._cents); } public Money add(Money other) { _cents += other._cents; return this; } public Money subtract(Money other) { _cents -= other._cents; return this; } public int dollars() { return (int) _cents / 100; } public int cents() { return (int) _cents % 100; } public boolean equals(Money other) { return _cents == other._cents; } public boolean less(Money other) { return _cents < other._cents; }

// Instance variable private long _cents; }

//

 //

Page 33: ATM Simulation Code

ATM Simulation Status Codes

/* * Example ATM simulation - file status.java * * This file declares a status code type that is returned by various * operations to indicate success or failure, and the reason for failure * * Copyright (c) 1997 - Russell C. Bjork * */

package atm.util;

public class Status { public static final int SUCCESS = 0; // Cash dispenser does not have enough cash for a withdrawl request public static final int TOO_LITTLE_CASH = 1;

// Customer did not deposit envelope within time out period public static final int ENVELOPE_DEPOSIT_TIMED_OUT = 2; // Various reasons why bank might reject a transaction public static final int UNKNOWN_CARD = 3; // Card number not recognized public static final int INVALID_PIN = 4; // PIN not correct for card public static final int NO_SUCH_ACCOUNT = 5; // Card holder does not have this type account public static final int CANT_WITHDRAW_FROM_ACCOUNT = 6; // Account doesn't allow ATM withdrawl public static final int INSUFFICIENT_AVAILABLE_BALANCE = 7; // Self-explanatory public static final int DAILY_WITHDRAWL_LIMIT_EXCEEDED = 8; // Ditto }

//

 //

Page 34: ATM Simulation Code

ATM Simulation - main program

/* * Example ATM simulation - file ATMMain.java * * This file contains the main program for the ATM simulation - stand-alone version * * Copyright (c) 1997 - Russell C. Bjork * */

import java.awt.*; import atm.ATM; import atm.Bank; import atm.util.Money;

public class ATMMain implements Runnable { // This method is invoked when ATMMain.class is run as an application. It // creates a new object of this class. Versions with and without arguments are // provided; Macs pop up a dialog box if main() needs arguments, and Linux // systems require main() to take arguments. Either way, the newly created // object does the work public static void main() { new ATMMain(); } public static void main(String argv[]) { new ATMMain(); }

// ATMMain constructor. // Create the ATM and simulated bank, plus the GUI - furnishing a frame for its // container, plus a thread to run the simulation (which executes the run() // method of this class). Start the thread and we're off!

public ATMMain() { _theFrame = new Frame(); _theFrame.setTitle("ATM number " + ATM_NUMBER + " at " + ATM_LOCATION); _theFrame.setResizable(false); _theBank = new Bank(); _theATM = new ATM(ATM_NUMBER, ATM_LOCATION, _theBank, _theFrame);

Page 35: ATM Simulation Code

_theFrame.pack(); _theFrame.show(); _theThread = new Thread(this); _theThread.start(); } // This method is run by the thread. The program will terminate when the // ATM is turned off. public void run() { Money initialCash = _theATM.startupOperation(); _theATM.serviceCustomers(initialCash); System.exit(0); }

private Frame _theFrame; private Bank _theBank; private ATM _theATM; private Thread _theThread; // Private constants private static final int ATM_NUMBER = 42; private static final String ATM_LOCATION = "GORDON COLLEGE"; }

//

 //

ATM Simulation - applet

/* * Example ATM simulation - file ATMApplet.java * * This file contains the main program for the ATM simulation - applet version * * Copyright (c) 1997 - Russell C. Bjork * */ import java.applet.Applet; import java.awt.*; import atm.ATM; import atm.Bank; import atm.util.Money;

Page 36: ATM Simulation Code

public class ATMApplet extends Applet implements Runnable { // Applet initialization. // Create the ATM and simulated bank, plus the GUI - using this as its // container, plus a thread to run the simulation (which executes the run() // method of this class.) public void init() { _theBank = new Bank(); _theATM = new ATM(ATM_NUMBER, ATM_LOCATION, _theBank, this); // If we are running in a frame we can get to, then set its title bar // to our title Component c = this; while (c.getParent() != null) c = c.getParent(); if (c instanceof Frame) { ((Frame) c).setTitle("ATM number " + ATM_NUMBER + " at " + ATM_LOCATION); ((Frame) c).setResizable(false); } _theThread = new Thread(this); _theThread.start(); } // stop() and start() are called as the applet is scrolled on and off the // screen. Simply suspend and resume the thread. public void start() { _theThread.resume(); } public void stop() { _theThread.suspend(); } // This method is run by the thread. Since there is no provision for an // applet to terminate itself, we let the operator turn the machine on and // off as often as desired. public void run() { while (true) { Money initialCash = _theATM.startupOperation(); _theATM.serviceCustomers(initialCash); } }

Page 37: ATM Simulation Code

private Bank _theBank; private ATM _theATM; private Thread _theThread; // Private constants private static final int ATM_NUMBER = 42; private static final String ATM_LOCATION = "GORDON COLLEGE"; }

//