Command Pattern / Scala / AOP

Please read Cross Cutting Concerns in Scala as well.

Assumption:
We have a JAX-RS (REST) resource and a updateUserInfo service located at the URL . . ./UserInfo. Every call to this service requires a database transaction that is “manually” created.

The question is: How do we handle this transaction scope (and how do we handle nested scopes)?

Java with GOF Command Pattern

One solution is the Gang of Four pattern Command (GOF Command Pattern).

Our update business code is encapsulated into a anonymous class with a method execute().

@PUT
@Path("UserInfo")
public void updateUserInfo(UserInfo ui) {
  withTrxAndCommit( new Command() {
    public void execute() {
      em.merge(ui);
    });
}

The method withTrxAndCommit calls the execute() method and surrounds it with the necessary transaction logic.

public void withTrxAndCommit(Command c) {
    boolean trxStartedHere = beginOrUseTrx();
    try {
      c.execute();
      if (trxStartedHere)
        commitTrx();
    }
    catch (Throwable t) {
	  . . .
	  throw t;
	}
}

The issues here are:

  • This does not look nice
  • we have a void return value (of course we can return Object, but we are loosing type safety then)
  • it would be tricky to use a flexible (several Command implementations coming from different independent libraries) and nested Command Pattern, isn’t it?

AspectJ with Annotations

If we consider the transaction code as Crosscutting Concerns, it is one possibility to use Aspect-oriented Programming. Defining a transaction around Aspects helps to separate the concern “transaction” from our business code.
Further there is no problem to use nested around aspects. In this case we are using an ExceptionWrapper to ensure that a possible transaction exception is properly mapped into a HTTP error code.

To ease the definition of the Pointcuts it makes sense to define Annotations where we can “point” to in our Pointcut expression.

@PUT
@Path("UserInfo")
@ExceptionWrapper
@WithTrxAndCommit
public void updateUserInfo(UserInfo ui) {
  em.merge(ui);
}

TrxAndCommitAspect with the necessary transaction code again:

public aspect TrxAndCommitAspect {
	pointcut trx():
      call(* *.update*(..)) && 
      @annotation(WithTrxAndCommit);

    Object around():trx() {
      boolean trxStartedHere = beginOrUseTrx();
      try {
        proceed();
        if (trxStartedHere)
          commitTrx();
       }
       catch (Throwable t) {
	     . . .
	     throw t;
	   }
	}
}

The ExceptionWrapperAspect uses the precedence statement to define which Aspects comes first (it is obvious that it makes a big difference which one is the inner Aspect).

public aspect ExceptionWrapperAspect {
	declare precedence: . . .
	pointcut . . . 
@annotation(ExceptionWrapper);
}

Aspects support easy replacement of advice code by runtime weaving of Aspects, which is a very flexible and powerful feature. F. e. one startup script starts the application with JNDI transactions and one other with local managed transactions.
You simply have to provide a javaagent for load time weaving. That increases application start time. (Only) for server applications not a real problem.

Scala with Traits

Scala is a modern functional language, so:

  • instead of Annotations we are using method calls with closures (no need to write more text)
  • using the cake pattern (or here) we can “inject” several implementations at compile time
  • traits do support application modularization
  • traits do not interfere with a given class hierarchy
  • type parameter together with type inference ensure type safety

updateUserInfo shows that we can use the traits methods in a type safe way. The business code has to return a UserInfo instance. If not, we will get a compile error.

@PUT
@Path("UserInfo")
def updateUserInfo(ui: UserInfo): UserInfo = {
  exceptionWrapper {
    withTrxAndCommit {
      em.merge(ui)
      ui
    }
  }
}

trait with the transaction code:

trait TransactionHandling {
 def withTrxAndCommit[T](f: => T): T = {
    var trxStartedHere = beginOrUseTrx
    try {
	  val ret = f
	  if (trxStartedHere)
	    commitTrx
	  ret
	}
	catch {
		case t: Throwable => {
			. . .
			throw t
		}
	}
 }
}

and the code for the Exception Wrapper:

trait ExceptionWrappers {
def exceptionWrapper[T](f: => T) = {
    try {
      f
    }
    catch {
      . . .
      case e: Throwable =>
        throw new MyHTTPExceptionMapper(e)
    }
  }
}

Comments are closed.