Qi4j

Qi4j in 10 minutes

  • Qi4j does not introduce any new programming language, no additional compilers needed and all your existing tools work just like before. It is pure Java 5.
  • Qi4j works with Composites.
  • The equivalent of an Object in OOP, is a Composite instance in Qi4j.
  • Composites are constructed from Fragments.
  • Fragments are Mixins, Concerns, Constraints and SideEffects.
  • Only Mixins carry Composite state. The others are shared between Composite instances.

Composition is done with Java interfaces and Annotations. Example;

@Concerns({PurchaseLimitConcern.class, InventoryConcern.class})
@Mixins( PropertiesMixin.class )
public interface OrderComposite
    extends Order, HasLineItems, Composite
{
}
This Composite is potentially complete. The PropertiesMixin is a so called Generic Mixin, which will handle JavaBeans style setters and getters declared in the Invoice and HasLineItems interfaces. The two Concerns are interceptors that are placed on the methods that the Concerns declare, for instance;
public abstract class InventoryConcern
    implements Invoice
{
    @Service InventoryService inventory;
    @ConcernFor Invoice next;

    public void addLineItem( LineItem item )
    {
        String productCode = item.getProductCode();
        int quantity = item.getQuantity();
        inventory.remove( productCode, quantity );
        next.addLineItem( item );
    }

    public void removeLineItem( LineItem item )
    {
        String productCode = item.getProductCode();
        int quantity = item.getQuantity();
        inventory.add( productCode, quantity );
        next.removeLineItem( item );
    }
}

The InventoryConcern is implemented as an abstract class, since we are not interested in the many other methods in the Invoice interface.
The @ConcernFor annotation is to create the interceptor call chain and each Concern is required to have one and only one such field.
We can also see that the InventoryService is provided to the Concern, which is done with dependency injection. Qi4j also supports dependency injection via constructors and methods.

But Qi4j also support persistence directly in its Core. Simply by changing the interface it extends to EntityComposite;

@Concerns({PurchaseLimitConcern.class, InventoryConcern.class})
@Mixins( PropertiesMixin.class )
public interface OrderComposite
    extends Order, HasLineItems, EntityComposite
{
}
No other changes are needed, provided that the Qi4j Runtime has been setup with one or more persisted stores.
There are other built-in Composite subtypes as well, such as ValueComposite and ServiceComposite. This distinction helps both to communicate intent as well as having more precisely defined functionality.

Now, let's say that we want to send a mail to sales@mycompany.com when the order is confirmed. This is a SideEffect, and will execute after the Constraints, Concerns and Mixins. We add the SideEffect to the OrderComposite;

@SideEffects( MailNotifySideEffect.class )
@Concerns({PurchaseLimitConcern.class, InventoryConcern.class})
@Mixins( PropertiesMixin.class )
public interface OrderComposite
    extends Order, HasLineItem, EntityComposite
{
}
The SideEffect implementation is fairly simple.
public abstract class MailNotifySideEffect
    implements Order
{
    @Service MailService mailer;
    @ThisCompositeAs HasLineItems hasItems;
    @ThisCompositeAs Order order;

    public void confirmOrder()
    {
        List<LineItem> items = hasItems.getLineItems();

        StringBuilder builder = new StringBuilder();
        builder.append( "An Order has been made.\n\n\n" );
        builder.append( "Total amount:" );
        builder.append( order.getOrderAmount() );
        builder.append( "\n\nItems ordered:\n" );
        for( LineItem item : items )
        {
            builder.append( item.getName() );
            builder.append( " : " );
            builder.append( item.getQuantity() );
            builder.append( "\n" );
        }
        mailer.send( "sales@mycompany.com", builder.toString() );
    }
}

The MailService is dependency injected, as we have seen before.

@ThisCompositeAs is telling Qi4j that the SideEffect needs a reference to the Composite instance that it belongs to. By asking for both the Order and the HasLineItems types, we get type-safety and don't need to bother with casts. In fact, Qi4j will ensure that you can't even cast the order to the HasLineItems type. By not referencing the aggregated interface OrderComposite, we reduce the coupling of this SideEffect and it can be used in any other Composite where the Order and HasLineItems combination is used.

So, build the report, send it via the MailService.

Conclusion

In this short introduction, we have covered the essence of Qi4j. We have looked at what is a Composite, seen some of the Fragments in action, and how simple it is to turn a Composite into a persisted Composite, known as an EntityComposite.

Powered by SiteVisionexternal link.