From b6201f65f3b28d0f63b95f858df030e7a2207918 Mon Sep 17 00:00:00 2001 From: Bogdan Apetrei Date: Mon, 31 Mar 2014 22:05:39 +0300 Subject: [PATCH 1/7] partial commit --- README.md | 6 + pom.xml | 79 +++++++--- src/main/java/app/Main.java | 30 ++++ src/main/java/app/domain/Account.java | 41 +++++ src/main/java/app/domain/Entity.java | 21 +++ src/main/java/app/domain/Transaction.java | 45 ++++++ .../app/repository/AccountRepository.java | 15 ++ .../app/repository/JdbcAccountRepository.java | 47 ++++++ .../repository/JdbcTransactionRepository.java | 29 ++++ .../app/repository/TransactionRepository.java | 9 ++ .../app/service/AccountManagerService.java | 55 +++++++ src/main/java/app/service/AccountService.java | 12 ++ .../app/service/MoneyTransferService.java | 41 +++++ .../service/TransactionManagerService.java | 29 ++++ .../java/app/service/TransactionService.java | 9 ++ .../java/app/service/TransferService.java | 9 ++ src/main/java/app/util/AccountMapper.java | 20 +++ .../java/app/util/TransactionValidator.java | 30 ++++ src/main/resources/database.properties | 4 + src/main/resources/logback.xml | 16 ++ .../resources/spring/application-config.xml | 9 ++ src/main/resources/spring/database-config.xml | 24 +++ src/main/resources/testdb/data.sql | 2 + src/main/resources/testdb/schema.sql | 19 +++ src/main/resources/testdbdata/data.log | 32 ++++ src/main/resources/testdbdata/data.properties | 4 + src/main/resources/testdbdata/data.script | 53 +++++++ .../repository/JdbcAccountRepositoryIT.java | 140 ++++++++++++++++++ .../JdbcTransactionRepositoryIT.java | 91 ++++++++++++ .../service/AccountManagerServiceTest.java | 121 +++++++++++++++ .../app/service/MoneyTransferServiceTest.java | 53 +++++++ .../TransactionManagerServiceTest.java | 67 +++++++++ .../JdbcAccountRepositoryIT-context.xml | 9 ++ .../JdbcTransactionRepositoryIT-context.xml | 9 ++ .../resources/spring/database-test-config.xml | 14 ++ 35 files changed, 1176 insertions(+), 18 deletions(-) create mode 100644 src/main/java/app/Main.java create mode 100644 src/main/java/app/domain/Account.java create mode 100644 src/main/java/app/domain/Entity.java create mode 100644 src/main/java/app/domain/Transaction.java create mode 100644 src/main/java/app/repository/AccountRepository.java create mode 100644 src/main/java/app/repository/JdbcAccountRepository.java create mode 100644 src/main/java/app/repository/JdbcTransactionRepository.java create mode 100644 src/main/java/app/repository/TransactionRepository.java create mode 100644 src/main/java/app/service/AccountManagerService.java create mode 100644 src/main/java/app/service/AccountService.java create mode 100644 src/main/java/app/service/MoneyTransferService.java create mode 100644 src/main/java/app/service/TransactionManagerService.java create mode 100644 src/main/java/app/service/TransactionService.java create mode 100644 src/main/java/app/service/TransferService.java create mode 100644 src/main/java/app/util/AccountMapper.java create mode 100644 src/main/java/app/util/TransactionValidator.java create mode 100644 src/main/resources/database.properties create mode 100644 src/main/resources/logback.xml create mode 100644 src/main/resources/spring/application-config.xml create mode 100644 src/main/resources/spring/database-config.xml create mode 100644 src/main/resources/testdb/data.sql create mode 100644 src/main/resources/testdb/schema.sql create mode 100644 src/main/resources/testdbdata/data.log create mode 100644 src/main/resources/testdbdata/data.properties create mode 100644 src/main/resources/testdbdata/data.script create mode 100644 src/test/java/app/repository/JdbcAccountRepositoryIT.java create mode 100644 src/test/java/app/repository/JdbcTransactionRepositoryIT.java create mode 100644 src/test/java/app/service/AccountManagerServiceTest.java create mode 100644 src/test/java/app/service/MoneyTransferServiceTest.java create mode 100644 src/test/java/app/service/TransactionManagerServiceTest.java create mode 100644 src/test/resources/app/repository/JdbcAccountRepositoryIT-context.xml create mode 100644 src/test/resources/app/repository/JdbcTransactionRepositoryIT-context.xml create mode 100644 src/test/resources/spring/database-test-config.xml diff --git a/README.md b/README.md index a1d2939..7f325bf 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,8 @@ SpringCore ========== +example with xml metadata configuration + +//homework - review code, ask questions +//homework - change constructor injection with setter injection, what about field injection +//homework - do validation for AccountMapper class +//homework - do validation for Transaction Validator \ No newline at end of file diff --git a/pom.xml b/pom.xml index 902ab97..4eaf1a3 100644 --- a/pom.xml +++ b/pom.xml @@ -1,28 +1,30 @@ - - 4.0.0 app SpringCore 1.0-SNAPSHOT + jar - - - 4.0.2.RELEASE + SpringCore + + 4.0.3.RELEASE + 1.4 + 2.3.2 1.7.6 1.1.1 - 4.11-20120805-1225 + 4.11 + 1.9.5 + Core utilities used by other modules. + Define this if you use Spring Utility APIs (org.springframework.core.*/org.springframework.util.*) + --> org.springframework spring-core @@ -59,16 +61,32 @@ ${org.springframework.version} - org.springframework - spring-context-support + spring-jdbc ${org.springframework.version} + + org.springframework + spring-test + ${org.springframework.version} + test + + + + + commons-dbcp + commons-dbcp + ${commons-dbcp.version} + + + + org.hsqldb + hsqldb + ${org.hsqldb.version} + + @@ -100,6 +118,12 @@ test + + org.mockito + mockito-core + ${mockito.version} + test + @@ -111,7 +135,12 @@ 1.7 1.7 - + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 org.codehaus.mojo @@ -119,10 +148,24 @@ 2.1 false + false + + org.apache.maven.plugins + maven-pmd-plugin + 3.0.1 + + + compile + + check + cpd-check + + + + - - \ No newline at end of file + diff --git a/src/main/java/app/Main.java b/src/main/java/app/Main.java new file mode 100644 index 0000000..9cd889b --- /dev/null +++ b/src/main/java/app/Main.java @@ -0,0 +1,30 @@ +package app; + +import app.domain.Account; +import app.domain.Transaction; +import app.service.AccountManagerService; +import app.service.MoneyTransferService; +import app.service.TransferService; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import java.math.BigDecimal; + +public class Main { + + public static void main(String[] args) { + + ApplicationContext context = new ClassPathXmlApplicationContext("/spring/application-config.xml","/spring/database-config.xml"); + + Transaction transaction = new Transaction("12345678901234", "12345678909876", BigDecimal.TEN); + TransferService transferService = context.getBean(MoneyTransferService.class); + transferService.transferAmount(transaction); + + AccountManagerService accountService = context.getBean(AccountManagerService.class); + Account payerAccount = accountService.findByNumber("12345678901234"); + Account beneficiaryAccount = accountService.findByNumber("12345678909876"); + + System.out.println(payerAccount); + System.out.println(beneficiaryAccount); + } +} diff --git a/src/main/java/app/domain/Account.java b/src/main/java/app/domain/Account.java new file mode 100644 index 0000000..d2809b8 --- /dev/null +++ b/src/main/java/app/domain/Account.java @@ -0,0 +1,41 @@ +package app.domain; + +import java.math.BigDecimal; + +public class Account extends Entity { + + private String number; + private String name; + private BigDecimal moneyAmount; + + public Account(String number, String name, BigDecimal moneyAmount) { + this.number = number; + this.name = name; + this.moneyAmount = moneyAmount; + } + + public String getNumber() { + return number; + } + + public String getName() { + return name; + } + + public BigDecimal getMoneyAmount() { + return moneyAmount; + } + + public void setMoneyAmount(BigDecimal moneyAmount) { + this.moneyAmount = moneyAmount; + } + + @Override + public String toString() { + return "Account{" + + "number='" + number + '\'' + + ", name='" + name + '\'' + + ", moneyAmount=" + moneyAmount + + '}'; + } +} diff --git a/src/main/java/app/domain/Entity.java b/src/main/java/app/domain/Entity.java new file mode 100644 index 0000000..969e057 --- /dev/null +++ b/src/main/java/app/domain/Entity.java @@ -0,0 +1,21 @@ +package app.domain; + +public class Entity { + + private long entityId; + + public long getEntityId() { + return entityId; + } + + public void setEntityId(long entityId) { + this.entityId = entityId; + } + + @Override + public String toString() { + return "Entity{" + + "entityId=" + entityId + + '}'; + } +} diff --git a/src/main/java/app/domain/Transaction.java b/src/main/java/app/domain/Transaction.java new file mode 100644 index 0000000..6271c7e --- /dev/null +++ b/src/main/java/app/domain/Transaction.java @@ -0,0 +1,45 @@ +package app.domain; + +import java.math.BigDecimal; +import java.util.Date; + +public class Transaction extends Entity { + + private String payerAccountNumber; + private String beneficiaryAccountNumber; + private BigDecimal moneyAmount; + private Date date; + + public Transaction(String payerAccountNumber, String beneficiaryAccount, BigDecimal moneyAmount) { + this.payerAccountNumber = payerAccountNumber; + this.beneficiaryAccountNumber = beneficiaryAccount; + this.moneyAmount = moneyAmount; + this.date = new Date(); + } + + public String getPayerAccountNumber() { + return payerAccountNumber; + } + + public String getBeneficiaryAccountNumber() { + return beneficiaryAccountNumber; + } + + public BigDecimal getMoneyAmount() { + return moneyAmount; + } + + public Date getDate() { + return date; + } + + @Override + public String toString() { + return "Transaction{" + + ", payerAccountNumber='" + payerAccountNumber + '\'' + + ", beneficiaryAccountNumber='" + beneficiaryAccountNumber + '\'' + + ", moneyAmount=" + moneyAmount + + ", date=" + date + + '}'; + } +} diff --git a/src/main/java/app/repository/AccountRepository.java b/src/main/java/app/repository/AccountRepository.java new file mode 100644 index 0000000..e1698c9 --- /dev/null +++ b/src/main/java/app/repository/AccountRepository.java @@ -0,0 +1,15 @@ +package app.repository; + + +import app.domain.Account; + +import java.util.List; + +public interface AccountRepository { + + List findByNumber(String number); + + int insert(Account account); + + int updateMoneyAmount(Account account); +} diff --git a/src/main/java/app/repository/JdbcAccountRepository.java b/src/main/java/app/repository/JdbcAccountRepository.java new file mode 100644 index 0000000..04fb970 --- /dev/null +++ b/src/main/java/app/repository/JdbcAccountRepository.java @@ -0,0 +1,47 @@ +package app.repository; + +import app.domain.Account; +import app.util.AccountMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; + +import javax.sql.DataSource; +import java.util.List; + +@Repository +public class JdbcAccountRepository implements AccountRepository { + + private JdbcTemplate jdbcTemplate; + + @Autowired + public JdbcAccountRepository(DataSource dataSource) { + this.jdbcTemplate = new JdbcTemplate(dataSource); + } + + @Override + public List findByNumber(String number) { + return jdbcTemplate.query( + "SELECT * FROM t_account WHERE number = ?", + new AccountMapper(), + number); + } + + @Override + public int insert(Account account) { + return jdbcTemplate.update( + "INSERT INTO t_account (number, name, money_amount) VALUES(?, ?, ?)", + account.getNumber(), + account.getName(), + account.getMoneyAmount()); + } + + @Override + public int updateMoneyAmount(Account account) { + return jdbcTemplate.update( + "UPDATE t_account SET money_amount = ? WHERE id = ?", + account.getMoneyAmount(), + account.getEntityId() + ); + } +} diff --git a/src/main/java/app/repository/JdbcTransactionRepository.java b/src/main/java/app/repository/JdbcTransactionRepository.java new file mode 100644 index 0000000..b60fe1a --- /dev/null +++ b/src/main/java/app/repository/JdbcTransactionRepository.java @@ -0,0 +1,29 @@ +package app.repository; + +import app.domain.Transaction; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; + +import javax.sql.DataSource; + +@Repository +public class JdbcTransactionRepository implements TransactionRepository { + + private JdbcTemplate jdbcTemplate; + + @Autowired + public JdbcTransactionRepository(DataSource dataSource) { + this.jdbcTemplate = new JdbcTemplate(dataSource); + } + + @Override + public int insert(Transaction transaction) { + return jdbcTemplate.update( + "INSERT INTO t_transaction (payer_account, beneficiary_account, money_amount, date) VALUES(?, ?, ?, ?)", + transaction.getPayerAccountNumber(), + transaction.getBeneficiaryAccountNumber(), + transaction.getMoneyAmount(), + transaction.getDate()); + } +} \ No newline at end of file diff --git a/src/main/java/app/repository/TransactionRepository.java b/src/main/java/app/repository/TransactionRepository.java new file mode 100644 index 0000000..9301e14 --- /dev/null +++ b/src/main/java/app/repository/TransactionRepository.java @@ -0,0 +1,9 @@ +package app.repository; + +import app.domain.Transaction; + +public interface TransactionRepository { + + int insert(Transaction transaction); + +} diff --git a/src/main/java/app/service/AccountManagerService.java b/src/main/java/app/service/AccountManagerService.java new file mode 100644 index 0000000..6098531 --- /dev/null +++ b/src/main/java/app/service/AccountManagerService.java @@ -0,0 +1,55 @@ +package app.service; + +import app.domain.Account; +import app.repository.AccountRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.dao.IncorrectResultSizeDataAccessException; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class AccountManagerService implements AccountService { + + private AccountRepository accountRepository; + + @Autowired + public AccountManagerService(AccountRepository accountRepository) { + this.accountRepository = accountRepository; + } + + @Override + public Account findByNumber(String number) { + List accounts = accountRepository.findByNumber(number); + if (accounts == null || accounts.size() ==0) { + throw new EmptyResultDataAccessException("No account found for number " + number + ".", 1); + } + if (accounts.size() > 1) { + throw new IncorrectResultSizeDataAccessException("More than one account found for number" + number + ".", 1); + } + return accounts.get(0); + } + + @Override + public void save(Account account) { + int count = accountRepository.insert(account); + if (count == 0) { + throw new IncorrectResultSizeDataAccessException("Account not saved.", 1); + } + if (count > 1) { + throw new IncorrectResultSizeDataAccessException("More than once account was saved.", 1); + } + } + + @Override + public void updateMoneyAmount(Account account) { + int count = accountRepository.updateMoneyAmount(account); + if (count == 0) { + throw new IncorrectResultSizeDataAccessException("No accounts were updated", 1); + } + if (count > 1) { + throw new IncorrectResultSizeDataAccessException("More than once account was updated", 1); + } + } +} diff --git a/src/main/java/app/service/AccountService.java b/src/main/java/app/service/AccountService.java new file mode 100644 index 0000000..49c9dd3 --- /dev/null +++ b/src/main/java/app/service/AccountService.java @@ -0,0 +1,12 @@ +package app.service; + +import app.domain.Account; + +public interface AccountService { + + Account findByNumber(String number); + + void save(Account account); + + void updateMoneyAmount(Account account); +} diff --git a/src/main/java/app/service/MoneyTransferService.java b/src/main/java/app/service/MoneyTransferService.java new file mode 100644 index 0000000..0cff135 --- /dev/null +++ b/src/main/java/app/service/MoneyTransferService.java @@ -0,0 +1,41 @@ +package app.service; + +import app.domain.Account; +import app.domain.Transaction; +import app.util.TransactionValidator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; + +@Service +public class MoneyTransferService implements TransferService { + + private AccountService accountService; + private TransactionService transactionService; + + @Autowired + public MoneyTransferService(AccountService accountService, TransactionService transactionService) { + this.accountService = accountService; + this.transactionService = transactionService; + } + + @Override + public void transferAmount(Transaction transaction) { + + TransactionValidator.validate(transaction); + + Account payerAccount = accountService.findByNumber(transaction.getPayerAccountNumber()); + Account beneficiaryAccount = accountService.findByNumber(transaction.getBeneficiaryAccountNumber()); + + BigDecimal amount = transaction.getMoneyAmount(); + payerAccount.setMoneyAmount(payerAccount.getMoneyAmount().subtract(amount)); + beneficiaryAccount.setMoneyAmount(beneficiaryAccount.getMoneyAmount().add(amount)); + + accountService.updateMoneyAmount(payerAccount); + accountService.updateMoneyAmount(beneficiaryAccount); + + transactionService.save(transaction); + } + +} diff --git a/src/main/java/app/service/TransactionManagerService.java b/src/main/java/app/service/TransactionManagerService.java new file mode 100644 index 0000000..6cf3ab8 --- /dev/null +++ b/src/main/java/app/service/TransactionManagerService.java @@ -0,0 +1,29 @@ +package app.service; + +import app.domain.Transaction; +import app.repository.TransactionRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.IncorrectResultSizeDataAccessException; +import org.springframework.stereotype.Service; + +@Service +public class TransactionManagerService implements TransactionService { + + private TransactionRepository transactionRepository; + + @Autowired + public TransactionManagerService(TransactionRepository transactionRepository) { + this.transactionRepository = transactionRepository; + } + + @Override + public void save(Transaction transaction) { + int count = transactionRepository.insert(transaction); + if (count == 0) { + throw new IncorrectResultSizeDataAccessException("Transaction not saved.", 1); + } + if (count > 1) { + throw new IncorrectResultSizeDataAccessException("More than once transaction was saved.", 1); + } + } +} diff --git a/src/main/java/app/service/TransactionService.java b/src/main/java/app/service/TransactionService.java new file mode 100644 index 0000000..3773b81 --- /dev/null +++ b/src/main/java/app/service/TransactionService.java @@ -0,0 +1,9 @@ +package app.service; + +import app.domain.Transaction; + +public interface TransactionService { + + void save(Transaction transaction); + +} diff --git a/src/main/java/app/service/TransferService.java b/src/main/java/app/service/TransferService.java new file mode 100644 index 0000000..9256b57 --- /dev/null +++ b/src/main/java/app/service/TransferService.java @@ -0,0 +1,9 @@ +package app.service; + +import app.domain.Transaction; + +public interface TransferService { + + void transferAmount(Transaction transaction); + +} diff --git a/src/main/java/app/util/AccountMapper.java b/src/main/java/app/util/AccountMapper.java new file mode 100644 index 0000000..c7adef8 --- /dev/null +++ b/src/main/java/app/util/AccountMapper.java @@ -0,0 +1,20 @@ +package app.util; + +import app.domain.Account; +import org.springframework.jdbc.core.RowMapper; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class AccountMapper implements RowMapper { + + @Override + public Account mapRow(ResultSet resultSet, int i) throws SQLException { + Account account = new Account( + resultSet.getString("number"), + resultSet.getString("name"), + resultSet.getBigDecimal("money_amount", 2)); + account.setEntityId(resultSet.getLong("id")); + return account; + } +} diff --git a/src/main/java/app/util/TransactionValidator.java b/src/main/java/app/util/TransactionValidator.java new file mode 100644 index 0000000..8ff3c2f --- /dev/null +++ b/src/main/java/app/util/TransactionValidator.java @@ -0,0 +1,30 @@ +package app.util; + +import app.domain.Transaction; + +import java.math.BigDecimal; + +public class TransactionValidator { + + private static final String ACCOUNT_NUMBER_FORMAT_REGEXP = "\\d{14}"; + + public static void validate(Transaction transaction) { + + BigDecimal amount = transaction.getMoneyAmount(); + if (amount == null || amount.compareTo(BigDecimal.ZERO) < 0) { + throw new IllegalArgumentException("Invalid transaction, amount value is null or less than zero."); + } + String payerAccount = transaction.getPayerAccountNumber(); + if (payerAccount == null || !isValidAccountNumberFormat(payerAccount)) { + throw new IllegalArgumentException("Invalid transaction, payer account has an invalid format."); + } + String beneficiaryAccount = transaction.getBeneficiaryAccountNumber(); + if (beneficiaryAccount == null || !isValidAccountNumberFormat(beneficiaryAccount)) { + throw new IllegalArgumentException("Invalid transaction, beneficiary account has an invalid format."); + } + } + + private static boolean isValidAccountNumberFormat(String accountNumber) { + return accountNumber.matches(ACCOUNT_NUMBER_FORMAT_REGEXP); + } +} diff --git a/src/main/resources/database.properties b/src/main/resources/database.properties new file mode 100644 index 0000000..3867621 --- /dev/null +++ b/src/main/resources/database.properties @@ -0,0 +1,4 @@ +db.driver=org.hsqldb.jdbcDriver +db.url=jdbc:hsqldb:file:src/main/resources/testdbdata/data +db.username=sa +db.password= \ No newline at end of file diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..50b03e0 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{5} - %msg%n + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/spring/application-config.xml b/src/main/resources/spring/application-config.xml new file mode 100644 index 0000000..fecdfc7 --- /dev/null +++ b/src/main/resources/spring/application-config.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/src/main/resources/spring/database-config.xml b/src/main/resources/spring/database-config.xml new file mode 100644 index 0000000..fd24228 --- /dev/null +++ b/src/main/resources/spring/database-config.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/testdb/data.sql b/src/main/resources/testdb/data.sql new file mode 100644 index 0000000..f83b7d3 --- /dev/null +++ b/src/main/resources/testdb/data.sql @@ -0,0 +1,2 @@ +insert into T_ACCOUNT (NUMBER, NAME, MONEY_AMOUNT) values ('12345678901234', 'Bogdan', '100.00'); +insert into T_ACCOUNT (NUMBER, NAME, MONEY_AMOUNT) values ('12345678909876', 'Dragos', '100.00'); diff --git a/src/main/resources/testdb/schema.sql b/src/main/resources/testdb/schema.sql new file mode 100644 index 0000000..3606469 --- /dev/null +++ b/src/main/resources/testdb/schema.sql @@ -0,0 +1,19 @@ +drop table T_ACCOUNT if exists; +drop table T_TRANSACTION if exists; + +create table T_ACCOUNT( + ID integer identity primary key, + NUMBER varchar(14) not null, + NAME varchar(50) not null, + MONEY_AMOUNT double not null, + unique(NUMBER) +); + +create table T_TRANSACTION( + ID integer identity primary key, + PAYER_ACCOUNT varchar(14) not null, + BENEFICIARY_ACCOUNT varchar(14) not null, + MONEY_AMOUNT double not null, + DATE date not null, + unique(PAYER_ACCOUNT, BENEFICIARY_ACCOUNT, MONEY_AMOUNT, DATE) +); \ No newline at end of file diff --git a/src/main/resources/testdbdata/data.log b/src/main/resources/testdbdata/data.log new file mode 100644 index 0000000..04da4a1 --- /dev/null +++ b/src/main/resources/testdbdata/data.log @@ -0,0 +1,32 @@ +/*C8*/SET SCHEMA PUBLIC +drop table T_ACCOUNT if exists +drop table T_TRANSACTION if exists +create table T_ACCOUNT( ID integer identity primary key, NUMBER varchar(14) not null, NAME varchar(50) not null, MONEY_AMOUNT double not null, unique(NUMBER) ) +create table T_TRANSACTION( ID integer identity primary key, PAYER_ACCOUNT varchar(14) not null, BENEFICIARY_ACCOUNT varchar(14) not null, MONEY_AMOUNT double not null, DATE date not null, unique(PAYER_ACCOUNT, BENEFICIARY_ACCOUNT, MONEY_AMOUNT, DATE) ) +INSERT INTO T_ACCOUNT VALUES(0,'12345678901234','Bogdan',100.0E0) +COMMIT +INSERT INTO T_ACCOUNT VALUES(1,'12345678909876','Dragos',100.0E0) +COMMIT +DISCONNECT +/*C9*/SET SCHEMA PUBLIC +DISCONNECT +/*C10*/SET SCHEMA PUBLIC +DISCONNECT +/*C11*/SET SCHEMA PUBLIC +DELETE FROM T_ACCOUNT WHERE ID=0 +INSERT INTO T_ACCOUNT VALUES(0,'12345678901234','Bogdan',90.0E0) +COMMIT +DISCONNECT +/*C12*/SET SCHEMA PUBLIC +DELETE FROM T_ACCOUNT WHERE ID=1 +INSERT INTO T_ACCOUNT VALUES(1,'12345678909876','Dragos',110.0E0) +COMMIT +DISCONNECT +/*C13*/SET SCHEMA PUBLIC +INSERT INTO T_TRANSACTION VALUES(0,'12345678901234','12345678909876',10.0E0,'2014-03-31') +COMMIT +DISCONNECT +/*C14*/SET SCHEMA PUBLIC +DISCONNECT +/*C15*/SET SCHEMA PUBLIC +DISCONNECT diff --git a/src/main/resources/testdbdata/data.properties b/src/main/resources/testdbdata/data.properties new file mode 100644 index 0000000..3e3289e --- /dev/null +++ b/src/main/resources/testdbdata/data.properties @@ -0,0 +1,4 @@ +#HSQL Database Engine 2.3.2 +#Mon Mar 31 22:03:20 EEST 2014 +version=2.3.2 +modified=yes diff --git a/src/main/resources/testdbdata/data.script b/src/main/resources/testdbdata/data.script new file mode 100644 index 0000000..49cdec5 --- /dev/null +++ b/src/main/resources/testdbdata/data.script @@ -0,0 +1,53 @@ +SET DATABASE UNIQUE NAME HSQLDB451294B2C7 +SET DATABASE GC 0 +SET DATABASE DEFAULT RESULT MEMORY ROWS 0 +SET DATABASE EVENT LOG LEVEL 0 +SET DATABASE TRANSACTION CONTROL LOCKS +SET DATABASE DEFAULT ISOLATION LEVEL READ COMMITTED +SET DATABASE TRANSACTION ROLLBACK ON CONFLICT TRUE +SET DATABASE TEXT TABLE DEFAULTS '' +SET DATABASE SQL NAMES FALSE +SET DATABASE SQL REFERENCES FALSE +SET DATABASE SQL SIZE TRUE +SET DATABASE SQL TYPES FALSE +SET DATABASE SQL TDC DELETE TRUE +SET DATABASE SQL TDC UPDATE TRUE +SET DATABASE SQL TRANSLATE TTI TYPES TRUE +SET DATABASE SQL CONCAT NULLS TRUE +SET DATABASE SQL UNIQUE NULLS TRUE +SET DATABASE SQL CONVERT TRUNCATE TRUE +SET DATABASE SQL AVG SCALE 0 +SET DATABASE SQL DOUBLE NAN TRUE +SET FILES WRITE DELAY 500 MILLIS +SET FILES BACKUP INCREMENT TRUE +SET FILES CACHE SIZE 10000 +SET FILES CACHE ROWS 50000 +SET FILES SCALE 32 +SET FILES LOB SCALE 32 +SET FILES DEFRAG 0 +SET FILES NIO TRUE +SET FILES NIO SIZE 256 +SET FILES LOG TRUE +SET FILES LOG SIZE 50 +CREATE USER SA PASSWORD DIGEST 'd41d8cd98f00b204e9800998ecf8427e' +ALTER USER SA SET LOCAL TRUE +CREATE SCHEMA PUBLIC AUTHORIZATION DBA +SET SCHEMA PUBLIC +CREATE MEMORY TABLE PUBLIC.T_ACCOUNT(ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,NUMBER VARCHAR(14) NOT NULL,NAME VARCHAR(50) NOT NULL,MONEY_AMOUNT DOUBLE NOT NULL,UNIQUE(NUMBER)) +ALTER TABLE PUBLIC.T_ACCOUNT ALTER COLUMN ID RESTART WITH 2 +CREATE MEMORY TABLE PUBLIC.T_TRANSACTION(ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,PAYER_ACCOUNT VARCHAR(14) NOT NULL,BENEFICIARY_ACCOUNT VARCHAR(14) NOT NULL,MONEY_AMOUNT DOUBLE NOT NULL,DATE DATE NOT NULL,UNIQUE(PAYER_ACCOUNT,BENEFICIARY_ACCOUNT,MONEY_AMOUNT,DATE)) +ALTER TABLE PUBLIC.T_TRANSACTION ALTER COLUMN ID RESTART WITH 1 +ALTER SEQUENCE SYSTEM_LOBS.LOB_ID RESTART WITH 1 +SET DATABASE DEFAULT INITIAL SCHEMA PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.SQL_IDENTIFIER TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.YES_OR_NO TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.TIME_STAMP TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.CARDINAL_NUMBER TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.CHARACTER_DATA TO PUBLIC +GRANT DBA TO SA +SET SCHEMA SYSTEM_LOBS +INSERT INTO BLOCKS VALUES(0,2147483647,0) +SET SCHEMA PUBLIC +INSERT INTO T_ACCOUNT VALUES(0,'12345678901234','Bogdan',90.0E0) +INSERT INTO T_ACCOUNT VALUES(1,'12345678909876','Dragos',110.0E0) +INSERT INTO T_TRANSACTION VALUES(0,'12345678901234','12345678909876',10.0E0,'2014-03-31') diff --git a/src/test/java/app/repository/JdbcAccountRepositoryIT.java b/src/test/java/app/repository/JdbcAccountRepositoryIT.java new file mode 100644 index 0000000..3dd2425 --- /dev/null +++ b/src/test/java/app/repository/JdbcAccountRepositoryIT.java @@ -0,0 +1,140 @@ +package app.repository; + +import app.domain.Account; +import app.util.AccountMapper; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import javax.sql.DataSource; +import java.math.BigDecimal; +import java.util.List; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsNull.notNullValue; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +public class JdbcAccountRepositoryIT { + + private static String ACCOUNT_NUMBER = "12345678901234"; + private static String ACCOUNT_NAME = "NAME"; + private static BigDecimal ACCOUNT_MONEY_AMOUNT = new BigDecimal("100.00"); + + @Autowired + private AccountRepository accountRepository; + + @Autowired + private DataSource dataSource; + + private JdbcTemplate jdbcTemplate; + + @Rule + public ExpectedException exception = ExpectedException.none(); + + @Before + public void setUp() throws Exception { + jdbcTemplate = new JdbcTemplate(dataSource); + } + + @Test + @DirtiesContext + public void testFindByNumberReturnOnceResult() throws Exception { + + jdbcTemplate.update( + "INSERT INTO t_account (number, name, money_amount) VALUES(?, ?, ?)", + ACCOUNT_NUMBER, ACCOUNT_NAME, ACCOUNT_MONEY_AMOUNT); + + List accounts = accountRepository.findByNumber(ACCOUNT_NUMBER); + + assertThat(accounts, is(notNullValue())); + assertThat(accounts.size(), is(1)); + + Account account = accounts.get(0); + assertThat(account.getEntityId(), is(0L)); + assertThat(account.getName(), is(ACCOUNT_NAME)); + assertThat(account.getNumber(), is(ACCOUNT_NUMBER)); + assertThat(account.getMoneyAmount(), is(ACCOUNT_MONEY_AMOUNT)); + } + + @Test + public void testFindByNumberReturnEmptyList() throws Exception { + + List accounts = accountRepository.findByNumber(ACCOUNT_NUMBER); + + assertThat(accounts, is(notNullValue())); + assertThat(accounts.size(), is(0)); + } + + @Test + @DirtiesContext + public void testInsertSuccess() throws Exception { + + accountRepository.insert(new Account(ACCOUNT_NUMBER, ACCOUNT_NAME, ACCOUNT_MONEY_AMOUNT)); + + List accounts = jdbcTemplate.query( + "SELECT * FROM t_account WHERE number = ?", + new AccountMapper(), + ACCOUNT_NUMBER); + + assertThat(accounts, is(notNullValue())); + assertThat(accounts.size(), is(1)); + + Account account = accounts.get(0); + assertThat(account.getEntityId(), is(0L)); + assertThat(account.getName(), is(ACCOUNT_NAME)); + assertThat(account.getNumber(), is(ACCOUNT_NUMBER)); + assertThat(account.getMoneyAmount(), is(ACCOUNT_MONEY_AMOUNT)); + } + + @Test + public void testInsertFailed() throws Exception { + exception.expect(DataIntegrityViolationException.class); + + accountRepository.insert(new Account(null, ACCOUNT_NAME, ACCOUNT_MONEY_AMOUNT)); + + } + + @Test + @DirtiesContext + public void testUpdateMoneyAmountSuccess() throws Exception { + + jdbcTemplate.update( + "INSERT INTO t_account (number, name, money_amount) VALUES(?, ?, ?)", + ACCOUNT_NUMBER, ACCOUNT_NAME, ACCOUNT_MONEY_AMOUNT); + + List accounts = jdbcTemplate.query("SELECT * FROM t_account WHERE number = ?", + new AccountMapper(), + ACCOUNT_NUMBER); + + BigDecimal NEW_MONEY_AMOUNT = ACCOUNT_MONEY_AMOUNT.add(BigDecimal.TEN); + Account account = accounts.get(0); + account.setMoneyAmount(NEW_MONEY_AMOUNT); + + accountRepository.updateMoneyAmount(account); + + BigDecimal moneyAmount = jdbcTemplate.queryForObject( + "SELECT money_amount FROM t_account WHERE id = ?", BigDecimal.class, account.getEntityId()); + moneyAmount = moneyAmount.setScale(2); + + assertThat(moneyAmount, is(NEW_MONEY_AMOUNT)); + } + + @Test + public void testUpdateMoneyAmountFail() throws Exception { + + Account account = new Account(ACCOUNT_NUMBER, ACCOUNT_NAME, ACCOUNT_MONEY_AMOUNT); + account.setEntityId(0L); + + accountRepository.updateMoneyAmount(account); + } +} \ No newline at end of file diff --git a/src/test/java/app/repository/JdbcTransactionRepositoryIT.java b/src/test/java/app/repository/JdbcTransactionRepositoryIT.java new file mode 100644 index 0000000..c366680 --- /dev/null +++ b/src/test/java/app/repository/JdbcTransactionRepositoryIT.java @@ -0,0 +1,91 @@ +package app.repository; + +import app.domain.Transaction; +import org.hamcrest.CoreMatchers; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import javax.sql.DataSource; +import java.math.BigDecimal; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsNull.notNullValue; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +public class JdbcTransactionRepositoryIT { + + private static final String PAYER_ACCOUNT_NUMBER = "12345678901234"; + private static final String BENEFICIARY_ACCOUNT_NUMBER = "12345678909876"; + private static final BigDecimal MONEY_AMOUNT = new BigDecimal("10.00"); + + @Autowired + private TransactionRepository transactionRepository; + + @Autowired + private DataSource dataSource; + + private JdbcTemplate jdbcTemplate; + + @Rule + public ExpectedException exception = ExpectedException.none(); + + @Before + public void setUp() throws Exception { + jdbcTemplate = new JdbcTemplate(dataSource); + } + + @Test + @DirtiesContext + public void testInsertSuccess() throws Exception { + + transactionRepository.insert(new Transaction(PAYER_ACCOUNT_NUMBER, BENEFICIARY_ACCOUNT_NUMBER, MONEY_AMOUNT)); + + List transactions = jdbcTemplate.query( + "SELECT * FROM t_transaction WHERE payer_account = ? and beneficiary_account = ? and money_amount = ?", + new RowMapper() { + @Override + public Transaction mapRow(ResultSet resultSet, int i) throws SQLException { + Transaction transaction = new Transaction( + resultSet.getString("payer_account"), + resultSet.getString("beneficiary_account"), + resultSet.getBigDecimal("money_amount", 2)); + transaction.setEntityId(resultSet.getLong("id")); + return transaction; + } + }, + PAYER_ACCOUNT_NUMBER, BENEFICIARY_ACCOUNT_NUMBER, MONEY_AMOUNT); + + assertThat(transactions, is(notNullValue())); + assertThat(transactions.size(), is(1)); + + Transaction transaction = transactions.get(0); + assertThat(transaction.getEntityId(), is(0L)); + assertThat(transaction.getPayerAccountNumber(), is(PAYER_ACCOUNT_NUMBER)); + assertThat(transaction.getBeneficiaryAccountNumber(), is(BENEFICIARY_ACCOUNT_NUMBER)); + assertThat(transaction.getMoneyAmount(), is(MONEY_AMOUNT)); + assertThat(transaction.getDate(), is(CoreMatchers.notNullValue())); + } + + @Test + public void testInsertFailed() throws Exception { + exception.expect(DataIntegrityViolationException.class); + + transactionRepository.insert(new Transaction(null, BENEFICIARY_ACCOUNT_NUMBER, MONEY_AMOUNT)); + + } +} diff --git a/src/test/java/app/service/AccountManagerServiceTest.java b/src/test/java/app/service/AccountManagerServiceTest.java new file mode 100644 index 0000000..5fe49a1 --- /dev/null +++ b/src/test/java/app/service/AccountManagerServiceTest.java @@ -0,0 +1,121 @@ +package app.service; + +import app.domain.Account; +import app.repository.AccountRepository; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.dao.IncorrectResultSizeDataAccessException; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.Collections; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class AccountManagerServiceTest { + + private static String ACCOUNT_NUMBER = "12345678901234"; + private static String ACCOUNT_NAME = "NAME"; + private static BigDecimal ACCOUNT_MONEY_AMOUNT = new BigDecimal("100.00"); + private static Account ACCOUNT = new Account(ACCOUNT_NUMBER, ACCOUNT_NAME, ACCOUNT_MONEY_AMOUNT); + + @InjectMocks + private AccountManagerService accountService; + + @Mock + private AccountRepository accountRepository; + + @Rule + public ExpectedException exception = ExpectedException.none(); + + @Test + public void testFindByNumberSuccess() throws Exception { + + when(accountRepository.findByNumber(ACCOUNT_NUMBER)).thenReturn(Arrays.asList(ACCOUNT)); + + Account actualAccount = accountService.findByNumber(ACCOUNT_NUMBER); + + assertThat(actualAccount, is(ACCOUNT)); + verify(accountRepository, times(1)).findByNumber(ACCOUNT_NUMBER); + } + + @Test + public void testFindByNumberFail() throws Exception { + exception.expect(EmptyResultDataAccessException.class); + exception.expectMessage("No account found for number " + ACCOUNT_NUMBER); + + when(accountRepository.findByNumber(ACCOUNT_NUMBER)).thenReturn(Collections.emptyList()); + + accountService.findByNumber(ACCOUNT_NUMBER); + } + + @Test + public void testSaveSuccess() throws Exception { + + when(accountRepository.insert(ACCOUNT)).thenReturn(1); + + accountService.save(ACCOUNT); + + verify(accountRepository, times(1)).insert(ACCOUNT); + } + + @Test + public void testSaveFailNoUpdate() throws Exception { + exception.expect(IncorrectResultSizeDataAccessException.class); + exception.expectMessage("Account not saved."); + + when(accountRepository.insert(ACCOUNT)).thenReturn(0); + + accountService.save(ACCOUNT); + + } + + @Test + public void testSaveFailMoreThanOneFieldUpdate() throws Exception { + exception.expect(IncorrectResultSizeDataAccessException.class); + exception.expectMessage("More than once account was saved."); + + when(accountRepository.insert(ACCOUNT)).thenReturn(2); + + accountService.save(ACCOUNT); + } + + @Test + public void testUpdateMoneyAmountSuccess() throws Exception { + + when(accountRepository.updateMoneyAmount(ACCOUNT)).thenReturn(1); + + accountService.updateMoneyAmount(ACCOUNT); + + verify(accountRepository, times(1)).updateMoneyAmount(ACCOUNT); + } + + @Test + public void testUpdateMoneyAmountFailNoUpdate() throws Exception { + exception.expect(IncorrectResultSizeDataAccessException.class); + exception.expectMessage("No accounts were updated"); + + when(accountRepository.updateMoneyAmount(ACCOUNT)).thenReturn(0); + + accountService.updateMoneyAmount(ACCOUNT); + } + + @Test + public void testUpdateMoneyAmountMoreThanOneFieldUpdate() throws Exception { + exception.expect(IncorrectResultSizeDataAccessException.class); + exception.expectMessage("More than once account was updated"); + + when(accountRepository.updateMoneyAmount(ACCOUNT)).thenReturn(2); + + accountService.updateMoneyAmount(ACCOUNT); + } +} \ No newline at end of file diff --git a/src/test/java/app/service/MoneyTransferServiceTest.java b/src/test/java/app/service/MoneyTransferServiceTest.java new file mode 100644 index 0000000..7d432ab --- /dev/null +++ b/src/test/java/app/service/MoneyTransferServiceTest.java @@ -0,0 +1,53 @@ +package app.service; + +import app.domain.Account; +import app.domain.Transaction; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import java.math.BigDecimal; + +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class MoneyTransferServiceTest { + + private static String PAYER_ACCOUNT_NUMBER = "12345678901234"; + private static String BENEFICIARY_ACCOUNT_NUMBER = "12345678909876"; + private static BigDecimal MONEY_AMOUNT = BigDecimal.TEN; + private static Account PAYER_ACCOUNT = new Account(PAYER_ACCOUNT_NUMBER, "NAME1", new BigDecimal("100.00")); + private static Account BENEFICIARY_ACCOUNT = new Account(BENEFICIARY_ACCOUNT_NUMBER, "NAME2", new BigDecimal("100.00")); + private static Transaction TRANSACTION = new Transaction(PAYER_ACCOUNT_NUMBER, BENEFICIARY_ACCOUNT_NUMBER, MONEY_AMOUNT); + + @InjectMocks + private MoneyTransferService transferService; + + @Mock + private TransactionService transactionService; + + @Mock + private AccountService accountService; + + @Before + public void setUp() throws Exception { + + when(accountService.findByNumber(PAYER_ACCOUNT_NUMBER)).thenReturn(PAYER_ACCOUNT); + when(accountService.findByNumber(BENEFICIARY_ACCOUNT_NUMBER)).thenReturn(BENEFICIARY_ACCOUNT); + } + + @Test + public void testTransferAmount() throws Exception { + + transferService.transferAmount(TRANSACTION); + + verify(accountService,times(1)).updateMoneyAmount(PAYER_ACCOUNT); + verify(accountService,times(1)).updateMoneyAmount(BENEFICIARY_ACCOUNT); + + verify(transactionService, times(1)).save(TRANSACTION); + } + +} diff --git a/src/test/java/app/service/TransactionManagerServiceTest.java b/src/test/java/app/service/TransactionManagerServiceTest.java new file mode 100644 index 0000000..56f6674 --- /dev/null +++ b/src/test/java/app/service/TransactionManagerServiceTest.java @@ -0,0 +1,67 @@ +package app.service; + +import app.domain.Transaction; +import app.repository.TransactionRepository; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.dao.IncorrectResultSizeDataAccessException; + +import java.math.BigDecimal; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class TransactionManagerServiceTest { + + private static final String PAYER_ACCOUNT_NUMBER = "12345678901234"; + private static final String BENEFICIARY_ACCOUNT_NUMBER = "12345678909876"; + private static final BigDecimal MONEY_AMOUNT = new BigDecimal("10.00"); + private static final Transaction TRANSACTION = new Transaction(PAYER_ACCOUNT_NUMBER, BENEFICIARY_ACCOUNT_NUMBER, MONEY_AMOUNT); + + @InjectMocks + private TransactionManagerService transactionService; + + @Mock + private TransactionRepository transactionRepository; + + @Rule + public ExpectedException exception = ExpectedException.none(); + + + @Test + public void testSaveSuccess() throws Exception { + + when(transactionRepository.insert(TRANSACTION)).thenReturn(1); + + transactionService.save(TRANSACTION); + + verify(transactionRepository, times(1)).insert(TRANSACTION); + } + + @Test + public void testSaveFailNoUpdate() throws Exception { + exception.expect(IncorrectResultSizeDataAccessException.class); + exception.expectMessage("Transaction not saved."); + + when(transactionRepository.insert(TRANSACTION)).thenReturn(0); + + transactionService.save(TRANSACTION); + } + + @Test + public void testSaveFailMoreThanOneFieldUpdate() throws Exception { + exception.expect(IncorrectResultSizeDataAccessException.class); + exception.expectMessage("More than once transaction was saved."); + + when(transactionRepository.insert(TRANSACTION)).thenReturn(2); + + transactionService.save(TRANSACTION); + } +} diff --git a/src/test/resources/app/repository/JdbcAccountRepositoryIT-context.xml b/src/test/resources/app/repository/JdbcAccountRepositoryIT-context.xml new file mode 100644 index 0000000..425a54d --- /dev/null +++ b/src/test/resources/app/repository/JdbcAccountRepositoryIT-context.xml @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/src/test/resources/app/repository/JdbcTransactionRepositoryIT-context.xml b/src/test/resources/app/repository/JdbcTransactionRepositoryIT-context.xml new file mode 100644 index 0000000..622b028 --- /dev/null +++ b/src/test/resources/app/repository/JdbcTransactionRepositoryIT-context.xml @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/src/test/resources/spring/database-test-config.xml b/src/test/resources/spring/database-test-config.xml new file mode 100644 index 0000000..dd79093 --- /dev/null +++ b/src/test/resources/spring/database-test-config.xml @@ -0,0 +1,14 @@ + + + + + + + + + \ No newline at end of file From 265354389382ef96eefc0f77fe1b5c05370eba5b Mon Sep 17 00:00:00 2001 From: thecodemaker Date: Mon, 31 Mar 2014 22:40:54 +0300 Subject: [PATCH 2/7] Update README.md --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7f325bf..0db4df9 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,9 @@ SpringCore example with xml metadata configuration //homework - review code, ask questions + //homework - change constructor injection with setter injection, what about field injection + //homework - do validation for AccountMapper class -//homework - do validation for Transaction Validator \ No newline at end of file + +//homework - do validation for Transaction Validator From 0e0ee3a5242220cafacc1d001beba412578afde9 Mon Sep 17 00:00:00 2001 From: vizdragos Date: Thu, 10 Apr 2014 16:32:21 +0300 Subject: [PATCH 3/7] spring transaction example --- pom.xml | 24 ++++++- src/main/java/app/Main.java | 62 ++++++++++++++++--- .../java/app/aop/security/Authenticated.java | 14 +++++ .../java/app/aop/security/SecurityAspect.java | 22 +++++++ .../app/aop/security/SecurityContext.java | 23 +++++++ .../java/app/exception/SecurityException.java | 13 ++++ ...erService.java => AccountServiceImpl.java} | 11 +++- .../java/app/service/SecurityService.java | 17 +++++ .../java/app/service/SecurityServiceImpl.java | 23 +++++++ ...rvice.java => TransactionServiceImpl.java} | 8 ++- ...rService.java => TransferServiceImpl.java} | 9 ++- src/main/resources/spring/aop-config.xml | 9 +++ src/main/resources/spring/database-config.xml | 2 +- src/main/resources/spring/tx-config.xml | 13 ++++ .../service/AccountManagerServiceTest.java | 2 +- .../app/service/MoneyTransferServiceTest.java | 2 +- .../TransactionManagerServiceTest.java | 2 +- 17 files changed, 236 insertions(+), 20 deletions(-) create mode 100644 src/main/java/app/aop/security/Authenticated.java create mode 100644 src/main/java/app/aop/security/SecurityAspect.java create mode 100644 src/main/java/app/aop/security/SecurityContext.java create mode 100644 src/main/java/app/exception/SecurityException.java rename src/main/java/app/service/{AccountManagerService.java => AccountServiceImpl.java} (83%) create mode 100644 src/main/java/app/service/SecurityService.java create mode 100644 src/main/java/app/service/SecurityServiceImpl.java rename src/main/java/app/service/{TransactionManagerService.java => TransactionServiceImpl.java} (74%) rename src/main/java/app/service/{MoneyTransferService.java => TransferServiceImpl.java} (78%) create mode 100644 src/main/resources/spring/aop-config.xml create mode 100644 src/main/resources/spring/tx-config.xml diff --git a/pom.xml b/pom.xml index 4eaf1a3..7bf0439 100644 --- a/pom.xml +++ b/pom.xml @@ -3,11 +3,11 @@ 4.0.0 app - SpringCore + SpringAOP 1.0-SNAPSHOT jar - SpringCore + SpringAOP 4.0.3.RELEASE @@ -17,6 +17,8 @@ 1.1.1 4.11 1.9.5 + 1.6.8 + 1.6.8 @@ -67,6 +69,12 @@ ${org.springframework.version} + + org.springframework + spring-aop + ${org.springframework.version} + + org.springframework spring-test @@ -87,6 +95,18 @@ ${org.hsqldb.version} + + org.aspectj + aspectjrt + ${aspectjrt.version} + + + + org.aspectj + aspectjweaver + ${aspectjweaver.version} + + diff --git a/src/main/java/app/Main.java b/src/main/java/app/Main.java index 9cd889b..10e8523 100644 --- a/src/main/java/app/Main.java +++ b/src/main/java/app/Main.java @@ -1,9 +1,10 @@ package app; +import app.aop.security.SecurityContext; import app.domain.Account; import app.domain.Transaction; -import app.service.AccountManagerService; -import app.service.MoneyTransferService; +import app.service.AccountService; +import app.service.SecurityService; import app.service.TransferService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; @@ -12,19 +13,64 @@ public class Main { + private static final String PAYER_ACCOUNT = "12345678901234"; + private static final String BENEFICIARY_ACCOUNT = "12345678909876"; + + private ApplicationContext context; + + private TransferService transferService; + private AccountService accountService; + private SecurityService securityService; + public static void main(String[] args) { + Main app = new Main(); + app.loadContext(); + app.loadServices(); + + app.login("guest", "endava"); + app.printAccountsBalance(); + app.transferMoney(BigDecimal.TEN); + app.printAccountsBalance(); - ApplicationContext context = new ClassPathXmlApplicationContext("/spring/application-config.xml","/spring/database-config.xml"); + app.cleanUp(); + } + + private void loadContext() { + context = new ClassPathXmlApplicationContext("/spring/application-config.xml", + "/spring/aop-config.xml", + "/spring/tx-config.xml", + "/spring/database-config.xml"); + } - Transaction transaction = new Transaction("12345678901234", "12345678909876", BigDecimal.TEN); - TransferService transferService = context.getBean(MoneyTransferService.class); + private void loadServices() { + transferService = context.getBean(TransferService.class); + accountService = context.getBean(AccountService.class); + securityService = context.getBean(SecurityService.class); + } + + private void login(String username, String password) { + securityService.authenticate(username, password); + } + + private void transferMoney(BigDecimal amount) { + // create transaction + Transaction transaction = new Transaction(PAYER_ACCOUNT, BENEFICIARY_ACCOUNT, amount); transferService.transferAmount(transaction); + } - AccountManagerService accountService = context.getBean(AccountManagerService.class); - Account payerAccount = accountService.findByNumber("12345678901234"); - Account beneficiaryAccount = accountService.findByNumber("12345678909876"); + private void printAccountsBalance() { + // check accounts + Account payerAccount = accountService.findByNumber(PAYER_ACCOUNT); + Account beneficiaryAccount = accountService.findByNumber(BENEFICIARY_ACCOUNT); + // print details + System.out.println("--- ACCOUNT BALANCE ---"); System.out.println(payerAccount); System.out.println(beneficiaryAccount); } + + private void cleanUp() { + SecurityContext.clear(); + } + } diff --git a/src/main/java/app/aop/security/Authenticated.java b/src/main/java/app/aop/security/Authenticated.java new file mode 100644 index 0000000..7b7d719 --- /dev/null +++ b/src/main/java/app/aop/security/Authenticated.java @@ -0,0 +1,14 @@ +package app.aop.security; + +import java.lang.annotation.*; + +/** + * Used to mark behaviors which should be executed only if authentication occur. + * + * @author dvizireanu + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Authenticated { +} diff --git a/src/main/java/app/aop/security/SecurityAspect.java b/src/main/java/app/aop/security/SecurityAspect.java new file mode 100644 index 0000000..c6e3c2e --- /dev/null +++ b/src/main/java/app/aop/security/SecurityAspect.java @@ -0,0 +1,22 @@ +package app.aop.security; + +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.springframework.stereotype.Component; + +/** + * Security aspect which check authentication / authorization in order to allow the access/execution of targeted resources. + * + * @author dvizireanu + */ +@Aspect +@Component +public class SecurityAspect { + + @Before("@annotation(Authenticated)") + public void secure() { + if (!SecurityContext.isAuthenticated()) { + throw new app.exception.SecurityException("Not authenticated !"); + } + } +} diff --git a/src/main/java/app/aop/security/SecurityContext.java b/src/main/java/app/aop/security/SecurityContext.java new file mode 100644 index 0000000..fd1cfca --- /dev/null +++ b/src/main/java/app/aop/security/SecurityContext.java @@ -0,0 +1,23 @@ +package app.aop.security; + +/** + * Security context, which holds information about logged user. + * + * @author dvizireanu + */ +public class SecurityContext { + + private static final ThreadLocal currentUser = new ThreadLocal<>(); + + public static boolean isAuthenticated() { + return currentUser.get() != null; + } + + public static void setCurrentUser(String username) { + currentUser.set(username); + } + + public static void clear() { + currentUser.remove(); + } +} diff --git a/src/main/java/app/exception/SecurityException.java b/src/main/java/app/exception/SecurityException.java new file mode 100644 index 0000000..faac6bc --- /dev/null +++ b/src/main/java/app/exception/SecurityException.java @@ -0,0 +1,13 @@ +package app.exception; + +/** + * Exception describing an security error case. + * + * @author dvizireanu + */ +public class SecurityException extends RuntimeException { + + public SecurityException(String message) { + super(message); + } +} diff --git a/src/main/java/app/service/AccountManagerService.java b/src/main/java/app/service/AccountServiceImpl.java similarity index 83% rename from src/main/java/app/service/AccountManagerService.java rename to src/main/java/app/service/AccountServiceImpl.java index 6098531..6291f8c 100644 --- a/src/main/java/app/service/AccountManagerService.java +++ b/src/main/java/app/service/AccountServiceImpl.java @@ -1,24 +1,29 @@ package app.service; +import app.aop.security.Authenticated; import app.domain.Account; import app.repository.AccountRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.List; @Service -public class AccountManagerService implements AccountService { +@Transactional +public class AccountServiceImpl implements AccountService { private AccountRepository accountRepository; @Autowired - public AccountManagerService(AccountRepository accountRepository) { + public AccountServiceImpl(AccountRepository accountRepository) { this.accountRepository = accountRepository; } + @Authenticated + @Transactional(readOnly = true) @Override public Account findByNumber(String number) { List accounts = accountRepository.findByNumber(number); @@ -31,6 +36,7 @@ public Account findByNumber(String number) { return accounts.get(0); } + @Authenticated @Override public void save(Account account) { int count = accountRepository.insert(account); @@ -42,6 +48,7 @@ public void save(Account account) { } } + @Authenticated @Override public void updateMoneyAmount(Account account) { int count = accountRepository.updateMoneyAmount(account); diff --git a/src/main/java/app/service/SecurityService.java b/src/main/java/app/service/SecurityService.java new file mode 100644 index 0000000..c316771 --- /dev/null +++ b/src/main/java/app/service/SecurityService.java @@ -0,0 +1,17 @@ +package app.service; + +/** + * Service responsible of authenticating and authorizing an user. + * + * @author dvizireanu + */ +public interface SecurityService { + + /** + * Authenticate user. + * + * @param username + * @param password + */ + void authenticate(String username, String password); +} diff --git a/src/main/java/app/service/SecurityServiceImpl.java b/src/main/java/app/service/SecurityServiceImpl.java new file mode 100644 index 0000000..658c5e9 --- /dev/null +++ b/src/main/java/app/service/SecurityServiceImpl.java @@ -0,0 +1,23 @@ +package app.service; + +import app.aop.security.SecurityContext; +import app.exception.SecurityException; +import org.springframework.stereotype.Service; + +/** + * @author dvizireanu + */ +@Service +public class SecurityServiceImpl implements SecurityService { + + @Override + public void authenticate(String username, String password) { + + if ("guest".equals(username) && "endava".equals(password)) { + SecurityContext.setCurrentUser(username); + } else { + throw new SecurityException("Wrong credentials !"); + } + + } +} diff --git a/src/main/java/app/service/TransactionManagerService.java b/src/main/java/app/service/TransactionServiceImpl.java similarity index 74% rename from src/main/java/app/service/TransactionManagerService.java rename to src/main/java/app/service/TransactionServiceImpl.java index 6cf3ab8..a0b2374 100644 --- a/src/main/java/app/service/TransactionManagerService.java +++ b/src/main/java/app/service/TransactionServiceImpl.java @@ -1,21 +1,25 @@ package app.service; +import app.aop.security.Authenticated; import app.domain.Transaction; import app.repository.TransactionRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @Service -public class TransactionManagerService implements TransactionService { +@Transactional +public class TransactionServiceImpl implements TransactionService { private TransactionRepository transactionRepository; @Autowired - public TransactionManagerService(TransactionRepository transactionRepository) { + public TransactionServiceImpl(TransactionRepository transactionRepository) { this.transactionRepository = transactionRepository; } + @Authenticated @Override public void save(Transaction transaction) { int count = transactionRepository.insert(transaction); diff --git a/src/main/java/app/service/MoneyTransferService.java b/src/main/java/app/service/TransferServiceImpl.java similarity index 78% rename from src/main/java/app/service/MoneyTransferService.java rename to src/main/java/app/service/TransferServiceImpl.java index 0cff135..0f14152 100644 --- a/src/main/java/app/service/MoneyTransferService.java +++ b/src/main/java/app/service/TransferServiceImpl.java @@ -1,25 +1,30 @@ package app.service; +import app.aop.security.Authenticated; import app.domain.Account; import app.domain.Transaction; import app.util.TransactionValidator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; @Service -public class MoneyTransferService implements TransferService { +@Transactional +public class TransferServiceImpl implements TransferService { private AccountService accountService; private TransactionService transactionService; @Autowired - public MoneyTransferService(AccountService accountService, TransactionService transactionService) { + public TransferServiceImpl(AccountService accountService, TransactionService transactionService) { this.accountService = accountService; this.transactionService = transactionService; } + @Authenticated + @Transactional(timeout = 5) @Override public void transferAmount(Transaction transaction) { diff --git a/src/main/resources/spring/aop-config.xml b/src/main/resources/spring/aop-config.xml new file mode 100644 index 0000000..4544b6b --- /dev/null +++ b/src/main/resources/spring/aop-config.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/src/main/resources/spring/database-config.xml b/src/main/resources/spring/database-config.xml index fd24228..0c899c6 100644 --- a/src/main/resources/spring/database-config.xml +++ b/src/main/resources/spring/database-config.xml @@ -9,7 +9,7 @@ - + diff --git a/src/main/resources/spring/tx-config.xml b/src/main/resources/spring/tx-config.xml new file mode 100644 index 0000000..bf9b017 --- /dev/null +++ b/src/main/resources/spring/tx-config.xml @@ -0,0 +1,13 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/app/service/AccountManagerServiceTest.java b/src/test/java/app/service/AccountManagerServiceTest.java index 5fe49a1..aa9fbe8 100644 --- a/src/test/java/app/service/AccountManagerServiceTest.java +++ b/src/test/java/app/service/AccountManagerServiceTest.java @@ -29,7 +29,7 @@ public class AccountManagerServiceTest { private static Account ACCOUNT = new Account(ACCOUNT_NUMBER, ACCOUNT_NAME, ACCOUNT_MONEY_AMOUNT); @InjectMocks - private AccountManagerService accountService; + private AccountServiceImpl accountService; @Mock private AccountRepository accountRepository; diff --git a/src/test/java/app/service/MoneyTransferServiceTest.java b/src/test/java/app/service/MoneyTransferServiceTest.java index 7d432ab..3457d79 100644 --- a/src/test/java/app/service/MoneyTransferServiceTest.java +++ b/src/test/java/app/service/MoneyTransferServiceTest.java @@ -24,7 +24,7 @@ public class MoneyTransferServiceTest { private static Transaction TRANSACTION = new Transaction(PAYER_ACCOUNT_NUMBER, BENEFICIARY_ACCOUNT_NUMBER, MONEY_AMOUNT); @InjectMocks - private MoneyTransferService transferService; + private TransferServiceImpl transferService; @Mock private TransactionService transactionService; diff --git a/src/test/java/app/service/TransactionManagerServiceTest.java b/src/test/java/app/service/TransactionManagerServiceTest.java index 56f6674..b1ed028 100644 --- a/src/test/java/app/service/TransactionManagerServiceTest.java +++ b/src/test/java/app/service/TransactionManagerServiceTest.java @@ -26,7 +26,7 @@ public class TransactionManagerServiceTest { private static final Transaction TRANSACTION = new Transaction(PAYER_ACCOUNT_NUMBER, BENEFICIARY_ACCOUNT_NUMBER, MONEY_AMOUNT); @InjectMocks - private TransactionManagerService transactionService; + private TransactionServiceImpl transactionService; @Mock private TransactionRepository transactionRepository; From decc1848dfe5c9bdb258978782042c549fd69608 Mon Sep 17 00:00:00 2001 From: vizdragos Date: Thu, 10 Apr 2014 16:36:52 +0300 Subject: [PATCH 4/7] spring aop example --- src/main/java/app/Main.java | 1 - src/main/java/app/service/AccountServiceImpl.java | 3 --- .../java/app/service/TransactionServiceImpl.java | 2 -- src/main/java/app/service/TransferServiceImpl.java | 3 --- src/main/resources/spring/tx-config.xml | 13 ------------- 5 files changed, 22 deletions(-) delete mode 100644 src/main/resources/spring/tx-config.xml diff --git a/src/main/java/app/Main.java b/src/main/java/app/Main.java index 10e8523..e9959ac 100644 --- a/src/main/java/app/Main.java +++ b/src/main/java/app/Main.java @@ -38,7 +38,6 @@ public static void main(String[] args) { private void loadContext() { context = new ClassPathXmlApplicationContext("/spring/application-config.xml", "/spring/aop-config.xml", - "/spring/tx-config.xml", "/spring/database-config.xml"); } diff --git a/src/main/java/app/service/AccountServiceImpl.java b/src/main/java/app/service/AccountServiceImpl.java index 6291f8c..13f6db0 100644 --- a/src/main/java/app/service/AccountServiceImpl.java +++ b/src/main/java/app/service/AccountServiceImpl.java @@ -7,12 +7,10 @@ import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import java.util.List; @Service -@Transactional public class AccountServiceImpl implements AccountService { private AccountRepository accountRepository; @@ -23,7 +21,6 @@ public AccountServiceImpl(AccountRepository accountRepository) { } @Authenticated - @Transactional(readOnly = true) @Override public Account findByNumber(String number) { List accounts = accountRepository.findByNumber(number); diff --git a/src/main/java/app/service/TransactionServiceImpl.java b/src/main/java/app/service/TransactionServiceImpl.java index a0b2374..3d44e9b 100644 --- a/src/main/java/app/service/TransactionServiceImpl.java +++ b/src/main/java/app/service/TransactionServiceImpl.java @@ -6,10 +6,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; @Service -@Transactional public class TransactionServiceImpl implements TransactionService { private TransactionRepository transactionRepository; diff --git a/src/main/java/app/service/TransferServiceImpl.java b/src/main/java/app/service/TransferServiceImpl.java index 0f14152..0611ccd 100644 --- a/src/main/java/app/service/TransferServiceImpl.java +++ b/src/main/java/app/service/TransferServiceImpl.java @@ -6,12 +6,10 @@ import app.util.TransactionValidator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; @Service -@Transactional public class TransferServiceImpl implements TransferService { private AccountService accountService; @@ -24,7 +22,6 @@ public TransferServiceImpl(AccountService accountService, TransactionService tra } @Authenticated - @Transactional(timeout = 5) @Override public void transferAmount(Transaction transaction) { diff --git a/src/main/resources/spring/tx-config.xml b/src/main/resources/spring/tx-config.xml deleted file mode 100644 index bf9b017..0000000 --- a/src/main/resources/spring/tx-config.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - \ No newline at end of file From 49f96ea863b3861c63bc0db3e70c34f57c30f03b Mon Sep 17 00:00:00 2001 From: vizdragos Date: Thu, 10 Apr 2014 16:38:46 +0300 Subject: [PATCH 5/7] spring aop example --- README.md | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/README.md b/README.md index 0db4df9..eab6a2e 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,2 @@ -SpringCore +Spring AOP ========== -example with xml metadata configuration - -//homework - review code, ask questions - -//homework - change constructor injection with setter injection, what about field injection - -//homework - do validation for AccountMapper class - -//homework - do validation for Transaction Validator From 2d57fec48a648077af8a57a67e49637f032a8580 Mon Sep 17 00:00:00 2001 From: vizdragos Date: Thu, 10 Apr 2014 17:09:05 +0300 Subject: [PATCH 6/7] spring aop exercise --- README.md | 14 ++++++++++++++ src/main/java/app/aop/security/SecurityAspect.java | 6 +++--- src/main/java/app/service/TransferServiceImpl.java | 2 +- src/main/resources/spring/aop-config.xml | 2 +- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index eab6a2e..c8b5e84 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,16 @@ Spring AOP ========== + +There is defined an @Authenticated annotation, for which there needs to be created and applied the SecurityAspect. + +For this to happen, you need to: + +1. in aop-config.xml enable @AspectJ support + +2. make SecurityAspect class as aspect + +3. make SecurityAspect class candidate for bean detection + +4. annotate TransferServiceImpl#transferAmount(...) with @Authenticated + +5. define SecurityAspect#secure() as advice and also define it's pointcut that should intercept all methods annotated with @Authenticated diff --git a/src/main/java/app/aop/security/SecurityAspect.java b/src/main/java/app/aop/security/SecurityAspect.java index c6e3c2e..2c6cd37 100644 --- a/src/main/java/app/aop/security/SecurityAspect.java +++ b/src/main/java/app/aop/security/SecurityAspect.java @@ -9,11 +9,11 @@ * * @author dvizireanu */ -@Aspect -@Component +// TODO -> 2. make class as aspect +// TODO -> 3. make class as aspect public class SecurityAspect { - @Before("@annotation(Authenticated)") + // TODO -> 5. define it as advice and also define it's pointcut that should intercept all methods annotated with @Authenticated public void secure() { if (!SecurityContext.isAuthenticated()) { throw new app.exception.SecurityException("Not authenticated !"); diff --git a/src/main/java/app/service/TransferServiceImpl.java b/src/main/java/app/service/TransferServiceImpl.java index 0611ccd..8301458 100644 --- a/src/main/java/app/service/TransferServiceImpl.java +++ b/src/main/java/app/service/TransferServiceImpl.java @@ -21,7 +21,7 @@ public TransferServiceImpl(AccountService accountService, TransactionService tra this.transactionService = transactionService; } - @Authenticated + // TODO -> 4. annotate to secure method @Override public void transferAmount(Transaction transaction) { diff --git a/src/main/resources/spring/aop-config.xml b/src/main/resources/spring/aop-config.xml index 4544b6b..8591b21 100644 --- a/src/main/resources/spring/aop-config.xml +++ b/src/main/resources/spring/aop-config.xml @@ -4,6 +4,6 @@ xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> - + \ No newline at end of file From 0861221041bafba8aee77e40c42cbf16728ea614 Mon Sep 17 00:00:00 2001 From: vizdragos Date: Thu, 10 Apr 2014 17:10:21 +0300 Subject: [PATCH 7/7] spring aop exercise --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c8b5e84..9a0599a 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ There is defined an @Authenticated annotation, for which there needs to be creat For this to happen, you need to: -1. in aop-config.xml enable @AspectJ support +1. enable @AspectJ support in aop-config.xml 2. make SecurityAspect class as aspect