An application that simulates the backend logic of a cash dispensing Automatic Teller Machine (ATM).
Click here for reading the instructions and requirements
This application provides a lightweight RESTful API using the Java API for RESTful Web Services (JAX-RS) on top of an embedded Jetty web application.
A deployed version is running and hosted on: http://atm-simulation-exercise.herokuapp.com/
Server:
- Jetty - Servlet Engine and HTTP Server
- Jersey - RESTful Web Services in Java
- FasterXML - Jackson JAX-RS JSON Provider
- Guava Libraries - Set of common libraries for Java
Test:
The design pattern used as a base for solving the cash dispenser problem was the Chain of Responsibility.
The typical implementation of a Chain of Responsibility for this specific problem (ATM simulation) has a flaw, mainly because it doesn't care if the request will be fully satisfied at the time the last object in the chain handles it.
For example:
Assuming that the ATM has notes of $20 and $50 only (and it has enough money to fulfil the withdraw):
- We want to withdraw $80
- There are two cash dispensers, one for $50 and other for $20 bills.
- The first one will dispense 1 X $50
- The second (and last one) will dispense 1 X $20
- $70 was dispensed so far
- There is no object in the chain to handle the $10 balance left, making this request to fail
It would work if the chain start with the $20 dispenser, but then another problem is introduced, because the small bills will finish a lot faster, creating an additional cost of constantly feeding the ATM.
The proposed solution is still using this design pattern as a base for its implementation, but it will check if the last object in the chain will satisfy the request before it handles the request to the next one: Dispenser.java
- Mac OSX (tested on 10.9 Mavericks)
- Linux (tested with OpenJDK 7)
- Heroku
- Java stand alone application
- Java 7
- Maven 3
Building the application:
$ mvn clean package
Running it:
$ mvn exec:java -Dexec.mainClass="com.github.golimpio.atm.Main"
Alternatively, there is a run script at the project root folder:
$ ./run
You might need to give execution permission to it:
$ chmod +x run
The REST API can be accessed from: http://atm-simulation-exercise.herokuapp.com/services
Or from your localhost if you're running the application locally: http://localhost:8080/services
Following the available services:
- init (initialise the ATM - GET)
- init/clear (remove all de available money from the ATM - POST)
- init/add (add money to the ATM - POST)
- withdraw (allow withdraw money and verify minimum and maximum amounts allowed - GET)
- withdraw/ (withdraw cash from the ATM - GET)
- withdraw/minimum (retrieve the minimum withdraw allowed - GET)
- withdraw/maximum (retrieve the maximum withdraw allowed - GET)
- monitor/money (retrieve the amount of notes available for withdraw - GET)
The simplest way to access the service API from the command line is via CURL (a command line tool for transferring data with URL syntax).
Note: replace the url from: http://localhost:8080/services/...
to: http://atm-simulation-exercise.herokuapp.com/services/...
for using the heroku deployment.
Request:
curl -X POST -H "Content-Type: application/json" http://atm-simulation-exercise.herokuapp.com/services/init/clear
or
curl -X POST -H "Content-Type: application/json" http://localhost:8080/services/init/clear
The response will be a HTTP status OK if it succeed or other status if it failed.
Request:
curl -X POST -H "Content-Type: application/json" -d $'[ { "note":"TWENTY", "numberOfNotes":150 }, { "note":"FIFTY", "numberOfNotes":40 } ]' http://atm-simulation-exercise.herokuapp.com/services/init/add
or
curl -X POST -H "Content-Type: application/json" -d $'[ { "note":"TWENTY", "numberOfNotes":150 }, { "note":"FIFTY", "numberOfNotes":40 } ]' http://localhost:8080/services/init/add
Allowed notes:
- FIVE
- TEN
- TWENTY
- FIFTY
- HUNDRED
The response will be a HTTP status OK if it succeed or other status if it failed.
curl -X GET -H "Content-Type: text/plain" -d $'90' http://atm-simulation-exercise.herokuapp.com/services/withdraw/
or
curl -X GET -H "Content-Type: text/plain" -d $'90' http://localhost:8080/services/withdraw/
Response:
[
{
"note":"FIFTY",
"numberOfNotes":1
},
{
"note":"TWENTY",
"numberOfNotes":2
}
]
Request:
curl -X GET -H "Content-Type: application/json" http://atm-simulation-exercise.herokuapp.com/services/withdraw/minimum
or
curl -X GET -H "Content-Type: application/json" http://localhost:8080/services/withdraw/minimum
Response:
{ "value":20 }
Request:
curl -X GET -H "Content-Type: application/json" http://atm-simulation-exercise.herokuapp.com/services/withdraw/maximum
or
curl -X GET -H "Content-Type: application/json" http://localhost:8080/services/withdraw/maximum
Response:
{ "value":5000 }
Request:
curl -X GET -H "Content-Type: application/json" http://atm-simulation-exercise.herokuapp.com/services/monitor/money
or
curl -X GET -H "Content-Type: application/json" http://localhost:8080/services/monitor/money
Response:
[
{
"note":"TWENTY",
"numberOfNotes":150
},
{
"note":"FIFTY",
"numberOfNotes":40
}
]