Wednesday, 23 September 2009

Qi4j - First application

Qi4j LogoIn the previous post I've shown how to set up Qi4j project with maven. In this post I'll show how to create application which will slowly evolve into basic rational number calculator in the future. I realize that using Qi4j in such simple application is an overkill but I think it's suitable for showing the basics. Qi4j derives many concepts from the famous Domain Driven Design. According to DDD principles an application should be comprised of layers. Each layer can have one or more modules. Qi4j uses assemblers to define application structure, layers, modules and dependencies between them. Assemblers are classes derived from interface org.qi4j.bootstrap.Assembler. In this simple application we'll use SingletonAssembler which instantiates one layer with one module inside. Step 1. Create application class. Create new class SimpleQi4jApplication in the package com.blogspot.javasnippet.qi4j which is located under directory src/main/java.
package com.blogspot.javasnippet.qi4j;

public class SimpleQi4jApplication {

    public static void main(final String[] args) {


    }

}
Step 2. Add SingletonAssembler.
public class SimpleQi4jApplication {

    public static void main(final String[] args) {
        SingletonAssembler assembler = new SingletonAssembler() {

            @Override
            public void assemble(ModuleAssembly module) throws AssemblyException {

            }
        };

    }
}
SingletonAssembler is an abstract class with abstract method assemble left to be implemented. I don't have anything to be assembled at the moment so I'm leaving it empty. Step 3. Activate application. Qi4j application has simple life-cycle. It can be activated and deactivated.
public class SimpleQi4jApplication {

    public static void main(final String[] args) throws Exception {
        SingletonAssembler assembler = new SingletonAssembler() {

            @Override
            public void assemble(ModuleAssembly module) throws AssemblyException {

            }
        };

        ApplicationSPI application = assembler.application();
    }
}
Now we can start this doing-nothing application. (I've added throws Exception to main() method for the sake of simplicity). We don't have to activate application explicitly because SingletonAssembler does this automatically. Step 3. Create composite. Let's model the rational number. Each rational number can be expressed as a ratio nominator/denominator, where both nominator and denominator are integers. Here is Rational interface created with Qi4j goodies.
import org.qi4j.api.property.Property;
import org.qi4j.api.value.ValueComposite;

public interface Rational extends ValueComposite {

    Property<Integer> nominator();

    Property<Integer> denominator();

}
Several new features come with this code snippet:
  • The properties are declared as methods with result type Property<Integer>. Qi4j deprecates classic POJO model and replaces it with this simple and powerful concept.
  • Interface Rational extends ValueComposite - this declaration makes Rational a Qi4j composite. In general Qi4j favours composites over objects (in Java meaning) and everything it manages is rather a composite than an object. There are several types of composites supported like value, entity, service and transient. In this example I choose to use value composite - an equivalent of DDD value object.
  • Interface Rational defines only properties - there is no behavior. One of the greatest features of Qi4j is its ability to manage composite state automatically (through generic mixins). That means we don't need to provide any implementation at the moment.
Now we can add Rational composite to the Qi4j runtime.
    public static void main(final String[] args) throws Exception {
        SingletonAssembler assembler = new SingletonAssembler() {

            @Override
            public void assemble(ModuleAssembly module) throws AssemblyException {
                module.addValues(Rational.class);
            }
        };

        ApplicationSPI application = assembler.application();
        application.activate();

        Module module = assembler.module();
        ValueBuilder<Rational> rb;
        rb = module.valueBuilderFactory().newValueBuilder(Rational.class);
        rb.prototype().nominator().set(2);
        rb.prototype().denominator().set(3);
        Rational r1 = rb.newInstance();

        System.out.println(r1.nominator().get() + "/" + r1.denominator().get());
    }
This program prints:
2/3
A lot of code for such easy task, hm? But remember that's just an example :-). There are several things worth to be noted:
  • No constructors - As we don't provide implementation for Rational we can't use constructor. With Qi4j we have to use builders to create new instances.
  • When rb.prototype is mutable the r1 is immutable - that's built-in property of value composites.
In the next post I'll finally implement behavior - operations add and multiply.

0 komentarze: