This project has retired. For details please refer to its Attic page.
Qi4j in 10 minutes - www.qi4j.org
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 instance 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})
public interface OrderComposite
    extends Order, HasSequenceNumber, HasCustomer,
            HasLineItems, Confirmable, Composite
{
}
This Composite is potentially complete. The Composite interface has a Mixin declared which is always present, the PropertyMixin, which will handle all properties we use. The two Concerns are interceptors that are placed on the methods that the Concerns declare, for instance;
public abstract class InventoryConcern extends ConcernOf<Order>
    implements Order
{
    @Service private InventoryService inventory;

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

    public void removeLineItem( LineItem item )
    {
        String productCode = item.productCode().get();
        int quantity = item.quantity().get();
        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 Order interface.
Extending the ConcernOf is a convenience mechanism, instaead of an explicit @ConcernFor annotation on a private field, which can be used in rare occasions when you are not able to extend. This base class defines the next field, which is set up by the Qi4j runtime and points to the next fragment in the call stack.
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.

The above example is not that good, since it is obviously doing persistence, and we have no code handling this. But Qi4j supports persistence directly in its Core. So simply by changing the interface it extends to EntityComposite;

@Concerns({PurchaseLimitConcern.class, InventoryConcern.class})
public interface OrderEntity
    extends Order, HasSequenceNumber, HasCustomer,
            HasLineItems, Confirmable, EntityComposite
{
}
No other changes are needed, provided that the Qi4j Runtime has been setup with one or more persisted entity stores. But we have a naming convention that EntityComposites have "Entity" as the suffix in its name.
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 OrderEntity;

@SideEffects( MailNotifySideEffect.class )
@Concerns({PurchaseLimitConcern.class, InventoryConcern.class})
public interface OrderEntity
    extends Order, HasSequenceNumber, HasCustomer,
            HasLineItems, Confirmable, EntityComposite
{
}
The SideEffect implementation is fairly simple.
public abstract class MailNotifySideEffect
    extends SideEffectOf<Confirmable>
    implements Confirmable
{
    @Service private MailService mailer;
    @This private HasLineItems hasItems;
    @This private HasCustomer hasCustomer;

    public void confirm()
    {
        StringBuilder builder = new StringBuilder();
        builder.append( "An Order has been made.\n\n\n" );
        builder.append( "Customer:" );
        builder.append( hasCustomer.name().get() );
        builder.append( "\n\nItems ordered:\n" );
        for( LineItem item : items.lineItems() )
        {
            builder.append( item.name().get() );
            builder.append( " : " );
            builder.append( item.quantity().get() );
            builder.append( "\n" );
        }
        mailer.send( "sales@mycompany.com", builder.toString() );
    }
}

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

@This is telling Qi4j that the SideEffect needs a reference to the Composite instance that it belongs to. By asking for both the HasCustomer 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 hasCustomer instance to the HasLineItems type. By not referencing the aggregated interface OrderEntity, we reduce the coupling of this SideEffect and it can be used in any other Composite where the HasCustomer and HasLineItems combination is used, for instance in an InvoiceEntity.

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.


Qi4j and the Qi4j logo are trademarks of Richard Öberg, Niclas Hedhman and the members of the Qi4j Core Team. See Qi4j licensing for more information.
Powered by SiteVisionexternal link.