Sie sind auf Seite 1von 35

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
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 Purpose


atm.h atm.cc ATM itself
atmparts.h atmparts.cc Component parts of ATM
session.h session.cc Perform a customer session
transaction.h transaction.cc Perform a transaction
bank.h bank.cc Manage communication with bank
money.h money.cc Abstract data type Money
status.h (None) Status code values
(None) main.cc Main program
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 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

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
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 Purpose


class ATM ATM.java ATM itself
class Bank Bank.java Manage communication with bank
class Session Session.java Perform a customer session
CardReader.java
CashDispenser.java
Display.java
package atm.atmparts EnvelopeAcceptor.java Component parts of ATM
Keyboard.java
OperatorPanel.java
ReceiptPrinter.java
package atm.transaction Transaction.java Perform a transaction
class Money Money.java Abstract data type Money
class 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)

//
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);
}

//
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;
}

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);
}

//

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;
}

//

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;
}

//

//

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();
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:

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;

//

//

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);
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()


{
// 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();

// 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;
}

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);
}

//

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;


}

//

//
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" +
"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)?");
}

//

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;

//

//

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
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;
}

//

// 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


{

//

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);
}

//

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.toStri
ng()));
}
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);
}

//

// 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

/*
* 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();
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;
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";
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;
}

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;


}

//

//

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
}

//

//

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);

_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;

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);
}
}

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";
}

//

Das könnte Ihnen auch gefallen