From 6f57f32ffc99f2651edfd95e4dc3cdf5214f90ee Mon Sep 17 00:00:00 2001 From: Twin Panichsombat Date: Mon, 24 Jul 2017 16:32:09 +0900 Subject: [PATCH 01/23] Change source to 1.8 --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index dd91bd7..7e6250c 100644 --- a/build.gradle +++ b/build.gradle @@ -30,8 +30,8 @@ dependencies { [compileJava, compileTestJava]*.options*.compilerArgs = ['-Xlint:all'] -sourceCompatibility = 1.6 -targetCompatibility = 1.6 +sourceCompatibility = 1.8 +targetCompatibility = 1.8 task wee(type: Wrapper) { gradleVersion = '2.10' //we want gradle 2.10 to run this project From 1af82ba349faf68d2e370323cb686ded1c3e41a7 Mon Sep 17 00:00:00 2001 From: Twin Panichsombat Date: Mon, 24 Jul 2017 16:32:32 +0900 Subject: [PATCH 02/23] Test Transfer Window --- .../internal/DefaultTransferWindowTest.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/test/com/bank/service/internal/DefaultTransferWindowTest.java b/src/test/com/bank/service/internal/DefaultTransferWindowTest.java index b51fa87..cf3b5c7 100644 --- a/src/test/com/bank/service/internal/DefaultTransferWindowTest.java +++ b/src/test/com/bank/service/internal/DefaultTransferWindowTest.java @@ -1,4 +1,54 @@ package com.bank.service.internal; +import net.sf.cglib.core.Local; +import org.junit.Assert; +import org.junit.Test; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.Date; + public class DefaultTransferWindowTest { + //private final + @Test + public void withinValidTransferWindow() { + CurrentTime currentTime = new CurrentTime("12:05:59"); + DefaultTransferWindow transferWindow = new DefaultTransferWindow("10:00:00", "22:00:00"); + Assert.assertTrue(transferWindow.isValidTimeForTransferMoney(currentTime.getCurrentTime())); + } + + @Test + public void withinInValidTransferWindow() { + CurrentTime currentTime = new CurrentTime("22:05:59"); + DefaultTransferWindow transferWindow = new DefaultTransferWindow("10:00:00", "22:00:00"); + Assert.assertFalse(transferWindow.isValidTimeForTransferMoney(currentTime.getCurrentTime())); + } + + class CurrentTime{ + private String specificTime = null; + public CurrentTime(String initial){ + this.specificTime = initial; + } + + public LocalTime getCurrentTime() { + if(this.specificTime != null) + return LocalTime.parse(this.specificTime); + return LocalTime.now(); + } + } + + class DefaultTransferWindow { + private LocalTime open; + private LocalTime close; + public DefaultTransferWindow(String open, String close) { + this.open = LocalTime.parse(open); + this.close = LocalTime.parse(close); + } + + public boolean isValidTimeForTransferMoney(LocalTime transactionTime) { + return (transactionTime.isAfter(open))&&(transactionTime.isBefore(close)); + } + } } From 2e8a311b6d2c252c0864f3a93fb390402ff9a748 Mon Sep 17 00:00:00 2001 From: Twin Panichsombat Date: Mon, 24 Jul 2017 16:49:07 +0900 Subject: [PATCH 03/23] Move DefaultTransferWindow --- .../com/bank/domain/DefaultTransferWindow.java | 16 ++++++++++++++++ .../internal/DefaultTransferWindowTest.java | 18 +----------------- 2 files changed, 17 insertions(+), 17 deletions(-) create mode 100644 src/main/com/bank/domain/DefaultTransferWindow.java diff --git a/src/main/com/bank/domain/DefaultTransferWindow.java b/src/main/com/bank/domain/DefaultTransferWindow.java new file mode 100644 index 0000000..56e5cf3 --- /dev/null +++ b/src/main/com/bank/domain/DefaultTransferWindow.java @@ -0,0 +1,16 @@ +package com.bank.domain; + +import java.time.LocalTime; + +public class DefaultTransferWindow { + private LocalTime open; + private LocalTime close; + public DefaultTransferWindow(String open, String close) { + this.open = LocalTime.parse(open); + this.close = LocalTime.parse(close); + } + + public boolean isValidTimeForTransferMoney(LocalTime transactionTime) { + return (transactionTime.isAfter(open))&&(transactionTime.isBefore(close)); + } +} diff --git a/src/test/com/bank/service/internal/DefaultTransferWindowTest.java b/src/test/com/bank/service/internal/DefaultTransferWindowTest.java index cf3b5c7..a5ba82d 100644 --- a/src/test/com/bank/service/internal/DefaultTransferWindowTest.java +++ b/src/test/com/bank/service/internal/DefaultTransferWindowTest.java @@ -1,14 +1,10 @@ package com.bank.service.internal; -import net.sf.cglib.core.Local; +import com.bank.domain.DefaultTransferWindow; import org.junit.Assert; import org.junit.Test; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.time.LocalDateTime; import java.time.LocalTime; -import java.util.Date; public class DefaultTransferWindowTest { //private final @@ -39,16 +35,4 @@ public LocalTime getCurrentTime() { } } - class DefaultTransferWindow { - private LocalTime open; - private LocalTime close; - public DefaultTransferWindow(String open, String close) { - this.open = LocalTime.parse(open); - this.close = LocalTime.parse(close); - } - - public boolean isValidTimeForTransferMoney(LocalTime transactionTime) { - return (transactionTime.isAfter(open))&&(transactionTime.isBefore(close)); - } - } } From f34583cf7738ded5f9380cf9b97d097472677eb0 Mon Sep 17 00:00:00 2001 From: Twin Panichsombat Date: Mon, 24 Jul 2017 17:06:13 +0900 Subject: [PATCH 04/23] Move CurrentTime --- src/main/com/bank/domain/CurrentTime.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/main/com/bank/domain/CurrentTime.java diff --git a/src/main/com/bank/domain/CurrentTime.java b/src/main/com/bank/domain/CurrentTime.java new file mode 100644 index 0000000..f82e071 --- /dev/null +++ b/src/main/com/bank/domain/CurrentTime.java @@ -0,0 +1,16 @@ +package com.bank.domain; + +import java.time.LocalTime; + +public class CurrentTime { + private String specificTime = null; + public CurrentTime(String initial){ + this.specificTime = initial; + } + + public LocalTime getCurrentTime() { + if(this.specificTime != null) + return LocalTime.parse(this.specificTime); + return LocalTime.now(); + } +} From d06881dbcca9438e8ac7bdefbc1e04a1d15a81a0 Mon Sep 17 00:00:00 2001 From: Twin Panichsombat Date: Mon, 24 Jul 2017 17:06:45 +0900 Subject: [PATCH 05/23] Add transaction time to receipt --- src/main/com/bank/domain/TransferReceipt.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/com/bank/domain/TransferReceipt.java b/src/main/com/bank/domain/TransferReceipt.java index f6b3ae0..5038be5 100644 --- a/src/main/com/bank/domain/TransferReceipt.java +++ b/src/main/com/bank/domain/TransferReceipt.java @@ -15,6 +15,8 @@ */ package com.bank.domain; +import java.time.LocalTime; + import static java.lang.String.format; public class TransferReceipt { @@ -25,6 +27,15 @@ public class TransferReceipt { private Account initialDestinationAccountCopy; private Account finalSourceAccountCopy; private Account finalDestinationAccountCopy; + private LocalTime transactionTime; + + public void setTransactionTime(LocalTime transactionTime) { + this.transactionTime = transactionTime; + } + + public LocalTime getTransactionTime() { + return this.transactionTime; + } public void setTransferAmount(double transferAmount) { this.transferAmount = transferAmount; From d1b8a766677cb39306332004eb8d917de5805d9b Mon Sep 17 00:00:00 2001 From: Twin Panichsombat Date: Mon, 24 Jul 2017 17:08:05 +0900 Subject: [PATCH 06/23] Move classes --- .../internal/DefaultTransferWindowTest.java | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/test/com/bank/service/internal/DefaultTransferWindowTest.java b/src/test/com/bank/service/internal/DefaultTransferWindowTest.java index a5ba82d..81fd5c6 100644 --- a/src/test/com/bank/service/internal/DefaultTransferWindowTest.java +++ b/src/test/com/bank/service/internal/DefaultTransferWindowTest.java @@ -1,11 +1,10 @@ package com.bank.service.internal; +import com.bank.domain.CurrentTime; import com.bank.domain.DefaultTransferWindow; import org.junit.Assert; import org.junit.Test; -import java.time.LocalTime; - public class DefaultTransferWindowTest { //private final @Test @@ -22,17 +21,4 @@ public void withinInValidTransferWindow() { Assert.assertFalse(transferWindow.isValidTimeForTransferMoney(currentTime.getCurrentTime())); } - class CurrentTime{ - private String specificTime = null; - public CurrentTime(String initial){ - this.specificTime = initial; - } - - public LocalTime getCurrentTime() { - if(this.specificTime != null) - return LocalTime.parse(this.specificTime); - return LocalTime.now(); - } - } - } From f4dfd3bac6e35ca59ff2e76c6880207c7ff17bd4 Mon Sep 17 00:00:00 2001 From: Twin Panichsombat Date: Mon, 24 Jul 2017 18:31:13 +0900 Subject: [PATCH 07/23] Very long refactor --- .../bank/domain/DefaultTransferWindow.java | 7 +++ src/main/com/bank/domain/TransferReceipt.java | 7 +-- .../com/bank/service/TransferService.java | 3 +- .../internal/DefaultTransferService.java | 21 +++++--- .../internal/InvalidTransferWindow.java | 6 +++ .../com/bank/config/xml/IntegrationTests.java | 3 +- .../internal/DefaultTransferServiceTests.java | 52 ++++++++++++++----- .../internal/DefaultTransferWindowTest.java | 2 +- 8 files changed, 73 insertions(+), 28 deletions(-) create mode 100644 src/main/com/bank/service/internal/InvalidTransferWindow.java diff --git a/src/main/com/bank/domain/DefaultTransferWindow.java b/src/main/com/bank/domain/DefaultTransferWindow.java index 56e5cf3..932b3e7 100644 --- a/src/main/com/bank/domain/DefaultTransferWindow.java +++ b/src/main/com/bank/domain/DefaultTransferWindow.java @@ -13,4 +13,11 @@ public DefaultTransferWindow(String open, String close) { public boolean isValidTimeForTransferMoney(LocalTime transactionTime) { return (transactionTime.isAfter(open))&&(transactionTime.isBefore(close)); } + + public LocalTime getOpen() { + return this.open; + } + public LocalTime getClose() { + return this.close; + } } diff --git a/src/main/com/bank/domain/TransferReceipt.java b/src/main/com/bank/domain/TransferReceipt.java index 5038be5..bb1d6bc 100644 --- a/src/main/com/bank/domain/TransferReceipt.java +++ b/src/main/com/bank/domain/TransferReceipt.java @@ -29,12 +29,9 @@ public class TransferReceipt { private Account finalDestinationAccountCopy; private LocalTime transactionTime; - public void setTransactionTime(LocalTime transactionTime) { - this.transactionTime = transactionTime; - } - public LocalTime getTransactionTime() { - return this.transactionTime; + public TransferReceipt(LocalTime transactionTime) { + this.transactionTime = transactionTime; } public void setTransferAmount(double transferAmount) { diff --git a/src/main/com/bank/service/TransferService.java b/src/main/com/bank/service/TransferService.java index 3b886d5..05d5a1b 100644 --- a/src/main/com/bank/service/TransferService.java +++ b/src/main/com/bank/service/TransferService.java @@ -17,11 +17,12 @@ import com.bank.domain.InsufficientFundsException; import com.bank.domain.TransferReceipt; +import com.bank.service.internal.InvalidTransferWindow; public interface TransferService { TransferReceipt transfer(double amount, String srcAcctId, String destAcctId) - throws InsufficientFundsException; + throws InsufficientFundsException, InvalidTransferWindow; void setMinimumTransferAmount(double minimumTransferAmount); } diff --git a/src/main/com/bank/service/internal/DefaultTransferService.java b/src/main/com/bank/service/internal/DefaultTransferService.java index 63c4c06..bffc6be 100644 --- a/src/main/com/bank/service/internal/DefaultTransferService.java +++ b/src/main/com/bank/service/internal/DefaultTransferService.java @@ -17,24 +17,28 @@ import static java.lang.String.format; +import com.bank.domain.*; import org.springframework.transaction.annotation.Transactional; -import com.bank.domain.Account; -import com.bank.domain.InsufficientFundsException; -import com.bank.domain.TransferReceipt; import com.bank.repository.AccountRepository; import com.bank.service.FeePolicy; import com.bank.service.TransferService; +import java.time.LocalTime; + public class DefaultTransferService implements TransferService { private final AccountRepository accountRepository; private final FeePolicy feePolicy; private double minimumTransferAmount = 1.00; + private CurrentTime currentTime; + private DefaultTransferWindow defaultTransferWindow; - public DefaultTransferService(AccountRepository accountRepository, FeePolicy feePolicy) { + public DefaultTransferService(AccountRepository accountRepository, FeePolicy feePolicy, CurrentTime currentTime, DefaultTransferWindow transferWindow) { this.accountRepository = accountRepository; this.feePolicy = feePolicy; + this.currentTime = currentTime; + this.defaultTransferWindow = transferWindow; } @Override @@ -44,12 +48,17 @@ public void setMinimumTransferAmount(double minimumTransferAmount) { @Override @Transactional - public TransferReceipt transfer(double amount, String srcAcctId, String dstAcctId) throws InsufficientFundsException { + public TransferReceipt transfer(double amount, String srcAcctId, String dstAcctId) throws InsufficientFundsException, InvalidTransferWindow { if (amount < minimumTransferAmount) { throw new IllegalArgumentException(format("transfer amount must be at least $%.2f", minimumTransferAmount)); } - TransferReceipt receipt = new TransferReceipt(); + LocalTime transactionTime = this.currentTime.getCurrentTime(); + if(!defaultTransferWindow.isValidTimeForTransferMoney(transactionTime)) { + throw new InvalidTransferWindow("We only allow to transfer between " + defaultTransferWindow.getOpen() + " and " + defaultTransferWindow.getClose()); + } + + TransferReceipt receipt = new TransferReceipt(transactionTime); Account srcAcct = accountRepository.findById(srcAcctId); Account dstAcct = accountRepository.findById(dstAcctId); diff --git a/src/main/com/bank/service/internal/InvalidTransferWindow.java b/src/main/com/bank/service/internal/InvalidTransferWindow.java new file mode 100644 index 0000000..8bd8da6 --- /dev/null +++ b/src/main/com/bank/service/internal/InvalidTransferWindow.java @@ -0,0 +1,6 @@ +package com.bank.service.internal; + +public class InvalidTransferWindow extends Throwable { + public InvalidTransferWindow(String s) { + } +} diff --git a/src/test/com/bank/config/xml/IntegrationTests.java b/src/test/com/bank/config/xml/IntegrationTests.java index 0656e32..0183b26 100644 --- a/src/test/com/bank/config/xml/IntegrationTests.java +++ b/src/test/com/bank/config/xml/IntegrationTests.java @@ -18,6 +18,7 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertThat; +import com.bank.service.internal.InvalidTransferWindow; import org.junit.Test; import org.springframework.context.support.GenericXmlApplicationContext; @@ -28,7 +29,7 @@ public class IntegrationTests { @Test - public void transferTenDollars() throws InsufficientFundsException { + public void transferTenDollars() throws InsufficientFundsException, InvalidTransferWindow { GenericXmlApplicationContext ctx = new GenericXmlApplicationContext(); ctx.getEnvironment().setActiveProfiles("dev"); ctx.load("classpath:/com/bank/config/xml/transfer-service-config.xml"); diff --git a/src/test/com/bank/service/internal/DefaultTransferServiceTests.java b/src/test/com/bank/service/internal/DefaultTransferServiceTests.java index 846befc..e0a4b1d 100644 --- a/src/test/com/bank/service/internal/DefaultTransferServiceTests.java +++ b/src/test/com/bank/service/internal/DefaultTransferServiceTests.java @@ -5,6 +5,8 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; +import com.bank.domain.CurrentTime; +import com.bank.domain.DefaultTransferWindow; import org.junit.Before; import org.junit.Test; @@ -15,9 +17,6 @@ import com.bank.repository.internal.SimpleAccountRepository; import com.bank.service.FeePolicy; import com.bank.service.TransferService; -import com.bank.service.internal.FlatFeePolicy; -import com.bank.service.internal.DefaultTransferService; -import com.bank.service.internal.ZeroFeePolicy; public class DefaultTransferServiceTests { @@ -28,14 +27,37 @@ public class DefaultTransferServiceTests { public void setUp() { accountRepository = new SimpleAccountRepository(); FeePolicy feePolicy = new ZeroFeePolicy(); - transferService = new DefaultTransferService(accountRepository, feePolicy); + CurrentTime currentTime = new CurrentTime(null); + DefaultTransferWindow transferWindow = new DefaultTransferWindow("06:00:00", "22:00:00"); + transferService = new DefaultTransferService(accountRepository, feePolicy, currentTime, transferWindow); assertThat(accountRepository.findById(A123_ID).getBalance(), equalTo(A123_INITIAL_BAL)); assertThat(accountRepository.findById(C456_ID).getBalance(), equalTo(C456_INITIAL_BAL)); } @Test - public void testTransfer() throws InsufficientFundsException { + public void invalidTransferWindow() { + double transferAmount = 100.00; + CurrentTime currentTime = new CurrentTime("23:00:00"); + DefaultTransferWindow transferWindow = new DefaultTransferWindow("06:00:00", "22:00:00"); + accountRepository = new SimpleAccountRepository(); + FeePolicy feePolicy = new ZeroFeePolicy(); + transferService = new DefaultTransferService(accountRepository, feePolicy, currentTime, transferWindow); + + try { + transferService.transfer(transferAmount, A123_ID, C456_ID); + fail("expected InvalidTransactionWindowTime"); + } catch (InsufficientFundsException e) { + //e.printStackTrace(); + } catch (InvalidTransferWindow invalidTransferWindow) { + //invalidTransferWindow.printStackTrace(); + } + assertThat(accountRepository.findById(A123_ID).getBalance(), equalTo(A123_INITIAL_BAL)); + assertThat(accountRepository.findById(C456_ID).getBalance(), equalTo(C456_INITIAL_BAL)); + } + + @Test + public void testTransfer() throws InsufficientFundsException, InvalidTransferWindow { double transferAmount = 100.00; TransferReceipt receipt = transferService.transfer(transferAmount, A123_ID, C456_ID); @@ -49,7 +71,7 @@ public void testTransfer() throws InsufficientFundsException { } @Test - public void testInsufficientFunds() { + public void testInsufficientFunds() throws InvalidTransferWindow { double overage = 9.00; double transferAmount = A123_INITIAL_BAL + overage; @@ -66,7 +88,7 @@ public void testInsufficientFunds() { } @Test - public void testNonExistentSourceAccount() throws InsufficientFundsException { + public void testNonExistentSourceAccount() throws InsufficientFundsException, InvalidTransferWindow { try { transferService.transfer(1.00, Z999_ID, C456_ID); fail("expected AccountNotFoundException"); @@ -77,7 +99,7 @@ public void testNonExistentSourceAccount() throws InsufficientFundsException { } @Test - public void testNonExistentDestinationAccount() throws InsufficientFundsException { + public void testNonExistentDestinationAccount() throws InsufficientFundsException, InvalidTransferWindow { try { transferService.transfer(1.00, A123_ID, Z999_ID); fail("expected AccountNotFoundException"); @@ -88,7 +110,7 @@ public void testNonExistentDestinationAccount() throws InsufficientFundsExceptio } @Test - public void testZeroTransferAmount() throws InsufficientFundsException { + public void testZeroTransferAmount() throws InsufficientFundsException, InvalidTransferWindow { try { transferService.transfer(0.00, A123_ID, C456_ID); fail("expected IllegalArgumentException"); @@ -97,7 +119,7 @@ public void testZeroTransferAmount() throws InsufficientFundsException { } @Test - public void testNegativeTransferAmount() throws InsufficientFundsException { + public void testNegativeTransferAmount() throws InsufficientFundsException, InvalidTransferWindow { try { transferService.transfer(-100.00, A123_ID, C456_ID); fail("expected IllegalArgumentException"); @@ -106,7 +128,7 @@ public void testNegativeTransferAmount() throws InsufficientFundsException { } @Test - public void testTransferAmountLessThanOneCent() throws InsufficientFundsException { + public void testTransferAmountLessThanOneCent() throws InsufficientFundsException, InvalidTransferWindow { try { transferService.transfer(0.009, A123_ID, C456_ID); fail("expected IllegalArgumentException"); @@ -115,7 +137,7 @@ public void testTransferAmountLessThanOneCent() throws InsufficientFundsExceptio } @Test - public void testCustomizedMinimumTransferAmount() throws InsufficientFundsException { + public void testCustomizedMinimumTransferAmount() throws InsufficientFundsException, InvalidTransferWindow { transferService.transfer(1.00, A123_ID, C456_ID); // should be fine transferService.setMinimumTransferAmount(10.00); transferService.transfer(10.00, A123_ID, C456_ID); // fine against new minimum @@ -127,10 +149,12 @@ public void testCustomizedMinimumTransferAmount() throws InsufficientFundsExcept } @Test - public void testNonZeroFeePolicy() throws InsufficientFundsException { + public void testNonZeroFeePolicy() throws InsufficientFundsException, InvalidTransferWindow { double flatFee = 5.00; double transferAmount = 10.00; - transferService = new DefaultTransferService(accountRepository, new FlatFeePolicy(flatFee)); + CurrentTime currentTime = new CurrentTime(null); + DefaultTransferWindow transferWindow = new DefaultTransferWindow("6:00:00", "22:00:00"); + transferService = new DefaultTransferService(accountRepository, new FlatFeePolicy(flatFee), currentTime, transferWindow); transferService.transfer(transferAmount, A123_ID, C456_ID); assertThat(accountRepository.findById(A123_ID).getBalance(), equalTo(A123_INITIAL_BAL - transferAmount - flatFee)); assertThat(accountRepository.findById(C456_ID).getBalance(), equalTo(C456_INITIAL_BAL + transferAmount)); diff --git a/src/test/com/bank/service/internal/DefaultTransferWindowTest.java b/src/test/com/bank/service/internal/DefaultTransferWindowTest.java index 81fd5c6..1c1e145 100644 --- a/src/test/com/bank/service/internal/DefaultTransferWindowTest.java +++ b/src/test/com/bank/service/internal/DefaultTransferWindowTest.java @@ -16,7 +16,7 @@ public void withinValidTransferWindow() { @Test public void withinInValidTransferWindow() { - CurrentTime currentTime = new CurrentTime("22:05:59"); + CurrentTime currentTime = new CurrentTime("23:00:00"); DefaultTransferWindow transferWindow = new DefaultTransferWindow("10:00:00", "22:00:00"); Assert.assertFalse(transferWindow.isValidTimeForTransferMoney(currentTime.getCurrentTime())); } From c2ba0b4fcd5cf873f23a821c25cf700ef8cea6e6 Mon Sep 17 00:00:00 2001 From: Twin Panichsombat Date: Tue, 25 Jul 2017 15:21:08 +0900 Subject: [PATCH 08/23] Create default constructor --- src/main/com/bank/domain/CurrentTime.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/com/bank/domain/CurrentTime.java b/src/main/com/bank/domain/CurrentTime.java index f82e071..2962d3a 100644 --- a/src/main/com/bank/domain/CurrentTime.java +++ b/src/main/com/bank/domain/CurrentTime.java @@ -1,13 +1,20 @@ package com.bank.domain; +import org.omg.CORBA.Current; + import java.time.LocalTime; public class CurrentTime { + private String specificTime = null; public CurrentTime(String initial){ this.specificTime = initial; } + public CurrentTime() { + + } + public LocalTime getCurrentTime() { if(this.specificTime != null) return LocalTime.parse(this.specificTime); From e1f3940c46a22e5d77ba8802f962c6df43d877c6 Mon Sep 17 00:00:00 2001 From: Twin Panichsombat Date: Tue, 25 Jul 2017 15:21:38 +0900 Subject: [PATCH 09/23] Rearrange code --- .../internal/DefaultTransferService.java | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/main/com/bank/service/internal/DefaultTransferService.java b/src/main/com/bank/service/internal/DefaultTransferService.java index bffc6be..7450160 100644 --- a/src/main/com/bank/service/internal/DefaultTransferService.java +++ b/src/main/com/bank/service/internal/DefaultTransferService.java @@ -34,7 +34,10 @@ public class DefaultTransferService implements TransferService { private CurrentTime currentTime; private DefaultTransferWindow defaultTransferWindow; - public DefaultTransferService(AccountRepository accountRepository, FeePolicy feePolicy, CurrentTime currentTime, DefaultTransferWindow transferWindow) { + public DefaultTransferService(AccountRepository accountRepository, + FeePolicy feePolicy, + CurrentTime currentTime, + DefaultTransferWindow transferWindow) { this.accountRepository = accountRepository; this.feePolicy = feePolicy; this.currentTime = currentTime; @@ -58,28 +61,23 @@ public TransferReceipt transfer(double amount, String srcAcctId, String dstAcctI throw new InvalidTransferWindow("We only allow to transfer between " + defaultTransferWindow.getOpen() + " and " + defaultTransferWindow.getClose()); } - TransferReceipt receipt = new TransferReceipt(transactionTime); - Account srcAcct = accountRepository.findById(srcAcctId); Account dstAcct = accountRepository.findById(dstAcctId); - - receipt.setInitialSourceAccount(srcAcct); - receipt.setInitialDestinationAccount(dstAcct); - double fee = feePolicy.calculateFee(amount); if (fee > 0) { srcAcct.debit(fee); } - - receipt.setTransferAmount(amount); - receipt.setFeeAmount(fee); - srcAcct.debit(amount); dstAcct.credit(amount); accountRepository.updateBalance(srcAcct); accountRepository.updateBalance(dstAcct); + TransferReceipt receipt = new TransferReceipt(transactionTime); + receipt.setInitialSourceAccount(srcAcct); + receipt.setInitialDestinationAccount(dstAcct); + receipt.setTransferAmount(amount); + receipt.setFeeAmount(fee); receipt.setFinalSourceAccount(srcAcct); receipt.setFinalDestinationAccount(dstAcct); From e111a5219a3fa85f546807ce9592df4b0782b16c Mon Sep 17 00:00:00 2001 From: Twin Panichsombat Date: Tue, 25 Jul 2017 15:22:12 +0900 Subject: [PATCH 10/23] Using default constructor --- .../com/bank/service/internal/DefaultTransferWindowTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/com/bank/service/internal/DefaultTransferWindowTest.java b/src/test/com/bank/service/internal/DefaultTransferWindowTest.java index 1c1e145..162b3f6 100644 --- a/src/test/com/bank/service/internal/DefaultTransferWindowTest.java +++ b/src/test/com/bank/service/internal/DefaultTransferWindowTest.java @@ -6,9 +6,9 @@ import org.junit.Test; public class DefaultTransferWindowTest { - //private final @Test public void withinValidTransferWindow() { + CurrentTime x = new CurrentTime(); CurrentTime currentTime = new CurrentTime("12:05:59"); DefaultTransferWindow transferWindow = new DefaultTransferWindow("10:00:00", "22:00:00"); Assert.assertTrue(transferWindow.isValidTimeForTransferMoney(currentTime.getCurrentTime())); From 5abca4ca55932220676884b0758e2655cd0e7085 Mon Sep 17 00:00:00 2001 From: Twin Panichsombat Date: Tue, 25 Jul 2017 15:22:46 +0900 Subject: [PATCH 11/23] Using default constructor --- .../bank/service/internal/DefaultTransferServiceTests.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/com/bank/service/internal/DefaultTransferServiceTests.java b/src/test/com/bank/service/internal/DefaultTransferServiceTests.java index e0a4b1d..3d86b25 100644 --- a/src/test/com/bank/service/internal/DefaultTransferServiceTests.java +++ b/src/test/com/bank/service/internal/DefaultTransferServiceTests.java @@ -27,7 +27,7 @@ public class DefaultTransferServiceTests { public void setUp() { accountRepository = new SimpleAccountRepository(); FeePolicy feePolicy = new ZeroFeePolicy(); - CurrentTime currentTime = new CurrentTime(null); + CurrentTime currentTime = new CurrentTime(); DefaultTransferWindow transferWindow = new DefaultTransferWindow("06:00:00", "22:00:00"); transferService = new DefaultTransferService(accountRepository, feePolicy, currentTime, transferWindow); @@ -152,8 +152,8 @@ public void testCustomizedMinimumTransferAmount() throws InsufficientFundsExcept public void testNonZeroFeePolicy() throws InsufficientFundsException, InvalidTransferWindow { double flatFee = 5.00; double transferAmount = 10.00; - CurrentTime currentTime = new CurrentTime(null); - DefaultTransferWindow transferWindow = new DefaultTransferWindow("6:00:00", "22:00:00"); + CurrentTime currentTime = new CurrentTime(); + DefaultTransferWindow transferWindow = new DefaultTransferWindow("06:00:00", "22:00:00"); transferService = new DefaultTransferService(accountRepository, new FlatFeePolicy(flatFee), currentTime, transferWindow); transferService.transfer(transferAmount, A123_ID, C456_ID); assertThat(accountRepository.findById(A123_ID).getBalance(), equalTo(A123_INITIAL_BAL - transferAmount - flatFee)); From c1d1876a9723fa95b1a79f0c3e256181294b7e45 Mon Sep 17 00:00:00 2001 From: Twin Panichsombat Date: Tue, 25 Jul 2017 15:23:05 +0900 Subject: [PATCH 12/23] Add constructor args --- src/main/com/bank/config/xml/transfer-service-config.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/com/bank/config/xml/transfer-service-config.xml b/src/main/com/bank/config/xml/transfer-service-config.xml index 7d16453..01cec38 100644 --- a/src/main/com/bank/config/xml/transfer-service-config.xml +++ b/src/main/com/bank/config/xml/transfer-service-config.xml @@ -10,6 +10,8 @@ + + @@ -18,6 +20,13 @@ + + + + + + + From 6963c9a9d0aa627c80ba5a6964c8c54a864a3285 Mon Sep 17 00:00:00 2001 From: Twin Panichsombat Date: Tue, 25 Jul 2017 15:30:27 +0900 Subject: [PATCH 13/23] Remove unused config in gradle --- build.gradle | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/build.gradle b/build.gradle index 7e6250c..6745496 100644 --- a/build.gradle +++ b/build.gradle @@ -12,19 +12,14 @@ repositories { } dependencies { - //compile 'org.springframework:spring-context:3.1.0.M1' - // https://mvnrepository.com/artifact/org.springframework/spring-context compile group: 'org.springframework', name: 'spring-context', version: '3.1.0.RELEASE' - // https://mvnrepository.com/artifact/org.springframework/spring-jdbc compile group: 'org.springframework', name: 'spring-jdbc', version: '3.1.0.RELEASE' - //compile 'org.springframework:spring-jdbc:3.1.0.M1' compile 'cglib:cglib-nodep:2.2' compile 'hsqldb:hsqldb:1.8.0.10' compile 'commons-logging:commons-logging:1.1.1' compile 'log4j:log4j:1.2.16' compile 'javax.inject:javax.inject:1' - //testCompile 'org.springframework:spring-test:3.1.0.M1' testCompile 'junit:junit:4.7' } @@ -37,16 +32,3 @@ task wee(type: Wrapper) { gradleVersion = '2.10' //we want gradle 2.10 to run this project } - -// consolidate source directories for ease of browsing -sourceSets { - main { - java { srcDir 'src/main' } - resources { srcDir 'src/main' } - } - test { - java { srcDir 'src/test' } - resources { srcDir 'src/test' } - } -} - From dd751bb2e4f6340287c21917d34b7e30ec261a57 Mon Sep 17 00:00:00 2001 From: Twin Panichsombat Date: Tue, 25 Jul 2017 16:01:40 +0900 Subject: [PATCH 14/23] Rename class to be more specific --- .../bank/config/xml/transfer-service-config.xml | 4 ++-- .../{CurrentTime.java => LocalTimeWrapper.java} | 6 +++--- .../service/internal/DefaultTransferService.java | 8 ++++---- .../internal/DefaultTransferServiceTests.java | 14 +++++++------- .../internal/DefaultTransferWindowTest.java | 12 ++++++------ 5 files changed, 22 insertions(+), 22 deletions(-) rename src/main/com/bank/domain/{CurrentTime.java => LocalTimeWrapper.java} (76%) diff --git a/src/main/com/bank/config/xml/transfer-service-config.xml b/src/main/com/bank/config/xml/transfer-service-config.xml index 01cec38..33b123a 100644 --- a/src/main/com/bank/config/xml/transfer-service-config.xml +++ b/src/main/com/bank/config/xml/transfer-service-config.xml @@ -10,7 +10,7 @@ - + @@ -20,7 +20,7 @@ - + diff --git a/src/main/com/bank/domain/CurrentTime.java b/src/main/com/bank/domain/LocalTimeWrapper.java similarity index 76% rename from src/main/com/bank/domain/CurrentTime.java rename to src/main/com/bank/domain/LocalTimeWrapper.java index 2962d3a..3758081 100644 --- a/src/main/com/bank/domain/CurrentTime.java +++ b/src/main/com/bank/domain/LocalTimeWrapper.java @@ -4,14 +4,14 @@ import java.time.LocalTime; -public class CurrentTime { +public class LocalTimeWrapper { private String specificTime = null; - public CurrentTime(String initial){ + public LocalTimeWrapper(String initial){ this.specificTime = initial; } - public CurrentTime() { + public LocalTimeWrapper() { } diff --git a/src/main/com/bank/service/internal/DefaultTransferService.java b/src/main/com/bank/service/internal/DefaultTransferService.java index 7450160..a31a0d6 100644 --- a/src/main/com/bank/service/internal/DefaultTransferService.java +++ b/src/main/com/bank/service/internal/DefaultTransferService.java @@ -31,16 +31,16 @@ public class DefaultTransferService implements TransferService { private final AccountRepository accountRepository; private final FeePolicy feePolicy; private double minimumTransferAmount = 1.00; - private CurrentTime currentTime; + private LocalTimeWrapper localTimeWrapper; private DefaultTransferWindow defaultTransferWindow; public DefaultTransferService(AccountRepository accountRepository, FeePolicy feePolicy, - CurrentTime currentTime, + LocalTimeWrapper localTimeWrapper, DefaultTransferWindow transferWindow) { this.accountRepository = accountRepository; this.feePolicy = feePolicy; - this.currentTime = currentTime; + this.localTimeWrapper = localTimeWrapper; this.defaultTransferWindow = transferWindow; } @@ -56,7 +56,7 @@ public TransferReceipt transfer(double amount, String srcAcctId, String dstAcctI throw new IllegalArgumentException(format("transfer amount must be at least $%.2f", minimumTransferAmount)); } - LocalTime transactionTime = this.currentTime.getCurrentTime(); + LocalTime transactionTime = this.localTimeWrapper.getCurrentTime(); if(!defaultTransferWindow.isValidTimeForTransferMoney(transactionTime)) { throw new InvalidTransferWindow("We only allow to transfer between " + defaultTransferWindow.getOpen() + " and " + defaultTransferWindow.getClose()); } diff --git a/src/test/com/bank/service/internal/DefaultTransferServiceTests.java b/src/test/com/bank/service/internal/DefaultTransferServiceTests.java index 3d86b25..c1db243 100644 --- a/src/test/com/bank/service/internal/DefaultTransferServiceTests.java +++ b/src/test/com/bank/service/internal/DefaultTransferServiceTests.java @@ -5,7 +5,7 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; -import com.bank.domain.CurrentTime; +import com.bank.domain.LocalTimeWrapper; import com.bank.domain.DefaultTransferWindow; import org.junit.Before; import org.junit.Test; @@ -27,9 +27,9 @@ public class DefaultTransferServiceTests { public void setUp() { accountRepository = new SimpleAccountRepository(); FeePolicy feePolicy = new ZeroFeePolicy(); - CurrentTime currentTime = new CurrentTime(); + LocalTimeWrapper localTimeWrapper = new LocalTimeWrapper(); DefaultTransferWindow transferWindow = new DefaultTransferWindow("06:00:00", "22:00:00"); - transferService = new DefaultTransferService(accountRepository, feePolicy, currentTime, transferWindow); + transferService = new DefaultTransferService(accountRepository, feePolicy, localTimeWrapper, transferWindow); assertThat(accountRepository.findById(A123_ID).getBalance(), equalTo(A123_INITIAL_BAL)); assertThat(accountRepository.findById(C456_ID).getBalance(), equalTo(C456_INITIAL_BAL)); @@ -38,11 +38,11 @@ public void setUp() { @Test public void invalidTransferWindow() { double transferAmount = 100.00; - CurrentTime currentTime = new CurrentTime("23:00:00"); + LocalTimeWrapper localTimeWrapper = new LocalTimeWrapper("23:00:00"); DefaultTransferWindow transferWindow = new DefaultTransferWindow("06:00:00", "22:00:00"); accountRepository = new SimpleAccountRepository(); FeePolicy feePolicy = new ZeroFeePolicy(); - transferService = new DefaultTransferService(accountRepository, feePolicy, currentTime, transferWindow); + transferService = new DefaultTransferService(accountRepository, feePolicy, localTimeWrapper, transferWindow); try { transferService.transfer(transferAmount, A123_ID, C456_ID); @@ -152,9 +152,9 @@ public void testCustomizedMinimumTransferAmount() throws InsufficientFundsExcept public void testNonZeroFeePolicy() throws InsufficientFundsException, InvalidTransferWindow { double flatFee = 5.00; double transferAmount = 10.00; - CurrentTime currentTime = new CurrentTime(); + LocalTimeWrapper localTimeWrapper = new LocalTimeWrapper(); DefaultTransferWindow transferWindow = new DefaultTransferWindow("06:00:00", "22:00:00"); - transferService = new DefaultTransferService(accountRepository, new FlatFeePolicy(flatFee), currentTime, transferWindow); + transferService = new DefaultTransferService(accountRepository, new FlatFeePolicy(flatFee), localTimeWrapper, transferWindow); transferService.transfer(transferAmount, A123_ID, C456_ID); assertThat(accountRepository.findById(A123_ID).getBalance(), equalTo(A123_INITIAL_BAL - transferAmount - flatFee)); assertThat(accountRepository.findById(C456_ID).getBalance(), equalTo(C456_INITIAL_BAL + transferAmount)); diff --git a/src/test/com/bank/service/internal/DefaultTransferWindowTest.java b/src/test/com/bank/service/internal/DefaultTransferWindowTest.java index 162b3f6..eb389c4 100644 --- a/src/test/com/bank/service/internal/DefaultTransferWindowTest.java +++ b/src/test/com/bank/service/internal/DefaultTransferWindowTest.java @@ -1,6 +1,6 @@ package com.bank.service.internal; -import com.bank.domain.CurrentTime; +import com.bank.domain.LocalTimeWrapper; import com.bank.domain.DefaultTransferWindow; import org.junit.Assert; import org.junit.Test; @@ -8,17 +8,17 @@ public class DefaultTransferWindowTest { @Test public void withinValidTransferWindow() { - CurrentTime x = new CurrentTime(); - CurrentTime currentTime = new CurrentTime("12:05:59"); + LocalTimeWrapper x = new LocalTimeWrapper(); + LocalTimeWrapper localTimeWrapper = new LocalTimeWrapper("12:05:59"); DefaultTransferWindow transferWindow = new DefaultTransferWindow("10:00:00", "22:00:00"); - Assert.assertTrue(transferWindow.isValidTimeForTransferMoney(currentTime.getCurrentTime())); + Assert.assertTrue(transferWindow.isValidTimeForTransferMoney(localTimeWrapper.getCurrentTime())); } @Test public void withinInValidTransferWindow() { - CurrentTime currentTime = new CurrentTime("23:00:00"); + LocalTimeWrapper localTimeWrapper = new LocalTimeWrapper("23:00:00"); DefaultTransferWindow transferWindow = new DefaultTransferWindow("10:00:00", "22:00:00"); - Assert.assertFalse(transferWindow.isValidTimeForTransferMoney(currentTime.getCurrentTime())); + Assert.assertFalse(transferWindow.isValidTimeForTransferMoney(localTimeWrapper.getCurrentTime())); } } From 79be149411e537aa0ea2312574dddd1e09703ef3 Mon Sep 17 00:00:00 2001 From: Twin Panichsombat Date: Tue, 25 Jul 2017 16:23:51 +0900 Subject: [PATCH 15/23] Bring back config --- build.gradle | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/build.gradle b/build.gradle index 6745496..627471e 100644 --- a/build.gradle +++ b/build.gradle @@ -32,3 +32,14 @@ task wee(type: Wrapper) { gradleVersion = '2.10' //we want gradle 2.10 to run this project } +sourceSets { + main { + java { srcDir 'src/main' } + resources { srcDir 'src/main' } + } + test { + java { srcDir 'src/test' } + resources { srcDir 'src/test' } + } +} + From 8b67114afa8e120a7a023fc12dada3404f2d45de Mon Sep 17 00:00:00 2001 From: Twin Panichsombat Date: Tue, 25 Jul 2017 16:24:32 +0900 Subject: [PATCH 16/23] Create idea project --- tdd-using-spring.ipr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tdd-using-spring.ipr b/tdd-using-spring.ipr index 090d734..01c1f3a 100644 --- a/tdd-using-spring.ipr +++ b/tdd-using-spring.ipr @@ -13,7 +13,7 @@ - + @@ -51,7 +51,7 @@ - + From 74a1c2188048916baeda3f0485dbd51325d65647 Mon Sep 17 00:00:00 2001 From: Twin Panichsombat Date: Tue, 25 Jul 2017 16:24:55 +0900 Subject: [PATCH 17/23] Refactor transfer method --- .../internal/DefaultTransferService.java | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/main/com/bank/service/internal/DefaultTransferService.java b/src/main/com/bank/service/internal/DefaultTransferService.java index a31a0d6..f2f254f 100644 --- a/src/main/com/bank/service/internal/DefaultTransferService.java +++ b/src/main/com/bank/service/internal/DefaultTransferService.java @@ -51,18 +51,15 @@ public void setMinimumTransferAmount(double minimumTransferAmount) { @Override @Transactional - public TransferReceipt transfer(double amount, String srcAcctId, String dstAcctId) throws InsufficientFundsException, InvalidTransferWindow { - if (amount < minimumTransferAmount) { - throw new IllegalArgumentException(format("transfer amount must be at least $%.2f", minimumTransferAmount)); - } + public TransferReceipt transfer(double amount, String srcAcctId, String dstAcctId) + throws InsufficientFundsException, InvalidTransferWindow { LocalTime transactionTime = this.localTimeWrapper.getCurrentTime(); - if(!defaultTransferWindow.isValidTimeForTransferMoney(transactionTime)) { - throw new InvalidTransferWindow("We only allow to transfer between " + defaultTransferWindow.getOpen() + " and " + defaultTransferWindow.getClose()); - } + checkEligibility(amount, transactionTime); Account srcAcct = accountRepository.findById(srcAcctId); Account dstAcct = accountRepository.findById(dstAcctId); + double fee = feePolicy.calculateFee(amount); if (fee > 0) { srcAcct.debit(fee); @@ -73,6 +70,10 @@ public TransferReceipt transfer(double amount, String srcAcctId, String dstAcctI accountRepository.updateBalance(srcAcct); accountRepository.updateBalance(dstAcct); + return getTransferReceipt(amount, transactionTime, srcAcct, dstAcct, fee); + } + + private TransferReceipt getTransferReceipt(double amount, LocalTime transactionTime, Account srcAcct, Account dstAcct, double fee) { TransferReceipt receipt = new TransferReceipt(transactionTime); receipt.setInitialSourceAccount(srcAcct); receipt.setInitialDestinationAccount(dstAcct); @@ -80,7 +81,17 @@ public TransferReceipt transfer(double amount, String srcAcctId, String dstAcctI receipt.setFeeAmount(fee); receipt.setFinalSourceAccount(srcAcct); receipt.setFinalDestinationAccount(dstAcct); - return receipt; } + + private void checkEligibility(double amount, LocalTime transactionTime) throws InvalidTransferWindow { + if (amount < minimumTransferAmount) { + throw new IllegalArgumentException(format("transfer amount must be at least $%.2f", minimumTransferAmount)); + } + + + if(!defaultTransferWindow.isValidTimeForTransferMoney(transactionTime)) { + throw new InvalidTransferWindow("We only allow to transfer between " + defaultTransferWindow.getOpen() + " and " + defaultTransferWindow.getClose()); + } + } } From 9e6010d126c4f3f300389ab05bd36d6444e9e61b Mon Sep 17 00:00:00 2001 From: Twin Panichsombat Date: Wed, 26 Jul 2017 11:04:00 +0900 Subject: [PATCH 18/23] Add universal ignore --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index e2cf1c9..646c4bc 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,8 @@ .gradle build/ out/ +.DS_Store +src/.DS_Store +src/main/.DS_Store +src/main/java/ +src/test/.DS_Store From f05b90bb4d7967a30d750c09002a76874f247be2 Mon Sep 17 00:00:00 2001 From: Twin Panichsombat Date: Wed, 26 Jul 2017 11:04:54 +0900 Subject: [PATCH 19/23] Migrate gradle and start using spring boot --- build.gradle | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 627471e..40abef2 100644 --- a/build.gradle +++ b/build.gradle @@ -1,17 +1,35 @@ +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.3.RELEASE") + } +} + group = 'org.springframework.samples' version = '1.0.0.SNAPSHOT' apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'idea' -apply from: 'src/build/admin-tasks.gradle' +apply plugin: 'org.springframework.boot' +//apply from: 'src/build/admin-tasks.gradle' repositories { - //mavenRepo urls: 'http://maven.springframework.org/milestone' mavenCentral() } dependencies { + // tag::jetty[] + compile("org.springframework.boot:spring-boot-starter-web") { + exclude module: "spring-boot-starter-tomcat" + } + compile("org.springframework.boot:spring-boot-starter-jetty") + // end::jetty[] + // tag::actuator[] + compile("org.springframework.boot:spring-boot-starter-actuator") + // end::actuator[] compile group: 'org.springframework', name: 'spring-context', version: '3.1.0.RELEASE' compile group: 'org.springframework', name: 'spring-jdbc', version: '3.1.0.RELEASE' From 88e689609d2da914117e66ca0ae3522951cb36db Mon Sep 17 00:00:00 2001 From: Twin Panichsombat Date: Wed, 26 Jul 2017 11:15:14 +0900 Subject: [PATCH 20/23] Restructure in proper way --- src/main/com/bank/domain/Account.java | 65 ------------- .../bank/domain/DefaultTransferWindow.java | 23 ----- src/main/com/bank/domain/DepositReceipt.java | 65 ------------- .../domain/InsufficientFundsException.java | 52 ---------- .../domain/InvalidDepositAmountException.java | 42 -------- .../com/bank/domain/LocalTimeWrapper.java | 23 ----- src/main/com/bank/domain/TransferReceipt.java | 90 ----------------- .../repository/AccountNotFoundException.java | 24 ----- .../bank/repository/AccountRepository.java | 25 ----- .../internal/JdbcAccountRepository.java | 53 ---------- .../internal/SimpleAccountRepository.java | 62 ------------ src/main/com/bank/service/DepositService.java | 18 ---- src/main/com/bank/service/FeePolicy.java | 20 ---- .../com/bank/service/TransferService.java | 28 ------ .../internal/DefaultDepositService.java | 52 ---------- .../internal/DefaultTransferService.java | 97 ------------------- .../bank/service/internal/FlatFeePolicy.java | 31 ------ .../internal/InvalidTransferWindow.java | 6 -- .../service/internal/VariableFeePolicy.java | 40 -------- .../bank/service/internal/ZeroFeePolicy.java | 30 ------ .../bank/config => resources}/sql/schema.sql | 0 .../config => resources}/sql/test-data.sql | 0 .../xml/transfer-service-config.xml | 4 +- .../bank/integration}/IntegrationTests.java | 4 +- .../internal/DefaultDepositServiceTests.java | 0 .../internal/DefaultTransferServiceTests.java | 0 .../internal/DefaultTransferWindowTest.java | 0 .../internal/VariableFeePolicyTests.java | 0 28 files changed, 4 insertions(+), 850 deletions(-) delete mode 100644 src/main/com/bank/domain/Account.java delete mode 100644 src/main/com/bank/domain/DefaultTransferWindow.java delete mode 100644 src/main/com/bank/domain/DepositReceipt.java delete mode 100644 src/main/com/bank/domain/InsufficientFundsException.java delete mode 100644 src/main/com/bank/domain/InvalidDepositAmountException.java delete mode 100644 src/main/com/bank/domain/LocalTimeWrapper.java delete mode 100644 src/main/com/bank/domain/TransferReceipt.java delete mode 100644 src/main/com/bank/repository/AccountNotFoundException.java delete mode 100644 src/main/com/bank/repository/AccountRepository.java delete mode 100644 src/main/com/bank/repository/internal/JdbcAccountRepository.java delete mode 100644 src/main/com/bank/repository/internal/SimpleAccountRepository.java delete mode 100644 src/main/com/bank/service/DepositService.java delete mode 100644 src/main/com/bank/service/FeePolicy.java delete mode 100644 src/main/com/bank/service/TransferService.java delete mode 100644 src/main/com/bank/service/internal/DefaultDepositService.java delete mode 100644 src/main/com/bank/service/internal/DefaultTransferService.java delete mode 100644 src/main/com/bank/service/internal/FlatFeePolicy.java delete mode 100644 src/main/com/bank/service/internal/InvalidTransferWindow.java delete mode 100644 src/main/com/bank/service/internal/VariableFeePolicy.java delete mode 100644 src/main/com/bank/service/internal/ZeroFeePolicy.java rename src/main/{com/bank/config => resources}/sql/schema.sql (100%) rename src/main/{com/bank/config => resources}/sql/test-data.sql (100%) rename src/main/{com/bank/config => resources}/xml/transfer-service-config.xml (91%) rename src/test/{com/bank/config/xml => java/com/bank/integration}/IntegrationTests.java (94%) rename src/test/{ => java}/com/bank/service/internal/DefaultDepositServiceTests.java (100%) rename src/test/{ => java}/com/bank/service/internal/DefaultTransferServiceTests.java (100%) rename src/test/{ => java}/com/bank/service/internal/DefaultTransferWindowTest.java (100%) rename src/test/{ => java}/com/bank/service/internal/VariableFeePolicyTests.java (100%) diff --git a/src/main/com/bank/domain/Account.java b/src/main/com/bank/domain/Account.java deleted file mode 100644 index bc95f75..0000000 --- a/src/main/com/bank/domain/Account.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.bank.domain; - -public class Account { - - private final String id; - private double balance; - - public Account(String id, double initialBalance) { - this.id = id; - this.balance = initialBalance; - } - - public void debit(double amount) throws InsufficientFundsException { - assertValid(amount); - - if (amount > balance) - throw new InsufficientFundsException(this, amount); - - balance -= amount; - } - - public void credit(double amount) { - assertValid(amount); - - balance += amount; - } - - public String getId() { - return id; - } - - public double getBalance() { - return balance; - } - - public void setBalance(double balance) { - this.balance = balance; - } - - private void assertValid(double amount) { - if (!(amount > 0.00)) - throw new IllegalArgumentException("amount must be greater than zero"); - } - - public static Account copy(Account account) { - return new Account(account.getId(), account.getBalance()); - } - -} diff --git a/src/main/com/bank/domain/DefaultTransferWindow.java b/src/main/com/bank/domain/DefaultTransferWindow.java deleted file mode 100644 index 932b3e7..0000000 --- a/src/main/com/bank/domain/DefaultTransferWindow.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.bank.domain; - -import java.time.LocalTime; - -public class DefaultTransferWindow { - private LocalTime open; - private LocalTime close; - public DefaultTransferWindow(String open, String close) { - this.open = LocalTime.parse(open); - this.close = LocalTime.parse(close); - } - - public boolean isValidTimeForTransferMoney(LocalTime transactionTime) { - return (transactionTime.isAfter(open))&&(transactionTime.isBefore(close)); - } - - public LocalTime getOpen() { - return this.open; - } - public LocalTime getClose() { - return this.close; - } -} diff --git a/src/main/com/bank/domain/DepositReceipt.java b/src/main/com/bank/domain/DepositReceipt.java deleted file mode 100644 index 43f63ab..0000000 --- a/src/main/com/bank/domain/DepositReceipt.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ - -package com.bank.domain; - -/** - * - * @author TwinP - */ -public class DepositReceipt { - private double depositAmount; - private Account initialDestinationAccountCopy; - private Account finalDestinationAccountCopy; - - /** - * @return the depositAmount - */ - public double getDepositAmount() { - return depositAmount; - } - - /** - * @param depositAmount the depositAmount to set - */ - public void setDepositAmount(double depositAmount) { - this.depositAmount = depositAmount; - } - - /** - * @return the initialDestinationAccountCopy - */ - public Account getInitialDestinationAccountCopy() { - return initialDestinationAccountCopy; - } - - /** - * @param initialDestinationAccountCopy the initialDestinationAccountCopy to set - */ - public void setInitialDestinationAccountCopy(Account initialDestinationAccountCopy) { - this.initialDestinationAccountCopy = initialDestinationAccountCopy; - } - - /** - * @return the finalDestinationAccountCopy - */ - public Account getFinalDestinationAccountCopy() { - return finalDestinationAccountCopy; - } - - /** - * @param finalDestinationAccountCopy the finalDestinationAccountCopy to set - */ - public void setFinalDestinationAccountCopy(Account finalDestinationAccountCopy) { - this.finalDestinationAccountCopy = finalDestinationAccountCopy; - } - - @Override - public String toString() { - return "DepositReceipt{" + "depositAmount=" + depositAmount + "initialDestinationAccountCopy=" + initialDestinationAccountCopy + "finalDestinationAccountCopy=" + finalDestinationAccountCopy + '}'; - } - - -} diff --git a/src/main/com/bank/domain/InsufficientFundsException.java b/src/main/com/bank/domain/InsufficientFundsException.java deleted file mode 100644 index 9030979..0000000 --- a/src/main/com/bank/domain/InsufficientFundsException.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.bank.domain; - -import static java.lang.String.format; - -@SuppressWarnings("serial") -public class InsufficientFundsException extends Exception { - - private final Account targetAccount; - private final double attemptedAmount; - - public InsufficientFundsException(Account targetAccount, double attemptedAmount) { - this.targetAccount = Account.copy(targetAccount); - this.attemptedAmount = attemptedAmount; - } - - public String getTargetAccountId() { - return targetAccount.getId(); - } - - public double getTargetAccountBalance() { - return targetAccount.getBalance(); - } - - public double getAttemptedAmount() { - return attemptedAmount; - } - - public double getOverage() { - return getAttemptedAmount() - getTargetAccountBalance(); - } - - public String toString() { - StringBuilder sb = new StringBuilder().append(format("Failed to transfer $%.2f from account %s. " - + "Reason: insufficient funds\n", getAttemptedAmount(), getTargetAccountId())).append(format("\tcurrent balance for target account is $%.2f\n", getTargetAccountBalance())).append(format("\ttransfer overage is $%.2f\n", getOverage())); - return sb.toString(); - } -} diff --git a/src/main/com/bank/domain/InvalidDepositAmountException.java b/src/main/com/bank/domain/InvalidDepositAmountException.java deleted file mode 100644 index c0c9579..0000000 --- a/src/main/com/bank/domain/InvalidDepositAmountException.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ - -package com.bank.domain; - -/** - * - * @author TwinP - */ -@SuppressWarnings("serial") -public class InvalidDepositAmountException extends Exception { - private double attemptedAmount; - /** - * Creates a new instance of InvalidDepositAmountException without detail message. - */ - public InvalidDepositAmountException(double attemptedAmount) { - this.attemptedAmount = attemptedAmount; - } - - /** - * @return the attemptedAmount - */ - public double getAttemptedAmount() { - return attemptedAmount; - } - - /** - * @param attemptedAmount the attemptedAmount to set - */ - public void setAttemptedAmount(double attemptedAmount) { - this.attemptedAmount = attemptedAmount; - } - - @Override - public String toString() { - return "InvalidDepositAmountException{" + "attemptedAmount=" + attemptedAmount + '}'; - } - - -} diff --git a/src/main/com/bank/domain/LocalTimeWrapper.java b/src/main/com/bank/domain/LocalTimeWrapper.java deleted file mode 100644 index 3758081..0000000 --- a/src/main/com/bank/domain/LocalTimeWrapper.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.bank.domain; - -import org.omg.CORBA.Current; - -import java.time.LocalTime; - -public class LocalTimeWrapper { - - private String specificTime = null; - public LocalTimeWrapper(String initial){ - this.specificTime = initial; - } - - public LocalTimeWrapper() { - - } - - public LocalTime getCurrentTime() { - if(this.specificTime != null) - return LocalTime.parse(this.specificTime); - return LocalTime.now(); - } -} diff --git a/src/main/com/bank/domain/TransferReceipt.java b/src/main/com/bank/domain/TransferReceipt.java deleted file mode 100644 index bb1d6bc..0000000 --- a/src/main/com/bank/domain/TransferReceipt.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.bank.domain; - -import java.time.LocalTime; - -import static java.lang.String.format; - -public class TransferReceipt { - - private double transferAmount; - private double feeAmount; - private Account initialSourceAccountCopy; - private Account initialDestinationAccountCopy; - private Account finalSourceAccountCopy; - private Account finalDestinationAccountCopy; - private LocalTime transactionTime; - - - public TransferReceipt(LocalTime transactionTime) { - this.transactionTime = transactionTime; - } - - public void setTransferAmount(double transferAmount) { - this.transferAmount = transferAmount; - } - - public double getTransferAmount() { - return transferAmount; - } - - public void setFeeAmount(double feeAmount) { - this.feeAmount = feeAmount; - } - - public double getFeeAmount() { - return feeAmount; - } - - public void setInitialSourceAccount(Account account) { - initialSourceAccountCopy = Account.copy(account); - } - - public void setFinalSourceAccount(Account account) { - finalSourceAccountCopy = Account.copy(account); - } - - public Account getFinalSourceAccount() { - return finalSourceAccountCopy; - } - - public void setInitialDestinationAccount(Account account) { - initialDestinationAccountCopy = Account.copy(account); - } - - public void setFinalDestinationAccount(Account account) { - finalDestinationAccountCopy = Account.copy(account); - } - - public Account getFinalDestinationAccount() { - return finalDestinationAccountCopy; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder().append(format("Transferred %.2f from account %s to %s, with fee amount: %.2f\n", - transferAmount, initialSourceAccountCopy.getId(), - initialDestinationAccountCopy.getId(), feeAmount)).append(format("\tinitial balance for account %s: %.2f; new balance: %.2f\n", - initialSourceAccountCopy.getId(), - initialSourceAccountCopy.getBalance(), - finalSourceAccountCopy.getBalance())).append(format("\tinitial balance for account %s: %.2f; new balance: %.2f\n", - initialDestinationAccountCopy.getId(), - initialDestinationAccountCopy.getBalance(), - finalDestinationAccountCopy.getBalance())); - return sb.toString(); - } -} diff --git a/src/main/com/bank/repository/AccountNotFoundException.java b/src/main/com/bank/repository/AccountNotFoundException.java deleted file mode 100644 index 1db00ff..0000000 --- a/src/main/com/bank/repository/AccountNotFoundException.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.bank.repository; - -@SuppressWarnings("serial") -public class AccountNotFoundException extends RuntimeException { - - public AccountNotFoundException(String acctId) { - super(String.format("account with id [%s] could not be found", acctId)); - } -} diff --git a/src/main/com/bank/repository/AccountRepository.java b/src/main/com/bank/repository/AccountRepository.java deleted file mode 100644 index d4c6954..0000000 --- a/src/main/com/bank/repository/AccountRepository.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.bank.repository; - -import com.bank.domain.Account; - -public interface AccountRepository { - - Account findById(String srcAcctId); - - void updateBalance(Account dstAcct); -} diff --git a/src/main/com/bank/repository/internal/JdbcAccountRepository.java b/src/main/com/bank/repository/internal/JdbcAccountRepository.java deleted file mode 100644 index 0600119..0000000 --- a/src/main/com/bank/repository/internal/JdbcAccountRepository.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.bank.repository.internal; - -import java.sql.ResultSet; -import java.sql.SQLException; - -import javax.sql.DataSource; - -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.RowMapper; - -import com.bank.domain.Account; -import com.bank.repository.AccountRepository; - -public class JdbcAccountRepository implements AccountRepository { - - private final JdbcTemplate jdbcTemplate; - - public JdbcAccountRepository(DataSource dataSource) { - jdbcTemplate = new JdbcTemplate(dataSource); - } - - @Override - public Account findById(String srcAcctId) { - return jdbcTemplate.queryForObject("select id, balance from account where id = ?", new AccountRowMapper(), srcAcctId); - } - - @Override - public void updateBalance(Account dstAcct) { - jdbcTemplate.update("update account set balance = ? where id = ?", dstAcct.getBalance(), dstAcct.getId()); - } - - private static class AccountRowMapper implements RowMapper { - @Override - public Account mapRow(ResultSet rs, int rowNum) throws SQLException { - return new Account(rs.getString("id"), rs.getDouble("balance")); - } - } -} diff --git a/src/main/com/bank/repository/internal/SimpleAccountRepository.java b/src/main/com/bank/repository/internal/SimpleAccountRepository.java deleted file mode 100644 index c1854e5..0000000 --- a/src/main/com/bank/repository/internal/SimpleAccountRepository.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.bank.repository.internal; - -import java.util.HashMap; -import java.util.Map; - -import com.bank.domain.Account; -import com.bank.repository.AccountNotFoundException; -import com.bank.repository.AccountRepository; - -public class SimpleAccountRepository implements AccountRepository { - - public static class Data { - - public static final String A123_ID = "A123"; - public static final String C456_ID = "C456"; - public static final String Z999_ID = "Z999"; // NON EXISTENT ID - public static final double A123_INITIAL_BAL = 100.00; - public static final double C456_INITIAL_BAL = 0.00; - } - @SuppressWarnings("serial") - private final Map accountsById = new HashMap() { - - { - put(Data.A123_ID, new Account(Data.A123_ID, Data.A123_INITIAL_BAL)); - put(Data.C456_ID, new Account(Data.C456_ID, Data.C456_INITIAL_BAL)); - } - }; - - @Override - public Account findById(String acctId) { - return Account.copy(nullSafeAccountLookup(acctId)); - } - - @Override - public void updateBalance(Account account) { - Account actualAccount = nullSafeAccountLookup(account.getId()); - actualAccount.setBalance(account.getBalance()); - } - - private Account nullSafeAccountLookup(String acctId) { - Account account = accountsById.get(acctId); - if (account == null) { - throw new AccountNotFoundException(acctId); - } - return account; - } -} diff --git a/src/main/com/bank/service/DepositService.java b/src/main/com/bank/service/DepositService.java deleted file mode 100644 index 557a8f8..0000000 --- a/src/main/com/bank/service/DepositService.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ - -package com.bank.service; - -import com.bank.domain.DepositReceipt; -import com.bank.domain.InvalidDepositAmountException; - -/** - * - * @author TwinP - */ -public interface DepositService { - void setMinimumDepositAmount(double minimumDepositAmount); - public DepositReceipt deposit(double amount, String destrinationAcc) throws InvalidDepositAmountException; -} diff --git a/src/main/com/bank/service/FeePolicy.java b/src/main/com/bank/service/FeePolicy.java deleted file mode 100644 index c2d9897..0000000 --- a/src/main/com/bank/service/FeePolicy.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.bank.service; - -public interface FeePolicy { - public double calculateFee(double transferAmount); -} diff --git a/src/main/com/bank/service/TransferService.java b/src/main/com/bank/service/TransferService.java deleted file mode 100644 index 05d5a1b..0000000 --- a/src/main/com/bank/service/TransferService.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.bank.service; - -import com.bank.domain.InsufficientFundsException; -import com.bank.domain.TransferReceipt; -import com.bank.service.internal.InvalidTransferWindow; - -public interface TransferService { - - TransferReceipt transfer(double amount, String srcAcctId, String destAcctId) - throws InsufficientFundsException, InvalidTransferWindow; - - void setMinimumTransferAmount(double minimumTransferAmount); -} diff --git a/src/main/com/bank/service/internal/DefaultDepositService.java b/src/main/com/bank/service/internal/DefaultDepositService.java deleted file mode 100644 index c3343b9..0000000 --- a/src/main/com/bank/service/internal/DefaultDepositService.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package com.bank.service.internal; -import static java.lang.String.format; - -import com.bank.domain.Account; -import com.bank.domain.DepositReceipt; -import com.bank.domain.InvalidDepositAmountException; -import com.bank.repository.AccountRepository; -import com.bank.service.DepositService; -import com.bank.service.FeePolicy; - -/** - * - * @author TwinP - */ -public class DefaultDepositService implements DepositService { - - private final AccountRepository accountRepository; - private final FeePolicy feePolicy; - private double minimumDepositAmount = 1.00; - - public DefaultDepositService(AccountRepository accountRepository, FeePolicy feePolicy) { - this.accountRepository = accountRepository; - this.feePolicy = feePolicy; - } - - @Override - public void setMinimumDepositAmount(double minimumDepositAmount) { - this.minimumDepositAmount = minimumDepositAmount; - } - - @Override - public DepositReceipt deposit(double amount, String destrinationAccountNumber) throws InvalidDepositAmountException { - if (amount <= this.minimumDepositAmount) { - throw new InvalidDepositAmountException(amount); - } - DepositReceipt depositReceipt = new DepositReceipt(); - Account destrinationAccount = accountRepository.findById(destrinationAccountNumber); - - depositReceipt.setDepositAmount(amount); - depositReceipt.setInitialDestinationAccountCopy(destrinationAccount); - - destrinationAccount.credit(amount); - accountRepository.updateBalance(destrinationAccount); - - depositReceipt.setFinalDestinationAccountCopy(destrinationAccount); - return depositReceipt; - } -} diff --git a/src/main/com/bank/service/internal/DefaultTransferService.java b/src/main/com/bank/service/internal/DefaultTransferService.java deleted file mode 100644 index f2f254f..0000000 --- a/src/main/com/bank/service/internal/DefaultTransferService.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.bank.service.internal; - -import static java.lang.String.format; - -import com.bank.domain.*; -import org.springframework.transaction.annotation.Transactional; - -import com.bank.repository.AccountRepository; -import com.bank.service.FeePolicy; -import com.bank.service.TransferService; - -import java.time.LocalTime; - -public class DefaultTransferService implements TransferService { - - private final AccountRepository accountRepository; - private final FeePolicy feePolicy; - private double minimumTransferAmount = 1.00; - private LocalTimeWrapper localTimeWrapper; - private DefaultTransferWindow defaultTransferWindow; - - public DefaultTransferService(AccountRepository accountRepository, - FeePolicy feePolicy, - LocalTimeWrapper localTimeWrapper, - DefaultTransferWindow transferWindow) { - this.accountRepository = accountRepository; - this.feePolicy = feePolicy; - this.localTimeWrapper = localTimeWrapper; - this.defaultTransferWindow = transferWindow; - } - - @Override - public void setMinimumTransferAmount(double minimumTransferAmount) { - this.minimumTransferAmount = minimumTransferAmount; - } - - @Override - @Transactional - public TransferReceipt transfer(double amount, String srcAcctId, String dstAcctId) - throws InsufficientFundsException, InvalidTransferWindow { - - LocalTime transactionTime = this.localTimeWrapper.getCurrentTime(); - checkEligibility(amount, transactionTime); - - Account srcAcct = accountRepository.findById(srcAcctId); - Account dstAcct = accountRepository.findById(dstAcctId); - - double fee = feePolicy.calculateFee(amount); - if (fee > 0) { - srcAcct.debit(fee); - } - srcAcct.debit(amount); - dstAcct.credit(amount); - - accountRepository.updateBalance(srcAcct); - accountRepository.updateBalance(dstAcct); - - return getTransferReceipt(amount, transactionTime, srcAcct, dstAcct, fee); - } - - private TransferReceipt getTransferReceipt(double amount, LocalTime transactionTime, Account srcAcct, Account dstAcct, double fee) { - TransferReceipt receipt = new TransferReceipt(transactionTime); - receipt.setInitialSourceAccount(srcAcct); - receipt.setInitialDestinationAccount(dstAcct); - receipt.setTransferAmount(amount); - receipt.setFeeAmount(fee); - receipt.setFinalSourceAccount(srcAcct); - receipt.setFinalDestinationAccount(dstAcct); - return receipt; - } - - private void checkEligibility(double amount, LocalTime transactionTime) throws InvalidTransferWindow { - if (amount < minimumTransferAmount) { - throw new IllegalArgumentException(format("transfer amount must be at least $%.2f", minimumTransferAmount)); - } - - - if(!defaultTransferWindow.isValidTimeForTransferMoney(transactionTime)) { - throw new InvalidTransferWindow("We only allow to transfer between " + defaultTransferWindow.getOpen() + " and " + defaultTransferWindow.getClose()); - } - } -} diff --git a/src/main/com/bank/service/internal/FlatFeePolicy.java b/src/main/com/bank/service/internal/FlatFeePolicy.java deleted file mode 100644 index 85dab5b..0000000 --- a/src/main/com/bank/service/internal/FlatFeePolicy.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.bank.service.internal; - -import com.bank.service.FeePolicy; - -public class FlatFeePolicy implements FeePolicy { - - private final double flatFee; - - public FlatFeePolicy(double flatFee) { - this.flatFee = flatFee; - } - - public double calculateFee(double transferAmount) { - return flatFee; - } -} diff --git a/src/main/com/bank/service/internal/InvalidTransferWindow.java b/src/main/com/bank/service/internal/InvalidTransferWindow.java deleted file mode 100644 index 8bd8da6..0000000 --- a/src/main/com/bank/service/internal/InvalidTransferWindow.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.bank.service.internal; - -public class InvalidTransferWindow extends Throwable { - public InvalidTransferWindow(String s) { - } -} diff --git a/src/main/com/bank/service/internal/VariableFeePolicy.java b/src/main/com/bank/service/internal/VariableFeePolicy.java deleted file mode 100644 index 329eff5..0000000 --- a/src/main/com/bank/service/internal/VariableFeePolicy.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.bank.service.internal; - -import com.bank.service.FeePolicy; - -public class VariableFeePolicy implements FeePolicy { - - private double feePercentage; - private double minimumFee; - - public void setMinimumFee(double minimumFee) { - this.minimumFee = minimumFee; - } - - public void setFeePercentage(double feePercentage) { - this.feePercentage = feePercentage; - } - - @Override - public double calculateFee(double transferAmount) { - double variableFee = transferAmount * (feePercentage/100); - return variableFee > minimumFee ? variableFee : minimumFee; - } - -} diff --git a/src/main/com/bank/service/internal/ZeroFeePolicy.java b/src/main/com/bank/service/internal/ZeroFeePolicy.java deleted file mode 100644 index 0323b87..0000000 --- a/src/main/com/bank/service/internal/ZeroFeePolicy.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.bank.service.internal; - -import com.bank.service.FeePolicy; - -public class ZeroFeePolicy implements FeePolicy { - - private static final double ZERO_AMOUNT = 0.00d; - - @Override - public double calculateFee(double transferAmount) { - return ZERO_AMOUNT; - } - -} diff --git a/src/main/com/bank/config/sql/schema.sql b/src/main/resources/sql/schema.sql similarity index 100% rename from src/main/com/bank/config/sql/schema.sql rename to src/main/resources/sql/schema.sql diff --git a/src/main/com/bank/config/sql/test-data.sql b/src/main/resources/sql/test-data.sql similarity index 100% rename from src/main/com/bank/config/sql/test-data.sql rename to src/main/resources/sql/test-data.sql diff --git a/src/main/com/bank/config/xml/transfer-service-config.xml b/src/main/resources/xml/transfer-service-config.xml similarity index 91% rename from src/main/com/bank/config/xml/transfer-service-config.xml rename to src/main/resources/xml/transfer-service-config.xml index 33b123a..b5a49b5 100644 --- a/src/main/com/bank/config/xml/transfer-service-config.xml +++ b/src/main/resources/xml/transfer-service-config.xml @@ -29,8 +29,8 @@ - - + + diff --git a/src/test/com/bank/config/xml/IntegrationTests.java b/src/test/java/com/bank/integration/IntegrationTests.java similarity index 94% rename from src/test/com/bank/config/xml/IntegrationTests.java rename to src/test/java/com/bank/integration/IntegrationTests.java index 0183b26..9d556f8 100644 --- a/src/test/com/bank/config/xml/IntegrationTests.java +++ b/src/test/java/com/bank/integration/IntegrationTests.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.bank.config.xml; +package com.bank.integration; import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertThat; @@ -32,7 +32,7 @@ public class IntegrationTests { public void transferTenDollars() throws InsufficientFundsException, InvalidTransferWindow { GenericXmlApplicationContext ctx = new GenericXmlApplicationContext(); ctx.getEnvironment().setActiveProfiles("dev"); - ctx.load("classpath:/com/bank/config/xml/transfer-service-config.xml"); + ctx.load("classpath:/xml/transfer-service-config.xml"); ctx.refresh(); TransferService transferService = ctx.getBean(TransferService.class); diff --git a/src/test/com/bank/service/internal/DefaultDepositServiceTests.java b/src/test/java/com/bank/service/internal/DefaultDepositServiceTests.java similarity index 100% rename from src/test/com/bank/service/internal/DefaultDepositServiceTests.java rename to src/test/java/com/bank/service/internal/DefaultDepositServiceTests.java diff --git a/src/test/com/bank/service/internal/DefaultTransferServiceTests.java b/src/test/java/com/bank/service/internal/DefaultTransferServiceTests.java similarity index 100% rename from src/test/com/bank/service/internal/DefaultTransferServiceTests.java rename to src/test/java/com/bank/service/internal/DefaultTransferServiceTests.java diff --git a/src/test/com/bank/service/internal/DefaultTransferWindowTest.java b/src/test/java/com/bank/service/internal/DefaultTransferWindowTest.java similarity index 100% rename from src/test/com/bank/service/internal/DefaultTransferWindowTest.java rename to src/test/java/com/bank/service/internal/DefaultTransferWindowTest.java diff --git a/src/test/com/bank/service/internal/VariableFeePolicyTests.java b/src/test/java/com/bank/service/internal/VariableFeePolicyTests.java similarity index 100% rename from src/test/com/bank/service/internal/VariableFeePolicyTests.java rename to src/test/java/com/bank/service/internal/VariableFeePolicyTests.java From bc1200c381a440ca6a566977a1a9f582cb158e26 Mon Sep 17 00:00:00 2001 From: Twin Panichsombat Date: Wed, 26 Jul 2017 11:24:13 +0900 Subject: [PATCH 21/23] Bring source back --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 646c4bc..5679128 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,4 @@ out/ .DS_Store src/.DS_Store src/main/.DS_Store -src/main/java/ src/test/.DS_Store From 704db0fed54cacf7fb18624aeebdd4ea3fcc5f04 Mon Sep 17 00:00:00 2001 From: Twin Panichsombat Date: Wed, 26 Jul 2017 11:24:31 +0900 Subject: [PATCH 22/23] Srcgit add .git add . --- src/main/java/com/bank/Application.java | 33 +++++++ .../bank/controller/TransferController.java | 14 +++ src/main/java/com/bank/domain/Account.java | 65 +++++++++++++ .../bank/domain/DefaultTransferWindow.java | 23 +++++ .../java/com/bank/domain/DepositReceipt.java | 65 +++++++++++++ .../domain/InsufficientFundsException.java | 52 ++++++++++ .../domain/InvalidDepositAmountException.java | 42 ++++++++ .../com/bank/domain/LocalTimeWrapper.java | 23 +++++ .../java/com/bank/domain/TransferReceipt.java | 90 +++++++++++++++++ .../repository/AccountNotFoundException.java | 24 +++++ .../bank/repository/AccountRepository.java | 25 +++++ .../internal/JdbcAccountRepository.java | 53 ++++++++++ .../internal/SimpleAccountRepository.java | 62 ++++++++++++ .../java/com/bank/service/DepositService.java | 18 ++++ src/main/java/com/bank/service/FeePolicy.java | 20 ++++ .../com/bank/service/TransferService.java | 28 ++++++ .../internal/DefaultDepositService.java | 52 ++++++++++ .../internal/DefaultTransferService.java | 97 +++++++++++++++++++ .../bank/service/internal/FlatFeePolicy.java | 31 ++++++ .../internal/InvalidTransferWindow.java | 6 ++ .../service/internal/VariableFeePolicy.java | 40 ++++++++ .../bank/service/internal/ZeroFeePolicy.java | 30 ++++++ 22 files changed, 893 insertions(+) create mode 100644 src/main/java/com/bank/Application.java create mode 100644 src/main/java/com/bank/controller/TransferController.java create mode 100644 src/main/java/com/bank/domain/Account.java create mode 100644 src/main/java/com/bank/domain/DefaultTransferWindow.java create mode 100644 src/main/java/com/bank/domain/DepositReceipt.java create mode 100644 src/main/java/com/bank/domain/InsufficientFundsException.java create mode 100644 src/main/java/com/bank/domain/InvalidDepositAmountException.java create mode 100644 src/main/java/com/bank/domain/LocalTimeWrapper.java create mode 100644 src/main/java/com/bank/domain/TransferReceipt.java create mode 100644 src/main/java/com/bank/repository/AccountNotFoundException.java create mode 100644 src/main/java/com/bank/repository/AccountRepository.java create mode 100644 src/main/java/com/bank/repository/internal/JdbcAccountRepository.java create mode 100644 src/main/java/com/bank/repository/internal/SimpleAccountRepository.java create mode 100644 src/main/java/com/bank/service/DepositService.java create mode 100644 src/main/java/com/bank/service/FeePolicy.java create mode 100644 src/main/java/com/bank/service/TransferService.java create mode 100644 src/main/java/com/bank/service/internal/DefaultDepositService.java create mode 100644 src/main/java/com/bank/service/internal/DefaultTransferService.java create mode 100644 src/main/java/com/bank/service/internal/FlatFeePolicy.java create mode 100644 src/main/java/com/bank/service/internal/InvalidTransferWindow.java create mode 100644 src/main/java/com/bank/service/internal/VariableFeePolicy.java create mode 100644 src/main/java/com/bank/service/internal/ZeroFeePolicy.java diff --git a/src/main/java/com/bank/Application.java b/src/main/java/com/bank/Application.java new file mode 100644 index 0000000..02a4429 --- /dev/null +++ b/src/main/java/com/bank/Application.java @@ -0,0 +1,33 @@ +package com.bank; + +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; + +import java.util.Arrays; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + + @Bean + public CommandLineRunner commandLineRunner(ApplicationContext ctx) { + return args -> { + + System.out.println("Let's inspect the beans provided by Spring Boot:"); + + String[] beanNames = ctx.getBeanDefinitionNames(); + Arrays.sort(beanNames); + for (String beanName : beanNames) { + System.out.println(beanName); + } + + }; + } + +} \ No newline at end of file diff --git a/src/main/java/com/bank/controller/TransferController.java b/src/main/java/com/bank/controller/TransferController.java new file mode 100644 index 0000000..65f675f --- /dev/null +++ b/src/main/java/com/bank/controller/TransferController.java @@ -0,0 +1,14 @@ +package com.bank.controller; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class TransferController { + + @RequestMapping("/") + public String index() { + return "Greetings from Spring Boot!"; + } + +} \ No newline at end of file diff --git a/src/main/java/com/bank/domain/Account.java b/src/main/java/com/bank/domain/Account.java new file mode 100644 index 0000000..bc95f75 --- /dev/null +++ b/src/main/java/com/bank/domain/Account.java @@ -0,0 +1,65 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.bank.domain; + +public class Account { + + private final String id; + private double balance; + + public Account(String id, double initialBalance) { + this.id = id; + this.balance = initialBalance; + } + + public void debit(double amount) throws InsufficientFundsException { + assertValid(amount); + + if (amount > balance) + throw new InsufficientFundsException(this, amount); + + balance -= amount; + } + + public void credit(double amount) { + assertValid(amount); + + balance += amount; + } + + public String getId() { + return id; + } + + public double getBalance() { + return balance; + } + + public void setBalance(double balance) { + this.balance = balance; + } + + private void assertValid(double amount) { + if (!(amount > 0.00)) + throw new IllegalArgumentException("amount must be greater than zero"); + } + + public static Account copy(Account account) { + return new Account(account.getId(), account.getBalance()); + } + +} diff --git a/src/main/java/com/bank/domain/DefaultTransferWindow.java b/src/main/java/com/bank/domain/DefaultTransferWindow.java new file mode 100644 index 0000000..932b3e7 --- /dev/null +++ b/src/main/java/com/bank/domain/DefaultTransferWindow.java @@ -0,0 +1,23 @@ +package com.bank.domain; + +import java.time.LocalTime; + +public class DefaultTransferWindow { + private LocalTime open; + private LocalTime close; + public DefaultTransferWindow(String open, String close) { + this.open = LocalTime.parse(open); + this.close = LocalTime.parse(close); + } + + public boolean isValidTimeForTransferMoney(LocalTime transactionTime) { + return (transactionTime.isAfter(open))&&(transactionTime.isBefore(close)); + } + + public LocalTime getOpen() { + return this.open; + } + public LocalTime getClose() { + return this.close; + } +} diff --git a/src/main/java/com/bank/domain/DepositReceipt.java b/src/main/java/com/bank/domain/DepositReceipt.java new file mode 100644 index 0000000..43f63ab --- /dev/null +++ b/src/main/java/com/bank/domain/DepositReceipt.java @@ -0,0 +1,65 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package com.bank.domain; + +/** + * + * @author TwinP + */ +public class DepositReceipt { + private double depositAmount; + private Account initialDestinationAccountCopy; + private Account finalDestinationAccountCopy; + + /** + * @return the depositAmount + */ + public double getDepositAmount() { + return depositAmount; + } + + /** + * @param depositAmount the depositAmount to set + */ + public void setDepositAmount(double depositAmount) { + this.depositAmount = depositAmount; + } + + /** + * @return the initialDestinationAccountCopy + */ + public Account getInitialDestinationAccountCopy() { + return initialDestinationAccountCopy; + } + + /** + * @param initialDestinationAccountCopy the initialDestinationAccountCopy to set + */ + public void setInitialDestinationAccountCopy(Account initialDestinationAccountCopy) { + this.initialDestinationAccountCopy = initialDestinationAccountCopy; + } + + /** + * @return the finalDestinationAccountCopy + */ + public Account getFinalDestinationAccountCopy() { + return finalDestinationAccountCopy; + } + + /** + * @param finalDestinationAccountCopy the finalDestinationAccountCopy to set + */ + public void setFinalDestinationAccountCopy(Account finalDestinationAccountCopy) { + this.finalDestinationAccountCopy = finalDestinationAccountCopy; + } + + @Override + public String toString() { + return "DepositReceipt{" + "depositAmount=" + depositAmount + "initialDestinationAccountCopy=" + initialDestinationAccountCopy + "finalDestinationAccountCopy=" + finalDestinationAccountCopy + '}'; + } + + +} diff --git a/src/main/java/com/bank/domain/InsufficientFundsException.java b/src/main/java/com/bank/domain/InsufficientFundsException.java new file mode 100644 index 0000000..9030979 --- /dev/null +++ b/src/main/java/com/bank/domain/InsufficientFundsException.java @@ -0,0 +1,52 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bank.domain; + +import static java.lang.String.format; + +@SuppressWarnings("serial") +public class InsufficientFundsException extends Exception { + + private final Account targetAccount; + private final double attemptedAmount; + + public InsufficientFundsException(Account targetAccount, double attemptedAmount) { + this.targetAccount = Account.copy(targetAccount); + this.attemptedAmount = attemptedAmount; + } + + public String getTargetAccountId() { + return targetAccount.getId(); + } + + public double getTargetAccountBalance() { + return targetAccount.getBalance(); + } + + public double getAttemptedAmount() { + return attemptedAmount; + } + + public double getOverage() { + return getAttemptedAmount() - getTargetAccountBalance(); + } + + public String toString() { + StringBuilder sb = new StringBuilder().append(format("Failed to transfer $%.2f from account %s. " + + "Reason: insufficient funds\n", getAttemptedAmount(), getTargetAccountId())).append(format("\tcurrent balance for target account is $%.2f\n", getTargetAccountBalance())).append(format("\ttransfer overage is $%.2f\n", getOverage())); + return sb.toString(); + } +} diff --git a/src/main/java/com/bank/domain/InvalidDepositAmountException.java b/src/main/java/com/bank/domain/InvalidDepositAmountException.java new file mode 100644 index 0000000..c0c9579 --- /dev/null +++ b/src/main/java/com/bank/domain/InvalidDepositAmountException.java @@ -0,0 +1,42 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package com.bank.domain; + +/** + * + * @author TwinP + */ +@SuppressWarnings("serial") +public class InvalidDepositAmountException extends Exception { + private double attemptedAmount; + /** + * Creates a new instance of InvalidDepositAmountException without detail message. + */ + public InvalidDepositAmountException(double attemptedAmount) { + this.attemptedAmount = attemptedAmount; + } + + /** + * @return the attemptedAmount + */ + public double getAttemptedAmount() { + return attemptedAmount; + } + + /** + * @param attemptedAmount the attemptedAmount to set + */ + public void setAttemptedAmount(double attemptedAmount) { + this.attemptedAmount = attemptedAmount; + } + + @Override + public String toString() { + return "InvalidDepositAmountException{" + "attemptedAmount=" + attemptedAmount + '}'; + } + + +} diff --git a/src/main/java/com/bank/domain/LocalTimeWrapper.java b/src/main/java/com/bank/domain/LocalTimeWrapper.java new file mode 100644 index 0000000..3758081 --- /dev/null +++ b/src/main/java/com/bank/domain/LocalTimeWrapper.java @@ -0,0 +1,23 @@ +package com.bank.domain; + +import org.omg.CORBA.Current; + +import java.time.LocalTime; + +public class LocalTimeWrapper { + + private String specificTime = null; + public LocalTimeWrapper(String initial){ + this.specificTime = initial; + } + + public LocalTimeWrapper() { + + } + + public LocalTime getCurrentTime() { + if(this.specificTime != null) + return LocalTime.parse(this.specificTime); + return LocalTime.now(); + } +} diff --git a/src/main/java/com/bank/domain/TransferReceipt.java b/src/main/java/com/bank/domain/TransferReceipt.java new file mode 100644 index 0000000..bb1d6bc --- /dev/null +++ b/src/main/java/com/bank/domain/TransferReceipt.java @@ -0,0 +1,90 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bank.domain; + +import java.time.LocalTime; + +import static java.lang.String.format; + +public class TransferReceipt { + + private double transferAmount; + private double feeAmount; + private Account initialSourceAccountCopy; + private Account initialDestinationAccountCopy; + private Account finalSourceAccountCopy; + private Account finalDestinationAccountCopy; + private LocalTime transactionTime; + + + public TransferReceipt(LocalTime transactionTime) { + this.transactionTime = transactionTime; + } + + public void setTransferAmount(double transferAmount) { + this.transferAmount = transferAmount; + } + + public double getTransferAmount() { + return transferAmount; + } + + public void setFeeAmount(double feeAmount) { + this.feeAmount = feeAmount; + } + + public double getFeeAmount() { + return feeAmount; + } + + public void setInitialSourceAccount(Account account) { + initialSourceAccountCopy = Account.copy(account); + } + + public void setFinalSourceAccount(Account account) { + finalSourceAccountCopy = Account.copy(account); + } + + public Account getFinalSourceAccount() { + return finalSourceAccountCopy; + } + + public void setInitialDestinationAccount(Account account) { + initialDestinationAccountCopy = Account.copy(account); + } + + public void setFinalDestinationAccount(Account account) { + finalDestinationAccountCopy = Account.copy(account); + } + + public Account getFinalDestinationAccount() { + return finalDestinationAccountCopy; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder().append(format("Transferred %.2f from account %s to %s, with fee amount: %.2f\n", + transferAmount, initialSourceAccountCopy.getId(), + initialDestinationAccountCopy.getId(), feeAmount)).append(format("\tinitial balance for account %s: %.2f; new balance: %.2f\n", + initialSourceAccountCopy.getId(), + initialSourceAccountCopy.getBalance(), + finalSourceAccountCopy.getBalance())).append(format("\tinitial balance for account %s: %.2f; new balance: %.2f\n", + initialDestinationAccountCopy.getId(), + initialDestinationAccountCopy.getBalance(), + finalDestinationAccountCopy.getBalance())); + return sb.toString(); + } +} diff --git a/src/main/java/com/bank/repository/AccountNotFoundException.java b/src/main/java/com/bank/repository/AccountNotFoundException.java new file mode 100644 index 0000000..1db00ff --- /dev/null +++ b/src/main/java/com/bank/repository/AccountNotFoundException.java @@ -0,0 +1,24 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bank.repository; + +@SuppressWarnings("serial") +public class AccountNotFoundException extends RuntimeException { + + public AccountNotFoundException(String acctId) { + super(String.format("account with id [%s] could not be found", acctId)); + } +} diff --git a/src/main/java/com/bank/repository/AccountRepository.java b/src/main/java/com/bank/repository/AccountRepository.java new file mode 100644 index 0000000..d4c6954 --- /dev/null +++ b/src/main/java/com/bank/repository/AccountRepository.java @@ -0,0 +1,25 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bank.repository; + +import com.bank.domain.Account; + +public interface AccountRepository { + + Account findById(String srcAcctId); + + void updateBalance(Account dstAcct); +} diff --git a/src/main/java/com/bank/repository/internal/JdbcAccountRepository.java b/src/main/java/com/bank/repository/internal/JdbcAccountRepository.java new file mode 100644 index 0000000..0600119 --- /dev/null +++ b/src/main/java/com/bank/repository/internal/JdbcAccountRepository.java @@ -0,0 +1,53 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bank.repository.internal; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import javax.sql.DataSource; + +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; + +import com.bank.domain.Account; +import com.bank.repository.AccountRepository; + +public class JdbcAccountRepository implements AccountRepository { + + private final JdbcTemplate jdbcTemplate; + + public JdbcAccountRepository(DataSource dataSource) { + jdbcTemplate = new JdbcTemplate(dataSource); + } + + @Override + public Account findById(String srcAcctId) { + return jdbcTemplate.queryForObject("select id, balance from account where id = ?", new AccountRowMapper(), srcAcctId); + } + + @Override + public void updateBalance(Account dstAcct) { + jdbcTemplate.update("update account set balance = ? where id = ?", dstAcct.getBalance(), dstAcct.getId()); + } + + private static class AccountRowMapper implements RowMapper { + @Override + public Account mapRow(ResultSet rs, int rowNum) throws SQLException { + return new Account(rs.getString("id"), rs.getDouble("balance")); + } + } +} diff --git a/src/main/java/com/bank/repository/internal/SimpleAccountRepository.java b/src/main/java/com/bank/repository/internal/SimpleAccountRepository.java new file mode 100644 index 0000000..c1854e5 --- /dev/null +++ b/src/main/java/com/bank/repository/internal/SimpleAccountRepository.java @@ -0,0 +1,62 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bank.repository.internal; + +import java.util.HashMap; +import java.util.Map; + +import com.bank.domain.Account; +import com.bank.repository.AccountNotFoundException; +import com.bank.repository.AccountRepository; + +public class SimpleAccountRepository implements AccountRepository { + + public static class Data { + + public static final String A123_ID = "A123"; + public static final String C456_ID = "C456"; + public static final String Z999_ID = "Z999"; // NON EXISTENT ID + public static final double A123_INITIAL_BAL = 100.00; + public static final double C456_INITIAL_BAL = 0.00; + } + @SuppressWarnings("serial") + private final Map accountsById = new HashMap() { + + { + put(Data.A123_ID, new Account(Data.A123_ID, Data.A123_INITIAL_BAL)); + put(Data.C456_ID, new Account(Data.C456_ID, Data.C456_INITIAL_BAL)); + } + }; + + @Override + public Account findById(String acctId) { + return Account.copy(nullSafeAccountLookup(acctId)); + } + + @Override + public void updateBalance(Account account) { + Account actualAccount = nullSafeAccountLookup(account.getId()); + actualAccount.setBalance(account.getBalance()); + } + + private Account nullSafeAccountLookup(String acctId) { + Account account = accountsById.get(acctId); + if (account == null) { + throw new AccountNotFoundException(acctId); + } + return account; + } +} diff --git a/src/main/java/com/bank/service/DepositService.java b/src/main/java/com/bank/service/DepositService.java new file mode 100644 index 0000000..557a8f8 --- /dev/null +++ b/src/main/java/com/bank/service/DepositService.java @@ -0,0 +1,18 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package com.bank.service; + +import com.bank.domain.DepositReceipt; +import com.bank.domain.InvalidDepositAmountException; + +/** + * + * @author TwinP + */ +public interface DepositService { + void setMinimumDepositAmount(double minimumDepositAmount); + public DepositReceipt deposit(double amount, String destrinationAcc) throws InvalidDepositAmountException; +} diff --git a/src/main/java/com/bank/service/FeePolicy.java b/src/main/java/com/bank/service/FeePolicy.java new file mode 100644 index 0000000..c2d9897 --- /dev/null +++ b/src/main/java/com/bank/service/FeePolicy.java @@ -0,0 +1,20 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bank.service; + +public interface FeePolicy { + public double calculateFee(double transferAmount); +} diff --git a/src/main/java/com/bank/service/TransferService.java b/src/main/java/com/bank/service/TransferService.java new file mode 100644 index 0000000..05d5a1b --- /dev/null +++ b/src/main/java/com/bank/service/TransferService.java @@ -0,0 +1,28 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bank.service; + +import com.bank.domain.InsufficientFundsException; +import com.bank.domain.TransferReceipt; +import com.bank.service.internal.InvalidTransferWindow; + +public interface TransferService { + + TransferReceipt transfer(double amount, String srcAcctId, String destAcctId) + throws InsufficientFundsException, InvalidTransferWindow; + + void setMinimumTransferAmount(double minimumTransferAmount); +} diff --git a/src/main/java/com/bank/service/internal/DefaultDepositService.java b/src/main/java/com/bank/service/internal/DefaultDepositService.java new file mode 100644 index 0000000..c3343b9 --- /dev/null +++ b/src/main/java/com/bank/service/internal/DefaultDepositService.java @@ -0,0 +1,52 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package com.bank.service.internal; +import static java.lang.String.format; + +import com.bank.domain.Account; +import com.bank.domain.DepositReceipt; +import com.bank.domain.InvalidDepositAmountException; +import com.bank.repository.AccountRepository; +import com.bank.service.DepositService; +import com.bank.service.FeePolicy; + +/** + * + * @author TwinP + */ +public class DefaultDepositService implements DepositService { + + private final AccountRepository accountRepository; + private final FeePolicy feePolicy; + private double minimumDepositAmount = 1.00; + + public DefaultDepositService(AccountRepository accountRepository, FeePolicy feePolicy) { + this.accountRepository = accountRepository; + this.feePolicy = feePolicy; + } + + @Override + public void setMinimumDepositAmount(double minimumDepositAmount) { + this.minimumDepositAmount = minimumDepositAmount; + } + + @Override + public DepositReceipt deposit(double amount, String destrinationAccountNumber) throws InvalidDepositAmountException { + if (amount <= this.minimumDepositAmount) { + throw new InvalidDepositAmountException(amount); + } + DepositReceipt depositReceipt = new DepositReceipt(); + Account destrinationAccount = accountRepository.findById(destrinationAccountNumber); + + depositReceipt.setDepositAmount(amount); + depositReceipt.setInitialDestinationAccountCopy(destrinationAccount); + + destrinationAccount.credit(amount); + accountRepository.updateBalance(destrinationAccount); + + depositReceipt.setFinalDestinationAccountCopy(destrinationAccount); + return depositReceipt; + } +} diff --git a/src/main/java/com/bank/service/internal/DefaultTransferService.java b/src/main/java/com/bank/service/internal/DefaultTransferService.java new file mode 100644 index 0000000..f2f254f --- /dev/null +++ b/src/main/java/com/bank/service/internal/DefaultTransferService.java @@ -0,0 +1,97 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bank.service.internal; + +import static java.lang.String.format; + +import com.bank.domain.*; +import org.springframework.transaction.annotation.Transactional; + +import com.bank.repository.AccountRepository; +import com.bank.service.FeePolicy; +import com.bank.service.TransferService; + +import java.time.LocalTime; + +public class DefaultTransferService implements TransferService { + + private final AccountRepository accountRepository; + private final FeePolicy feePolicy; + private double minimumTransferAmount = 1.00; + private LocalTimeWrapper localTimeWrapper; + private DefaultTransferWindow defaultTransferWindow; + + public DefaultTransferService(AccountRepository accountRepository, + FeePolicy feePolicy, + LocalTimeWrapper localTimeWrapper, + DefaultTransferWindow transferWindow) { + this.accountRepository = accountRepository; + this.feePolicy = feePolicy; + this.localTimeWrapper = localTimeWrapper; + this.defaultTransferWindow = transferWindow; + } + + @Override + public void setMinimumTransferAmount(double minimumTransferAmount) { + this.minimumTransferAmount = minimumTransferAmount; + } + + @Override + @Transactional + public TransferReceipt transfer(double amount, String srcAcctId, String dstAcctId) + throws InsufficientFundsException, InvalidTransferWindow { + + LocalTime transactionTime = this.localTimeWrapper.getCurrentTime(); + checkEligibility(amount, transactionTime); + + Account srcAcct = accountRepository.findById(srcAcctId); + Account dstAcct = accountRepository.findById(dstAcctId); + + double fee = feePolicy.calculateFee(amount); + if (fee > 0) { + srcAcct.debit(fee); + } + srcAcct.debit(amount); + dstAcct.credit(amount); + + accountRepository.updateBalance(srcAcct); + accountRepository.updateBalance(dstAcct); + + return getTransferReceipt(amount, transactionTime, srcAcct, dstAcct, fee); + } + + private TransferReceipt getTransferReceipt(double amount, LocalTime transactionTime, Account srcAcct, Account dstAcct, double fee) { + TransferReceipt receipt = new TransferReceipt(transactionTime); + receipt.setInitialSourceAccount(srcAcct); + receipt.setInitialDestinationAccount(dstAcct); + receipt.setTransferAmount(amount); + receipt.setFeeAmount(fee); + receipt.setFinalSourceAccount(srcAcct); + receipt.setFinalDestinationAccount(dstAcct); + return receipt; + } + + private void checkEligibility(double amount, LocalTime transactionTime) throws InvalidTransferWindow { + if (amount < minimumTransferAmount) { + throw new IllegalArgumentException(format("transfer amount must be at least $%.2f", minimumTransferAmount)); + } + + + if(!defaultTransferWindow.isValidTimeForTransferMoney(transactionTime)) { + throw new InvalidTransferWindow("We only allow to transfer between " + defaultTransferWindow.getOpen() + " and " + defaultTransferWindow.getClose()); + } + } +} diff --git a/src/main/java/com/bank/service/internal/FlatFeePolicy.java b/src/main/java/com/bank/service/internal/FlatFeePolicy.java new file mode 100644 index 0000000..85dab5b --- /dev/null +++ b/src/main/java/com/bank/service/internal/FlatFeePolicy.java @@ -0,0 +1,31 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bank.service.internal; + +import com.bank.service.FeePolicy; + +public class FlatFeePolicy implements FeePolicy { + + private final double flatFee; + + public FlatFeePolicy(double flatFee) { + this.flatFee = flatFee; + } + + public double calculateFee(double transferAmount) { + return flatFee; + } +} diff --git a/src/main/java/com/bank/service/internal/InvalidTransferWindow.java b/src/main/java/com/bank/service/internal/InvalidTransferWindow.java new file mode 100644 index 0000000..8bd8da6 --- /dev/null +++ b/src/main/java/com/bank/service/internal/InvalidTransferWindow.java @@ -0,0 +1,6 @@ +package com.bank.service.internal; + +public class InvalidTransferWindow extends Throwable { + public InvalidTransferWindow(String s) { + } +} diff --git a/src/main/java/com/bank/service/internal/VariableFeePolicy.java b/src/main/java/com/bank/service/internal/VariableFeePolicy.java new file mode 100644 index 0000000..329eff5 --- /dev/null +++ b/src/main/java/com/bank/service/internal/VariableFeePolicy.java @@ -0,0 +1,40 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.bank.service.internal; + +import com.bank.service.FeePolicy; + +public class VariableFeePolicy implements FeePolicy { + + private double feePercentage; + private double minimumFee; + + public void setMinimumFee(double minimumFee) { + this.minimumFee = minimumFee; + } + + public void setFeePercentage(double feePercentage) { + this.feePercentage = feePercentage; + } + + @Override + public double calculateFee(double transferAmount) { + double variableFee = transferAmount * (feePercentage/100); + return variableFee > minimumFee ? variableFee : minimumFee; + } + +} diff --git a/src/main/java/com/bank/service/internal/ZeroFeePolicy.java b/src/main/java/com/bank/service/internal/ZeroFeePolicy.java new file mode 100644 index 0000000..0323b87 --- /dev/null +++ b/src/main/java/com/bank/service/internal/ZeroFeePolicy.java @@ -0,0 +1,30 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.bank.service.internal; + +import com.bank.service.FeePolicy; + +public class ZeroFeePolicy implements FeePolicy { + + private static final double ZERO_AMOUNT = 0.00d; + + @Override + public double calculateFee(double transferAmount) { + return ZERO_AMOUNT; + } + +} From 63da0d66dd5b4e4e935d0303bab9365821fa7b36 Mon Sep 17 00:00:00 2001 From: Twin Panichsombat Date: Wed, 26 Jul 2017 18:03:45 +0900 Subject: [PATCH 23/23] Ignore log4j from build for removing error --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 40abef2..ea0ba68 100644 --- a/build.gradle +++ b/build.gradle @@ -36,7 +36,7 @@ dependencies { compile 'cglib:cglib-nodep:2.2' compile 'hsqldb:hsqldb:1.8.0.10' compile 'commons-logging:commons-logging:1.1.1' - compile 'log4j:log4j:1.2.16' + //compile 'log4j:log4j:1.2.16' compile 'javax.inject:javax.inject:1' testCompile 'junit:junit:4.7' }