Sunday, June 13, 2010

Bootstrap Bonanza

This post is a copy of this google doc describing littleware's bootstrap process.

I recently reworked the littleware bootstrap and dependency injection process. In the new system Guice manages dependency injection; java's ServiceLoader utility discovers the littleware modules available in the classpath, and OSGi manages startup and shutdown of subsystems. The new bootstrap code also supports different runtime profiles similar in spirit to java EE6 profiles or configurations in Apache Ivy. The new code both simplifies the process an application follows to configure, startup, and shutdown a littleware application; and also simplifies the artifacts that a littleware extension module must provide to register itself with littleware's runtime to expose its functionality to the application.

Littleware has a multi-step bootstrap process. The parent application determines whether to start littleware in a "server", "client", or "app" configuration. With the "client" configuration littleware's bootstrap establishes and authenticates a user session with a remote littleware server (which is another application running a "server" configuration). The "app" configuration allows applications that do not interact with a littleware server to still take advantage of littleware tools that support generic standalone GUI and CLI applications.

The "server", "client", and "app" systems have similar bootstrap processes. A "client" application begins by allocating a ClientBootstrap.ClientBuilder type object:

       final ClientBootstrap.ClientBuilder builder =           
             ClientBootstrap.clientProvider.get();

The ClientBuilder automatically loads the ClientModuleFactory service providers registered in the application class path, and gives the application the opportunity to add or remove modules from the bootstrap module set. The ClientBuilder also allows the application to specify a a profile from the AppBootstrap.AppProfile enumeration. The available profiles include AppProfile.SwingApp (the default), AppProfile.JNDI, AppProfile.CliApp, and AppProfile.WebApp.

The ClientBuilder constructs a LoginSetup object that provides methods to manage user authentication including an automatic method that prompts the user for his credentials in a way appropriate to the AppProfile, and returns a ClientBootstrap object. The ClientBootstrap bootstrap method injects and returns an application supplied type.

        final ClientBootstrap boot = 
               builder.addModuleFactory( new MyModuleFactory() 
                         ).profile( AppBootstrap.AppProfile.CliApp 
                         ).automatic();
        final MyTool tool = boot.bootstrap(MyTool.class);

The littleware runtime is up and running at this point. The MyTool class should be annotated so Guice injects whatever dependences the application needs.

         class MyTool {
                 ...
                   @Inject
                    public MyTool( AssetSearchManager search ) {
                           this.search = search;
                    }
                 ...

Under the bootstrap hood ClientBootstrap loops over the ClientModuleFactory service providers to build a ClientModule (a Guice Module subtype) configured :

         factory.build( profile )

ClientBootstrap builds a Guice Injector configured by the resulting collection of ClientModule objects, then loops over the ClientModule collection again to inject the OSGi BundleActivator associated with each module. Next ClientBootstrap launches an OSGi runtime to startup the activators. Finally, ClientBootstrap injects and returns MyTool.class the application passed to the bootstrap() method.