· 4 years ago · Apr 23, 2021, 03:52 PM
1package banking;
2
3import java.util.Random;
4import java.util.Arrays;
5import java.util.Scanner;
6
7import org.sqlite.SQLiteDataSource;
8
9import java.sql.Connection;
10import java.sql.ResultSet;
11import java.sql.SQLException;
12import java.sql.Statement;
13import java.util.Random;
14
15class WrongLoginParametersException extends Exception {
16 public WrongLoginParametersException(String message) {
17 super(message);
18 }
19}
20
21class BankingService {
22 public enum State {
23 LOGGED_OUT, LOGGED_IN
24 }
25
26 private static final String BANK_ID = "400000";
27
28 private final String URL;
29
30 private int currAccountId;
31 private State currState;
32 private SQLiteDataSource dataSource;
33
34 public BankingService(String dbFile) throws SQLException {
35 URL = String.format("jdbc:sqlite:%s", dbFile);
36 currAccountId = -1;
37 currState = State.LOGGED_OUT;
38
39 dataSource = new SQLiteDataSource();
40 dataSource.setUrl(URL);
41 try (Connection connection = dataSource.getConnection()) {
42 try (Statement statement = connection.createStatement()) {
43 statement.execute("CREATE TABLE IF NOT EXISTS accounts (" +
44 "id INTEGER NOT NULL," +
45 "number TEXT NOT NULL," +
46 "pin TEXT NOT NULL," +
47 "balance INTEGER DEFAULT 0)");
48 }
49 }
50 }
51
52 public long addAccount() throws SQLException {
53 long accountId = getNextId();
54 Random random = new Random();
55 String cardNumber;
56 int pin;
57
58 StringBuffer sb = new StringBuffer();
59 sb.append(BANK_ID);
60 sb.append(String.format("%09d", accountId));
61 sb.append(calculateChecksum(sb.toString()));
62
63 cardNumber = sb.toString();
64 pin = random.nextInt(10000);
65
66 try (Connection connection = dataSource.getConnection()) {
67 try (Statement statement = connection.createStatement()) {
68 statement.executeUpdate(String.format("INSERT INTO accounts VALUES " +
69 "(%d, '%s', '%04d', 0)", accountId, cardNumber, pin));
70 }
71 }
72 return accountId;
73 }
74
75 public void login(String cardNumber, String pin) throws SQLException, WrongLoginParametersException {
76 int id;
77 String currentCardNumber;
78 String currentPin;
79
80 try (Connection connection = dataSource.getConnection()) {
81 try (Statement statement = connection.createStatement()) {
82 try (ResultSet accounts = statement.executeQuery("SELECT id, number, pin FROM accounts")) {
83 while (accounts.next()) {
84 id = accounts.getInt("id");
85 currentCardNumber = accounts.getString("number");
86 currentPin = accounts.getString("pin");
87 if (cardNumber.equals(currentCardNumber)) {
88 if (pin.equals(currentPin)) {
89 currAccountId = id;
90 currState = State.LOGGED_IN;
91 return;
92 }
93 throw new WrongLoginParametersException("Wrong card number or PIN!");
94 }
95 }
96 }
97 }
98 }
99 throw new WrongLoginParametersException("Wrong card number or PIN!");
100 }
101
102 public void logout() {
103 currAccountId = -1;
104 currState = State.LOGGED_OUT;
105 }
106
107 public State getState() {
108 return currState;
109 }
110
111 public int getBalance() throws SQLException {
112 return (getBalance(currAccountId));
113 }
114
115 public int getBalance(long id) throws SQLException {
116 try (Connection connection = dataSource.getConnection()) {
117 try (Statement statement = connection.createStatement()) {
118 try (ResultSet accounts = statement.executeQuery("SELECT balance FROM accounts " +
119 "WHERE id = " + id)) {
120 return accounts.getInt("balance");
121 }
122 }
123 }
124 }
125
126 public String getCardNumber() throws SQLException {
127 return getCardNumber(currAccountId);
128 }
129
130 public String getCardNumber(long id) throws SQLException {
131 try (Connection connection = dataSource.getConnection()) {
132 try (Statement statement = connection.createStatement()) {
133 try (ResultSet accounts = statement.executeQuery("SELECT number FROM accounts " +
134 "WHERE id = " + id)) {
135 return accounts.getString("number");
136 }
137 }
138 }
139 }
140
141 public String getPin() throws SQLException {
142 return getPin(currAccountId);
143 }
144
145 public String getPin(long id) throws SQLException {
146 try (Connection connection = dataSource.getConnection()) {
147 try (Statement statement = connection.createStatement()) {
148 try (ResultSet accounts = statement.executeQuery("SELECT pin FROM accounts " +
149 "WHERE id = " + id)) {
150 return accounts.getString("pin");
151 }
152 }
153 }
154 }
155
156 private long getNextId() throws SQLException {
157 try (Connection connection = dataSource.getConnection()) {
158 try (Statement statement = connection.createStatement()) {
159 try (ResultSet accounts = statement.executeQuery("SELECT IFNULL(MAX(id), 0) AS id FROM accounts")) {
160 return accounts.getLong("id") + 1;
161 }
162 }
163 }
164 }
165
166 private int calculateChecksum(String cardNumber) {
167 int sum = 0;
168 for (int i = 0; i < cardNumber.length(); i++) {
169 int n = cardNumber.charAt(i) - '0';
170 if (i % 2 == 0) {
171 n *= 2;
172 }
173 if (n > 9) {
174 n -= 9;
175 }
176 sum += n;
177 }
178 return ((10 - (sum % 10)) % 10);
179 }
180}
181
182class Menu {
183 private interface Handler {
184 void call();
185 }
186
187 private class AccountCreationHandler implements Handler {
188 public void call() {
189 try {
190 long id = service.addAccount();
191 System.out.println("Your card has been created");
192 System.out.println("Your card number:");
193 System.out.println(service.getCardNumber(id));
194 System.out.println("Your card PIN:");
195 System.out.println(service.getPin(id));
196 } catch (SQLException e) {
197 System.out.println("Database error");
198 }
199 }
200 }
201
202 private class LoginHandler implements Handler {
203 public void call() {
204 System.out.println("Enter your card number:");
205 String cardNumber = getUserInput(false);
206 System.out.println("Enter your PIN:");
207 String pin = getUserInput(true);
208 try {
209 service.login(cardNumber, pin);
210 System.out.println("You have successfully logged in!");
211 } catch (WrongLoginParametersException e) {
212 System.out.println(e.getMessage());
213 } catch (SQLException e) {
214 System.out.println("Database error");
215 }
216 }
217 }
218
219 private class BalanceHandler implements Handler {
220 public void call() {
221 try {
222 System.out.printf("Balance: %d%n", service.getBalance());
223 } catch (SQLException e) {
224 System.out.println("Database error");
225 }
226 }
227 }
228
229 private class LogoutHandler implements Handler {
230 public void call() {
231 service.logout();
232 System.out.println("You have successfully logged out!");
233 }
234 }
235
236 private static final String[] startMenuOptions = { "Create an account", "Log into account" };
237 private static final String[] accountMenuOptions = { "Balance", "Log out" };
238 private static final Scanner scanner = new Scanner(System.in);
239
240 private final BankingService service;
241
242 public Menu(String dbFile) throws SQLException {
243 service = new BankingService(dbFile);
244 }
245
246 public void launch() {
247 while (true) {
248 showOptions();
249 String input = getUserInput(true);
250 if (input.equals("0")) {
251 break;
252 }
253 switch (service.getState()) {
254 case LOGGED_OUT:
255 handleInputLoggedOut(input);
256 break;
257 case LOGGED_IN:
258 handleInputLoggedIn(input);
259 break;
260 }
261 System.out.println();
262 }
263 System.out.println("Bye!");
264 }
265
266 private String getUserInput(boolean doPrintNewline) {
267 System.out.print("> ");
268 String input = scanner.nextLine();
269 if (doPrintNewline) {
270 System.out.println();
271 }
272 return input;
273 }
274
275 private void showOptions() {
276 String[] options = null;
277
278 switch (service.getState()) {
279 case LOGGED_OUT:
280 options = startMenuOptions;
281 break;
282 case LOGGED_IN:
283 options = accountMenuOptions;
284 break;
285 default:
286 System.err.println("Unknown service state");
287 System.exit(1);
288 }
289 for (int i = 0; i < options.length; i++) {
290 System.out.printf("%d. %s%n", i + 1, options[i]);
291 }
292 System.out.println("0. Exit");
293 }
294
295 private void handleInputLoggedOut(String input) {
296 Handler handler;
297
298 switch (input) {
299 case "1":
300 handler = new AccountCreationHandler();
301 break;
302 case "2":
303 handler = new LoginHandler();
304 break;
305 default:
306 System.out.println("Invalid option. Try again");
307 return;
308 }
309 handler.call();
310 }
311
312 private void handleInputLoggedIn(String input) {
313 Handler handler;
314
315 switch (input) {
316 case "1":
317 handler = new BalanceHandler();
318 break;
319 case "2":
320 handler = new LogoutHandler();
321 break;
322 default:
323 System.out.println("Invalid option. Try again");
324 return;
325 }
326 handler.call();
327 }
328}
329
330public class Main {
331 public static void main(String[] args) {
332 if (args.length != 2 || !args[0].equals("-fileName")) {
333 System.out.printf("Invalid arguments%nUsage: ./program -fileName [DATABASE_FILE_NAME]%n");
334 return;
335 }
336 try {
337 Menu menu = new Menu(args[1]);
338 menu.launch();
339 } catch (SQLException e) {
340 System.out.println("Error: Cannot connect to database");
341 }
342 }
343}