Application

There is one and only one Application instance per Qi4j runtime instance. But there is nothing preventing code to create additional Qi4j Runtime instances inside the same JVM. However, these runtimes are isolated from each other.

The main purpose of the Application structure artifact is to keep everything in the same box, and allowing us to navigate the Structure. So, from a client code perspective, the Application is of no use, other than being part of bring Qi4j to life. Qi4j doesn't start automatically and can be run in most environments, by requiring that the bootstrapping of Qi4j is done by client code. We call this the Bootstrap Phase. The code in the custom bootstrapper will need to access additional Jars from the regular domain code, and we strongly recommend that you make this separation in your project as well.

Assembly


Assembly is the part of the bootstrap phase where the application Structure is declared (programmatically). The Assembly will be consumed by the ApplicationBuilder, which produces an ApplicationInstance. This instance does not contain any custom objects, and is fully serializable. All the application structure has been built, all the layers and modules been wired up, and all the sub-composite structures are in place to quickly instantiate the various parts of the application.

Initialization

At this point, where an ApplicationInstance exists, it is possible to initialize the application components with instances created in, data computed in or received from, the controlling bootstrap code.

Activation

Once the initialization phase is complete, the bootstrap controller will call the ApplicationInstance.activate() method to start things up.

Bootstrap Phase Summary

Recap of sequence;

  • Create, obtain or lookup Assemblers.
  • Establish the application structures.
  • Create a Qi4j Runtime instance.
  • Create an ApplicationAssemblyFactory.
  • Create an ApplicationFactory.
  • Call ApplicationFactory.newApplication() to create an ApplicationContext.
  • Call ApplicationContext.newApplicationInstance() to create an ApplicationInstance.
  • Do the initialization of the application.
  • Call activate() on the ApplicationInstance.

Singleton Assembler

For really small applications, demos, testcases and so forth, it doesn't make sense to create a elaborate Application structure. For this purpose, there is a convenient short-cut to establish a single Layer, single Module application. The full code looks like this;

SingletonAssembler qi4j = new SingletonAssembler()
{
    public void assemble( ModuleAssembly assembly )
        throws AssemblyException
    {
        assembly.addComposite( MyStuffComposite.class );
    }
}

Single Module Layering

Behind the scenes of the SingletonAssembler a little bit more elaborate bootstrap sequence is happening. The code below shows what is the actual required sequence to start up Qi4j.

Qi4j is = new Energy4Java();
ApplicationAssemblyFactory assemblyFactory = new ApplicationAssemblyFactory();
ApplicationFactory factory = new ApplicationFactory( is, assemblyFactory );
Assembler assembler = ...;
ApplicationContext context = factory.newApplication( assembler );
ApplicationInstance application = context.newInstance( appTitle );

// initialize the Structure
:

// activate the application
application.activate()

In the above example we are only creating an Application with a single Layer and a single Module in that Layer. This is derived from the fact that the factory.newApplication() method takes a single Assembler argument.

The Assembler.assemble( ModuleAssembly assembly ) method is called when the Qi4j Runtime needs to populate the ModuleAssembly with its Composites, Objects, Services and other information.

"Pancake" Layering

Another standard setup is applications consisting of a small number of Layers that are directly on top of each other (with out bypassing, forking and converging Layers), you can supply a Assembler[][][], with Layer in the first index, Module in the second index and any number of Assembler instances in the last index. This will look like;


Assembler[][][] assemblers =
{
    { // web layer
        { // Customer Module
            customerListEditAssembler,
            customerEditAssembler,
            customerSearchAssembler
        },
        { // Accounts Module
            accountsListEditAssembler,
            accountsEditAssembler,
            accountsSearchAssembler
        }
    },
    { // domain layer
        { // Customer Module
            customerDomainAssembler,
        },
        { // Accounts Module
            accountsDomainAssembler,
        }
    }
};
ApplicationContext context = factory.newApplication( assemblers );
The array initialization feature in Java is used to give us a semi-visual idea of the actual application structure. It has been commented to highlight this further. Also note that one can pass any number of Assembler instances to each Module. This is an important aspect of subsystem creation and re-use.

Full Layering

Finally, we can assemble the Application by manually building up the Modules and Layers. This allow for a totally free structure, as long as the rules for no cyclic reference of the Layers are kept.


public class Main
{
    private static Main instance;
    private Qi4jRuntime runtime;

    public static void Main( String[] args )
    {
        instance = new Main();
        instance.setUp();
        // assuming some code has a non-daemon thread.
    }

    private void setUp()
    {
        Qi4jRuntime is = new Energy4Java();
        runtime = is;
        ApplicationAssemblyFactory assemblyFactory =
            new ApplicationAssemblyFactory();
        ApplicationFactory factory =
            new ApplicationFactory( runtime, assemblyFactory );

        ApplicationAssembly app = createAssembly( assemblyFactory );

        ApplicationContext context = factory.newApplication( assembly );

        String applicationName = "Example Application";
        ApplicationInstance instance =
            context.newApplicationInstance( applicationName );
    }

    private ApplicationAssembly createAssembly(
        ApplicationAssemblyFactory factory )
    {
        ApplicationAssembly app = factory.newApplicationAssembly();
        LayerAssembly webLayer = createWebLayer( app );
        LayerAssembly domainLayer = createDomainLayer( app );
        LayerAssembly infraLayer = createInfrastructureLayer( app );
        webLayer.uses( domainLayer );
        webLayer.uses( infraLayer );  // Accesses the WebService
        domainLayer.uses( infraLayer ); // For persistence
        return app;
    }

    private LayerAssembly createWebLayer(
        ApplicationAssembly application )
    {
        LayerAssembly layer = application.newLayerAssembly();
        createCustomerWebModule( layer );
        return layer;
    }

    private LayerAssembly createDomainLayer(
        ApplicationAssembly application )
    {
        LayerAssembly layer = application.newLayerAssembly();
        createCustomerDomainModule( layer );
        // :
        // :
        return layer;
    }

    private LayerAssembly createInfrastructureLayer(
        ApplicationAssembly application )
    {
        LayerAssembly layer = application.newLayerAssembly();
        createWebServiceModule( layer );
        createPersistenceModule( layer );
        return layer;
    }

    private void createCustomerWebModule( LayerAssembly layer )
    {
        ModuleAssembly assembly = layer.newModuleAssembly();
        assembly.addComposites( CustomerViewComposite.class );
        assembly.addComposites( CustomerEditComposite.class );
        assembly.addComposites( CustomerListViewComposite.class );
        assembly.addComposites( CustomerSearchComposite.class );
    }

    private void createCustomerDomainModule( LayerAssembly layer )
    {
        ModuleAssembly assembly = layer.newModuleAssembly();
        assembly.addEntities( CustomerEntity.class );
        assembly.addEntities( CountryEntity.class );
        assembly.addComposites( AddressComposite.class );
    }

    private void createWebServiceModule( LayerAssembly layer )
    {
        ModuleAssembly assembly = layer.newModuleAssembly();
        // Someone has created an assembler for a Jetty Web Service.
        JettyAssembler jetty = new JettyAssembler( 8080 );
        assembly.addAssembler( neo );
    }

    private void createPersistenceModule( LayerAssembly layer )
    {
        ModuleAssembly assembly = layer.newModuleAssembly();
        // Someone has created an assembler for the Neo EntityStore
        NeoAssembler neo = new NeoAssembler( "./neostore" );
        assembly.addAssembler( neo );
    }
}

Powered by SiteVisionexternal link.