scp2: task 2 + 3

This commit is contained in:
2025-11-07 12:22:09 +01:00
parent 2a3141ed9f
commit a187ea07b4
2 changed files with 93 additions and 35 deletions

View File

@@ -1,4 +1,5 @@
import collection.mutable.Map
import java.util.UUID
class Bank(val allowedAttempts: Integer = 3) {
@@ -9,54 +10,95 @@ class Bank(val allowedAttempts: Integer = 3) {
def processing: Boolean = !transactionsPool.isEmpty
// TODO
// Adds a new transaction for the transfer to the transaction pool
def transfer(from: String, to: String, amount: Double): Unit = ???
def transfer(from: String, to: String, amount: Double): Unit = {
if (amount <= 0) {
val t = new Transaction(from, to, amount)
t.fail()
completedTransactions.add(t)
return
}
val f = getAccount(from)
val t = getAccount(to)
if (f.isEmpty || t.isEmpty) {
val t = new Transaction(from, to, amount)
t.fail()
completedTransactions.add(t)
return
}
if (f.get.balance < amount) {
val t = new Transaction(from, to, amount)
t.fail()
completedTransactions.add(t)
return
}
transactionsPool.add(new Transaction(from, to, amount))
}
// TODO
// Process the transactions in the transaction pool
// The implementation needs to be completed and possibly fixed
def processTransactions: Unit = {
// val workers : List[Thread] = transactionsPool.iterator.toList
// .filter(/* select only pending transactions */)
// .map(processSingleTransaction)
val workers: List[Thread] = transactionsPool.iterator.toList
.filter(_.isPending)
.map(processSingleTransaction)
// workers.map( element => element.start() )
// workers.map( element => element.join() )
workers.map(element => element.start())
workers.map(element => element.join())
/* TODO: change to select only transactions that succeeded */
// val succeded : List[Transaction] = transactionsPool
val succeded: List[Transaction] =
transactionsPool.iterator.toList.filter(_.succeeded)
/* TODO: change to select only transactions that failed */
// val failed : List[Transaction] = transactionsPool
val failed: List[Transaction] =
transactionsPool.iterator.toList.filter(_.failed)
// succeded.map(/* remove transactions from the transaction pool */)
// succeded.map(/* add transactions to the completed transactions queue */)
succeded.map(transactionsPool.remove(_))
succeded.map(completedTransactions.add(_))
// failed.map(t => {
/* transactions that failed need to be set as pending again;
if the number of retry has exceeded they also need to be removed from
the transaction pool and to be added to the queue of completed transactions */
// })
failed.map(t => {
t.setPending()
t.incrementAttempt()
if (t.exceeded) {
transactionsPool.remove(t)
completedTransactions.add(t)
}
})
if (!transactionsPool.isEmpty) {
processTransactions
}
}
// TODO
// The function creates a new thread ready to process
// the transaction, and returns it as a return value
private def processSingleTransaction(t: Transaction): Thread = ???
private def processSingleTransaction(t: Transaction): Thread =
new Thread(() => {
accountsRegistry.synchronized {
val fromOpt = getAccount(t.from)
val toOpt = getAccount(t.to)
// TODO
// Creates a new account and returns its code to the user.
// The account is stored in the local registry of bank accounts.
def createAccount(initialBalance: Double): String = ???
(fromOpt, toOpt) match {
case (Some(from), Some(to)) =>
from.withdraw(t.amount) match {
case Right(updatedFrom) =>
to.deposit(t.amount) match {
case Right(updatedTo) =>
accountsRegistry(t.from) = updatedFrom
accountsRegistry(t.to) = updatedTo
t.succeed()
case Left(_) => t.fail()
}
case Left(_) => t.fail()
}
case _ => t.fail()
}
}
})
// TODO
// Return information about a certain account based on its code.
// Remember to handle the case in which the account does not exist
def getAccount(code: String): Option[Account] = ???
def createAccount(initialBalance: Double): String = {
val code = UUID.randomUUID().toString
accountsRegistry(code) = new Account(code, initialBalance)
code
}
def getAccount(code: String): Option[Account] = accountsRegistry.get(code)
}

View File

@@ -29,7 +29,23 @@ class Transaction(
private var status: TransactionStatus.Value = TransactionStatus.PENDING
private var attempts = 0
def getStatus() = status
def getStatus(): TransactionStatus.Value = status
def isPending(): Boolean = status == TransactionStatus.PENDING
def succeeded(): Boolean = status == TransactionStatus.SUCCESS
def failed(): Boolean = status == TransactionStatus.FAILED
def setPending(): Unit = status = TransactionStatus.PENDING
def incrementAttempt(): Unit = attempts += 1
def exceeded(): Boolean = attempts > retries
def succeed(): Unit = status = TransactionStatus.SUCCESS
def fail(): Unit = status = TransactionStatus.FAILED
// TODO: Implement methods that change the status of the transaction