Skip to content
This repository has been archived by the owner on Jan 17, 2022. It is now read-only.

Implementation interview tasks #54

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions src/main/java/com/devexperts/account/Account.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.devexperts.account;

import java.math.BigDecimal;

public class Account {
private final AccountKey accountKey;
private final String firstName;
private final String lastName;
private Double balance;
private BigDecimal balance;

public Account(AccountKey accountKey, String firstName, String lastName, Double balance) {
public Account(AccountKey accountKey, String firstName, String lastName, BigDecimal balance) {
this.accountKey = accountKey;
this.firstName = firstName;
this.lastName = lastName;
Expand All @@ -25,11 +27,11 @@ public String getLastName() {
return lastName;
}

public Double getBalance() {
public BigDecimal getBalance() {
return balance;
}

public void setBalance(Double balance) {
public void setBalance(BigDecimal balance) {
this.balance = balance;
}
}
4 changes: 4 additions & 0 deletions src/main/java/com/devexperts/account/AccountKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
public class AccountKey {
private final long accountId;

public long getAccountId() {
return accountId;
}

private AccountKey(long accountId) {
this.accountId = accountId;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.devexperts.exeptions;

public class AccountAlreadyExistsException extends RuntimeException {
public AccountAlreadyExistsException(){
super("Account already exists");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.devexperts.exeptions;

public class NotEnoughFundsException extends RuntimeException {
public NotEnoughFundsException(){
super("Not Enough Funds");
}
}
32 changes: 30 additions & 2 deletions src/main/java/com/devexperts/rest/AccountController.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,42 @@
package com.devexperts.rest;

import com.devexperts.account.Account;
import com.devexperts.exeptions.NotEnoughFundsException;
import com.devexperts.service.AccountService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;

@RestController
@RequestMapping("/api")
public class AccountController extends AbstractAccountController {

public ResponseEntity<Void> transfer(long sourceId, long targetId, double amount) {
return null;
private AccountService accountService;

public AccountController(AccountService accountService) {
this.accountService = accountService;
}
@PostMapping(path = "/operations/transfer")
public ResponseEntity<Void> transfer(@RequestParam("source_id") long sourceId,
@RequestParam("target_id") long targetId,
@RequestParam("amount") double amount)
{
Account accountSource = accountService.getAccount(sourceId);
Account accountTarget = accountService.getAccount(targetId);
if (accountSource == null || accountTarget == null) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
try {
accountService.transfer(accountSource, accountTarget, BigDecimal.valueOf(amount));
} catch (NotEnoughFundsException e) {
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}

return new ResponseEntity<>(HttpStatus.OK);
}
}
7 changes: 5 additions & 2 deletions src/main/java/com/devexperts/service/AccountService.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.devexperts.service;

import com.devexperts.account.Account;
import com.devexperts.account.AccountKey;

import java.math.BigDecimal;

public interface AccountService {

Expand All @@ -16,7 +19,7 @@ public interface AccountService {
* @param account account entity to add or update
* @throws IllegalArgumentException if account is already present
* */
void createAccount(Account account);
void createAccount(AccountKey accountKey, Account account);

/**
* Get account from the cache
Expand All @@ -33,5 +36,5 @@ public interface AccountService {
* @param target account to transfer money to
* @param amount dollar amount to transfer
* */
void transfer(Account source, Account target, double amount);
void transfer(Account source, Account target, BigDecimal amount);
}
49 changes: 38 additions & 11 deletions src/main/java/com/devexperts/service/AccountServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,63 @@

import com.devexperts.account.Account;
import com.devexperts.account.AccountKey;
import com.devexperts.exeptions.AccountAlreadyExistsException;
import com.devexperts.exeptions.NotEnoughFundsException;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.math.BigDecimal;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class AccountServiceImpl implements AccountService {

private final List<Account> accounts = new ArrayList<>();
private final Map<AccountKey, Account> accounts = new ConcurrentHashMap<>();

@Override
public void clear() {
accounts.clear();
}

@Override
public void createAccount(Account account) {
accounts.add(account);
public void createAccount(AccountKey accountKey, Account account) {
if (accountKey == null || account == null){
throw new IllegalArgumentException("Account or AccountKey is invalid");
}
if (accounts.putIfAbsent(accountKey, account) == null){
throw new AccountAlreadyExistsException();
}
}

@Override
public Account getAccount(long id) {
return accounts.stream()
.filter(account -> account.getAccountKey() == AccountKey.valueOf(id))
.findAny()
.orElse(null);
return accounts.get(AccountKey.valueOf(id));
}

/*@Override
public void transfer(Account source, Account target, BigDecimal amount) {
source.setBalance(source.getBalance().subtract(amount));
target.setBalance(target.getBalance().add(amount));
}*/

@Override
public void transfer(Account source, Account target, double amount) {
//do nothing for now
public void transfer(final Account source, final Account target, final BigDecimal amount) {
if (source == null || target == null || amount == null){
throw new IllegalArgumentException("account or accountKey or amount is invalid");
}
if (source.getBalance().subtract(amount).compareTo(new BigDecimal("0")) < 0) {
throw new NotEnoughFundsException();
}
final boolean prioritySourceTarget = source.getAccountKey().getAccountId() > target.getAccountKey().getAccountId();
synchronized (prioritySourceTarget ? source : target) {
synchronized (prioritySourceTarget ? target : source) {
doTransfer(source, target, amount);
}
}
}

private void doTransfer(Account source, Account target, BigDecimal amount) {
source.setBalance(source.getBalance().subtract(amount));
target.setBalance(target.getBalance().add(amount));
}
}
6 changes: 6 additions & 0 deletions src/main/resources/sql/data/accounts.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
CREATE TABLE IF NOT EXISTS accounts (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
first_name VARCHAR(255) NOT NULL,
last_name VARCHAR(255) NOT NULL,
balance BIGINT NOT NULL
);
1 change: 1 addition & 0 deletions src/main/resources/sql/data/select.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SELECT source_id FROM transfers GROUP BY source_id HAVING SUM(amount)>=1000 WHERE transfer_time>'2019-01-01'::timestamp;
7 changes: 7 additions & 0 deletions src/main/resources/sql/data/transfers.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CREATE TABLE IF NOT EXISTS transfers(
id BIGINT AUTO_INCREMENT PRIMARY KEY,
source_id BIGINT NOT NULL,
target_id BIGINT NOT NULL,
amount BIGINT NOT NULL,
transfer_time TIMESTAMP NOT NULL,
);