Return-Path: X-Original-To: apmail-zest-dev-archive@minotaur.apache.org Delivered-To: apmail-zest-dev-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id BE43518734 for ; Tue, 16 Jun 2015 08:29:15 +0000 (UTC) Received: (qmail 71876 invoked by uid 500); 16 Jun 2015 08:29:15 -0000 Delivered-To: apmail-zest-dev-archive@zest.apache.org Received: (qmail 71838 invoked by uid 500); 16 Jun 2015 08:29:15 -0000 Mailing-List: contact dev-help@zest.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@zest.apache.org Delivered-To: mailing list dev@zest.apache.org Received: (qmail 71826 invoked by uid 99); 16 Jun 2015 08:29:15 -0000 Received: from Unknown (HELO spamd1-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 16 Jun 2015 08:29:15 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd1-us-west.apache.org (ASF Mail Server at spamd1-us-west.apache.org) with ESMTP id 0281DCE249 for ; Tue, 16 Jun 2015 08:29:15 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd1-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: 2.901 X-Spam-Level: ** X-Spam-Status: No, score=2.901 tagged_above=-999 required=6.31 tests=[DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, HTML_MESSAGE=3, URIBL_BLOCKED=0.001] autolearn=disabled Authentication-Results: spamd1-us-west.apache.org (amavisd-new); dkim=pass (2048-bit key) header.d=gmail.com Received: from mx1-us-east.apache.org ([10.40.0.8]) by localhost (spamd1-us-west.apache.org [10.40.0.7]) (amavisd-new, port 10024) with ESMTP id 4-ihHNK43lrB for ; Tue, 16 Jun 2015 08:29:00 +0000 (UTC) Received: from mail-wi0-f176.google.com (mail-wi0-f176.google.com [209.85.212.176]) by mx1-us-east.apache.org (ASF Mail Server at mx1-us-east.apache.org) with ESMTPS id D556043AC7 for ; Tue, 16 Jun 2015 08:28:59 +0000 (UTC) Received: by wifx6 with SMTP id x6so11755741wif.0 for ; Tue, 16 Jun 2015 01:28:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :content-type; bh=7nUrCAQOqxBNr8Qd5v3Hps1m0bM4qJWLqj6f0sWM2M4=; b=lL6t5kfhSPk4GbLhsoM6cVjtgcCFIqXVqS0yc3ZzbExOv/Kk4iQ8de7/QObRJLnvn4 xRvcxDWyqgNQaqAuy7geJsXi1cVl91OQGb42lL2go0KRFbCTKPPqXxgCRk72OqXC6ndW WT91s7sRrVDcflYvzSGj1l7PlUkU78AoXtGvAFQi72mCIu5CPZbqSkUF/tDWL7U6syw4 AKpyiFdGsgoc8uAhgVr+sK/ZZ3AQXVVbqknaUDD80aRqlUAHOk/akufvckQOB0m6MR9W Z+bH5ZvAz/kWOA0r/dNesdaJUOqJevs3iDynq8lj3clTsYSXKM3HLdWFKZ9y43cB4owL 8hMA== MIME-Version: 1.0 X-Received: by 10.180.95.163 with SMTP id dl3mr40746845wib.30.1434443339107; Tue, 16 Jun 2015 01:28:59 -0700 (PDT) Received: by 10.27.128.193 with HTTP; Tue, 16 Jun 2015 01:28:59 -0700 (PDT) In-Reply-To: References: Date: Tue, 16 Jun 2015 10:28:59 +0200 Message-ID: Subject: Re: Assembly proposal From: Jiri Jetmar To: dev@zest.apache.org Content-Type: multipart/alternative; boundary=f46d0444ea8fad91e205189e5dea --f46d0444ea8fad91e205189e5dea Content-Type: text/plain; charset=UTF-8 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 : > 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 > --f46d0444ea8fad91e205189e5dea--