Skip to content
This repository has been archived by the owner on Dec 3, 2019. It is now read-only.

Никишин А.А. #2

Open
wants to merge 7 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
11 changes: 9 additions & 2 deletions src/main/java/com/moneytransfer/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.moneytransfer.service.TransactionService;
import com.moneytransfer.service.UserService;

import com.moneytransfer.utils.Utils;
import org.apache.log4j.Logger;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.Server;
Expand All @@ -25,8 +26,14 @@ public class Application {
public static void main(String[] args) throws Exception {
// Initialize H2 database with demo data
log.info("Initialize demo .....");
DAOFactory h2DaoFactory = DAOFactory.getDAOFactory(DAOFactory.H2);
h2DaoFactory.populateTestData();
String param="";
for (String arg:args) {
if ("-dao=".equals(arg.substring(0,5)))
param=arg.substring(5);
}
DAOFactory.setDAOFactory(param);
DAOFactory DaoFactory = DAOFactory.getDAOFactory();
DaoFactory.populateTestData();
log.info("Initialisation Complete....");
// Host service on jetty
startService();
Expand Down
17 changes: 17 additions & 0 deletions src/main/java/com/moneytransfer/dao/DAOFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,34 @@ public abstract class DAOFactory {

public static final int H2 = 1;

public static final int HM = 2;

private static int DAOType = 0;

public abstract UserDAO getUserDAO();

public abstract AccountDAO getAccountDAO();

public abstract void populateTestData() throws CustomException;

public static void setDAOFactory(String factoryName) {
if (factoryName==null || !factoryName.toLowerCase().equals("hm"))
DAOType = H2;
else
DAOType = HM;
}

public static DAOFactory getDAOFactory() {
return getDAOFactory(DAOType);
}

public static DAOFactory getDAOFactory(int factoryCode) {

switch (factoryCode) {
case H2:
return new H2DAOFactory();
case HM:
return new HMDAOFactory();
default:
// by default using H2 in memory database
return new H2DAOFactory();
Expand Down
6 changes: 2 additions & 4 deletions src/main/java/com/moneytransfer/dao/H2DAOFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,11 @@ public static Connection getConnection() throws SQLException {
}

public UserDAO getUserDAO() {
DbUtils.loadDriver(h2_driver);
return new UserDAOImpl();
return userDAO;
}

public AccountDAO getAccountDAO() {
DbUtils.loadDriver(h2_driver);
return new AccountDAOImpl();
return accountDAO;
}

@Override
Expand Down
58 changes: 58 additions & 0 deletions src/main/java/com/moneytransfer/dao/HMDAOFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.moneytransfer.dao;

import com.moneytransfer.dao.impl.AccountHMDAOImpl;
import com.moneytransfer.dao.impl.UserHMDAOImpl;
import com.moneytransfer.exception.CustomException;
import com.moneytransfer.model.Account;
import com.moneytransfer.model.User;
import com.moneytransfer.utils.Utils;
import org.apache.commons.dbutils.DbUtils;
import org.apache.log4j.Logger;
import org.h2.tools.RunScript;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

/**
* H2 DAO
*/
public class HMDAOFactory extends DAOFactory {

private static Logger log = Logger.getLogger(H2DAOFactory.class);

private static final UserHMDAOImpl userDAO = new UserHMDAOImpl();
private static final AccountHMDAOImpl accountDAO = new AccountHMDAOImpl();

public UserDAO getUserDAO() {
return userDAO;
}

public AccountDAO getAccountDAO() {
return accountDAO;
}

@Override
public void populateTestData() throws CustomException {
log.info("Populating Test User Table and data ..... ");
Boolean f=true;
if (userDAO.insertUser(new User("test2","[email protected]"))==0) f=false;
if (userDAO.insertUser(new User("test1","[email protected]"))==0) f=false;
if (userDAO.insertUser(new User("yangluo","[email protected]"))==0) f=false;
if (userDAO.insertUser(new User("qinfran","[email protected]"))==0) f=false;
if (userDAO.insertUser(new User("liusisi","[email protected]"))==0) f=false;
if (accountDAO.createAccount(new Account("yangluo",new BigDecimal(100.0000),"USD"))==0) f=false;
if (accountDAO.createAccount(new Account("qinfran",new BigDecimal(200.0000),"USD"))==0) f=false;
if (accountDAO.createAccount(new Account("yangluo",new BigDecimal(500.0000),"EUR"))==0) f=false;
if (accountDAO.createAccount(new Account("qinfran",new BigDecimal(500.0000),"EUR"))==0) f=false;
if (accountDAO.createAccount(new Account("yangluo",new BigDecimal(500.0000),"GBP"))==0) f=false;
if (accountDAO.createAccount(new Account("qinfran",new BigDecimal(500.0000),"GBP"))==0) f=false;
if (f==false){
log.error("populateTestData(): Error populating user data");
throw new RuntimeException();
}
}
}
6 changes: 1 addition & 5 deletions src/main/java/com/moneytransfer/dao/impl/AccountDAOImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,7 @@ public Account getAccountByUser(String user, String currency) throws CustomExcep
log.debug("Retrieve Account By userId: " + acc);
}
}
return getAllAccounts()
.stream()
.filter(account -> account.getUserName().equals(user) && account.getCurrencyCode().equals(currency))
.findFirst()
.orElse(null);
return acc;
} catch (SQLException e) {
throw new CustomException("getAccountById(): Error reading account data", e);
} finally {
Expand Down
232 changes: 232 additions & 0 deletions src/main/java/com/moneytransfer/dao/impl/AccountHMDAOImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
package com.moneytransfer.dao.impl;

import com.moneytransfer.dao.AccountDAO;
import com.moneytransfer.exception.CustomException;
import com.moneytransfer.model.Account;
import com.moneytransfer.model.MoneyUtil;
import com.moneytransfer.model.UserTransaction;
import org.apache.log4j.Logger;

import java.math.BigDecimal;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicLong;

public class AccountHMDAOImpl implements AccountDAO {

private static Logger log = Logger.getLogger(AccountHMDAOImpl.class);

private static final ConcurrentHashMap <Long, Account> accountsById = new ConcurrentHashMap<>(500);
private static final ConcurrentHashMap <userKey, Long> accountsByUser = new ConcurrentHashMap<>(500);
private static final AtomicLong accountNewId = new AtomicLong(1);

/**
* Get all accounts.
*/
public Set<Account> getAllAccounts() throws CustomException {
Set<Account> allAccounts = new HashSet<>(accountsById.values());
for (Account acc : allAccounts) {
if (log.isDebugEnabled()) {
log.debug("getAllAccounts(): Get Account " + acc);
}
}
return allAccounts;
}

/**
* Get account by id
*/
public Account getAccountById(long accountId) throws CustomException {
Account acc;
if (accountsById.containsKey(accountId))
acc = accountsById.get(accountId);
else
return null;
/* if (acc==null)
{
if (log.isDebugEnabled()) {
log.error("getAccountById(): Account not find.");
}
throw new CustomException("Account not find");
}*/
if (log.isDebugEnabled()) {
log.debug("Retrieve Account By Id: " + acc);
}
return acc;
}

public Account getAccountByUser(String user, String currency) throws CustomException {
long accountId;
if (accountsByUser.containsKey(new userKey(user,currency)))
accountId = accountsByUser.get(new userKey(user,currency));
else
return null;
/* if (accountId == 0) {
if (log.isDebugEnabled()) {
log.error("getAccountByUser(): Account ID not find.");
}
throw new CustomException("Account ID not find");
}*/
if (log.isDebugEnabled()) {
log.debug("Retrieve Account ID By User: " + accountId);
}
Account acc=null;
if (accountsById.containsKey(accountId))
acc = accountsById.get(accountId);
else
return null;
/* if (acc==null)
{
if (log.isDebugEnabled()) {
log.error("getAccountByUser(): Account not find.");
}
throw new CustomException("Account not find");
}*/
if (log.isDebugEnabled()) {
log.debug("Retrieve Account By User: " + acc);
}
return acc;
}

/**
* Create account
*/
public long createAccount(Account account) throws CustomException {
if (accountsByUser.containsKey(new userKey(account.getUserName(),account.getCurrencyCode())))
{
log.error("createAccount(): Creating account failed, no rows affected.");
throw new CustomException("Account Cannot be created");
}
Account acc = new Account(accountNewId.getAndIncrement(),account.getUserName(),account.getBalance(),account.getCurrencyCode());
accountsById.put(acc.getAccountId(),acc);
accountsByUser.put(new userKey(acc.getUserName(),acc.getCurrencyCode()),acc.getAccountId());
return acc.getAccountId();
}

/**
* Delete account by id
*/
public int deleteAccountById(long accountId) throws CustomException {
Account acc = accountsById.remove(accountId);
if (acc==null)
{
log.error("deleteAccountById(): Error deleting user account Id " + accountId);
throw new CustomException("Account Cannot be deleted");
}
long delAcc = accountsByUser.remove(new userKey(acc.getUserName(),acc.getCurrencyCode()));
if (delAcc==0 || delAcc!=accountId)
{
log.error("deleteAccountById(): Error deleting user account Id " + accountId);
throw new CustomException("Account Cannot be deleted");
}
return 1;
}

/**
* Update account balance
*/
public int updateAccountBalance(long accountId, BigDecimal deltaAmount) throws CustomException {
Account targetAccount=null;
if (accountsById.containsKey(accountId))
targetAccount = accountsById.get(accountId);
if (targetAccount==null)
{
if (log.isDebugEnabled()) {
log.error("updateAccountBalance(): Account not find.");
}
throw new CustomException("Account not find");
}
targetAccount.getBalance().add(deltaAmount);
if (targetAccount.getBalance().compareTo(MoneyUtil.zeroAmount) < 0) {
throw new CustomException("Not sufficient Fund for account: " + accountId);
}
if (accountsById.replace(targetAccount.getAccountId(),targetAccount)==null && log.isDebugEnabled())
{
log.error("updateAccountBalance(): User Transaction Failed for: " + accountId);
throw new CustomException("User transaction Failed");
}
if (log.isDebugEnabled()) {
log.debug("New Balance after Update: " + targetAccount);
}
return 1;
}

/**
* Transfer balance between two accounts.
*/
public int transferAccountBalance(UserTransaction userTransaction) throws CustomException {
int result = 0;
Account fromAccount = null;
Account toAccount = null;
if (accountsById.containsKey(userTransaction.getFromAccountId()))
fromAccount=accountsById.get(userTransaction.getFromAccountId());
if (accountsById.containsKey(userTransaction.getToAccountId()))
toAccount=accountsById.get(userTransaction.getToAccountId());

// check locking status
if (fromAccount == null || toAccount == null) {
if (log.isDebugEnabled()) {
log.error("transferAccountBalance(): Account not find.");
}
throw new CustomException("Fail to find both accounts");
}

// check transaction currency
if (!fromAccount.getCurrencyCode().equals(userTransaction.getCurrencyCode())) {
throw new CustomException(
"Fail to transfer Fund, transaction ccy are different from source/destination");
}

// check ccy is the same for both accounts
if (!fromAccount.getCurrencyCode().equals(toAccount.getCurrencyCode())) {
throw new CustomException(
"Fail to transfer Fund, the source and destination account are in different currency");
}

// check enough fund in source account
fromAccount.getBalance().subtract(userTransaction.getAmount());
if (fromAccount.getBalance().compareTo(MoneyUtil.zeroAmount) < 0) {
throw new CustomException("Not enough Fund from source Account ");
}

if (log.isDebugEnabled()) {
log.debug("transferAccountBalance from Account: " + fromAccount);
log.debug("transferAccountBalance to Account: " + toAccount);
}

if (accountsById.replace(fromAccount.getAccountId(), fromAccount) != null) {
result++;
}
if (accountsById.replace(toAccount.getAccountId(), toAccount) != null) {
result++;
}
return result;
}

private class userKey
{
final String user;
final String currency;

userKey(String user, String currency)
{
this.user=user;
this.currency=currency;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
userKey key = (userKey) o;
return Objects.equals(user, key.user) && Objects.equals(currency, key.currency);
}

@Override
public int hashCode() {
return 31*(user==null?0:user.hashCode())+(currency==null?0:currency.hashCode());
}
}
}
Loading