You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polygene.apache.org by ni...@apache.org on 2015/06/17 05:10:07 UTC

[1/6] zest-qi4j git commit: Add an Option to serialize Maps in a more condense format; "map" : { "name" : "Niclas", "country" : "Malaysia" } instead of "map" : [ { "key" : "name", "value" : "Niclas" }, { "key" : "country", "value" : "Malaysia

Repository: zest-qi4j
Updated Branches:
  refs/heads/develop 813aacf33 -> b86b66d4e


Add an Option to serialize Maps in a more condense format;
     "map" : {  "name" : "Niclas", "country" : "Malaysia" }
 instead of
     "map" : [ { "key" : "name", "value" : "Niclas" }, { "key" : "country", "value" : "Malaysia" } ]


Project: http://git-wip-us.apache.org/repos/asf/zest-qi4j/repo
Commit: http://git-wip-us.apache.org/repos/asf/zest-qi4j/commit/6b068deb
Tree: http://git-wip-us.apache.org/repos/asf/zest-qi4j/tree/6b068deb
Diff: http://git-wip-us.apache.org/repos/asf/zest-qi4j/diff/6b068deb

Branch: refs/heads/develop
Commit: 6b068deb3a24788f6f4f32c8c68cb49efad72aaa
Parents: 813aacf
Author: Niclas Hedhman <ni...@hedhman.org>
Authored: Wed Jun 17 10:32:46 2015 +0800
Committer: Niclas Hedhman <ni...@hedhman.org>
Committed: Wed Jun 17 10:32:46 2015 +0800

----------------------------------------------------------------------
 .../qi4j/spi/value/ValueSerializerAdapter.java  | 46 +++++++++++++-------
 1 file changed, 31 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/6b068deb/core/spi/src/main/java/org/qi4j/spi/value/ValueSerializerAdapter.java
----------------------------------------------------------------------
diff --git a/core/spi/src/main/java/org/qi4j/spi/value/ValueSerializerAdapter.java b/core/spi/src/main/java/org/qi4j/spi/value/ValueSerializerAdapter.java
index 71717db..3625a21 100644
--- a/core/spi/src/main/java/org/qi4j/spi/value/ValueSerializerAdapter.java
+++ b/core/spi/src/main/java/org/qi4j/spi/value/ValueSerializerAdapter.java
@@ -48,7 +48,6 @@ import org.qi4j.api.value.ValueSerializationException;
 import org.qi4j.api.value.ValueSerializer;
 import org.qi4j.functional.Function;
 import org.qi4j.functional.Function2;
-import org.qi4j.spi.Qi4jSPI;
 
 import static org.qi4j.functional.Iterables.first;
 
@@ -417,6 +416,7 @@ public abstract class ValueSerializerAdapter<OutputType>
 
         onObjectStart( output );
 
+        //noinspection ConstantConditions
         if( options.getBoolean( Options.INCLUDE_TYPE_INFO ) && !rootPass )
         {
             onFieldStart( output, "_type" );
@@ -517,26 +517,42 @@ public abstract class ValueSerializerAdapter<OutputType>
     {
         @SuppressWarnings( "unchecked" )
         Map<Object, Object> map = (Map<Object, Object>) object;
-        onArrayStart( output );
-        for( Map.Entry<Object, Object> entry : map.entrySet() )
+        if( options.getBoolean( Options.MAP_ENTRIES_AS_OBJECTS ) )
         {
             onObjectStart( output );
+            for( Map.Entry<Object, Object> entry : map.entrySet() )
+            {
+                onFieldStart( output, entry.getKey().toString() );
+                onValueStart( output );
+                doSerialize( options, entry.getValue(), output, false );
+                onValueEnd( output );
+                onFieldEnd( output );
+            }
+            onObjectEnd( output );
+        }
+        else
+        {
+            onArrayStart( output );
+            for( Map.Entry<Object, Object> entry : map.entrySet() )
+            {
+                onObjectStart( output );
 
-            onFieldStart( output, "key" );
-            onValueStart( output );
-            onValue( output, entry.getKey().toString() );
-            onValueEnd( output );
-            onFieldEnd( output );
+                onFieldStart( output, "key" );
+                onValueStart( output );
+                onValue( output, entry.getKey().toString() );
+                onValueEnd( output );
+                onFieldEnd( output );
 
-            onFieldStart( output, "value" );
-            onValueStart( output );
-            doSerialize( options, entry.getValue(), output, false );
-            onValueEnd( output );
-            onFieldEnd( output );
+                onFieldStart( output, "value" );
+                onValueStart( output );
+                doSerialize( options, entry.getValue(), output, false );
+                onValueEnd( output );
+                onFieldEnd( output );
 
-            onObjectEnd( output );
+                onObjectEnd( output );
+            }
+            onArrayEnd( output );
         }
-        onArrayEnd( output );
     }
 
     private void serializeBase64Serializable( Object object, OutputType output )


[4/6] zest-qi4j git commit: There is an assumeNoException(), which should be used.

Posted by ni...@apache.org.
There is an assumeNoException(), which should be used.


Project: http://git-wip-us.apache.org/repos/asf/zest-qi4j/repo
Commit: http://git-wip-us.apache.org/repos/asf/zest-qi4j/commit/ed98b17e
Tree: http://git-wip-us.apache.org/repos/asf/zest-qi4j/tree/ed98b17e
Diff: http://git-wip-us.apache.org/repos/asf/zest-qi4j/diff/ed98b17e

Branch: refs/heads/develop
Commit: ed98b17e27e9f72024e7120870137af1e0ed8eaf
Parents: b49e394
Author: Niclas Hedhman <ni...@hedhman.org>
Authored: Wed Jun 17 10:37:48 2015 +0800
Committer: Niclas Hedhman <ni...@hedhman.org>
Committed: Wed Jun 17 10:37:48 2015 +0800

----------------------------------------------------------------------
 core/testsupport/src/main/java/org/qi4j/test/util/Assume.java | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/ed98b17e/core/testsupport/src/main/java/org/qi4j/test/util/Assume.java
----------------------------------------------------------------------
diff --git a/core/testsupport/src/main/java/org/qi4j/test/util/Assume.java b/core/testsupport/src/main/java/org/qi4j/test/util/Assume.java
index f8b23e4..f60b0d3 100644
--- a/core/testsupport/src/main/java/org/qi4j/test/util/Assume.java
+++ b/core/testsupport/src/main/java/org/qi4j/test/util/Assume.java
@@ -73,11 +73,12 @@ public class Assume
         }
         catch( SocketException ex )
         {
-            assumeFalse( true );
+            assumeNoException( ex );
         }
     }
 
     /**
+     * // TODO: qi4j.org will soon go down.
      * If called on a runtime with no access to qi4j.org on port 80, the test will halt and be ignored.
      */
     public static void assumeConnectivity()
@@ -99,7 +100,7 @@ public class Assume
         }
         catch( IOException ex )
         {
-            assumeFalse( true );
+            assumeNoException( ex );
         }
     }
 


[5/6] zest-qi4j git commit: Removed unused import.

Posted by ni...@apache.org.
Removed unused import.


Project: http://git-wip-us.apache.org/repos/asf/zest-qi4j/repo
Commit: http://git-wip-us.apache.org/repos/asf/zest-qi4j/commit/454154e8
Tree: http://git-wip-us.apache.org/repos/asf/zest-qi4j/tree/454154e8
Diff: http://git-wip-us.apache.org/repos/asf/zest-qi4j/diff/454154e8

Branch: refs/heads/develop
Commit: 454154e8212df3b11c411a6925d538e218ad710c
Parents: ed98b17
Author: Niclas Hedhman <ni...@hedhman.org>
Authored: Wed Jun 17 10:38:21 2015 +0800
Committer: Niclas Hedhman <ni...@hedhman.org>
Committed: Wed Jun 17 10:38:21 2015 +0800

----------------------------------------------------------------------
 .../org/qi4j/index/rdf/assembly/RdfNativeSesameStoreAssembler.java  | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/454154e8/extensions/indexing-rdf/src/main/java/org/qi4j/index/rdf/assembly/RdfNativeSesameStoreAssembler.java
----------------------------------------------------------------------
diff --git a/extensions/indexing-rdf/src/main/java/org/qi4j/index/rdf/assembly/RdfNativeSesameStoreAssembler.java b/extensions/indexing-rdf/src/main/java/org/qi4j/index/rdf/assembly/RdfNativeSesameStoreAssembler.java
index 919824d..15782a6 100644
--- a/extensions/indexing-rdf/src/main/java/org/qi4j/index/rdf/assembly/RdfNativeSesameStoreAssembler.java
+++ b/extensions/indexing-rdf/src/main/java/org/qi4j/index/rdf/assembly/RdfNativeSesameStoreAssembler.java
@@ -22,6 +22,7 @@ import org.qi4j.index.rdf.RdfIndexingEngineService;
 import org.qi4j.index.rdf.query.RdfQueryParserFactory;
 import org.qi4j.library.rdf.entity.EntityStateSerializer;
 import org.qi4j.library.rdf.entity.EntityTypeSerializer;
+import org.qi4j.library.rdf.repository.NativeConfiguration;
 import org.qi4j.library.rdf.repository.NativeRepositoryService;
 import org.qi4j.valueserialization.orgjson.OrgJsonValueSerializationService;
 


[2/6] zest-qi4j git commit: For got to commit the Option setting for the new Map serialization to work.

Posted by ni...@apache.org.
For got to commit the Option setting for the new Map serialization to work.


Project: http://git-wip-us.apache.org/repos/asf/zest-qi4j/repo
Commit: http://git-wip-us.apache.org/repos/asf/zest-qi4j/commit/c2dafaf5
Tree: http://git-wip-us.apache.org/repos/asf/zest-qi4j/tree/c2dafaf5
Diff: http://git-wip-us.apache.org/repos/asf/zest-qi4j/diff/c2dafaf5

Branch: refs/heads/develop
Commit: c2dafaf516401561c8aaf88eb32b3849ac2948f5
Parents: 6b068de
Author: Niclas Hedhman <ni...@hedhman.org>
Authored: Wed Jun 17 10:34:22 2015 +0800
Committer: Niclas Hedhman <ni...@hedhman.org>
Committed: Wed Jun 17 10:34:22 2015 +0800

----------------------------------------------------------------------
 .../main/java/org/qi4j/api/value/ValueSerializer.java   | 12 ++++++++++++
 1 file changed, 12 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/c2dafaf5/core/api/src/main/java/org/qi4j/api/value/ValueSerializer.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/qi4j/api/value/ValueSerializer.java b/core/api/src/main/java/org/qi4j/api/value/ValueSerializer.java
index 7f22d70..337c37e 100644
--- a/core/api/src/main/java/org/qi4j/api/value/ValueSerializer.java
+++ b/core/api/src/main/java/org/qi4j/api/value/ValueSerializer.java
@@ -174,6 +174,7 @@ public interface ValueSerializer
          * Default to TRUE.
          */
         public static final String INCLUDE_TYPE_INFO = "includeTypeInfo";
+        public static final String MAP_ENTRIES_AS_OBJECTS = "mapentriesasobjects";
         private final Map<String, String> options = new HashMap<>();
 
         /**
@@ -182,6 +183,7 @@ public interface ValueSerializer
         public Options()
         {
             this.options.put( INCLUDE_TYPE_INFO, "true" );
+            this.options.put( MAP_ENTRIES_AS_OBJECTS, "false" );
         }
 
         /**
@@ -202,6 +204,16 @@ public interface ValueSerializer
             return put( INCLUDE_TYPE_INFO, false );
         }
 
+        public Options withMapEntriesAsObjects()
+        {
+            return put( MAP_ENTRIES_AS_OBJECTS, true );
+        }
+
+        public Options withMapEntriesAsKeyValuePairs()
+        {
+            return put( MAP_ENTRIES_AS_OBJECTS, false );
+        }
+
         /**
          * Get Boolean option value.
          * @param option The option


[3/6] zest-qi4j git commit: Ignored testcase, which is not clear to me why it is ignored or what it is trying to test. Uncommenting everything, and it doesn't compile, so time to chuck it away.

Posted by ni...@apache.org.
Ignored testcase, which is not clear to me why it is ignored or what it is trying to test. Uncommenting everything, and it doesn't compile, so time to chuck it away.


Project: http://git-wip-us.apache.org/repos/asf/zest-qi4j/repo
Commit: http://git-wip-us.apache.org/repos/asf/zest-qi4j/commit/b49e3949
Tree: http://git-wip-us.apache.org/repos/asf/zest-qi4j/tree/b49e3949
Diff: http://git-wip-us.apache.org/repos/asf/zest-qi4j/diff/b49e3949

Branch: refs/heads/develop
Commit: b49e3949be71af384f6bcf4d67c628e016421218
Parents: c2dafaf
Author: Niclas Hedhman <ni...@hedhman.org>
Authored: Wed Jun 17 10:36:36 2015 +0800
Committer: Niclas Hedhman <ni...@hedhman.org>
Committed: Wed Jun 17 10:36:36 2015 +0800

----------------------------------------------------------------------
 .../common/UnitOfWorkCallbackEntityTest.java    | 81 --------------------
 1 file changed, 81 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/b49e3949/core/runtime/src/test/java/org/qi4j/api/common/UnitOfWorkCallbackEntityTest.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/test/java/org/qi4j/api/common/UnitOfWorkCallbackEntityTest.java b/core/runtime/src/test/java/org/qi4j/api/common/UnitOfWorkCallbackEntityTest.java
deleted file mode 100644
index 8adb31f..0000000
--- a/core/runtime/src/test/java/org/qi4j/api/common/UnitOfWorkCallbackEntityTest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (c) 2008, Rickard Öberg. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package org.qi4j.api.common;
-
-import org.junit.Ignore;
-import org.junit.Test;
-import org.qi4j.api.entity.EntityComposite;
-import org.qi4j.api.unitofwork.UnitOfWork;
-import org.qi4j.api.unitofwork.UnitOfWorkCompletionException;
-import org.qi4j.bootstrap.AssemblyException;
-import org.qi4j.bootstrap.ModuleAssembly;
-import org.qi4j.test.AbstractQi4jTest;
-import org.qi4j.test.EntityTestAssembler;
-
-import static org.junit.Assert.fail;
-
-/**
- * Test UnitOfWorkCallback and Validatable
- */
-public class UnitOfWorkCallbackEntityTest
-    extends AbstractQi4jTest
-{
-    public void assemble( ModuleAssembly module )
-        throws AssemblyException
-    {
-        module.entities( TestCase.class );
-        new EntityTestAssembler().assemble( module );
-    }
-
-    @Test
-    @Ignore( "Validation is moved to sandbox, and UoW is under massive refactoring." )
-    public void givenCompositeWithValidatableWhenUnitCompletesThenPerformValidation()
-        throws UnitOfWorkCompletionException
-    {
-        UnitOfWork uow = module.newUnitOfWork();
-        TestCase test = uow.newEntity( TestCase.class );
-
-        try
-        {
-            uow.complete();
-            fail( "Validation did not occur" );
-        }
-        finally
-        {
-            uow.discard();
-        }
-    }
-
-    //    @Concerns( TestValidatableConcern.class )
-
-    interface TestCase
-        extends EntityComposite  //, ValidatableAbstractComposite
-    {
-    }
-/*
-    public static abstract class TestValidatableConcern extends AbstractValidatableConcern
-    {
-        @Override protected void isValid( Validator validator )
-        {
-            validator.error( true, "Validation error" );
-        }
-
-        @Override protected String getResourceBundle()
-        {
-            return null;
-        }
-    }
-*/
-}


[6/6] zest-qi4j git commit: New way to structure the bootstrap code, to make it easier than the low-level primitives that are required under the hood. It betters suits the mental model, rather than the internal programming model.

Posted by ni...@apache.org.
New way to structure the bootstrap code, to make it easier than the low-level primitives that are required under the hood. It betters suits the mental model, rather than the internal programming model.


Project: http://git-wip-us.apache.org/repos/asf/zest-qi4j/repo
Commit: http://git-wip-us.apache.org/repos/asf/zest-qi4j/commit/b86b66d4
Tree: http://git-wip-us.apache.org/repos/asf/zest-qi4j/tree/b86b66d4
Diff: http://git-wip-us.apache.org/repos/asf/zest-qi4j/diff/b86b66d4

Branch: refs/heads/develop
Commit: b86b66d4ec80e51dceb0f608082a5b0b4062d16c
Parents: 454154e
Author: Niclas Hedhman <ni...@hedhman.org>
Authored: Wed Jun 17 10:39:36 2015 +0800
Committer: Niclas Hedhman <ni...@hedhman.org>
Committed: Wed Jun 17 10:39:36 2015 +0800

----------------------------------------------------------------------
 core/bootstrap/src/docs/bootstrap.txt           |  86 +++++++--
 .../bootstrap/builder/ApplicationBuilder.java   |  19 +-
 .../qi4j/bootstrap/layered/LayerAssembler.java  |  10 +
 .../layered/LayeredApplicationAssembler.java    | 189 +++++++++++++++++++
 .../layered/LayeredLayerAssembler.java          |  62 ++++++
 .../qi4j/bootstrap/layered/ModuleAssembler.java |  11 ++
 .../LayeredApplicationAssemblerTest.java        |  23 +++
 .../bootstrap/assembly/TestApplication.java     |  43 +++++
 .../assembly/config/ConfigurationLayer.java     |  15 ++
 .../connectivity/ConnectivityLayer.java         |  17 ++
 .../bootstrap/assembly/domain/DomainLayer.java  |  17 ++
 .../assembly/domain/InvoicingModule.java        |  17 ++
 .../bootstrap/assembly/domain/OrderModule.java  |  38 ++++
 .../assembly/infrastructure/IndexingModule.java |  26 +++
 .../infrastructure/InfrastructureLayer.java     |  29 +++
 .../infrastructure/SerializationModule.java     |  18 ++
 .../assembly/infrastructure/StorageModule.java  |  26 +++
 .../assembly/service/ServiceLayer.java          |  17 ++
 18 files changed, 647 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/b86b66d4/core/bootstrap/src/docs/bootstrap.txt
----------------------------------------------------------------------
diff --git a/core/bootstrap/src/docs/bootstrap.txt b/core/bootstrap/src/docs/bootstrap.txt
index 80da48e..22165c9 100644
--- a/core/bootstrap/src/docs/bootstrap.txt
+++ b/core/bootstrap/src/docs/bootstrap.txt
@@ -30,7 +30,8 @@ to a module and visibility rules define default behaviors, enforcement of archit
 The _assembly_ is preceeded by the creation of the _Qi4j Runtime_. The _assembly_ can be declared fully by defining
 all modules and layers, and how the layers are sitting on top of each other, OR one can utilize one of the two
 convenience assemblies, one for a _pancake_ pattern, where all layers are top on each other, or one with a single module
-in a single layer, useful for small applications, spikes and tests.
+in a single layer, useful for small applications, spikes and tests. The +bootstrap+ system has several ways to acheive
+this, and they are listed below in <<core-bootstrap-assembly-layered>>.
 
 During _assembly_, the application (JVM level) architecture and the application model is defined. You define which
 layers exist and how they relate to each other. For each layer, you define which modules it contains. And for each
@@ -125,15 +126,6 @@ tag=properties-defaults
 == Setting meta information on assembled types ==
 
 
-== Facilities ==
-
-=== Assembly Specifications ===
-
-=== Class Scanner ===
-
-=== Application Builder ===
-
-
 == Using Assemblers ==
 Many <<libraries,libraries>> and <<extensions,extensions>> provides a cookie-cutter _Assembler_, to simplify the set up
 of such component. Often these are suitable, but sometimes they won't fit the application in hand, in which case the
@@ -173,6 +165,44 @@ tag=UsingAssembler
 --------------
 
 
+[[core-bootstrap-assembly-layered,Layered Application Assembler]]
+== Layered Application Assembler (RECOMMENDED!) ==
+
+In 2.1, a new way to instantiate Qi4j applications was introduced. It starts with subclassing the
++LayeredApplicationAssembler+, and implementing the +assembleLayers()+ method.
+
+In the +assembleLayers()+ method, one is epected to either call the +createLayer()+ method in the super class
+with the Class of the LayerAssembler,
+
+[source,java]
+----
+    LayerAssembly domainLayer = createLayer( DomainLayer.class );
+----
+
+OR manually instantiate and call the LayerAssembler.
+
+[source,java]
+----
+    LayerAssembly infraLayer = new InfrastructureLayer( configModule ).assemble( assembly.layer( InfrastructureLayer.NAME  ));
+----
+
+This is to make the normal case as simple as possible, yet allow the special needs that occssionally surfaces.
+
+Each LayerAssembler implementation may optionally extend the +LayeredLayerAssembler+, to get access to the
++createModule()+ method, which again simplifies the creation of modules in the +assemble()+ method.
+
+[source,java]
+----
+    createModule( layer, InvoicingModule.class );
+----
+
++ModuleAssembler+ implementations typically use +Assembler+ classes to put together, or call the +entities()+,
++values()+ methods described elsewhere on this page. There is no superclass to use.
+
++ModuleAssembler+ implementations should have a name ending with "Module" and the naming will insert a human-readable
+space within the module name, e.g. +InvoicingModule+ will be named "Invoicing Module".
+
+For example code, see the tutorial <<howto-assemble-application>>.
 
 
 == Singleton Assembler ==
@@ -193,7 +223,39 @@ Once the SingletonAssembler constructor returns, the Qi4j application is up and
 The SingletonAssembler also makes common system resources available from the bootstrap code, such as
 Module, UnitOfWorkFactory and others. This is possible since there is only one Module.
 
-
+== Application Builder ==
+Some applications has no need for runtime determination of the exact application structure, and no need for
+advanced alterations to a staright-forward layered application structure. By using the +ApplicationBuilder+
+it is possible to define the application structure from a JSON document, AND call the provided +main()+ class,
+taking the JSON document as input on +System.in+.
+
+The format of the JSON document, directly reflects the application structure, such as
+[source,json]
+----
+{
+    "name": "Build from JSON test.",
+    "layers": [
+        { "name": "service", "uses": [ "domain", "config"] },
+        { "name": "donfig" },
+        {
+            "name": "domain",
+            "modules" : [
+                {
+                    "name" : "Invoicing",
+                    "assemblers" : [
+                        "org.hedhman.niclas.bootstrap.InvoicingAssembler"
+                    ]
+                }
+            ]
+        }
+    ]
+}
+----
+
+At the moment, the JSON format only support +Assembler+ classes to do the work.
+
+Another way to use the +ApplicationBuilder+ is to subclass it, optionally use the +configureFromJSON()+ method,
+and then programmatically enhance the structure before calling +newApplication()+.
 
 == Pancake Assembly ==
 There is one case that stands out as a common case, and forms a reasonable middle-ground. It is where each layer sits
@@ -210,8 +272,6 @@ source=core/bootstrap/src/test/java/org/qi4j/bootstrap/DocumentationSupport.java
 tag=pancake
 --------------
 
-
-
 == Full Assembly ==
 Full Assembly means that you have the opportunity to create any layer/module hierarchy that are within the rules of the
 Qi4j runtime. It requires more support in your code to be useful, and the example below is by no means a recommended way

http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/b86b66d4/core/bootstrap/src/main/java/org/qi4j/bootstrap/builder/ApplicationBuilder.java
----------------------------------------------------------------------
diff --git a/core/bootstrap/src/main/java/org/qi4j/bootstrap/builder/ApplicationBuilder.java b/core/bootstrap/src/main/java/org/qi4j/bootstrap/builder/ApplicationBuilder.java
index c008e5f..d68a3d5 100644
--- a/core/bootstrap/src/main/java/org/qi4j/bootstrap/builder/ApplicationBuilder.java
+++ b/core/bootstrap/src/main/java/org/qi4j/bootstrap/builder/ApplicationBuilder.java
@@ -180,6 +180,19 @@ public class ApplicationBuilder
     {
         String applicationName = root.getString( "name" );
         ApplicationBuilder builder = new ApplicationBuilder( applicationName );
+        builder.configureWithJson( root );
+        return builder;
+    }
+
+    /** Configures the application struucture from a JSON document.
+     *
+     * @param root The JSON document root.
+     * @throws JSONException if the JSON document isn't valid.
+     * @throws AssemblyException if probelms in the Assemblers provided in the JSON document.
+     */
+    protected void configureWithJson( JSONObject root )
+        throws JSONException, AssemblyException
+    {
         JSONArray layers = root.optJSONArray( "layers" );
         if( layers != null )
         {
@@ -187,7 +200,7 @@ public class ApplicationBuilder
             {
                 JSONObject layerObject = layers.getJSONObject( i );
                 String layerName = layerObject.getString( "name" );
-                LayerDeclaration layerDeclaration = builder.withLayer( layerName );
+                LayerDeclaration layerDeclaration = withLayer( layerName );
                 JSONArray using = layerObject.optJSONArray( "uses" );
                 if( using != null )
                 {
@@ -209,14 +222,14 @@ public class ApplicationBuilder
                         {
                             for( int m = 0; m < assemblers.length(); m++ )
                             {
-                                moduleDeclaration.withAssembler( assemblers.getString( m ) );
+                                String string = assemblers.getString( m );
+                                moduleDeclaration.withAssembler( string );
                             }
                         }
                     }
                 }
             }
         }
-        return builder;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/b86b66d4/core/bootstrap/src/main/java/org/qi4j/bootstrap/layered/LayerAssembler.java
----------------------------------------------------------------------
diff --git a/core/bootstrap/src/main/java/org/qi4j/bootstrap/layered/LayerAssembler.java b/core/bootstrap/src/main/java/org/qi4j/bootstrap/layered/LayerAssembler.java
new file mode 100644
index 0000000..b922b98
--- /dev/null
+++ b/core/bootstrap/src/main/java/org/qi4j/bootstrap/layered/LayerAssembler.java
@@ -0,0 +1,10 @@
+package org.qi4j.bootstrap.layered;
+
+import org.qi4j.bootstrap.AssemblyException;
+import org.qi4j.bootstrap.LayerAssembly;
+
+public interface LayerAssembler
+{
+    LayerAssembly assemble( LayerAssembly layer )
+        throws AssemblyException;
+}

http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/b86b66d4/core/bootstrap/src/main/java/org/qi4j/bootstrap/layered/LayeredApplicationAssembler.java
----------------------------------------------------------------------
diff --git a/core/bootstrap/src/main/java/org/qi4j/bootstrap/layered/LayeredApplicationAssembler.java b/core/bootstrap/src/main/java/org/qi4j/bootstrap/layered/LayeredApplicationAssembler.java
new file mode 100644
index 0000000..7eb00d5
--- /dev/null
+++ b/core/bootstrap/src/main/java/org/qi4j/bootstrap/layered/LayeredApplicationAssembler.java
@@ -0,0 +1,189 @@
+package org.qi4j.bootstrap.layered;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import org.qi4j.api.activation.ActivationException;
+import org.qi4j.api.activation.PassivationException;
+import org.qi4j.api.structure.Application;
+import org.qi4j.api.structure.ApplicationDescriptor;
+import org.qi4j.bootstrap.ApplicationAssembler;
+import org.qi4j.bootstrap.ApplicationAssembly;
+import org.qi4j.bootstrap.ApplicationAssemblyFactory;
+import org.qi4j.bootstrap.AssemblyException;
+import org.qi4j.bootstrap.Energy4Java;
+import org.qi4j.bootstrap.LayerAssembly;
+
+public abstract class LayeredApplicationAssembler
+    implements ApplicationAssembler
+{
+    protected Application application;
+    protected String name;
+    protected String version;
+    private final Application.Mode mode;
+    private ApplicationAssembly assembly;
+
+    private HashMap<Class<? extends LayerAssembler>, LayerAssembler> assemblers = new HashMap<>();
+
+    public LayeredApplicationAssembler( String name, String version, Application.Mode mode )
+        throws AssemblyException
+    {
+        this.name = name;
+        this.version = version;
+        this.mode = mode;
+        Energy4Java qi4j = new Energy4Java();
+        ApplicationDescriptor model = qi4j.newApplicationModel( this );
+        onModelCreated( model );
+        instantiateApplication( qi4j, model );
+    }
+
+    /**
+     * This method is called from the constructor to instantiate the Qi4j application from the application model.
+     *
+     * <p>
+     * The default implementation simply calls;
+     * <pre><code>
+     *   application = model.newInstance( qi4j.spi() );
+     * </code></pre>
+     * </p>
+     *
+     * @param qi4j  The Qi4j runtime engine.
+     * @param model The application model descriptor.
+     */
+    protected void instantiateApplication( Energy4Java qi4j, ApplicationDescriptor model )
+    {
+        application = model.newInstance( qi4j.spi() );
+    }
+
+    /**
+     * This method is called after the Application Model has been created, before the instantiation of the Qi4j
+     * application.
+     *
+     * <p>
+     * The default implementation does nothing. Applications may have advanced features to inspect or
+     * modify the model prior to instantiation, and this is the place where such advanced manipulation is
+     * expected to take place.
+     * </p>
+     *
+     * @param model
+     */
+    protected void onModelCreated( ApplicationDescriptor model )
+    {
+    }
+
+    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
+    {
+        assembly = applicationFactory.newApplicationAssembly();
+        assembly.setName( name );
+        assembly.setVersion( version );
+        assembly.setMode( mode );
+        assembleLayers( assembly );
+        return assembly;
+    }
+
+    protected LayerAssembly createLayer( Class<? extends LayerAssembler> layerAssemblerClass )
+        throws IllegalArgumentException
+    {
+        try
+        {
+            String classname = layerAssemblerClass.getSimpleName();
+            if( classname.endsWith( "Layer" ) )
+            {
+                classname = classname.substring( 0, classname.length() - 5 ) + " Layer";
+            }
+            setNameIfPresent( layerAssemblerClass, classname );
+            LayerAssembly layer = assembly.layer( classname );
+
+            LayerAssembler layerAssembler = instantiateAssembler( layerAssemblerClass, layer );
+            assemblers.put( layerAssemblerClass, layerAssembler );
+            LayerAssembly assembly = layerAssembler.assemble( layer );
+            if( assembly == null )
+            {
+                // Assume that people forgot, and let's not require a "return layer", since we can do that ourselves.
+                return layer;
+            }
+            return assembly;
+        }
+        catch( Exception e )
+        {
+            throw new IllegalArgumentException( "Unable to instantiate layer with " + layerAssemblerClass.getSimpleName(), e );
+        }
+    }
+
+    private LayerAssembler instantiateAssembler( Class<? extends LayerAssembler> layerAssemblerClass,
+                                                 LayerAssembly layer
+    )
+        throws InstantiationException, IllegalAccessException, java.lang.reflect.InvocationTargetException
+    {
+        LayerAssembler layerAssembler;
+        try
+        {
+            Constructor<? extends LayerAssembler> assemblyConstructor = layerAssemblerClass.getConstructor( LayerAssembly.class );
+            layerAssembler = assemblyConstructor.newInstance( layer );
+        }
+        catch( NoSuchMethodException e )
+        {
+            // Use default constructor then.
+            layerAssembler = layerAssemblerClass.newInstance();
+        }
+        return layerAssembler;
+    }
+
+    static void setNameIfPresent( Class<?> clazz, String classname )
+        throws IllegalAccessException
+    {
+        try
+        {
+            Field field = clazz.getDeclaredField( "NAME" );
+            if( Modifier.isStatic( field.getModifiers() ) )
+            {
+                field.setAccessible( true );
+                field.set( null, classname );
+            }
+        }
+        catch( Exception e )
+        {
+            // Ignore and consider normal.
+        }
+    }
+
+    @SuppressWarnings( "unchecked" )
+    protected <T extends LayerAssembler> T assemblerOf( Class<T> layerAssemblerClass )
+    {
+        return (T) assemblers.get( layerAssemblerClass );
+    }
+
+    /**
+     * Called from the constructor to assemble the layers in the applcation.
+     *
+     * <p>
+     * This method must be implemented, and is typically a list of LayerAssmebler instantitations, followed
+     * by {@link LayerAssembly#uses(LayerAssembly...)} declarations.
+     * <pre><code>
+     *
+     * </code></pre>
+     * </p>
+     */
+    protected abstract void assembleLayers( ApplicationAssembly assembly )
+        throws AssemblyException;
+}

http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/b86b66d4/core/bootstrap/src/main/java/org/qi4j/bootstrap/layered/LayeredLayerAssembler.java
----------------------------------------------------------------------
diff --git a/core/bootstrap/src/main/java/org/qi4j/bootstrap/layered/LayeredLayerAssembler.java b/core/bootstrap/src/main/java/org/qi4j/bootstrap/layered/LayeredLayerAssembler.java
new file mode 100644
index 0000000..91ca286
--- /dev/null
+++ b/core/bootstrap/src/main/java/org/qi4j/bootstrap/layered/LayeredLayerAssembler.java
@@ -0,0 +1,62 @@
+package org.qi4j.bootstrap.layered;
+
+import java.lang.reflect.Constructor;
+import java.util.HashMap;
+import org.qi4j.bootstrap.LayerAssembly;
+import org.qi4j.bootstrap.ModuleAssembly;
+
+public abstract class LayeredLayerAssembler
+    implements LayerAssembler
+{
+    private HashMap<Class<? extends ModuleAssembler>, ModuleAssembler> assemblers = new HashMap<>();
+
+    protected ModuleAssembly createModule( LayerAssembly layer, Class<? extends ModuleAssembler> modulerAssemblerClass )
+    {
+        try
+        {
+            ModuleAssembler moduleAssembler = instantiateAssembler( layer, modulerAssemblerClass );
+            String classname = modulerAssemblerClass.getSimpleName();
+            if( classname.endsWith( "Module" ) )
+            {
+                classname = classname.substring( 0, classname.length() - 6 ) + " Module";
+            }
+            LayeredApplicationAssembler.setNameIfPresent( modulerAssemblerClass, classname );
+            ModuleAssembly module = layer.module( classname );
+            assemblers.put( modulerAssemblerClass, moduleAssembler );
+            ModuleAssembly assembly = moduleAssembler.assemble( layer, module );
+            if( assembly == null )
+            {
+                return module;
+            }
+            return assembly;
+        }
+        catch( Exception e )
+        {
+            throw new IllegalArgumentException( "Unable to instantiate module with " + modulerAssemblerClass.getSimpleName(), e );
+        }
+    }
+
+    private ModuleAssembler instantiateAssembler( LayerAssembly layer,
+                                                  Class<? extends ModuleAssembler> modulerAssemblerClass
+    )
+        throws InstantiationException, IllegalAccessException, java.lang.reflect.InvocationTargetException
+    {
+        ModuleAssembler moduleAssembler;
+        try
+        {
+            Constructor<? extends ModuleAssembler> assemblyConstructor = modulerAssemblerClass.getConstructor( ModuleAssembly.class );
+            moduleAssembler = assemblyConstructor.newInstance( layer );
+        }
+        catch( NoSuchMethodException e )
+        {
+            moduleAssembler = modulerAssemblerClass.newInstance();
+        }
+        return moduleAssembler;
+    }
+
+    @SuppressWarnings( "unchecked" )
+    protected <T extends ModuleAssembler> T assemblerOf( Class<T> moduleAssemblerType )
+    {
+        return (T) assemblers.get( moduleAssemblerType );
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/b86b66d4/core/bootstrap/src/main/java/org/qi4j/bootstrap/layered/ModuleAssembler.java
----------------------------------------------------------------------
diff --git a/core/bootstrap/src/main/java/org/qi4j/bootstrap/layered/ModuleAssembler.java b/core/bootstrap/src/main/java/org/qi4j/bootstrap/layered/ModuleAssembler.java
new file mode 100644
index 0000000..d09bac5
--- /dev/null
+++ b/core/bootstrap/src/main/java/org/qi4j/bootstrap/layered/ModuleAssembler.java
@@ -0,0 +1,11 @@
+package org.qi4j.bootstrap.layered;
+
+import org.qi4j.bootstrap.AssemblyException;
+import org.qi4j.bootstrap.LayerAssembly;
+import org.qi4j.bootstrap.ModuleAssembly;
+
+public interface ModuleAssembler
+{
+    ModuleAssembly assemble( LayerAssembly layer, ModuleAssembly module )
+        throws AssemblyException;
+}

http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/b86b66d4/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/LayeredApplicationAssemblerTest.java
----------------------------------------------------------------------
diff --git a/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/LayeredApplicationAssemblerTest.java b/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/LayeredApplicationAssemblerTest.java
new file mode 100644
index 0000000..c63a3bd
--- /dev/null
+++ b/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/LayeredApplicationAssemblerTest.java
@@ -0,0 +1,23 @@
+package org.qi4j.bootstrap.assembly;
+
+import org.junit.Test;
+import org.qi4j.api.activation.ActivationException;
+import org.qi4j.api.structure.Application;
+import org.qi4j.bootstrap.AssemblyException;
+
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+
+public class LayeredApplicationAssemblerTest
+{
+    @Test
+    public void validateThatAssemblerCreatesApplication()
+        throws AssemblyException, ActivationException
+    {
+        TestApplication assembler = new TestApplication( "Test Application", "1.0.1", Application.Mode.test );
+        assembler.start();
+
+        assertThat( assembler.application().name(), equalTo("Test Application") );
+        assertThat( assembler.application().version(), equalTo("1.0.1") );
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/b86b66d4/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/TestApplication.java
----------------------------------------------------------------------
diff --git a/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/TestApplication.java b/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/TestApplication.java
new file mode 100644
index 0000000..4f44c7f
--- /dev/null
+++ b/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/TestApplication.java
@@ -0,0 +1,43 @@
+package org.qi4j.bootstrap.assembly;
+
+import org.qi4j.api.structure.Application;
+import org.qi4j.bootstrap.ApplicationAssembly;
+import org.qi4j.bootstrap.AssemblyException;
+import org.qi4j.bootstrap.layered.LayeredApplicationAssembler;
+import org.qi4j.bootstrap.LayerAssembly;
+import org.qi4j.bootstrap.ModuleAssembly;
+import org.qi4j.bootstrap.assembly.config.ConfigurationLayer;
+import org.qi4j.bootstrap.assembly.connectivity.ConnectivityLayer;
+import org.qi4j.bootstrap.assembly.domain.DomainLayer;
+import org.qi4j.bootstrap.assembly.infrastructure.InfrastructureLayer;
+import org.qi4j.bootstrap.assembly.service.ServiceLayer;
+
+// START SNIPPET: application
+public class TestApplication extends LayeredApplicationAssembler
+{
+
+    public TestApplication( String name, String version, Application.Mode mode )
+        throws AssemblyException
+    {
+        super( name, version, mode );
+    }
+
+    @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 );
+    }
+}
+// END SNIPPET: application

http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/b86b66d4/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/config/ConfigurationLayer.java
----------------------------------------------------------------------
diff --git a/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/config/ConfigurationLayer.java b/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/config/ConfigurationLayer.java
new file mode 100644
index 0000000..419a789
--- /dev/null
+++ b/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/config/ConfigurationLayer.java
@@ -0,0 +1,15 @@
+package org.qi4j.bootstrap.assembly.config;
+
+import org.qi4j.bootstrap.AssemblyException;
+import org.qi4j.bootstrap.layered.LayerAssembler;
+import org.qi4j.bootstrap.LayerAssembly;
+
+public class ConfigurationLayer implements LayerAssembler
+{
+    @Override
+    public LayerAssembly assemble( LayerAssembly layer )
+        throws AssemblyException
+    {
+        return layer;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/b86b66d4/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/connectivity/ConnectivityLayer.java
----------------------------------------------------------------------
diff --git a/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/connectivity/ConnectivityLayer.java b/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/connectivity/ConnectivityLayer.java
new file mode 100644
index 0000000..5631a68
--- /dev/null
+++ b/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/connectivity/ConnectivityLayer.java
@@ -0,0 +1,17 @@
+package org.qi4j.bootstrap.assembly.connectivity;
+
+import org.qi4j.bootstrap.AssemblyException;
+import org.qi4j.bootstrap.layered.LayerAssembler;
+import org.qi4j.bootstrap.LayerAssembly;
+
+public class ConnectivityLayer implements LayerAssembler
+{
+    public static final String NAME = "Connectivity";
+
+    @Override
+    public LayerAssembly assemble( LayerAssembly layer )
+        throws AssemblyException
+    {
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/b86b66d4/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/domain/DomainLayer.java
----------------------------------------------------------------------
diff --git a/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/domain/DomainLayer.java b/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/domain/DomainLayer.java
new file mode 100644
index 0000000..ea7a12f
--- /dev/null
+++ b/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/domain/DomainLayer.java
@@ -0,0 +1,17 @@
+package org.qi4j.bootstrap.assembly.domain;
+
+import org.qi4j.bootstrap.AssemblyException;
+import org.qi4j.bootstrap.LayerAssembly;
+import org.qi4j.bootstrap.layered.LayeredLayerAssembler;
+
+public class DomainLayer extends LayeredLayerAssembler
+{
+    @Override
+    public LayerAssembly assemble( LayerAssembly layer )
+        throws AssemblyException
+    {
+        createModule( layer, InvoicingModule.class );
+        createModule( layer, OrderModule.class );
+        return layer;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/b86b66d4/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/domain/InvoicingModule.java
----------------------------------------------------------------------
diff --git a/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/domain/InvoicingModule.java b/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/domain/InvoicingModule.java
new file mode 100644
index 0000000..0a654b5
--- /dev/null
+++ b/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/domain/InvoicingModule.java
@@ -0,0 +1,17 @@
+package org.qi4j.bootstrap.assembly.domain;
+
+import org.qi4j.bootstrap.AssemblyException;
+import org.qi4j.bootstrap.LayerAssembly;
+import org.qi4j.bootstrap.ModuleAssembly;
+import org.qi4j.bootstrap.layered.ModuleAssembler;
+
+public class InvoicingModule
+    implements ModuleAssembler
+{
+    @Override
+    public ModuleAssembly assemble( LayerAssembly layer, ModuleAssembly module )
+        throws AssemblyException
+    {
+        return module;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/b86b66d4/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/domain/OrderModule.java
----------------------------------------------------------------------
diff --git a/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/domain/OrderModule.java b/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/domain/OrderModule.java
new file mode 100644
index 0000000..b721332
--- /dev/null
+++ b/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/domain/OrderModule.java
@@ -0,0 +1,38 @@
+package org.qi4j.bootstrap.assembly.domain;
+
+import org.qi4j.api.association.Association;
+import org.qi4j.api.property.Property;
+import org.qi4j.bootstrap.AssemblyException;
+import org.qi4j.bootstrap.LayerAssembly;
+import org.qi4j.bootstrap.ModuleAssembly;
+import org.qi4j.bootstrap.layered.ModuleAssembler;
+
+public class OrderModule
+    implements ModuleAssembler
+{
+    @Override
+    public ModuleAssembly assemble( LayerAssembly layer, ModuleAssembly module )
+        throws AssemblyException
+    {
+        module.entities( Order.class, Customer.class );
+        module.values( Address.class );
+        return module;
+    }
+
+    public interface Order
+    {
+        Association<Customer> customer();
+
+        Property<Address> invoicingAddress();
+
+        Property<Address> deliveryAddress();
+    }
+
+    public interface Customer
+    {
+    }
+
+    public interface Address
+    {
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/b86b66d4/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/infrastructure/IndexingModule.java
----------------------------------------------------------------------
diff --git a/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/infrastructure/IndexingModule.java b/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/infrastructure/IndexingModule.java
new file mode 100644
index 0000000..a06a0f7
--- /dev/null
+++ b/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/infrastructure/IndexingModule.java
@@ -0,0 +1,26 @@
+package org.qi4j.bootstrap.assembly.infrastructure;
+
+import org.qi4j.api.common.Visibility;
+import org.qi4j.bootstrap.AssemblyException;
+import org.qi4j.bootstrap.LayerAssembly;
+import org.qi4j.bootstrap.ModuleAssembly;
+import org.qi4j.bootstrap.layered.ModuleAssembler;
+
+public class IndexingModule
+    implements ModuleAssembler
+{
+    public static final String NAME = "Indexing Module";
+    private final ModuleAssembly configModule;
+
+    public IndexingModule( ModuleAssembly configModule )
+    {
+        this.configModule = configModule;
+    }
+
+    @Override
+    public ModuleAssembly assemble( LayerAssembly layer, ModuleAssembly module )
+        throws AssemblyException
+    {
+        return module;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/b86b66d4/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/infrastructure/InfrastructureLayer.java
----------------------------------------------------------------------
diff --git a/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/infrastructure/InfrastructureLayer.java b/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/infrastructure/InfrastructureLayer.java
new file mode 100644
index 0000000..5ba33ba
--- /dev/null
+++ b/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/infrastructure/InfrastructureLayer.java
@@ -0,0 +1,29 @@
+package org.qi4j.bootstrap.assembly.infrastructure;
+
+import org.qi4j.bootstrap.AssemblyException;
+import org.qi4j.bootstrap.LayerAssembly;
+import org.qi4j.bootstrap.ModuleAssembly;
+import org.qi4j.bootstrap.layered.LayerAssembler;
+import org.qi4j.bootstrap.layered.LayeredLayerAssembler;
+
+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( configModule ).assemble( layer, layer.module( StorageModule.NAME ) );
+        new IndexingModule( configModule ).assemble( layer, layer.module( IndexingModule.NAME ) );
+        createModule( layer, SerializationModule.class );
+        return layer;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/b86b66d4/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/infrastructure/SerializationModule.java
----------------------------------------------------------------------
diff --git a/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/infrastructure/SerializationModule.java b/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/infrastructure/SerializationModule.java
new file mode 100644
index 0000000..19edd6f
--- /dev/null
+++ b/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/infrastructure/SerializationModule.java
@@ -0,0 +1,18 @@
+package org.qi4j.bootstrap.assembly.infrastructure;
+
+import org.qi4j.bootstrap.AssemblyException;
+import org.qi4j.bootstrap.LayerAssembly;
+import org.qi4j.bootstrap.ModuleAssembly;
+import org.qi4j.bootstrap.layered.ModuleAssembler;
+
+public class SerializationModule
+    implements ModuleAssembler
+{
+    @Override
+    public ModuleAssembly assemble( LayerAssembly layer, ModuleAssembly module
+    )
+        throws AssemblyException
+    {
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/b86b66d4/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/infrastructure/StorageModule.java
----------------------------------------------------------------------
diff --git a/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/infrastructure/StorageModule.java b/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/infrastructure/StorageModule.java
new file mode 100644
index 0000000..424c653
--- /dev/null
+++ b/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/infrastructure/StorageModule.java
@@ -0,0 +1,26 @@
+package org.qi4j.bootstrap.assembly.infrastructure;
+
+import org.qi4j.api.common.Visibility;
+import org.qi4j.bootstrap.AssemblyException;
+import org.qi4j.bootstrap.LayerAssembly;
+import org.qi4j.bootstrap.ModuleAssembly;
+import org.qi4j.bootstrap.layered.ModuleAssembler;
+
+public class StorageModule
+    implements ModuleAssembler
+{
+    public static final String NAME = "Storage Module";
+    private final ModuleAssembly configModule;
+
+    public StorageModule( ModuleAssembly configModule )
+    {
+        this.configModule = configModule;
+    }
+
+    @Override
+    public ModuleAssembly assemble( LayerAssembly layer, ModuleAssembly module )
+        throws AssemblyException
+    {
+        return module;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/b86b66d4/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/service/ServiceLayer.java
----------------------------------------------------------------------
diff --git a/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/service/ServiceLayer.java b/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/service/ServiceLayer.java
new file mode 100644
index 0000000..14f6ae1
--- /dev/null
+++ b/core/bootstrap/src/test/java/org/qi4j/bootstrap/assembly/service/ServiceLayer.java
@@ -0,0 +1,17 @@
+package org.qi4j.bootstrap.assembly.service;
+
+import org.qi4j.bootstrap.AssemblyException;
+import org.qi4j.bootstrap.layered.LayerAssembler;
+import org.qi4j.bootstrap.LayerAssembly;
+
+public class ServiceLayer implements LayerAssembler
+{
+    public static final String NAME = "Service";
+
+    @Override
+    public LayerAssembly assemble( LayerAssembly layer )
+        throws AssemblyException
+    {
+        return null;
+    }
+}