Fancy UI

All About Crazy IT Stuff

Spring / GWT Software Architecture for scalable applications – Part 2

with 7 comments

During this article you will learn how to build efficiently and quickly the backend (based upon the solution described on part one : http://goo.gl/T2pLQ) that is going to be used later by any kind of clients (GWT, Android,…). My aim is to guide step by step on building an example application and gives you all the best practices on each step to achieve high quality code.

Specifically, you will do the following in this article:

  • Methodology based on UI prototyping to define the service layer of the application (how many services, what functionality’s they must offer…)
  • Setting up the infrastructure of the project : libraries, configuration files, logger…
  • Setting up the persistence layer : business entities, persistence related configuration files…
  • Setting up the DAO layer using Spring Data API : bind queries to DAO methods, conventional DAO method naming.
  • Setting up the service layer : transaction configuration, security configuration.
  • Setting up Test classes using JUnit and Spring Test.

Extracting services

From my experience the best way to determine the required services is by establishing first all the UI prototype for your web application, the next step is to analyze all prototypes carefully and try to form groups of coherent and consistent features which are our services.

Below UI prototype of the application we are going to build during this prototype :

From this annotated UI prototype you can clearly see that we have tow services, one for managing Transactions and the other for Accounts. Each services contain the following methods :

  • Transaction service contain a reference to TransactionRepo and AccountRepoand have the following methods :
    • add(Transaction new) : for adding a new transaction, it should also update the account balance.
    • loadTransactionByAccountId(accountId, period, type) : load transactions of the selected account and selected period (this month, this quarter, this year…) and type filter (income, expense, all).
    • loadTotalAmountByAccountId(accountId, period, type) : calculate the total amount of transactions of the selected account and selected period and type filter.
  • Account service contain a reference to AccountRepo and TransactionRepo have the following methods :
    • loadAll() : load all accounts.
    • add(Account new) : for adding a new account, if the initial balance is specified should create a new Income transaction attached to this account.

Back end infrastructure

In order to speed up the project setup (libraries, log4j setting, applicationContext…) I choose to use Spring Roo which will prepare all required infrastructure code for a spring based project. On this project I’m going to use the following  libraries and tools :

  • MongoDB : I choose to use a NoSQL database instead of the old relational one (Just a personal preference). For more information about how to setup the latest version of MongoDB on Ubuntu  see http://goo.gl/x4hBD.
  • Spring ROO 1.2 the first version that support MongoDB code generation and service oriented architecture see http://goo.gl/jvw4w for more information.
  • I’ll be using SpringSource Tool Suite 2.8.1 as IDE which is the best environment to build Spring powered applications, see http://goo.gl/ooe2.

To prepare our project, in STS create a new ROO project, give it a name and the topLevelPackage, then ROO generate automatically all required files (Log4j, applicationsContext, pom.xml,…) for a Spring project, normally this project works out of the box.

Business entities setup

From the ROO shell we are going to setup mongo database and create our tow business entities (Account and Transaction) :

//Setting up mongo add-on
mongo setup

//Creating the Account entity
entity mongo --class ~.domain.Account
field string --fieldName name --notNull
field number --fieldName balance --type double

//Creating the Transaction entity
entity mongo --class ~.domain.Transaction
field string --fieldName payee
field other --fieldName accountId --type org.bson.types.ObjectId
field date --fieldName dateTransaction --type java.util.Date --notNull
field string --fieldName tags
field string --fieldName type --notNull
field number --fieldName amount --type double

You did notice that the Transaction entity hold the ObjectID of the Account (because there is a one to many relation between the tow entities), to simplify things I prefer to manage this association manually without using advanced concept like DBRef or embedded lists.

Repository layer setup

Beginning from Spring ROO 1.2, there is support for generating Spring Data repositories (service oriented architecture).

The generated DAO’s offer simple database access methods (create, update, findAll…), we can add our own custom methods by following naming convention no implementation code need (see http://goo.gl/Z2wJs for more details) or if we have complexes queries with some business logic we declare them in the Repository interface and write theirs implementation (see http://goo.gl/DfQmu).

From ROO shell I’m going to create tow empty DAO one to manage Account and the other for Transaction :

//Account Repository
repository mongo --interface ~.repository.AccountRepo --entity ~.domain.Account

//Transaction Repository
repository mongo --interface ~.repository.TransactionRepo --entity ~.domain.Transaction

Theses repositories contain only standard methods offered by MongoRepository abstract class (more detail http://goo.gl/wDbR1) we still need to add our custom methods for both AccountRepository and TransactionRepository manually.

Account repository

From the list of methods extracted (loadAll, add) in the Account service we see that they already exists on the MongoRepository, except that when adding a new transaction we need to update the current balance of the account attached to the transaction, this can’t be done with just a conventional naming DAO method.

//DAO methods without implementation code : conventional naming
@RooMongoRepository(domainType = Account.class)
public interface AccountRepo extends AccountRepoAdvance {
    List<Account> findAll();

    Account findByName(String name);
}

//Advanced DAO methods which required implementation code
public interface AccountRepoAdvance {
    void updateAccountBalance(BigInteger accountId, Double transactionAmount, String type);
}

public class AccountRepoImpl implements AccountRepoAdvance {
    @Autowired
    MongoOperations mongoOps;

    public void updateAccountBalance(BigInteger accountId, Double transactionAmount, String type) {
        //Implementation code Here...
    }
}

Transaction repository

On this repository we need a conventional method to load transactions by accountId, period and type (no need for code implementation), this method have to be called findByAccountIdAndDateBetweenAndTypeLike this name will be parsed by Spring Data in order to generate the query on the fly.

Spring Data conventional naming

The last required DAO method is totalAmountByAccountId, this one is an aggregation query and will use the group feature of MongoDB. This method can’t be implemented using the conventional naming way because we have to use the MongoOperations object to execute this kind of more advanced queries.

Below a snippet of code source for TransactionRepository :

//DAO methods without implementation code : conventional naming
@RooMongoRepository(domainType = Transaction.class)
public interface TransactionRepo extends TransactionAdvancedRepo {
    List<Transaction> findByAccountIdAndDateBetweenAndTypeLike(ObjectId accountId,
            Date start, Date end, String type);
}

//Advanced DAO methods which required implementation code
public interface TransactionAdvancedRepo {
    Double totalAmountByAccountId(ObjectId accountId, Date start,Date end, String type);
}

class TransactionAdvancedImpl implements TransactionAdvancedRepo {
    @Autowired
    MongoOperations mongoOps;

    public Double totalAmountByAccountId(.....) {
        //Implementation code Here...
    }
}

Check out this great cheat sheet http://goo.gl/B56w if you are an experienced SQL programmer and want to learn how to write MongoDB queries.

Service layer setup

The final step on this tutorial is to setup the service layer, this layer use services offered by the repository (plain simple CRUD and querying methods)  and add to them the business logic. For example when adding a new transaction we are going to use the method save of the repository TransactionRepo but also we need to assure that the balance of the account attached to this transaction is updated (this is the business logic to control).

I’m going  also to use ROO to generate the service layer, by typing the following commands :

//Account Service
service --entity ~.domain.Account --interface ~.service.AccountService

//Transaction Service
service --entity ~.domain.Transaction --interface ~.service.TransactionService
ROO will generate nice and clean services holding a reference for the required repository (all this code is hidden in generated aspects, it is just an infrastructure code). Below the source code of the generated interfaces along with extracted methods described earlier :
@RooService(domainTypes = { Account.class })
public interface AccountService {
    void addNewAccount(Account account);
    List<Account> loadAllAccounts();
}

//The TransactionService require both Transaction and Account repositories
@RooService(domainTypes = { Transaction.class, Account.class })
public interface TransactionService {
    void addNewTransaction(Transaction transaction);
    List<Transaction> loadTransactionsByAccountId(BigInteger accountId, Integer period,
            String type);
    Double loadTotalAmountByAccountId(BigInteger accountId, Integer period, String type);
}
I’m not going to describe in here the implementation code of the service, at the end of this article there is an archive containing the whole project.

Testing Services and repositories

The last step on this article, is to test if everything works the way we want, this is a very crucial step on building a great and organized service layer, and generally on this step sometimes we intend to tweak a little bit the repositories, entities and services if we forgot something in step 1.

Because we are working on a little example, all what I’m going to show is how to test services and see if they works correctly using JUnit and Spring Test (for more details visit http://goo.gl/lcUza), for more details see the code below  :

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath*:META-INF/spring/applicationContext.xml",
                                 "classpath*:META-INF/spring/applicationContext-mongo.xml"})
public class TestServices {
    @Autowired AccountRepo accountRepository;
    @Autowired TransactionRepo transactionRepository;
    @Autowired AccountService accountService;
    @Autowired TransactionService transactionService;

    @Test
    public void cleaningOldData() {
        accountRepository.deleteAll();
        transactionRepository.deleteall();
    }

    @Test
    public void testCreatingAccount() {
        //Test creating new Account here...
    }

    //... More Test Methods here, check attached source code for more details
}

That’s it for this article, I hop that you have a big picture of the back end part, this is just a little example but I think it will help some of you to build easily high quality application very quickly. I’m open to any suggestion or enhancement.

Full Project source code can be downloaded from here : Project source.

Written by imrabti

January 2, 2012 at 11:35 am

7 Responses

Subscribe to comments with RSS.

  1. […] Spring / GWT Software Architecture for scalable applications – Part 2 « Fancy UI – During this article you will learn how to build efficiently and quickly the backend (based upon the solution described on part one) that is going to be used later by any kind of clients (GWT, Android,…). My aim is to guide step by step on building an example application and gives you all the best practices on each step to achieve high quality code. […]

  2. It would be very helpful if you put a link in each article referencing the previous and next article in the series.

    Allan

    January 6, 2012 at 2:28 pm

  3. The full project source code link is missing the GWT code.

    Chris Jansen

    January 24, 2012 at 2:28 pm

    • There is no GWT code yet. I’m working on Part3 which will describe how to write GWT client for the given server side.

      imrabti

      January 24, 2012 at 2:45 pm

  4. Didn’t you try the firing the GWT Roo add-on (at least, to bootstrap most of the tedious work) ?

    John

    February 29, 2012 at 4:43 pm

    • Yes I have, but there is so much Boilerplate code everything is generic and complicated, I did take some code from the generated code and adapt it.

      imrabti

      May 11, 2012 at 10:47 am

  5. the full project source code link is not working

    pvr

    April 5, 2014 at 9:10 am


Leave a reply to John Cancel reply