Declarative Programming with Annotation

Leave a comment

June 19, 2010 by huionn

Last month, I was asked to attend a free Business Rule Management System (BRMS) workshop. From the workshop, I learnt that rule engine is good for

  1. externalizing business rules so that they can be modified by non-technical business analysts/domain experts
  2. business rules that change frequently as the rules can be written, tested and deployed on-the-fly

To me, the benefits do not justify the cost and complexity of applying BRMS in the system I am developing – no complex rule and the rules are static.

Two weeks ago,  I went to watch a vendor demo whose system has a in-house ‘rule engine’.  The rule engine is quite limited in functionalities compared with full fledged BRMS. However it did show a good benefit of rule engine – visibility and transparency.

After a user perform a transaction, he can view the fired and un-fired rules. This feature is good for verification by QA or end users.


A few days ago, I attended a in-house training about our system. There is pricing policies by category for amount/discount (absolute value or percentage). The pricing policies are setup and stored in a database table. The logic itself is straightforward, but it can be easily obscured by other rules and policies.

I am thinking whether declarative design (Domain Driven Design) can help…

Generally, a rule consists of conditions and actions

Rule:
    if
        condition(s)
    then
        actions

Code snippets:

@Rule
public class PricingRule {
    private String category;
    …

    @Condition(“patient in category #{category}”)
    public boolean isQualified(Category c) {
        ……

    }
    
    @Action(returnValue=”new price”)
    public BigDecimal calculatePrice(Category c, BigDecimal originalPrice) {
        …..

        return newPrice;
    }

         ….

where @Rule is a Seam component annotation to define its interceptor

@Target(TYPE)
@Retention(RUNTIME)
@Interceptors(RuleInterceptor.class)
public @interface Rule{}

My idea is that, by using Seam interceptor, RuleInterceptor will intercept method annotated with @Condition and @Action. If he methods annotated with @Condition (return true) and @Action are invoked, this rule is registered as ‘fired’ in current context. If only @Condition is invoked (its return value is false), it is registered as ‘unfired’. So, when the user view the fired rules, he can see it as “patient in category A1, new price is $180”.


After testing the idea, unfortunately Seam interceptor is not an ideal solution. There are a few limitations:

  1. Interceptor is only be invoked when the public method is called by external client. The method called by the intercepted object itself will not be intercepted.
    (reference: http://seamframework.org/Documentation/WhyIsntBijectionRunOnInternalMethodCalls)
  2. The intercepted object need to be instantiated by using Component.forName(“componentName”).newInstance(). Although it can be encapsulated into a builder class, the client need to do extra work and only default constructor will be used.

A more powerful AOP such as AspectJ is required for build-time weaving or load-time weaving, so that the rule tracking aspect is totally transparent to client.

I found out that there is one more advantage in using AspectJ – a new aspect instance can be associated with each new execution object using perthis()

code snippets:

public aspect RuleTrackingAspect perthis(ruleOperation()) {
    public pointcut ruleOperation() : conditionOperation() || actionOperation();

    pointcut conditionOperation() : execution(@Condition * @Rule *.*(..));

    pointcut actionOperation() : execution(@Action * @Rule *.*(..));

    Object around() : conditionOperation() {
        Object ret = proceed();
        processCondition(thisJoinPoint, ret);
        return ret;
    }

    Object around() : actionOperation() {
        Object ret = proceed();
        processAction(thisJoinPoint, ret);
        return ret;
    }

……

It was tested successfully in JBoss AS with Seam using build-time weaving. Later I will try with load-time weaving as this is the weaving model I am going to use…

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: