Chris Richardson - enterprise POJOs

My book

Calendar

««May 2008»»
SMTWTFS
     123
45678910
11121314151617
18192021222324
25262728293031

My Top Tags

                                                                               

My RSS Feeds








 

I run a consulting and training company that helps organizations build better software faster.

We provide a variety of services including:

  • Development - we can build your application for you
  • Deployment - we can find a hosting partner or deploy your application on Amazon EC2
  • Training classes for Spring, Hibernate and Acegi Security
  • Jumpstarts to get your project off to the right start
  • Reviews to improve your architecture, code and development process

For more information contact me.

 

My bookmarks

Mailing List

Latest Entries

Spring Class at Java University; Java User Groups Panel at Community One; Amazon EC2, Cloud Tools and Groovy at JavaOne

Tuesday, 29 April 2008 7:02 A GMT-08

Next week is going to be a busy week:

I hope to see you there!

 

Enhancements to the Cloud Tools Maven plugin for deploying Java EE applications on Amazon EC2

Wednesday, 23 April 2008 7:08 A GMT-08

I recently added some new goals to the Cloud Tools Maven plugin that expand its capabilities:

  • cloudtools:dbsave - save a database snapshot in S3
  • cloudtools:dbrestore - restore the database from S3
  • cloudtools:clone - creates a copy of the cluster
  • cloudtools:describe - describes the cluster showing the instances
  • cloudtools:list - lists the available clusters
  • cloudtools:sql - runs an SQL script

You can also specify the structure of the cluster when using cloudtools:deploy:

  • cloudtools:deploy -Dcloudtools.topology=MultipleInstancesTopology - puts MySql, Tomcat and Apache on separate instances
  • cloudtools:deploy -Dcloudtools.topology=SingleInstanceTopology - puts MySql, Tomcat and Apache on the same instance
Please see the Cloud Tools website for more information.

 

tags:                  

East Bay Java SIG: The eBay Architecture - Striking a balance between site stability, feature velocity, performance and cost

Tuesday, 15 April 2008 1:31 P GMT-08

At the East Bay/Oakland Java SIG on Wednesday night (4/16), Dan Pritchett and Randy Shoup will be talking about the eBay architecture.

System designers constantly struggle with how to build a feature that fulfills product requirements, while keeping the system fluid and maintainable. As product requirements get more and more complicated, tighter integration with existing data and product features becomes increasingly important to keep the negative impact to the user experience at a minimum. If the page or program loads more slowly, while giving the user the rich experience - have we succeeded or failed?

In this session, eBay's Dan Pritchett and Randy Shoup will delve into the strategies and driving principles that guide eBay's development teams across the world. They will talk about real world examples of how these principles will allow you to design what, until now, has been thought to be impossible - scalable, high performance and agile systems that do not get in the way of the organization's feature velocity. The guiding principles, methodology, and patterns are what have allowed eBay to scale a large development organization across four continents.

Attendees will learn:
This session will cover the key enabling design patterns, methodologies, and best practices that allow us to maximize these factors and produce a highly scalable eCommerce platform that is used by millions of people each day. The following questions will be answered:

  • What is eBay's architecture today?
  • What made eBay make the decision to go with Java?
  • What key lessons has eBay learned from scaling Java?
  • Where do we see eBay's architecture going in the future?

The meeting starts at 6.30pm in downtown Oakland.

Reed Smith Law firm
1999 Harrison St
24th Floor
Oakland, CA 94612-3572

See the directions and don't forget to register in order to ensure that we order enough pizza (and to keep building security happy).

The Java SIG meets on the 3rd wednesday of the month and we primarily talk about enterprise Java related topics. In May, Bill Venners (http://www.artima.com/) will be talking about the Scala language and in June Tom Hill will be talking about Lucene and Solr.

I hope to see you there.. 

tags:                

Grails plugin for deploying to Amazon EC2

Monday, 7 April 2008 6:42 A GMT-08

Cloud Tools now includes a plugin for deploying Grails applications to Amazon's Elastic Compute Cloud (EC2). Like the Cloud tools Maven plugin, this plugin makes deploying a web application to EC2 extremely easy. It currently provides the following Grails scripts:

  • cloud-tools-deploy - Launches EC2 instances (MySQL master and slaves, tomcats and Apache) and deploys the web application
  • cloud-tools-describe - Displays information about the instances
  • cloud-tools-redeploy - Redeploys the web application
  • cloud-tools-stop  - Terminates the EC2 instances

I plan to release it in the next few days but in the meantime please contact me if you would like to try it out.

tags:          

Cleaning up your code with real objects, dependency injection and aspects

Wednesday, 13 February 2008 8:05 A GMT-08

Over the past year I've given a few presentations on how to clean up those bloated service classes that are sadly all to common in Java EE applications. A real-world example of this kind of service would be too large to include in a blog so here is an example that is only a minor mess:

public class AccountServiceProceduralImpl implements AccountService {

  private Log logger = LogFactory.getLog(getClass());

  private final AccountDao accountDao;

  private final BankingTransactionDao bankingTransactionDao;

  public AccountServiceProceduralImpl() {
    this.accountDao = new JdbcAccountDao();
    this.bankingTransactionDao = new JdbcBankingTransactionDao();
  }

  public BankingTransaction transfer(String fromAccountId, String toAccountId,
      double amount) {

    BankingSecurityManager.verifyCallerAuthorized(AccountService.class,
        "transfer");

    logger.debug("Entering AccountServiceProceduralImpl.transfer()");

    TransactionManager.getInstance().begin();

    AuditingManager.getInstance().audit(AccountService.class, "transfer",
        new Object[] { fromAccountId, toAccountId, amount });

    try {
      Account fromAccount = accountDao.findAccount(fromAccountId);
      Account toAccount = accountDao.findAccount(toAccountId);
      double newBalance = fromAccount.getBalance() - amount;
      switch (fromAccount.getOverdraftPolicy()) {
      case Account.NEVER:
        if (newBalance < 0)
          throw new MoneyTransferException("Insufficient funds");
        break;
      case Account.ALLOWED:
        Calendar then = Calendar.getInstance();
        then.setTime(fromAccount.getDateOpened());
        Calendar now = Calendar.getInstance();

        double yearsOpened = now.get(Calendar.YEAR) - then.get(Calendar.YEAR);
        int monthsOpened = now.get(Calendar.MONTH) - then.get(Calendar.MONTH);
        if (monthsOpened < 0) {
          yearsOpened--;
          monthsOpened += 12;
        }
        yearsOpened = yearsOpened + (monthsOpened / 12.0);
        if (yearsOpened < fromAccount.getRequiredYearsOpen()
            || newBalance < fromAccount.getLimit())
          throw new MoneyTransferException("Limit exceeded");
        break;
      default:
        throw new MoneyTransferException("Unknown overdraft type: "
            + fromAccount.getOverdraftPolicy());

      }
      fromAccount.setBalance(newBalance);
      toAccount.setBalance(toAccount.getBalance() + amount);

      accountDao.saveAccount(fromAccount);
      accountDao.saveAccount(toAccount);

      TransferTransaction txn = new TransferTransaction(fromAccount, toAccount,
          amount, new Date());
      bankingTransactionDao.addTransaction(txn);

      TransactionManager.getInstance().commit();

      logger.debug("Leaving AccountServiceProceduralImpl.transfer()");
      return txn;
    } catch (MoneyTransferException e) {
      logger.debug(
          "Exception thrown in AccountServiceProceduralImpl.transfer()", e);
      TransactionManager.getInstance().commit();
      throw e;
    } catch (RuntimeException e) {
      logger.debug(
          "Exception thrown in AccountServiceProceduralImpl.transfer()", e);
      throw e;
    } finally {
      TransactionManager.getInstance().rollbackIfNecessary();
    }
  }

  public void create(Account account) {
    BankingSecurityManager.verifyCallerAuthorized(AccountService.class,
        "create");

    logger.debug("Entering AccountServiceProceduralImpl.create()");

    TransactionManager.getInstance().begin();

    AuditingManager.getInstance().audit(AccountService.class, "create",
        new Object[] { account.getAccountId() });

    try {
      accountDao.addAccount(account);

      TransactionManager.getInstance().commit();

      logger.debug("Leaving AccountServiceProceduralImpl.create()");
    } catch (RuntimeException e) {
      logger.debug("Exception thrown in AccountServiceProceduralImpl.create()",
          e);
      throw e;
    } finally {
      TransactionManager.getInstance().rollbackIfNecessary();
    }

  }

}

This code has a few characteristics that make it difficult to maintain and test:

  • Tight coupling - it directly instantiates the DAOs and accesses other infrastructure related classes through static methods or singletons.
  • Tangling - the service contains a mixture of business logic and infrastructure (security/transactions/auditing/logging/etc) code.
  • Scattering - the infrastructure logic is duplicated in every service method
  • Anemic domain model - the "domain objects" are dumb data objects - all of the business logic is concentrated in the bloated service class

Compare and contrast this with a service from version of the same code that uses aspects, dependency injection and a real domain model:

public class AccountServiceImpl implements AccountService {

    private final AccountRepository accountRepository;

    private final BankingTransactionRepository bankingTransactionRepository;

    public MoneyTransferServiceImpl(AccountRepository accountRepository,
            BankingTransactionRepository bankingTransactionRepository) {
        this.accountRepository = accountRepository;
        this.bankingTransactionRepository = bankingTransactionRepository;
    }

    public BankingTransaction transfer(String fromAccountId,
            String toAccountId, double amount) throws MoneyTransferException {
        Account fromAccount = accountRepository.findAccount(fromAccountId);
        Account toAccount = accountRepository.findAccount(toAccountId);
        fromAccount.debit(amount);
        toAccount.credit(amount);
        TransferTransaction txn = new TransferTransaction(fromAccount,
                toAccount, amount, new Date());
        bankingTransactionRepository.addTransaction(txn);
        return txn;
    }
  public void create(Account account) {
    accountRepository.addAccount(account);
  }

}
 

As you can see there are some significant improvements:

  • Simpler code - the service method is a lot smaller
  • Improved separation of concerns - it does not contain any infrastructure-related logic
  • Less coupled - it is written in terms of repository/dao interface
  • More object-oriented - the service contains very little business logic: that's now in the Account class and elsewhere

To find out more take a look at these presentations:

You can also find the example code in my Aspects and Objects project.

 

 

Latest LinkBlogs