You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@polygene.apache.org by Niclas Hedhman <ni...@hedhman.org> on 2015/05/13 09:45:00 UTC

Assembly proposal

Gang, (warning; long)

Long tima ago, when the Assembly system was first created, we had very
little experience of what would be needed, and kept the API very
minimalistic. One area that was left out completely (on purpose) was to
provide a more declarative way author the application structure.

A few applications later, I keep re-implementing the same thing over and
over. It looks like this;


    public interface LayerAssembler
    {
        LayerAssembly assemble() throws AssemblyException;
    }

    public interface ModuleAssembler
    {
        ModuleAssembly assemble()
            throws AssemblyException;
    }

And then implementations of those becomes like this;

    public class DomainLayer
        implements LayerAssembler
    {
        public static final String NAME = "domain";
        private final LayerAssembly layer;

        public DomainLayer( LayerAssembly layer )
        {
            this.layer = layer;
        }

        @Override
        public LayerAssembly assemble()
            throws AssemblyException
        {
            new CommandLineModule( layer.module( CommandLineModule.NAME )
).assemble();
            new HostModule( layer.module( HostModule.NAME ) ).assemble();
            new ContainersModule( layer.module( ContainersModule.NAME )
).assemble();
            return layer;
        }
    }


    public class CommandLineModule
        implements ModuleAssembler
    {
        public static final String NAME = "domain";
        private final ModuleAssembly module;

        public CommandLineModule( ModuleAssembly module )
        {
            this.module = module;
        }

        @Override
        public ModuleAssembly assemble()
            throws AssemblyException
        {
            module.services( CommandLineExecutor.class ).visibleIn(
Visibility.layer );
            module.values( CommandLine.class );
            return module;
        }
    }

The reason for injecting the layer and module into the constructor instead
of assemble() method, is because every now and then additional arguments
might be needed.

So it is all put together as

    public class MyAppAssembler
        implements ApplicationAssembler
    {
        private static final String NAME = "My Application Name";
        private static final String VERSION = "1.0";
        private final Application application;

        public MyAppAssembler()
            throws AssemblyException
        {
            Energy4Java qi4j = new Energy4Java();
            ApplicationDescriptor model = qi4j.newApplicationModel( this );
            application = model.newInstance( qi4j.spi() );
        }

        public Application application()
        {
            return application;
        }

        public void start()
            throws ActivationException
        {
            application.activate();
        }

        public void stop()
            throws PassivationException
        {
            application.passivate();
        }

        @Override
        public ApplicationAssembly assemble( ApplicationAssemblyFactory
applicationFactory )
            throws AssemblyException
        {
            ApplicationAssembly assembly =
applicationFactory.newApplicationAssembly();
            assembly.setName( NAME );
            assembly.setName( VERSION );
            LayerAssembly infraLayer = new InfrastructureLayer(
assembly.layer( InfrastructureLayer.NAME ) ).assemble();
            LayerAssembly domainLayer = new DomainLayer( assembly.layer(
DomainLayer.NAME ) ).assemble();
            LayerAssembly serviceLayer = new ServiceLayer( assembly.layer(
ServiceLayer.NAME ) ).assemble();
            LayerAssembly connectivityLayer = new ConnectivityLayer(
assembly.layer( ConnectivityLayer.NAME ) ).assemble();

            connectivityLayer.uses( serviceLayer );
            serviceLayer.uses( domainLayer );
            serviceLayer.uses( infraLayer );
            domainLayer.uses( infraLayer );
            return assembly;
        }
    }


So, first I would like to add the ModuleAssembler and LayerAssembler as
Core Bootstrap classes. Secondly, I would to create a abstract class,
perhaps named LayeredApplicationAssembler, which encapsulates the
boilerplate code, and defines a "Layer DSL", maybe something like this;

    public class MyAppAssembler extends LayeredApplicationAssembler
    {
        public MyAppAssembler( String name, String version, Mode mode )
        {
            super( name, version, mode );
        }

        protected void onAssembly()
        {
            LayerAssembly infraLayer = layer().definedBy( new
InfrastructureLayer() );
            LayerAssembly domainLayer = layer().definedBy( new
DomainLayer() ).uses( infraLayer );
            LayerAssembly serviceLayer = layer().definedBy( new
ServiceLayer() ).uses( domainLayer, infraLayer );
            layer().definedBy( new ConnectivityLayer() ).uses( serviceLayer
);
        }
    }

IMHO, this is quite a nice improvement over the current flexibility that
exists.

But, I have also previously mentioned that an annotated solution might be
even cooler.

public class MyAppAssembler extends AnnotatedApplicationAssembler
{
    @Uses( ServiceLayer.class )
    interface ConnectivityLayer
    {
        ModuleAssembler MODULES = {
            RestModule.class,
            WebAppModule.class
        };
    }

    @Uses( { DomainLayer.class, InfrastructureLayer.class } )
    interface ServiceLayer
    {
        ModuleAssembler MODULES = {
            DeploymentModule.class,
            ManagementModule.class,
            MonitoringModule.class
        };
    }

    @Uses( InfrastructureLayer.class )
    interface DomainLayer
    {
        ModuleAssembler MODULES = {
            CommandLineModule.class,
            HostsModule.class,
            ContainersModule.class
        };
    }

    interface InfrastructureLayer
    {
        ModuleAssembler MODULES = {
            StorageModule.class,
            ConfigModule.class,
            IndexingModule.class
        };
    }
}

The entire application structure overview captured in a single document,
with all the implementation detail noise removed.
One feature that is not present without anything additional is that via the
LayerAssembly interface, it is possible to apply cross-cutting concerns on
Composites across an entire layer. I suggest that this is provided via
method call in the AnnotatedApplicationAssembler super type. For instance,
let's say that we want to apply the UnitOfWorkPropagationConcern to all
Services in the service layer.

public class MyAppAssembler extends AnnotatedApplicationAssembler
{
    :  // all the above at the top...

    public MyAppAssembler( String name, String version, Mode mode )
    {
        super( name, version, mode );
        withConcerns( UnitOfWorkPropagationConcern.class ).inLayer(
ServiceLayer.class );
    }
}

Looks neat enough to me, and should be able to be expanded for all the
features that are currently possible.

FINALLY,
IF the AnnotatedApplicationAssembler also provides a complete bootstrapper,
and we would only add

    public static void main( String[] args )
    {
        new MyAppAssembler().run(args);
    }

then we could start things from command line, provide an abstraction for
Application Arguments, which would also be available from a
WebApplicationAssembler (probably a subclass of the above).
And I am also toying with the idea that optional modules could be provided
from the commandline, such as which entity store to be used, enabling JMX
or Tracing, and other modules that can be made completely optional.


WDYAT?


Cheers
--
Niclas Hedhman, Software Developer
http://zest.apache.org - New Energy for Java

Re: Assembly proposal

Posted by Jiri Jetmar <ju...@gmail.com>.
Hi,

interessting approach - I need some more time to understand the details.

The reason for the "Tower" approach we did was that Zest Apps can be
structured
together in so many ways. When compared to e.g. the Spring/JBoss world,
where one have
a proposed and proved approach how to structure Apps, where one has
to put configurations, how/where to configure repositories and other
infrastructure.

When I joined the Zest challenge, I was somehow lost in terms of how to
structure & bootstrap
Apps in a standard, easy way.

So the proposed API can be a internal view, but from my position there is
still the external
view missing, how exactly Zest Apps should be structured.

Cheers,
Jiri

2015-05-13 9:45 GMT+02:00 Niclas Hedhman <ni...@hedhman.org>:

> Gang, (warning; long)
>
> Long tima ago, when the Assembly system was first created, we had very
> little experience of what would be needed, and kept the API very
> minimalistic. One area that was left out completely (on purpose) was to
> provide a more declarative way author the application structure.
>
> A few applications later, I keep re-implementing the same thing over and
> over. It looks like this;
>
>
>     public interface LayerAssembler
>     {
>         LayerAssembly assemble() throws AssemblyException;
>     }
>
>     public interface ModuleAssembler
>     {
>         ModuleAssembly assemble()
>             throws AssemblyException;
>     }
>
> And then implementations of those becomes like this;
>
>     public class DomainLayer
>         implements LayerAssembler
>     {
>         public static final String NAME = "domain";
>         private final LayerAssembly layer;
>
>         public DomainLayer( LayerAssembly layer )
>         {
>             this.layer = layer;
>         }
>
>         @Override
>         public LayerAssembly assemble()
>             throws AssemblyException
>         {
>             new CommandLineModule( layer.module( CommandLineModule.NAME )
> ).assemble();
>             new HostModule( layer.module( HostModule.NAME ) ).assemble();
>             new ContainersModule( layer.module( ContainersModule.NAME )
> ).assemble();
>             return layer;
>         }
>     }
>
>
>     public class CommandLineModule
>         implements ModuleAssembler
>     {
>         public static final String NAME = "domain";
>         private final ModuleAssembly module;
>
>         public CommandLineModule( ModuleAssembly module )
>         {
>             this.module = module;
>         }
>
>         @Override
>         public ModuleAssembly assemble()
>             throws AssemblyException
>         {
>             module.services( CommandLineExecutor.class ).visibleIn(
> Visibility.layer );
>             module.values( CommandLine.class );
>             return module;
>         }
>     }
>
> The reason for injecting the layer and module into the constructor instead
> of assemble() method, is because every now and then additional arguments
> might be needed.
>
> So it is all put together as
>
>     public class MyAppAssembler
>         implements ApplicationAssembler
>     {
>         private static final String NAME = "My Application Name";
>         private static final String VERSION = "1.0";
>         private final Application application;
>
>         public MyAppAssembler()
>             throws AssemblyException
>         {
>             Energy4Java qi4j = new Energy4Java();
>             ApplicationDescriptor model = qi4j.newApplicationModel( this );
>             application = model.newInstance( qi4j.spi() );
>         }
>
>         public Application application()
>         {
>             return application;
>         }
>
>         public void start()
>             throws ActivationException
>         {
>             application.activate();
>         }
>
>         public void stop()
>             throws PassivationException
>         {
>             application.passivate();
>         }
>
>         @Override
>         public ApplicationAssembly assemble( ApplicationAssemblyFactory
> applicationFactory )
>             throws AssemblyException
>         {
>             ApplicationAssembly assembly =
> applicationFactory.newApplicationAssembly();
>             assembly.setName( NAME );
>             assembly.setName( VERSION );
>             LayerAssembly infraLayer = new InfrastructureLayer(
> assembly.layer( InfrastructureLayer.NAME ) ).assemble();
>             LayerAssembly domainLayer = new DomainLayer( assembly.layer(
> DomainLayer.NAME ) ).assemble();
>             LayerAssembly serviceLayer = new ServiceLayer( assembly.layer(
> ServiceLayer.NAME ) ).assemble();
>             LayerAssembly connectivityLayer = new ConnectivityLayer(
> assembly.layer( ConnectivityLayer.NAME ) ).assemble();
>
>             connectivityLayer.uses( serviceLayer );
>             serviceLayer.uses( domainLayer );
>             serviceLayer.uses( infraLayer );
>             domainLayer.uses( infraLayer );
>             return assembly;
>         }
>     }
>
>
> So, first I would like to add the ModuleAssembler and LayerAssembler as
> Core Bootstrap classes. Secondly, I would to create a abstract class,
> perhaps named LayeredApplicationAssembler, which encapsulates the
> boilerplate code, and defines a "Layer DSL", maybe something like this;
>
>     public class MyAppAssembler extends LayeredApplicationAssembler
>     {
>         public MyAppAssembler( String name, String version, Mode mode )
>         {
>             super( name, version, mode );
>         }
>
>         protected void onAssembly()
>         {
>             LayerAssembly infraLayer = layer().definedBy( new
> InfrastructureLayer() );
>             LayerAssembly domainLayer = layer().definedBy( new
> DomainLayer() ).uses( infraLayer );
>             LayerAssembly serviceLayer = layer().definedBy( new
> ServiceLayer() ).uses( domainLayer, infraLayer );
>             layer().definedBy( new ConnectivityLayer() ).uses( serviceLayer
> );
>         }
>     }
>
> IMHO, this is quite a nice improvement over the current flexibility that
> exists.
>
> But, I have also previously mentioned that an annotated solution might be
> even cooler.
>
> public class MyAppAssembler extends AnnotatedApplicationAssembler
> {
>     @Uses( ServiceLayer.class )
>     interface ConnectivityLayer
>     {
>         ModuleAssembler MODULES = {
>             RestModule.class,
>             WebAppModule.class
>         };
>     }
>
>     @Uses( { DomainLayer.class, InfrastructureLayer.class } )
>     interface ServiceLayer
>     {
>         ModuleAssembler MODULES = {
>             DeploymentModule.class,
>             ManagementModule.class,
>             MonitoringModule.class
>         };
>     }
>
>     @Uses( InfrastructureLayer.class )
>     interface DomainLayer
>     {
>         ModuleAssembler MODULES = {
>             CommandLineModule.class,
>             HostsModule.class,
>             ContainersModule.class
>         };
>     }
>
>     interface InfrastructureLayer
>     {
>         ModuleAssembler MODULES = {
>             StorageModule.class,
>             ConfigModule.class,
>             IndexingModule.class
>         };
>     }
> }
>
> The entire application structure overview captured in a single document,
> with all the implementation detail noise removed.
> One feature that is not present without anything additional is that via the
> LayerAssembly interface, it is possible to apply cross-cutting concerns on
> Composites across an entire layer. I suggest that this is provided via
> method call in the AnnotatedApplicationAssembler super type. For instance,
> let's say that we want to apply the UnitOfWorkPropagationConcern to all
> Services in the service layer.
>
> public class MyAppAssembler extends AnnotatedApplicationAssembler
> {
>     :  // all the above at the top...
>
>     public MyAppAssembler( String name, String version, Mode mode )
>     {
>         super( name, version, mode );
>         withConcerns( UnitOfWorkPropagationConcern.class ).inLayer(
> ServiceLayer.class );
>     }
> }
>
> Looks neat enough to me, and should be able to be expanded for all the
> features that are currently possible.
>
> FINALLY,
> IF the AnnotatedApplicationAssembler also provides a complete bootstrapper,
> and we would only add
>
>     public static void main( String[] args )
>     {
>         new MyAppAssembler().run(args);
>     }
>
> then we could start things from command line, provide an abstraction for
> Application Arguments, which would also be available from a
> WebApplicationAssembler (probably a subclass of the above).
> And I am also toying with the idea that optional modules could be provided
> from the commandline, such as which entity store to be used, enabling JMX
> or Tracing, and other modules that can be made completely optional.
>
>
> WDYAT?
>
>
> Cheers
> --
> Niclas Hedhman, Software Developer
> http://zest.apache.org - New Energy for Java
>

Re: Assembly proposal

Posted by Niclas Hedhman <ni...@hedhman.org>.
Great... I have committed that to 'develop', together with a bunch of other
things.

On Tue, Jun 16, 2015 at 11:15 PM, Paul Merlin <pa...@nosphere.org> wrote:

> Niclas,
>
> I agree that the ApplicationBuilder DSL gets messy easily. Just like any
> home-made assembly using the low-level api. It's JSON support is neat
> but I had no use of it yet, so ...
>
> I like your approach for Layered applications. I can't see any limit to
> what can be done that way and it feels cleaner than low-level assembly.
> Probably much easier for newcomers.
>
> Jiri, I agree, this solves only a part of the "problem". For "external
> view", I'd say something like Tower or Stacks/BluePrints that we
> discussed in the past will be needed.
>
> My 0.2c.
>
> /Paul
>
>
>
>
> Niclas Hedhman a écrit :
> > Gang, (again, a bit long...)
> >
> > I am comparing the ApplicationBuilder, with its DSL and the way I did it
> in
> > my latest application.
> > The ApplicationBuilder is cute that it supports JSON, but IMHO it doesn't
> > read nicely in code, as there is no "natural" isolation/separation, and
> > quickly gets rather 'unruly'. Such 'messy' tendency might become the case
> > of the "magic" that I wrote about earlier in this thread as well, since I
> > haven't tested that yet. That will be revisited later...
> >
> > But the ModuleAssembler, LayerAssembler and LayeredApplicationAssembler
> > that I am using "feels" quite nice, at least to me and I think(!) that it
> > is easier for a newbie to follow and "do the right thing" rather than the
> > DSL, which easily gets messy without discipline.
> >
> > Let's look at a concrete example, and a STRESS that there are no "snips"
> in
> > the assembler classes below other than "import", the classes below are
> > complete...
> >
> > The top application ends up look like this;
> >
> > public class TestingLayeredApplicationAssembler extends
> > LayeredApplicationAssembler
> > {
> >     public TestingLayeredApplicationAssembler( String name, String
> version )
> >         throws AssemblyException
> >     {
> >         super( name, version );
> >     }
> >
> >     @Override
> >     protected void assembleLayers( ApplicationAssembly assembly )
> >         throws AssemblyException
> >     {
> >         LayerAssembly configLayer = createLayer(
> ConfigurationLayer.class );
> >         ModuleAssembly configModule = configLayer.module(
> > "Configuration Module" );
> >         LayerAssembly infraLayer = new InfrastructureLayer(
> > configModule ).assemble( assembly.layer( InfrastructureLayer.NAME  ));
> >         LayerAssembly domainLayer = createLayer( DomainLayer.class );
> >         LayerAssembly serviceLayer = createLayer( ServiceLayer.class );
> >         LayerAssembly connectivityLayer = createLayer(
> > ConnectivityLayer.class );
> >
> >         connectivityLayer.uses( serviceLayer );
> >         connectivityLayer.uses( domainLayer );
> >         serviceLayer.uses( domainLayer );
> >         domainLayer.uses( infraLayer );
> >         infraLayer.uses( configLayer );
> >     }
> > }
> >
> > And Layers can either be 'manual' such as in the InfrastructureLayer
> > example above, or can be 'magical' as the others are. Name to the layer
> is
> > given through the classname of the LayerAssembler.
> >
> > So, the DomainLayer would look like;
> >
> > public class DomainLayer extends LayeredLayerAssembler
> > {
> >     @Override
> >     public LayerAssembly assemble( LayerAssembly layer )
> >         throws AssemblyException
> >     {
> >         createModule( layer, InvoicingModule.class );
> >         createModule( layer, OrderModule.class );
> >         return layer;
> >     }
> > }
> >
> >
> > where again it is mostly 'magical' deriving names from the
> ModuleAssembler
> > name, but can be 'manual' as we need in the InfrastructureLayer;
> >
> > public class InfrastructureLayer extends LayeredLayerAssembler
> >     implements LayerAssembler
> > {
> >     public static final String NAME = "Infrastructure Layer";
> >     private final ModuleAssembly configModule;
> >
> >     public InfrastructureLayer( ModuleAssembly configModule )
> >     {
> >         this.configModule = configModule;
> >     }
> >
> >     @Override
> >     public LayerAssembly assemble( LayerAssembly layer )
> >         throws AssemblyException
> >     {
> >         new StorageModule( layer.module( StorageModule.NAME ),
> > configModule ).assemble();
> >         new IndexingModule( layer.module( IndexingModule.NAME ),
> > configModule ).assemble();
> >         createModule( layer, SerializationModule.class );
> >         return layer;
> >     }
> > }
> >
> >
> > since we are using the DSL in the Assemblers of storage and indexing.
> >
> > ModuleAssemblers have no 'magical' part, so they are fairly straight
> > forward. So from the above, an OrderModuler could be;
> >
> > public class OrderModule implements ModuleAssembler
> > {
> >     @Override
> >     public ModuleAssembly assemble( ModuleAssembly module )
> >         throws AssemblyException
> >     {
> >         module.entities( Order.class, Customer.class );
> >         module.values( Address.class );
> >         return module;
> >     }
> > }
> >
> >
> > and the IndexingModule would have something like;
> >
> > public class IndexingModule
> >     implements ModuleAssembler
> > {
> >     private final ModuleAssembly configModule;
> >
> >     public IndexingModule( ModuleAssembly configModule )
> >     {
> >         this.configModule = configModule;
> >     }
> >
> >     @Override
> >     public ModuleAssembly assemble( LayerAssembly layer, ModuleAssembly
> module )
> >         throws AssemblyException
> >     {
> >         new FileConfigurationAssembler().assemble( module );
> >         new ESFilesystemIndexQueryAssembler()
> >             .visibleIn( Visibility.application )
> >             .withConfig( configModule, Visibility.application )
> >             .assemble( module );
> >         return module;
> >     }
> > }
> >
> >
> > So, what's the verdict? I have this more or less ready (need to document
> > it), and although I think it "competes" with other ways of doing
> assembly,
> > I think it is quite neat and tidy, helping newcomers to get structured (I
> > create one package per layer, and its parent contains the
> > ApplicationAssembler implementation)
> >
> >
> > Cheers
>



-- 
Niclas Hedhman, Software Developer
http://zest.apache.org - New Energy for Java

Re: Assembly proposal

Posted by Paul Merlin <pa...@nosphere.org>.
Niclas,

I agree that the ApplicationBuilder DSL gets messy easily. Just like any
home-made assembly using the low-level api. It's JSON support is neat
but I had no use of it yet, so ...

I like your approach for Layered applications. I can't see any limit to
what can be done that way and it feels cleaner than low-level assembly.
Probably much easier for newcomers.

Jiri, I agree, this solves only a part of the "problem". For "external
view", I'd say something like Tower or Stacks/BluePrints that we
discussed in the past will be needed.

My 0.2c.

/Paul




Niclas Hedhman a écrit :
> Gang, (again, a bit long...)
>
> I am comparing the ApplicationBuilder, with its DSL and the way I did it in
> my latest application.
> The ApplicationBuilder is cute that it supports JSON, but IMHO it doesn't
> read nicely in code, as there is no "natural" isolation/separation, and
> quickly gets rather 'unruly'. Such 'messy' tendency might become the case
> of the "magic" that I wrote about earlier in this thread as well, since I
> haven't tested that yet. That will be revisited later...
>
> But the ModuleAssembler, LayerAssembler and LayeredApplicationAssembler
> that I am using "feels" quite nice, at least to me and I think(!) that it
> is easier for a newbie to follow and "do the right thing" rather than the
> DSL, which easily gets messy without discipline.
>
> Let's look at a concrete example, and a STRESS that there are no "snips" in
> the assembler classes below other than "import", the classes below are
> complete...
>
> The top application ends up look like this;
>
> public class TestingLayeredApplicationAssembler extends
> LayeredApplicationAssembler
> {
>     public TestingLayeredApplicationAssembler( String name, String version )
>         throws AssemblyException
>     {
>         super( name, version );
>     }
>
>     @Override
>     protected void assembleLayers( ApplicationAssembly assembly )
>         throws AssemblyException
>     {
>         LayerAssembly configLayer = createLayer( ConfigurationLayer.class );
>         ModuleAssembly configModule = configLayer.module(
> "Configuration Module" );
>         LayerAssembly infraLayer = new InfrastructureLayer(
> configModule ).assemble( assembly.layer( InfrastructureLayer.NAME  ));
>         LayerAssembly domainLayer = createLayer( DomainLayer.class );
>         LayerAssembly serviceLayer = createLayer( ServiceLayer.class );
>         LayerAssembly connectivityLayer = createLayer(
> ConnectivityLayer.class );
>
>         connectivityLayer.uses( serviceLayer );
>         connectivityLayer.uses( domainLayer );
>         serviceLayer.uses( domainLayer );
>         domainLayer.uses( infraLayer );
>         infraLayer.uses( configLayer );
>     }
> }
>
> And Layers can either be 'manual' such as in the InfrastructureLayer
> example above, or can be 'magical' as the others are. Name to the layer is
> given through the classname of the LayerAssembler.
>
> So, the DomainLayer would look like;
>
> public class DomainLayer extends LayeredLayerAssembler
> {
>     @Override
>     public LayerAssembly assemble( LayerAssembly layer )
>         throws AssemblyException
>     {
>         createModule( layer, InvoicingModule.class );
>         createModule( layer, OrderModule.class );
>         return layer;
>     }
> }
>
>
> where again it is mostly 'magical' deriving names from the ModuleAssembler
> name, but can be 'manual' as we need in the InfrastructureLayer;
>
> public class InfrastructureLayer extends LayeredLayerAssembler
>     implements LayerAssembler
> {
>     public static final String NAME = "Infrastructure Layer";
>     private final ModuleAssembly configModule;
>
>     public InfrastructureLayer( ModuleAssembly configModule )
>     {
>         this.configModule = configModule;
>     }
>
>     @Override
>     public LayerAssembly assemble( LayerAssembly layer )
>         throws AssemblyException
>     {
>         new StorageModule( layer.module( StorageModule.NAME ),
> configModule ).assemble();
>         new IndexingModule( layer.module( IndexingModule.NAME ),
> configModule ).assemble();
>         createModule( layer, SerializationModule.class );
>         return layer;
>     }
> }
>
>
> since we are using the DSL in the Assemblers of storage and indexing.
>
> ModuleAssemblers have no 'magical' part, so they are fairly straight
> forward. So from the above, an OrderModuler could be;
>
> public class OrderModule implements ModuleAssembler
> {
>     @Override
>     public ModuleAssembly assemble( ModuleAssembly module )
>         throws AssemblyException
>     {
>         module.entities( Order.class, Customer.class );
>         module.values( Address.class );
>         return module;
>     }
> }
>
>
> and the IndexingModule would have something like;
>
> public class IndexingModule
>     implements ModuleAssembler
> {
>     private final ModuleAssembly configModule;
>
>     public IndexingModule( ModuleAssembly configModule )
>     {
>         this.configModule = configModule;
>     }
>
>     @Override
>     public ModuleAssembly assemble( LayerAssembly layer, ModuleAssembly module )
>         throws AssemblyException
>     {
>         new FileConfigurationAssembler().assemble( module );
>         new ESFilesystemIndexQueryAssembler()
>             .visibleIn( Visibility.application )
>             .withConfig( configModule, Visibility.application )
>             .assemble( module );
>         return module;
>     }
> }
>
>
> So, what's the verdict? I have this more or less ready (need to document
> it), and although I think it "competes" with other ways of doing assembly,
> I think it is quite neat and tidy, helping newcomers to get structured (I
> create one package per layer, and its parent contains the
> ApplicationAssembler implementation)
>
>
> Cheers

Re: Assembly proposal

Posted by Niclas Hedhman <ni...@hedhman.org>.
Gang, (again, a bit long...)

I am comparing the ApplicationBuilder, with its DSL and the way I did it in
my latest application.
The ApplicationBuilder is cute that it supports JSON, but IMHO it doesn't
read nicely in code, as there is no "natural" isolation/separation, and
quickly gets rather 'unruly'. Such 'messy' tendency might become the case
of the "magic" that I wrote about earlier in this thread as well, since I
haven't tested that yet. That will be revisited later...

But the ModuleAssembler, LayerAssembler and LayeredApplicationAssembler
that I am using "feels" quite nice, at least to me and I think(!) that it
is easier for a newbie to follow and "do the right thing" rather than the
DSL, which easily gets messy without discipline.

Let's look at a concrete example, and a STRESS that there are no "snips" in
the assembler classes below other than "import", the classes below are
complete...

The top application ends up look like this;

public class TestingLayeredApplicationAssembler extends
LayeredApplicationAssembler
{
    public TestingLayeredApplicationAssembler( String name, String version )
        throws AssemblyException
    {
        super( name, version );
    }

    @Override
    protected void assembleLayers( ApplicationAssembly assembly )
        throws AssemblyException
    {
        LayerAssembly configLayer = createLayer( ConfigurationLayer.class );
        ModuleAssembly configModule = configLayer.module(
"Configuration Module" );
        LayerAssembly infraLayer = new InfrastructureLayer(
configModule ).assemble( assembly.layer( InfrastructureLayer.NAME  ));
        LayerAssembly domainLayer = createLayer( DomainLayer.class );
        LayerAssembly serviceLayer = createLayer( ServiceLayer.class );
        LayerAssembly connectivityLayer = createLayer(
ConnectivityLayer.class );

        connectivityLayer.uses( serviceLayer );
        connectivityLayer.uses( domainLayer );
        serviceLayer.uses( domainLayer );
        domainLayer.uses( infraLayer );
        infraLayer.uses( configLayer );
    }
}

And Layers can either be 'manual' such as in the InfrastructureLayer
example above, or can be 'magical' as the others are. Name to the layer is
given through the classname of the LayerAssembler.

So, the DomainLayer would look like;

public class DomainLayer extends LayeredLayerAssembler
{
    @Override
    public LayerAssembly assemble( LayerAssembly layer )
        throws AssemblyException
    {
        createModule( layer, InvoicingModule.class );
        createModule( layer, OrderModule.class );
        return layer;
    }
}


where again it is mostly 'magical' deriving names from the ModuleAssembler
name, but can be 'manual' as we need in the InfrastructureLayer;

public class InfrastructureLayer extends LayeredLayerAssembler
    implements LayerAssembler
{
    public static final String NAME = "Infrastructure Layer";
    private final ModuleAssembly configModule;

    public InfrastructureLayer( ModuleAssembly configModule )
    {
        this.configModule = configModule;
    }

    @Override
    public LayerAssembly assemble( LayerAssembly layer )
        throws AssemblyException
    {
        new StorageModule( layer.module( StorageModule.NAME ),
configModule ).assemble();
        new IndexingModule( layer.module( IndexingModule.NAME ),
configModule ).assemble();
        createModule( layer, SerializationModule.class );
        return layer;
    }
}


since we are using the DSL in the Assemblers of storage and indexing.

ModuleAssemblers have no 'magical' part, so they are fairly straight
forward. So from the above, an OrderModuler could be;

public class OrderModule implements ModuleAssembler
{
    @Override
    public ModuleAssembly assemble( ModuleAssembly module )
        throws AssemblyException
    {
        module.entities( Order.class, Customer.class );
        module.values( Address.class );
        return module;
    }
}


and the IndexingModule would have something like;

public class IndexingModule
    implements ModuleAssembler
{
    private final ModuleAssembly configModule;

    public IndexingModule( ModuleAssembly configModule )
    {
        this.configModule = configModule;
    }

    @Override
    public ModuleAssembly assemble( LayerAssembly layer, ModuleAssembly module )
        throws AssemblyException
    {
        new FileConfigurationAssembler().assemble( module );
        new ESFilesystemIndexQueryAssembler()
            .visibleIn( Visibility.application )
            .withConfig( configModule, Visibility.application )
            .assemble( module );
        return module;
    }
}


So, what's the verdict? I have this more or less ready (need to document
it), and although I think it "competes" with other ways of doing assembly,
I think it is quite neat and tidy, helping newcomers to get structured (I
create one package per layer, and its parent contains the
ApplicationAssembler implementation)


Cheers
-- 
Niclas Hedhman, Software Developer
http://zest.apache.org - New Energy for Java

Re: Assembly proposal

Posted by Niclas Hedhman <ni...@hedhman.org>.
On Thu, May 21, 2015 at 6:09 PM, Paul Merlin <pa...@nosphere.org> wrote:

> Looks neat. Kind of magic. Shouldn't we wait to master assembly using
> Java 8 constructs before adding something like that?
>

That might be a really good idea, actually... Let's revisit after 2.1
release and heading into 3.0.

Cheers
-- 
Niclas Hedhman, Software Developer
http://zest.apache.org - New Energy for Java

Re: Assembly proposal

Posted by Paul Merlin <pa...@nosphere.org>.
Niclas Hedhman a écrit :
> Gang, (warning; long)
Took me a while to ingest. Some comments inline.

> Long tima ago, when the Assembly system was first created, we had very
> little experience of what would be needed, and kept the API very
> minimalistic. One area that was left out completely (on purpose) was to
> provide a more declarative way author the application structure.
>
> A few applications later, I keep re-implementing the same thing over and
> over. It looks like this;
>
>
>     public interface LayerAssembler
>     {
>         LayerAssembly assemble() throws AssemblyException;
>     }
>
>     public interface ModuleAssembler
>     {
>         ModuleAssembly assemble()
>             throws AssemblyException;
>     }
>
> And then implementations of those becomes like this;
>
>     public class DomainLayer
>         implements LayerAssembler
>     {
>         public static final String NAME = "domain";
>         private final LayerAssembly layer;
>
>         public DomainLayer( LayerAssembly layer )
>         {
>             this.layer = layer;
>         }
>
>         @Override
>         public LayerAssembly assemble()
>             throws AssemblyException
>         {
>             new CommandLineModule( layer.module( CommandLineModule.NAME )
> ).assemble();
>             new HostModule( layer.module( HostModule.NAME ) ).assemble();
>             new ContainersModule( layer.module( ContainersModule.NAME )
> ).assemble();
>             return layer;
>         }
>     }
>
>
>     public class CommandLineModule
>         implements ModuleAssembler
>     {
>         public static final String NAME = "domain";
>         private final ModuleAssembly module;
>
>         public CommandLineModule( ModuleAssembly module )
>         {
>             this.module = module;
>         }
>
>         @Override
>         public ModuleAssembly assemble()
>             throws AssemblyException
>         {
>             module.services( CommandLineExecutor.class ).visibleIn(
> Visibility.layer );
>             module.values( CommandLine.class );
>             return module;
>         }
>     }
>
> The reason for injecting the layer and module into the constructor instead
> of assemble() method, is because every now and then additional arguments
> might be needed.
>
> So it is all put together as
>
>     public class MyAppAssembler
>         implements ApplicationAssembler
>     {
>         private static final String NAME = "My Application Name";
>         private static final String VERSION = "1.0";
>         private final Application application;
>
>         public MyAppAssembler()
>             throws AssemblyException
>         {
>             Energy4Java qi4j = new Energy4Java();
>             ApplicationDescriptor model = qi4j.newApplicationModel( this );
>             application = model.newInstance( qi4j.spi() );
>         }
>
>         public Application application()
>         {
>             return application;
>         }
>
>         public void start()
>             throws ActivationException
>         {
>             application.activate();
>         }
>
>         public void stop()
>             throws PassivationException
>         {
>             application.passivate();
>         }
>
>         @Override
>         public ApplicationAssembly assemble( ApplicationAssemblyFactory
> applicationFactory )
>             throws AssemblyException
>         {
>             ApplicationAssembly assembly =
> applicationFactory.newApplicationAssembly();
>             assembly.setName( NAME );
>             assembly.setName( VERSION );
>             LayerAssembly infraLayer = new InfrastructureLayer(
> assembly.layer( InfrastructureLayer.NAME ) ).assemble();
>             LayerAssembly domainLayer = new DomainLayer( assembly.layer(
> DomainLayer.NAME ) ).assemble();
>             LayerAssembly serviceLayer = new ServiceLayer( assembly.layer(
> ServiceLayer.NAME ) ).assemble();
>             LayerAssembly connectivityLayer = new ConnectivityLayer(
> assembly.layer( ConnectivityLayer.NAME ) ).assemble();
>
>             connectivityLayer.uses( serviceLayer );
>             serviceLayer.uses( domainLayer );
>             serviceLayer.uses( infraLayer );
>             domainLayer.uses( infraLayer );
>             return assembly;
>         }
>     }
>
>
> So, first I would like to add the ModuleAssembler and LayerAssembler as
> Core Bootstrap classes. Secondly, I would to create a abstract class,
> perhaps named LayeredApplicationAssembler, which encapsulates the
> boilerplate code, and defines a "Layer DSL", maybe something like this;
>
>     public class MyAppAssembler extends LayeredApplicationAssembler
>     {
>         public MyAppAssembler( String name, String version, Mode mode )
>         {
>             super( name, version, mode );
>         }
>
>         protected void onAssembly()
>         {
>             LayerAssembly infraLayer = layer().definedBy( new
> InfrastructureLayer() );
>             LayerAssembly domainLayer = layer().definedBy( new
> DomainLayer() ).uses( infraLayer );
>             LayerAssembly serviceLayer = layer().definedBy( new
> ServiceLayer() ).uses( domainLayer, infraLayer );
>             layer().definedBy( new ConnectivityLayer() ).uses( serviceLayer
> );
>         }
>     }
>
> IMHO, this is quite a nice improvement over the current flexibility that
> exists.
This LGTM and should work well with existing helpers in Assemblers
(config/identity/visibility).


> But, I have also previously mentioned that an annotated solution might be
> even cooler.
>
> public class MyAppAssembler extends AnnotatedApplicationAssembler
> {
>     @Uses( ServiceLayer.class )
>     interface ConnectivityLayer
>     {
>         ModuleAssembler MODULES = {
>             RestModule.class,
>             WebAppModule.class
>         };
>     }
>
>     @Uses( { DomainLayer.class, InfrastructureLayer.class } )
>     interface ServiceLayer
>     {
>         ModuleAssembler MODULES = {
>             DeploymentModule.class,
>             ManagementModule.class,
>             MonitoringModule.class
>         };
>     }
>
>     @Uses( InfrastructureLayer.class )
>     interface DomainLayer
>     {
>         ModuleAssembler MODULES = {
>             CommandLineModule.class,
>             HostsModule.class,
>             ContainersModule.class
>         };
>     }
>
>     interface InfrastructureLayer
>     {
>         ModuleAssembler MODULES = {
>             StorageModule.class,
>             ConfigModule.class,
>             IndexingModule.class
>         };
>     }
> }
>
> The entire application structure overview captured in a single document,
> with all the implementation detail noise removed.
Looks neat. Kind of magic. Shouldn't we wait to master assembly using
Java 8 constructs before adding something like that?

That's it for now.

Cheers

/Paul