ATM Simulation Code: Operation Description Forms
ATM Simulation Code: Operation Description Forms
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
transactions. (This is basically an enum in C++, and a class that consists of
static final int's in Java.)
C++ Implementation
Java Implementation
C++ Implementation
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.
Java Implementation
• package atm
o major classes: ATM, Bank, Session
o package atmparts - individual component parts of the ATM
o package transaction - class Transaction and its subclasses
o package util - utility classes Money, Status
• main class for standalone application: class ATMMain
• main class for applet: class ATMApplet
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
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).
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)
//
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
{
//
_number = number;
_location = location;
_bank = bank;
GUILayout.doLayout(container,
_cardReader, _display, _keyboard,
_cashDispenser,
_envelopeAcceptor, _receiptPrinter,
_operatorPanel);
}
//
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();
}
//
if (_state == RUNNING)
switch (readerStatus)
{
case CardReader.CARD_HAS_BEEN_READ:
{
Session session = new
Session(_cardReader.cardNumber(),
this,
_bank);
session.doSessionUseCase();
break;
}
case CardReader.UNREADABLE_CARD:
_display.reportCardUnreadable();
_cardReader.ejectCard();
_display.clearDisplay();
}
}
}
//
//
//
//
//
//
//
//
//
//
//
//
public int number()
{ return _number; }
//
//
//
/*
* 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
//
//
do
{
String anotherMenu[] = { "Yes", "No" };
_currentTransaction = Transaction.chooseTransaction(this,
_atm, _bank);
int status = _currentTransaction.doTransactionUseCase();
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();
}
//
//
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));
}
}
//
//
//
// Instance variables
//
//
/*
* 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 CardReader()
{ super("Click to insert Card");
_status = NO_CARD;
_originalBounds = null; // Must get this after GUI is all laid
out
}
//
setLabel("Ejecting card");
Rectangle currentBounds =
new Rectangle(_originalBounds.x + _originalBounds.width / 2,
_originalBounds.y + _originalBounds.height /
2,
_originalBounds.width /
_originalBounds.height, 1);
show();
hide();
_status = NO_CARD;
}
//
//
//
if (_originalBounds == null)
_originalBounds = bounds();
else
reshape(_originalBounds.x, _originalBounds.y,
_originalBounds.width, _originalBounds.height);
try
{ wait(1000); }
catch (InterruptedException e)
{ }
if (_status == NO_CARD) // This happens if we timeout
{ hide();
return NO_CARD;
}
Rectangle currentBounds =
new Rectangle(_originalBounds.x, _originalBounds.y,
_originalBounds.width,
_originalBounds.height);
hide();
QuestionDialog cardNumberDialog =
new QuestionDialog("Enter card number:", this);
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;
}
//
//
// Instance variables
//
/* The following method and field are needed for the GUI */
//
//
/*
* 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 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);
}
//
//
//
//
// Instance variable
//
//
//
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 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 displayMenu(String whatToChoose,
int numItems,
String items[])
{ write(whatToChoose);
for (int i = 0; i < numItems; i ++)
write((i + 1) + ") " + items[i]);
}
//
//
//
//
//
//
//
//
//
//
//
/*
* 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 EnvelopeAcceptor()
{ super("Click to insert Envelope");
_originalBounds = null; // Must get this after GUI is all laid
out
}
//
show();
repaint();
requestFocus();
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);
hide();
return _inserted;
}
//
//
//
/*
* 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 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);
}
//
//
//
//
//
//
/*
* 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 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);
}
//
//
//
//
//
/*
* 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;
import atm.util.Money;
//
Class ReceiptPrinter
//
public ReceiptPrinter()
{
super(GUILayout.PRINTABLE_LINES, GUILayout.PRINTABLE_CHARS);
setBackground(Color.white);
setForeground(Color.black);
setFont(new Font("Courier", Font.PLAIN, 12));
setEditable(false);
}
//
// Animate it
//
//
/*
* Example ATM simulation - file Money.java
*
* This file implements the class used to represent money,
*
* Copyright (c) 1997 - Russell C. Bjork
*
*/
package atm.util;
// Instance variable
//
//
/*
* 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;
// Cash dispenser does not have enough cash for a withdrawl request
//
//
/*
* 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;
// 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);
_theFrame.pack();
_theFrame.show();
System.exit(0);
}
// Private constants
//
//
import java.applet.Applet;
import java.awt.*;
import atm.ATM;
import atm.Bank;
import atm.util.Money;
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);
}
// Private constants
//