Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import java.math.BigDecimal;
- import java.util.ArrayList;
- import java.util.concurrent.TimeUnit;
- public class BankSimApp {
- public static void main(String[] args) {
- BankAccount account = new BankAccount(0.0, "1254 12 1245 45646546547");
- int operationCounter = 0;
- while(true) {
- (new BankOperation(operationCounter++, account, OperationType.Deposit, 600.6, "Paysheet", 4)).start();
- (new BankOperation(operationCounter++, account, OperationType.Reintegrate, 400.0, "Mortgage", 4, PostponedType.AlwaysWhenDeposit)).start();
- (new BankOperation(operationCounter++, account, OperationType.Reintegrate, 40.0, "Electricity", 4, PostponedType.Once)).start();
- (new BankOperation(operationCounter++, account, OperationType.Reintegrate, 30.0, "Water", 4, PostponedType.Once)).start();
- (new BankOperation(operationCounter++, account, OperationType.Reintegrate, 50.0, "Purchases", 2)).start();
- (new BankOperation(operationCounter++, account, OperationType.Reintegrate, 20.0, "Cash withdrawal", 2)).start();
- (new BankOperation(operationCounter++, account, OperationType.Reintegrate, 100.0, "Life insurance", 4, PostponedType.AlwaysPeriod)).start();
- try {
- TimeUnit.SECONDS.sleep(4);
- } catch (InterruptedException e) {
- }
- }
- }
- }
- class BankOperation extends Thread {
- private final OperationType operationType;
- private final double amount;
- private final String concept;
- private final PostponedType postponedType;
- private final BankAccount account;
- private final int waitToPerformOperation;
- private final int operationId;
- public BankOperation(int operationId, BankAccount account,OperationType operationType, double amount, String concept, int waitToPerformOperation, PostponedType postponedType) {
- this.operationType = operationType;
- this.amount = amount;
- this.concept = concept;
- this.postponedType = postponedType;
- this.account = account;
- this.waitToPerformOperation = waitToPerformOperation;
- this.operationId = operationId;
- }
- public BankOperation(int operationId, BankAccount account,OperationType operationType, double amount, String concept, int waitToPerformOperation) {
- this(operationId, account, operationType, amount, concept, waitToPerformOperation, PostponedType.Deny);
- }
- public void run() {
- boolean tryAgain = true;
- boolean isPosponedOperation = false;
- final StringBuilder message = new StringBuilder();
- int retryCounter = 0;
- BankMovement bankMovement = null;
- try {
- TimeUnit.SECONDS.sleep(this.waitToPerformOperation);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- while(tryAgain) {
- message.delete(0, message.length());
- if(this.operationType == OperationType.Reintegrate) {
- if((bankMovement = this.account.reintegrate(this.amount, this.concept)) == null) {
- message.append("[").append(this.operationId).append(": ").append(this.concept).append("] ");
- if(this.postponedType == PostponedType.Deny) {
- message.append("There is insufficient balance to perform this operation. Please try again later.");
- tryAgain = false;
- } else if(this.postponedType == PostponedType.AlwaysPeriod) {
- message.append("There is insufficient balance to perform this operation. This operation will be postponed for a period of time");
- try {
- TimeUnit.SECONDS.sleep(this.waitToPerformOperation / 2);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- } else if(this.postponedType == PostponedType.AlwaysWhenDeposit) {
- message.append("There is insufficient balance to perform this operation. This operation will be postponed until deposit is made.");
- this.account.waitUnitDepositIsMade();
- } else if(this.postponedType == PostponedType.Once) {
- if(retryCounter <= 0) {
- message.append("There is insufficient balance to perform this operation. " + (retryCounter <= 0 ? "This operation will be postponed for a period of time. (1 try)" : " The recive is returned"));
- try {
- TimeUnit.SECONDS.sleep(this.waitToPerformOperation / 2);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- } else {
- message.append("There is insufficient balance to perform this operation. This receve is returned.");
- tryAgain = false;
- }
- }
- Display.getInstance().err(message.toString());
- retryCounter++;
- isPosponedOperation = true;
- } else {
- message.append("[").append(this.operationId).append("]: ").append(bankMovement).append((isPosponedOperation) ? " (Postponed operation)" : "");
- Display.getInstance().out(message.toString());
- tryAgain = false;
- }
- } else {
- bankMovement = this.account.deposit(this.amount, this.concept);
- message.append('[').append(this.operationId).append("]: ").append(bankMovement);
- Display.getInstance().out(message.toString());
- tryAgain = false;
- }
- }
- }
- }
- class BankAccount {
- private double balance; // Guarded by this
- private int movementCounter; // Guarded by this
- private final ArrayList<BankMovement> movements; // Guarded by this
- private String accountNumber;
- private final Object depositLock = new Object();
- public BankAccount(final double initialBalance, String accountNumber) {
- this.balance = initialBalance;
- this.accountNumber = accountNumber;
- this.movementCounter = 0;
- this.movements = new ArrayList<>();
- }
- public synchronized int getNextMovementId() {
- return ++this.movementCounter;
- }
- public void waitUnitDepositIsMade() {
- synchronized (this.depositLock) {
- try {
- this.depositLock.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- public synchronized double getCurrentBalance() {
- return this.balance;
- }
- public BankMovement deposit(double amount, String concept) {
- BankMovement bankMovement = null;
- synchronized (this) {
- this.balance += amount;
- bankMovement = new BankMovement(this.getNextMovementId(), concept, this.balance, amount);
- this.movements.add(bankMovement);
- }
- synchronized (this.depositLock) {
- this.depositLock.notifyAll();
- }
- return bankMovement;
- }
- public synchronized BankMovement reintegrate(double amount, String concept) {
- if((this.balance - amount) < 0.0) {
- return null;
- }
- this.balance -= amount;
- BankMovement bankMovement = new BankMovement(this.getNextMovementId(), concept, this.balance, -(amount));
- this.movements.add(bankMovement);
- return bankMovement;
- }
- }
- class BankMovement {
- private final int movementId;
- private final String concept;
- private final double balance;
- private final double amount;
- public BankMovement(int movementId, String concept, double balance, double amount) {
- this.movementId = movementId;
- this.concept = concept;
- this.balance = balance;
- this.amount = amount;
- }
- private static BigDecimal truncateDecimal(double x, int numberofDecimals) {
- return (x > 0) ? new BigDecimal(String.valueOf(x)).setScale(numberofDecimals, BigDecimal.ROUND_FLOOR) :
- new BigDecimal(String.valueOf(x)).setScale(numberofDecimals, BigDecimal.ROUND_CEILING);
- }
- @Override
- public String toString() {
- StringBuilder result = new StringBuilder();
- result.append("#").append(this.movementId).append('\t').append(this.concept).append('\t').append(this.truncateDecimal(this.amount, 2).toString())
- .append('\t').append(this.truncateDecimal(this.balance, 2).toString());
- return result.toString();
- }
- }
- class Display {
- private final static Display instance = new Display();
- private Display() {}
- public synchronized void out(String str) {
- System.out.println(str);
- System.out.flush();
- }
- public synchronized void err(String str) {
- System.err.println(str);
- System.err.flush();
- }
- public static Display getInstance() {
- return instance;
- }
- }
- enum OperationType {
- Reintegrate, Deposit
- }
- enum PostponedType {
- Deny, Once, AlwaysPeriod, AlwaysWhenDeposit
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement