This is an automated email from the ASF dual-hosted git repository.

aleks pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git


The following commit(s) were added to refs/heads/develop by this push:
     new 83eb084  FINERACT-1532: Create an example for pluggability
83eb084 is described below

commit 83eb0842dcd3cc58b90c9925dd1a26b270b48ad8
Author: Aleksandar Vidakovic <[email protected]>
AuthorDate: Thu Mar 17 11:35:12 2022 +0100

    FINERACT-1532: Create an example for pluggability
---
 build.gradle                                       |  18 +-
 config/spotbugs/exclude.xml                        |  20 ++
 settings.gradle => custom/foo/build.gradle         |   9 +-
 settings.gradle => custom/foo/service/build.gradle |  13 +-
 .../foo/service/dependencies.gradle                |  13 +-
 .../fineract/foo/service/FooDummyServiceImpl.java  |  21 +-
 fineract-client/build.gradle                       |   3 +
 fineract-client/dependencies.gradle                |   4 -
 .../src/test/resources/cucumber.properties         |   1 +
 fineract-doc/build.gradle                          |   3 +-
 fineract-doc/src/docs/en/colophon.adoc             |   1 +
 fineract-doc/src/docs/en/deployment.adoc           |   2 +-
 .../docs/en/diagrams/custom-folder-structure.puml  |  17 ++
 .../docs/en/diagrams/modules-folder-structure.puml |  39 ++++
 .../src/docs/en/images/apache-fineract-logo.png    | Bin 0 -> 22038 bytes
 fineract-doc/src/docs/en/index.adoc                |   4 +
 fineract-doc/src/docs/en/license.adoc              |  15 ++
 fineract-doc/src/docs/en/modules.adoc              | 250 +++++++++++++++++++++
 fineract-provider/dependencies.gradle              |   6 +-
 .../core/boot/ApplicationExitUtil.java             |  63 ------
 .../{boot => config}/WebFrontEndConfiguration.java |   2 +-
 .../loanaccount/api/LoansApiResource.java          |   8 +-
 .../note/service/NoteReadPlatformServiceImpl.java  |   4 -
 .../NoteWritePlatformServiceJpaRepositoryImpl.java |   4 -
 .../note/starter/NoteAutoConfiguration.java        |  53 +++++
 .../org/apache/fineract/TestConfiguration.java     |  23 +-
 .../example/DummyServiceStepDefinitions.java       |  54 +++++
 .../module/example/TestDefaultConfiguration.java   |  15 +-
 .../module/example/TestFooConfiguration.java       |  17 +-
 .../module/service/ServiceStepDefinitions.java     |  58 +++++
 .../module/service/TestDefaultConfiguration.java   |  84 +++++++
 .../module/service/TestOverrideConfiguration.java  |  83 +++++++
 .../custom/CustomNoteReadPlatformService.java      |  28 ++-
 .../custom/CustomNoteWritePlatformService.java     |  49 ++++
 .../src/test/resources/cucumber.properties         |   1 +
 .../features/module/modules.example.feature        |  12 +
 .../features/module/modules.service.feature        |  14 ++
 gradle.properties                                  |   2 +-
 integration-tests/build.gradle                     |   4 +
 .../src/test/resources/cucumber.properties         |   1 +
 settings.gradle => module/build.gradle             |   9 +-
 settings.gradle => module/dummy/build.gradle       |   9 +-
 settings.gradle => module/dummy/core/build.gradle  |  13 +-
 .../dummy/core/dependencies.gradle                 |  12 +-
 .../fineract/dummy/core/data/DummyMessage.java     |  25 ++-
 .../fineract/dummy/core/service/DummyService.java  |  15 +-
 .../dummy/service/build.gradle                     |  13 +-
 .../dummy/service/dependencies.gradle              |  13 +-
 .../fineract/dummy/service/DummyServiceImpl.java   |  19 +-
 .../dummy/starter/build.gradle                     |  13 +-
 .../dummy/starter/dependencies.gradle              |  14 +-
 .../dummy/starter/DummyAutoConfiguration.java      |  24 +-
 .../src/main/resources/META-INF/spring.factories   |   2 +
 oauth2-tests/build.gradle                          |   5 +
 oauth2-tests/dependencies.gradle                   |   6 -
 .../src/test/resources/cucumber.properties         |   1 +
 settings.gradle                                    |   4 +
 twofactor-tests/build.gradle                       |   5 +
 twofactor-tests/dependencies.gradle                |   8 +-
 .../src/test/resources/cucumber.properties         |   1 +
 60 files changed, 972 insertions(+), 257 deletions(-)

diff --git a/build.gradle b/build.gradle
index 7a4cbf4..8bcfb04 100644
--- a/build.gradle
+++ b/build.gradle
@@ -61,7 +61,7 @@ plugins {
     id 'com.github.jk1.dependency-license-report' version '2.1' apply false
     id 'org.openapi.generator' version '4.3.1' apply false
     id 'org.zeroturnaround.gradle.jrebel' version '1.1.11' apply false
-    id 'org.springframework.boot' version '2.6.4' apply false
+    id 'org.springframework.boot' version '2.6.5' apply false
     id 'net.ltgt.errorprone' version '2.0.2' apply false
     id 'io.swagger.core.v3.swagger-gradle-plugin' version '2.1.13' apply false
     id 'com.gorylenko.gradle-git-properties' version '2.4.0' apply false
@@ -99,6 +99,8 @@ allprojects  {
         mavenCentral()
     }
 
+    apply plugin: 'idea'
+    apply plugin: 'java'
     apply plugin: 'io.spring.dependency-management'
     apply plugin: 'com.adarshr.test-logger'
     apply plugin: 'com.diffplug.spotless'
@@ -112,10 +114,11 @@ allprojects  {
     dependencyManagement {
         imports {
             mavenBom 'org.springframework:spring-framework-bom:5.3.17'
-            mavenBom 'org.springframework.boot:spring-boot-dependencies:2.6.4'
+            mavenBom 'org.springframework.boot:spring-boot-dependencies:2.6.5'
             mavenBom 'org.junit:junit-bom:5.8.2'
             mavenBom 'com.fasterxml.jackson:jackson-bom:2.13.2'
             mavenBom 'io.cucumber:cucumber-bom:7.2.3'
+            mavenBom 'io.netty:netty-bom:4.1.75.Final'
         }
 
         dependencies {
@@ -139,13 +142,13 @@ allprojects  {
             dependency 'com.jayway.jsonpath:json-path:2.7.0'
             dependency 'org.apache.tika:tika-core:2.3.0'
             dependency 'org.apache.httpcomponents:httpclient:4.5.13'
-            dependency 'io.swagger.core.v3:swagger-annotations:2.1.13'
             dependency 
'jakarta.management.j2ee:jakarta.management.j2ee-api:1.1.4'
             dependency 'jakarta.jms:jakarta.jms-api:2.0.3'
             dependency 'jakarta.xml.bind:jakarta.xml.bind-api:2.3.3' // 
Swagger needs exactly this version
             dependency 'org.glassfish.jaxb:jaxb-runtime:2.3.6' // Swagger 
needs exactly this version
             dependency 'org.apache.activemq:activemq-broker:5.16.4'
             dependency 'org.apache.bval:org.apache.bval.bundle:2.0.5'
+            dependency 'joda-time:joda-time:2.10.14'
 
             dependency 'io.github.classgraph:classgraph:4.8.141'
             dependency 'org.awaitility:awaitility:4.2.0'
@@ -191,6 +194,12 @@ allprojects  {
             dependency "org.bouncycastle:bcpkix-jdk15to18:1.70"
             dependency "org.bouncycastle:bcprov-jdk15to18:1.70"
 
+
+            dependency 'io.swagger.core.v3:swagger-annotations:2.1.13'
+            dependency ('io.swagger.core.v3:swagger-jaxrs2:2.1.13') {
+                exclude 'jakarta.activation:jakarta.activation-api'
+            }
+
             dependency ('org.liquibase:liquibase-core:4.9.0') {
                 exclude 'javax.xml.bind:jaxb-api'
             }
@@ -299,6 +308,7 @@ allprojects  {
             '**/*.puml',
             '**/*.github/**',
             '**/MANIFEST.MF',
+            '**/spring.factories',
             '**/*.json',
             '**/*.json.template',
             '**/*.txt',
@@ -641,7 +651,7 @@ configure(project.fineractJavaProjects) {
     cucumber {
         tags = 'not @ignore'
         main = 'io.cucumber.core.cli.Main'
-        shorten = "argfile"
+        shorten = 'argfile'
     }
 
     // Configuration for spotbugs plugin
diff --git a/config/spotbugs/exclude.xml b/config/spotbugs/exclude.xml
index 19a9dc0..b5c1ed4 100644
--- a/config/spotbugs/exclude.xml
+++ b/config/spotbugs/exclude.xml
@@ -1,4 +1,24 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements. See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership. The ASF licenses this file
+    to you 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.
+
+-->
 <FindBugsFilter
         xmlns="https://github.com/spotbugs/filter/3.0.0";
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
diff --git a/settings.gradle b/custom/foo/build.gradle
similarity index 79%
copy from settings.gradle
copy to custom/foo/build.gradle
index 0a304eb..9b72338 100644
--- a/settings.gradle
+++ b/custom/foo/build.gradle
@@ -16,11 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-rootProject.name='fineract'
-include ':fineract-provider'
-include ':fineract-war'
-include ':integration-tests'
-include ':twofactor-tests'
-include ':oauth2-tests'
-include ':fineract-client'
-include ':fineract-doc'
+description = 'ACME Corp.: Fineract Foo'
diff --git a/settings.gradle b/custom/foo/service/build.gradle
similarity index 79%
copy from settings.gradle
copy to custom/foo/service/build.gradle
index 0a304eb..8a0f207 100644
--- a/settings.gradle
+++ b/custom/foo/service/build.gradle
@@ -16,11 +16,8 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-rootProject.name='fineract'
-include ':fineract-provider'
-include ':fineract-war'
-include ':integration-tests'
-include ':twofactor-tests'
-include ':oauth2-tests'
-include ':fineract-client'
-include ':fineract-doc'
+description = 'ACME Corp.: Fineract Foo Service'
+
+group = 'com.acmecorp.fineract.foo.service'
+
+apply from: 'dependencies.gradle'
diff --git a/settings.gradle b/custom/foo/service/dependencies.gradle
similarity index 79%
copy from settings.gradle
copy to custom/foo/service/dependencies.gradle
index 0a304eb..517ab7d 100644
--- a/settings.gradle
+++ b/custom/foo/service/dependencies.gradle
@@ -16,11 +16,8 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-rootProject.name='fineract'
-include ':fineract-provider'
-include ':fineract-war'
-include ':integration-tests'
-include ':twofactor-tests'
-include ':oauth2-tests'
-include ':fineract-client'
-include ':fineract-doc'
+
+dependencies {
+    implementation(project(':module:dummy:core'),
+            'org.springframework:spring-context')
+}
diff --git a/settings.gradle 
b/custom/foo/service/src/main/java/com/acmecorp/fineract/foo/service/FooDummyServiceImpl.java
similarity index 67%
copy from settings.gradle
copy to 
custom/foo/service/src/main/java/com/acmecorp/fineract/foo/service/FooDummyServiceImpl.java
index 0a304eb..fc4323a 100644
--- a/settings.gradle
+++ 
b/custom/foo/service/src/main/java/com/acmecorp/fineract/foo/service/FooDummyServiceImpl.java
@@ -16,11 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-rootProject.name='fineract'
-include ':fineract-provider'
-include ':fineract-war'
-include ':integration-tests'
-include ':twofactor-tests'
-include ':oauth2-tests'
-include ':fineract-client'
-include ':fineract-doc'
+package com.acmecorp.fineract.foo.service;
+
+import org.apache.fineract.dummy.core.data.DummyMessage;
+import org.apache.fineract.dummy.core.service.DummyService;
+import org.springframework.stereotype.Service;
+
+@Service
+public class FooDummyServiceImpl implements DummyService {
+    @Override
+    public DummyMessage getMessage() {
+        return new DummyMessage("Hello: FOO!");
+    }
+}
diff --git a/fineract-client/build.gradle b/fineract-client/build.gradle
index d20c2a5..845486b 100644
--- a/fineract-client/build.gradle
+++ b/fineract-client/build.gradle
@@ -22,6 +22,9 @@ apply plugin: 'org.openapi.generator'
 
 apply from: 'dependencies.gradle'
 
+// enable when all tests are migrated
+tasks.cucumber.onlyIf {false}
+
 // TODO: @vidakovic we should publish this lib to Maven Central; do in 
separate PR
 
 openApiMeta {
diff --git a/fineract-client/dependencies.gradle 
b/fineract-client/dependencies.gradle
index cba7dba..e497f86 100644
--- a/fineract-client/dependencies.gradle
+++ b/fineract-client/dependencies.gradle
@@ -37,10 +37,6 @@ dependencies {
 
     testImplementation(
             'org.junit.jupiter:junit-jupiter-api',
-            'io.cucumber:cucumber-core',
-            'io.cucumber:cucumber-java',
-            'io.cucumber:cucumber-java8',
-            'io.cucumber:cucumber-junit-platform-engine',
             'com.google.truth:truth',
             'com.google.truth.extensions:truth-java8-extension'
             )
diff --git a/fineract-client/src/test/resources/cucumber.properties 
b/fineract-client/src/test/resources/cucumber.properties
index d3b2786..a745f74 100644
--- a/fineract-client/src/test/resources/cucumber.properties
+++ b/fineract-client/src/test/resources/cucumber.properties
@@ -18,3 +18,4 @@
 #
 
 cucumber.publish.quiet=true
+cucumber.glue=org.apache.fineract
diff --git a/fineract-doc/build.gradle b/fineract-doc/build.gradle
index b457ada..7cfd31a 100644
--- a/fineract-doc/build.gradle
+++ b/fineract-doc/build.gradle
@@ -44,11 +44,12 @@ asciidoctorj {
     version = '2.4.0'
 
     attributes = [
+        version: "$project.version",
         generated: "${buildDir}/generated/asciidoc",
         imagesdir: 'images',
         diagrams: 'diagrams',
         years: '2015-2022',
-        revnumber: "$version".toString(),
+        revnumber: "$project.version".toString(),
         rootdir: "$rootDir".toString(),
         baseurl: 'fineract.apache.org'
     ]
diff --git a/fineract-doc/src/docs/en/colophon.adoc 
b/fineract-doc/src/docs/en/colophon.adoc
index 70910c4..8c8032f 100644
--- a/fineract-doc/src/docs/en/colophon.adoc
+++ b/fineract-doc/src/docs/en/colophon.adoc
@@ -32,6 +32,7 @@
 
 | Aleksandar Vidakovic | Initial version | 2020-10-26 | 1.4.0
 | Arnold Galovics | Database architecture section | 2022-03-11 | 1.7.0
+| Aleksandar Vidakovic | Module section | 2022-03-23 | 1.7.0
 |===
 
 toc::[]
diff --git a/fineract-doc/src/docs/en/deployment.adoc 
b/fineract-doc/src/docs/en/deployment.adoc
index c5386f5..b3f29a6 100644
--- a/fineract-doc/src/docs/en/deployment.adoc
+++ b/fineract-doc/src/docs/en/deployment.adoc
@@ -37,4 +37,4 @@ The Fineract API client supports an insecure mode 
(`FineractClient.Builder#insec
 
 The https://www.fineract.dev demo server runs on Google Cloud.
 
-https://docs.google.com/presentation/d/1-VP4bNkc5kZ3B0yme_vYLiY1qpswnfz8ainnX5fp3l8/[The
 Running Fineract.dev, SRE style presentation] given at _ApacheCon 20202_ has 
some related background.
+https://docs.google.com/presentation/d/1-VP4bNkc5kZ3B0yme_vYLiY1qpswnfz8ainnX5fp3l8/[The
 Running Fineract.dev, SRE style presentation] given at _ApacheCon 2020_ has 
some related background.
diff --git a/fineract-doc/src/docs/en/diagrams/custom-folder-structure.puml 
b/fineract-doc/src/docs/en/diagrams/custom-folder-structure.puml
new file mode 100644
index 0000000..bc9b3b5
--- /dev/null
+++ b/fineract-doc/src/docs/en/diagrams/custom-folder-structure.puml
@@ -0,0 +1,17 @@
+@startsalt
+{
+    {T
+    + custom
+    ++ mycustom
+    +++ service
+    ++++ src
+    +++++ main
+    ++++++ java
+    +++++++ org.apache.fineract.mymodule.service
+    ++++++++ MyServiceImpl.java
+    ++++ build.gradle
+    ++++ dependencies.gradle
+    +++ build.gradle
+    }
+}
+@endsalt
\ No newline at end of file
diff --git a/fineract-doc/src/docs/en/diagrams/modules-folder-structure.puml 
b/fineract-doc/src/docs/en/diagrams/modules-folder-structure.puml
new file mode 100644
index 0000000..f7a61dd
--- /dev/null
+++ b/fineract-doc/src/docs/en/diagrams/modules-folder-structure.puml
@@ -0,0 +1,39 @@
+@startsalt
+{
+    {T
+    + module
+    ++ mymodule
+    +++ core
+    ++++ src
+    +++++ main
+    ++++++ java
+    +++++++ org.apache.fineract.mymodule.core
+    ++++++++ data
+    +++++++++ MyData.java
+    ++++++++ service
+    +++++++++ MyService.java
+    ++++ build.gradle
+    ++++ dependencies.gradle
+    +++ service
+    ++++ src
+    +++++ main
+    ++++++ java
+    +++++++ org.apache.fineract.mymodule.service
+    ++++++++ MyServiceImpl.java
+    ++++ build.gradle
+    ++++ dependencies.gradle
+    +++ starter
+    ++++ src
+    +++++ main
+    ++++++ java
+    +++++++ org.apache.fineract.mymodule.starter
+    ++++++++ MyAutoConfiguration.java
+    ++++ resources
+    +++++ META-INF
+    ++++++ spring.factories
+    ++++ build.gradle
+    ++++ dependencies.gradle
+    +++ build.gradle
+    }
+}
+@endsalt
\ No newline at end of file
diff --git a/fineract-doc/src/docs/en/images/apache-fineract-logo.png 
b/fineract-doc/src/docs/en/images/apache-fineract-logo.png
new file mode 100644
index 0000000..9b6f470
Binary files /dev/null and 
b/fineract-doc/src/docs/en/images/apache-fineract-logo.png differ
diff --git a/fineract-doc/src/docs/en/index.adoc 
b/fineract-doc/src/docs/en/index.adoc
index ee07edf..6f32d29 100644
--- a/fineract-doc/src/docs/en/index.adoc
+++ b/fineract-doc/src/docs/en/index.adoc
@@ -4,6 +4,8 @@ include::config.adoc[]
 
 = Fineract Documentation
 
+include::license.adoc[]
+
 include::preface.adoc[]
 
 include::colophon.adoc[]
@@ -14,6 +16,8 @@ include::deployment.adoc[]
 
 include::architecture.adoc[]
 
+include::modules.adoc[]
+
 include::oauth.adoc[]
 
 // include::api.adoc[]
diff --git a/fineract-doc/src/docs/en/license.adoc 
b/fineract-doc/src/docs/en/license.adoc
new file mode 100644
index 0000000..9bd9be3
--- /dev/null
+++ b/fineract-doc/src/docs/en/license.adoc
@@ -0,0 +1,15 @@
+== License
+
+Copyright 2022 Apache Foundation
+
+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.
diff --git a/fineract-doc/src/docs/en/modules.adoc 
b/fineract-doc/src/docs/en/modules.adoc
new file mode 100644
index 0000000..f96fc7d8
--- /dev/null
+++ b/fineract-doc/src/docs/en/modules.adoc
@@ -0,0 +1,250 @@
+== Modules
+
+Currently modules are a proof of concept feature in Fineract.
+
+=== How to create a Fineract module
+
+NOTE: At the moment the only module we have that follows these stricter 
guidelines is the example module we describe in detail in the next section. In 
the future we will try to split up Fineract's monolithic code base and move 
features (like loan product, accounts etc.) to separate modules as described 
here. Before that happens we need to do some code cleanups first.
+
+1. Create a folder under `module` and name it _mymodule_.
+1. Create a folder named _core_ under `module/mymodule`.
+1. Create a folder named _service_ under `module/mymodule`.
+1. Create a folder named _starter_ under `module/mymodule`.
+1. Setup folders and Gradle build files for a Java project under `core`, 
`service` and `starter`.
+1. Create a text file called _spring.factories in folder 
`modules/mymodule/starter/src/main/resources/META-INF`.
++
+The final folder and file structure should look somewhat like this:
++
+[plantuml, format=svg]
+----
+include::diagrams/modules-folder-structure.puml[]
+----
+
+1. Make sure that your new modules are present in settings.gradle:
++
+[source,groovy]
+----
+rootProject.name='fineract'
+include ':module:mymodule:core' // <.>
+include ':module:mymodule:service'
+include ':module:mymodule:starter'
+include ':fineract-provider'
+include ':fineract-war'
+include ':integration-tests'
+include ':twofactor-tests'
+include ':oauth2-tests'
+include ':fineract-client'
+include ':fineract-doc'
+----
+<.> The `settings.gradle` file should contain something like this (and 
following).
+
+=== How to replace an existing Fineract service
+
+Creating customizations for Fineract services is easy. The method described 
here will work both with our future module guidelines (aka "clean room" 
modules) and with the intermediary solution we will put in place to avoid major 
refactorings.
+
+You can of course choose whatever folder/project structure you like for your 
custom modules. But we'll describe here some best practices to avoid merge 
conflicts when fetching updates from Fineract's upstream Git repository. For 
the time being we suggest to create your custom modules in the same folder as 
Fineract in a forked Git repo.
+
+As soon as we can publish Fineract module JARs to Maven Central you'll have 
more freedom to setup your projects (including to setup separate Git repos).
+
+1. Create a folder under `custom` and name it _mycustom_.
+1. Create a folder named _service_ under `custom/mycustom`.
+1. Setup folders and Gradle build files for a Java project under `service`.
+1. Create a text file called _spring.factories in folder 
`modules/mymodule/starter/src/main/resources/META-INF`:
++
+[source,properties]
+----
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+ org.apache.fineract.mymodule.starter.MyAutoConfiguration
+----
++
+The final folder and file structure should look somewhat like this:
++
+[plantuml, format=svg]
+----
+include::diagrams/custom-folder-structure.puml[]
+----
++
+Please make sure that your `service` module's build.gradle file has a unique 
group:
++
+[source,groovy]
+----
+description = 'My Company: Fineract My Custom Service'
+
+group = 'com.mycompany.fineract.custom.service' // <.>
+
+apply from: 'dependencies.gradle'
+----
++
+<.> The best choice here is to name it like you would name your JAR artifact 
on Maven Central.
+
+1. Make sure that your custom modules are present in settings.gradle: :
++
+[source,groovy]
+----
+rootProject.name='fineract'
+include ':custom:mycustom:service' // <.>
+include ':fineract-provider'
+include ':fineract-war'
+include ':integration-tests'
+include ':twofactor-tests'
+include ':oauth2-tests'
+include ':fineract-client'
+include ':fineract-doc'
+----
+<.> The `settings.gradle` file should contain something like this.
+1. The dependency.gradle file could look something like this:
+[source,groovy]
+----
+dependencies {
+    implementation(project(':module:mymodule:core'), // <.>
+            'org.springframework:spring-context')
+    compileOnly project(':fineract-provider') // <.>
+}
+----
+<.> If you are replacing a "clean room" module then you just need to include a 
dependency on the modules `core` library.
+<.> If you are replacing a service that is not yet extracted from 
`fineract-provider` then you need to add a dependency on it (only needed during 
compilation).
+1. When the custom module is built then you can add the JAR in your Fineract's 
libs folder (or in Tomcat's libs folder if you are deploying as a WAR app).
+
+IMPORTANT: Do not include your custom module in `fineract-provider`'s 
dependency.gradle file. This creates a circular dependency and will fail your 
build. Instead you have to add your JAR file e. g. to the Docker image (in 
Fineract's libs folder; similar like we do it with Pentaho reporting). This 
setup will give you the best developer experience for now with proper source 
references until we have separate JAR files ready on Maven Central. In the next 
section we describe the "clean room" [...]
+
+=== Example
+
+==== Dummy Module Structure
+
+We've created a demonstration how modules are supposed to be used. A module 
has usually at least two sub-modules:
+
+1. a _core_ module that contains mostly Java interfaces of the services and/or 
other components that we'd like to make replacable. The _core_ module could 
also contain data (DTO) or domain (entity) classes if necessary.
+2. a _service_ module
+
+IMPORTANT: Replacing parts of the existing REST API and extending it with 
custom endpoints is at the moment out of scope. Probably we'll need to cleanup 
and improve the REST layer quite a bit (remove boilerplate code as much as 
possible, use Jackson for JSON de-/serialization instead of the manual GSON 
mappers/helper everywhere) before this can happen. For now we'll concentrate 
primarily on service classes.
+
+Let's assume we have a service `DummyService` in our system. The service is 
outlined as a Java interface in module folder `module/dummy/core`.
+
+[source,java]
+----
+include::{rootdir}/module/dummy/core/src/main/java/org/apache/fineract/dummy/core/service/DummyService.java[lines=19..]
+----
+
+To make it a little bit more interesting the service's only function returns a 
simple data object that has one string attribute:
+
+[source,java]
+----
+include::{rootdir}/module/dummy/core/src/main/java/org/apache/fineract/dummy/core/data/DummyMessage.java[lines=19..]
+----
+
+A default implementation of `DummyService` is provided with `DummyServiceImpl`:
+
+[source,java]
+----
+include::{rootdir}/module/dummy/service/src/main/java/org/apache/fineract/dummy/service/DummyServiceImpl.java[lines=19..]
+----
+
+As you can see there are no annotations like `@Service` or `@Component`. To 
have full control over the instantiation and dependency injection we provide a 
so called _starter_ module. This module just contains one or more (auto-) 
configuration classes. In this case it's just one configuration class. This is 
basically a very simple Spring Java configuration class annotated with 
`@Configuration` containing one method that instantiates our default service 
implementation (annotated with `@Bean`):
+
+[source,java]
+----
+include::{rootdir}/module/dummy/starter/src/main/java/org/apache/fineract/dummy/starter/DummyAutoConfiguration.java[lines=19..]
+----
+
+The interesting part is this line:
+
+[source,java]
+----
+include::{rootdir}/module/dummy/starter/src/main/java/org/apache/fineract/dummy/starter/DummyAutoConfiguration.java[lines=28..28]
+----
+
+This annotation ensures that our default implementation is only instantiated 
if no other implementation for `DummyService` is provided. There's only one 
piece missing to make auto configuration work seamlessly and without any 
explicit configuration in `fineract-provider`:
+
+[source,properties]
+----
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+ org.apache.fineract.dummy.starter.DummyAutoConfiguration
+----
+
+This means if we would only include the following dependencies in our main 
project (e. g. `fineract-provider`)...
+
+[source,groovy]
+----
+dependencies {
+    implementation project(':module:dummy:core')
+    implementation project(':module:dummy:service')
+    implementation project(':module:dummy:starter')
+}
+----
+
+\... then the message object would contain
+
+[source,text]
+----
+Hello: DEFAULT DUMMY!
+----
+
+==== Replace the default implementation of DummyService
+
+This is why we created module `foo` in folder `module/foo`. There's only only 
one sub-module that contains an implementation of `DummyService` that will 
replace the default implementation:
+
+[source,java]
+----
+include::{rootdir}/custom/foo/service/src/main/java/com/acmecorp/fineract/foo/service/FooDummyServiceImpl.java[lines=19..]
+----
+
+As you can see we have no other sub-modules (e. g. there's no starter module) 
and this implementation contains the well known `@Service` annotation. If we 
add this dependency to our main project...
+
+[source,groovy]
+----
+dependencies {
+    implementation project(':module:dummy:core')
+    implementation project(':module:dummy:service')
+    implementation project(':module:dummy:starter')
+    implementation project(':custom:foo:service')
+}
+----
+
+\... then the expected behavior is that we'll get the message
+
+[source,text]
+----
+Hello: Foo!
+----
+
+==== Testing
+
+There's a simple unit test in `fineract-provider` that demonstrates both 
scenarios (without any override of the default implementation and with an 
overriding alternative implementation)
+
+[source,gherkin]
+----
+include::{rootdir}/fineract-provider/src/test/resources/features/module/modules.example.feature[]
+----
+
+Here's the Spring Java configuration that does *NOT* load the `foo` module:
+
+[source,java]
+----
+include::{rootdir}/fineract-provider/src/test/java/org/apache/fineract/module/example/TestDefaultConfiguration.java[lines=19..]
+----
+
+\... and here's the configuration that loads the `foo` module (and overrides 
the deefault implementation)
+
+[source,java]
+----
+include::{rootdir}/fineract-provider/src/test/java/org/apache/fineract/module/example/TestFooConfiguration.java[lines=19..]
+----
+
+The important part in the `foo` configuration is this line:
+
+[source,java]
+----
+include::{rootdir}/fineract-provider/src/test/java/org/apache/fineract/module/example/TestFooConfiguration.java[lines=26..26]
+----
+
+==== Deployment
+
+Modules (better: the JAR files) only need to be dropped in Fineract's `libs` 
folder. Dynamic loading of external JARs is provided since Fineract version 
1.5.0.
+
+==== How can I start replacing services now
+
+As said the "clean room" modules will take a while to arrive. In the meanwhile 
we'll prepare the existing monolithic code base for pluggability. As a proof of 
concept the services 
`org.apache.fineract.portfolio.note.service.NoteReadPlatformService` and 
`org.apache.fineract.portfolio.note.service.NoteWritePlatformService` can be 
replaced/overriden by custom implementations. We'll add more shortly and will 
list them here.
+
+==== Outlook
+
+If this proof of concept is accepted we could refactor Fineract's services one 
by one and rearrange them in the proposed module structure. As discussed at 
ApacheCon 2021 there will be most likely some work to do to properly extract 
those modules (loan product, client, savings account etc.) from the monolithic 
code base. The main challenge are cross-dependencies between the _modules_, but 
there are major benefits if we split up the code like this. One - as 
demonstrated - is the replacemen [...]
diff --git a/fineract-provider/dependencies.gradle 
b/fineract-provider/dependencies.gradle
index 348f63d..eb19783 100644
--- a/fineract-provider/dependencies.gradle
+++ b/fineract-provider/dependencies.gradle
@@ -135,7 +135,11 @@ dependencies {
             'io.cucumber:cucumber-java8',
             'io.cucumber:cucumber-junit-platform-engine',
             'io.cucumber:cucumber-spring',
-            'io.github.classgraph:classgraph'
+            'io.github.classgraph:classgraph',
+            project(':module:dummy:core'),
+            project(':module:dummy:service'),
+            project(':module:dummy:starter'),
+            project(':custom:foo:service'),
             )
     testImplementation ('org.springframework.boot:spring-boot-starter-test') {
         exclude group: 'com.jayway.jsonpath', module: 'json-path'
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/boot/ApplicationExitUtil.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/boot/ApplicationExitUtil.java
deleted file mode 100644
index 7406a41..0000000
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/boot/ApplicationExitUtil.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.fineract.infrastructure.core.boot;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.nio.charset.StandardCharsets;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.context.ConfigurableApplicationContext;
-
-public abstract class ApplicationExitUtil {
-
-    private static final Logger LOG = 
LoggerFactory.getLogger(ApplicationExitUtil.class);
-
-    private ApplicationExitUtil() {}
-
-    public static void 
waitForKeyPressToCleanlyExit(ConfigurableApplicationContext ctx) throws 
IOException {
-        // In some environments, System.console() is not available (e.g. 
"./gradlew bootRun", or in a container, or in
-        // Eclipse, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=122429.
-        //
-        // Also (but as a separate problem), e.g. in Eclipse, the Shutdown 
Hooks are not invoked on Exit with the Red
-        // Button of the Console view (see 
https://bugs.eclipse.org/bugs/show_bug.cgi?id=38016); that's a problem e.g.
-        // in the case of MariaDB4j, because then mysqld won't be stopped; 
same problem similarly applies on any other
-        // library else that relies on an orderly Spring Context / JVM 
shutdown.
-        //
-        if (System.console() == null) {
-            LOG.info("\nNo Console available, running until stopped by 
signal/Ctrl-C...");
-            boolean interrupted = false;
-            do {
-                try {
-                    Thread.sleep(Long.MAX_VALUE);
-                } catch (InterruptedException e) {
-                    interrupted = true;
-                }
-            } while (!interrupted);
-        } else {
-            LOG.info("\nHit Enter to quit...");
-            BufferedReader d = new BufferedReader(new 
InputStreamReader(System.in, StandardCharsets.UTF_8));
-            d.readLine();
-
-            ctx.stop();
-            ctx.close();
-        }
-    }
-}
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/boot/WebFrontEndConfiguration.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/WebFrontEndConfiguration.java
similarity index 97%
rename from 
fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/boot/WebFrontEndConfiguration.java
rename to 
fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/WebFrontEndConfiguration.java
index 6bea470..7e85d1e 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/boot/WebFrontEndConfiguration.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/WebFrontEndConfiguration.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.fineract.infrastructure.core.boot;
+package org.apache.fineract.infrastructure.core.config;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
index 7c671a5..2041813 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
@@ -133,14 +133,13 @@ import 
org.apache.fineract.portfolio.loanproduct.service.LoanDropdownReadPlatfor
 import 
org.apache.fineract.portfolio.loanproduct.service.LoanProductReadPlatformService;
 import org.apache.fineract.portfolio.note.data.NoteData;
 import org.apache.fineract.portfolio.note.domain.NoteType;
-import org.apache.fineract.portfolio.note.service.NoteReadPlatformServiceImpl;
+import org.apache.fineract.portfolio.note.service.NoteReadPlatformService;
 import org.apache.fineract.portfolio.rate.data.RateData;
 import org.apache.fineract.portfolio.rate.service.RateReadService;
 import org.apache.fineract.portfolio.savings.DepositAccountType;
 import org.apache.fineract.portfolio.savings.domain.SavingsAccountStatusType;
 import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
 import org.glassfish.jersey.media.multipart.FormDataParam;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Scope;
 import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;
@@ -244,7 +243,7 @@ public class LoansApiResource {
     private final FromJsonHelper fromJsonHelper;
     private final PortfolioCommandSourceWritePlatformService 
commandsSourceWritePlatformService;
     private final CalendarReadPlatformService calendarReadPlatformService;
-    private final NoteReadPlatformServiceImpl noteReadPlatformService;
+    private final NoteReadPlatformService noteReadPlatformService;
     private final PortfolioAccountReadPlatformService 
portfolioAccountReadPlatformService;
     private final AccountAssociationsReadPlatformService 
accountAssociationsReadPlatformService;
     private final LoanScheduleHistoryReadPlatformService 
loanScheduleHistoryReadPlatformService;
@@ -258,7 +257,6 @@ public class LoansApiResource {
     private final GLIMAccountInfoReadPlatformService 
glimAccountInfoReadPlatformService;
     private final LoanCollateralManagementReadPlatformService 
loanCollateralManagementReadPlatformService;
 
-    @Autowired
     public LoansApiResource(final PlatformSecurityContext context, final 
LoanReadPlatformService loanReadPlatformService,
             final LoanProductReadPlatformService 
loanProductReadPlatformService,
             final LoanDropdownReadPlatformService dropdownReadPlatformService, 
final FundReadPlatformService fundReadPlatformService,
@@ -272,7 +270,7 @@ public class LoansApiResource {
             final DefaultToApiJsonSerializer<LoanScheduleData> 
loanScheduleToApiJsonSerializer,
             final ApiRequestParameterHelper apiRequestParameterHelper, final 
FromJsonHelper fromJsonHelper,
             final PortfolioCommandSourceWritePlatformService 
commandsSourceWritePlatformService,
-            final CalendarReadPlatformService calendarReadPlatformService, 
final NoteReadPlatformServiceImpl noteReadPlatformService,
+            final CalendarReadPlatformService calendarReadPlatformService, 
final NoteReadPlatformService noteReadPlatformService,
             final PortfolioAccountReadPlatformService 
portfolioAccountReadPlatformServiceImpl,
             final AccountAssociationsReadPlatformService 
accountAssociationsReadPlatformService,
             final LoanScheduleHistoryReadPlatformService 
loanScheduleHistoryReadPlatformService,
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/service/NoteReadPlatformServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/service/NoteReadPlatformServiceImpl.java
index fcedec4..377e5fb 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/service/NoteReadPlatformServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/service/NoteReadPlatformServiceImpl.java
@@ -32,18 +32,14 @@ import 
org.apache.fineract.infrastructure.core.service.RoutingDataSource;
 import org.apache.fineract.portfolio.note.data.NoteData;
 import org.apache.fineract.portfolio.note.domain.NoteType;
 import org.apache.fineract.portfolio.note.exception.NoteNotFoundException;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.dao.EmptyResultDataAccessException;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.jdbc.core.RowMapper;
-import org.springframework.stereotype.Service;
 
-@Service
 public class NoteReadPlatformServiceImpl implements NoteReadPlatformService {
 
     private final JdbcTemplate jdbcTemplate;
 
-    @Autowired
     public NoteReadPlatformServiceImpl(final RoutingDataSource dataSource) {
         this.jdbcTemplate = new JdbcTemplate(dataSource);
     }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/service/NoteWritePlatformServiceJpaRepositoryImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/service/NoteWritePlatformServiceJpaRepositoryImpl.java
index 52cdca4..9803356 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/service/NoteWritePlatformServiceJpaRepositoryImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/service/NoteWritePlatformServiceJpaRepositoryImpl.java
@@ -42,10 +42,7 @@ import 
org.apache.fineract.portfolio.note.exception.NoteResourceNotSupportedExce
 import 
org.apache.fineract.portfolio.note.serialization.NoteCommandFromApiJsonDeserializer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
 
-@Service
 public class NoteWritePlatformServiceJpaRepositoryImpl implements 
NoteWritePlatformService {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(NoteWritePlatformServiceJpaRepositoryImpl.class);
@@ -56,7 +53,6 @@ public class NoteWritePlatformServiceJpaRepositoryImpl 
implements NoteWritePlatf
     private final LoanTransactionRepository loanTransactionRepository;
     private final NoteCommandFromApiJsonDeserializer fromApiJsonDeserializer;
 
-    @Autowired
     public NoteWritePlatformServiceJpaRepositoryImpl(final NoteRepository 
noteRepository, final ClientRepositoryWrapper clientRepository,
             final GroupRepository groupRepository, final LoanRepositoryWrapper 
loanRepository,
             final LoanTransactionRepository loanTransactionRepository, final 
NoteCommandFromApiJsonDeserializer fromApiJsonDeserializer) {
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/starter/NoteAutoConfiguration.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/starter/NoteAutoConfiguration.java
new file mode 100644
index 0000000..1bea6c8
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/starter/NoteAutoConfiguration.java
@@ -0,0 +1,53 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fineract.portfolio.note.starter;
+
+import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
+import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
+import org.apache.fineract.portfolio.group.domain.GroupRepository;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
+import 
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
+import org.apache.fineract.portfolio.note.domain.NoteRepository;
+import 
org.apache.fineract.portfolio.note.serialization.NoteCommandFromApiJsonDeserializer;
+import org.apache.fineract.portfolio.note.service.NoteReadPlatformService;
+import org.apache.fineract.portfolio.note.service.NoteReadPlatformServiceImpl;
+import org.apache.fineract.portfolio.note.service.NoteWritePlatformService;
+import 
org.apache.fineract.portfolio.note.service.NoteWritePlatformServiceJpaRepositoryImpl;
+import 
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class NoteAutoConfiguration {
+
+    @Bean
+    @ConditionalOnMissingBean
+    public NoteReadPlatformService noteReadPlatformService(RoutingDataSource 
routingDataSource) {
+        return new NoteReadPlatformServiceImpl(routingDataSource);
+    }
+
+    @Bean
+    @ConditionalOnMissingBean
+    public NoteWritePlatformService noteWritePlatformService(NoteRepository 
noteRepository, ClientRepositoryWrapper clientRepository,
+            GroupRepository groupRepository, LoanRepositoryWrapper 
loanRepository, LoanTransactionRepository loanTransactionRepository,
+            NoteCommandFromApiJsonDeserializer fromApiJsonDeserializer) {
+        return new NoteWritePlatformServiceJpaRepositoryImpl(noteRepository, 
clientRepository, groupRepository, loanRepository,
+                loanTransactionRepository, fromApiJsonDeserializer);
+    }
+}
diff --git 
a/fineract-provider/src/test/java/org/apache/fineract/TestConfiguration.java 
b/fineract-provider/src/test/java/org/apache/fineract/TestConfiguration.java
index 39a3e35..9ef2543 100644
--- a/fineract-provider/src/test/java/org/apache/fineract/TestConfiguration.java
+++ b/fineract-provider/src/test/java/org/apache/fineract/TestConfiguration.java
@@ -22,7 +22,6 @@ import static org.mockito.Mockito.mock;
 
 import com.zaxxer.hikari.HikariDataSource;
 import javax.sql.DataSource;
-import 
org.apache.fineract.infrastructure.core.boot.AbstractApplicationConfiguration;
 import org.apache.fineract.infrastructure.core.config.FineractProperties;
 import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
 import 
org.apache.fineract.infrastructure.core.service.database.DatabaseIndependentQueryService;
@@ -37,19 +36,37 @@ import org.mockito.Mockito;
 import org.mockito.junit.jupiter.MockitoExtension;
 import org.mockito.junit.jupiter.MockitoSettings;
 import org.mockito.quality.Strictness;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import 
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
+import 
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration;
+import 
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
 import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties;
+import 
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
 import 
org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import 
org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
 
 /**
  * Spring @Configuration which does not require a running database. It also 
does not load any job configuration (as they
  * are in the DB), thus nor starts any background jobs. For some integration 
tests, this may be perfectly sufficient
  * (and faster to run such tests).
  */
-@EnableConfigurationProperties({ FineractProperties.class })
+@Configuration
+@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class, 
HibernateJpaAutoConfiguration.class,
+        DataSourceTransactionManagerAutoConfiguration.class, 
GsonAutoConfiguration.class, JdbcTemplateAutoConfiguration.class,
+        LiquibaseAutoConfiguration.class })
+@EnableTransactionManagement
+@EnableWebSecurity
+@EnableConfigurationProperties({ FineractProperties.class, 
LiquibaseProperties.class })
+@ComponentScan(basePackages = "org.apache.fineract")
 @ExtendWith(MockitoExtension.class)
 @MockitoSettings(strictness = Strictness.LENIENT)
-public class TestConfiguration extends AbstractApplicationConfiguration {
+public class TestConfiguration {
 
     @Bean
     public TenantDataSourceFactory tenantDataSourceFactory() {
diff --git 
a/fineract-provider/src/test/java/org/apache/fineract/module/example/DummyServiceStepDefinitions.java
 
b/fineract-provider/src/test/java/org/apache/fineract/module/example/DummyServiceStepDefinitions.java
new file mode 100644
index 0000000..ccbacd7
--- /dev/null
+++ 
b/fineract-provider/src/test/java/org/apache/fineract/module/example/DummyServiceStepDefinitions.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fineract.module.example;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import io.cucumber.java8.En;
+import org.apache.fineract.dummy.core.data.DummyMessage;
+import org.apache.fineract.dummy.core.service.DummyService;
+import org.apache.fineract.dummy.starter.DummyAutoConfiguration;
+import org.springframework.boot.autoconfigure.AutoConfigurations;
+import org.springframework.boot.test.context.runner.ApplicationContextRunner;
+
+public class DummyServiceStepDefinitions implements En {
+
+    private DummyMessage message;
+
+    private ApplicationContextRunner contextRunner = new 
ApplicationContextRunner()
+            
.withConfiguration(AutoConfigurations.of(DummyAutoConfiguration.class));
+
+    public DummyServiceStepDefinitions() {
+        Given("/^A dummy service configuration (.*)$/", (String 
configurationClass) -> {
+            contextRunner = 
contextRunner.withUserConfiguration(Class.forName(configurationClass.trim()));
+        });
+
+        When("The user gets the dummy service message", () -> {
+            contextRunner.run((ctx) -> {
+                assertThat(ctx).hasSingleBean(DummyService.class);
+                this.message = ctx.getBean(DummyService.class).getMessage();
+            });
+        });
+
+        Then("/^The dummy service message should match (.*)$/", (String msg) 
-> {
+            assertThat(this.message).isNotNull();
+            assertThat(msg).isEqualTo(this.message.getMessage());
+        });
+    }
+}
diff --git a/settings.gradle 
b/fineract-provider/src/test/java/org/apache/fineract/module/example/TestDefaultConfiguration.java
similarity index 72%
copy from settings.gradle
copy to 
fineract-provider/src/test/java/org/apache/fineract/module/example/TestDefaultConfiguration.java
index 0a304eb..6978660 100644
--- a/settings.gradle
+++ 
b/fineract-provider/src/test/java/org/apache/fineract/module/example/TestDefaultConfiguration.java
@@ -16,11 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-rootProject.name='fineract'
-include ':fineract-provider'
-include ':fineract-war'
-include ':integration-tests'
-include ':twofactor-tests'
-include ':oauth2-tests'
-include ':fineract-client'
-include ':fineract-doc'
+package org.apache.fineract.module.example;
+
+import org.apache.fineract.infrastructure.core.config.FineractProperties;
+import 
org.springframework.boot.context.properties.EnableConfigurationProperties;
+
+@EnableConfigurationProperties({ FineractProperties.class })
+public class TestDefaultConfiguration {}
diff --git a/settings.gradle 
b/fineract-provider/src/test/java/org/apache/fineract/module/example/TestFooConfiguration.java
similarity index 66%
copy from settings.gradle
copy to 
fineract-provider/src/test/java/org/apache/fineract/module/example/TestFooConfiguration.java
index 0a304eb..c22bf63 100644
--- a/settings.gradle
+++ 
b/fineract-provider/src/test/java/org/apache/fineract/module/example/TestFooConfiguration.java
@@ -16,11 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-rootProject.name='fineract'
-include ':fineract-provider'
-include ':fineract-war'
-include ':integration-tests'
-include ':twofactor-tests'
-include ':oauth2-tests'
-include ':fineract-client'
-include ':fineract-doc'
+package org.apache.fineract.module.example;
+
+import org.apache.fineract.infrastructure.core.config.FineractProperties;
+import 
org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.ComponentScan;
+
+@EnableConfigurationProperties({ FineractProperties.class })
+@ComponentScan("com.acmecorp.fineract.foo")
+public class TestFooConfiguration {}
diff --git 
a/fineract-provider/src/test/java/org/apache/fineract/module/service/ServiceStepDefinitions.java
 
b/fineract-provider/src/test/java/org/apache/fineract/module/service/ServiceStepDefinitions.java
new file mode 100644
index 0000000..1759097
--- /dev/null
+++ 
b/fineract-provider/src/test/java/org/apache/fineract/module/service/ServiceStepDefinitions.java
@@ -0,0 +1,58 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fineract.module.service;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import io.cucumber.java8.En;
+import org.springframework.boot.autoconfigure.AutoConfigurations;
+import org.springframework.boot.test.context.runner.ApplicationContextRunner;
+
+public class ServiceStepDefinitions implements En {
+
+    private Class interfaceClass;
+
+    private Class implementationClass;
+
+    private ApplicationContextRunner contextRunner;
+
+    public ServiceStepDefinitions() {
+        Given("/^An auto configuration (.*) and a service configuration 
(.*)$/",
+                (String autoConfigurationClassName, String 
configurationClassName) -> {
+                    contextRunner = new ApplicationContextRunner()
+                            
.withConfiguration(AutoConfigurations.of(Class.forName(autoConfigurationClassName)))
+                            
.withUserConfiguration(Class.forName(configurationClassName.trim()));
+                });
+
+        When("/^The user retrieves the service of interface class (.*)$/", 
(String interfaceClassName) -> {
+            contextRunner.run((ctx) -> {
+                this.interfaceClass = Class.forName(interfaceClassName.trim());
+
+                assertThat(this.interfaceClass.isInterface()).isTrue();
+                assertThat(ctx).hasSingleBean(this.interfaceClass);
+
+                this.implementationClass = 
ctx.getBean(interfaceClass).getClass();
+            });
+        });
+
+        Then("/^The service class should match (.*)$/", (String 
serviceClassName) -> {
+            
assertThat(Class.forName(serviceClassName.trim())).isEqualTo(this.implementationClass);
+        });
+    }
+}
diff --git 
a/fineract-provider/src/test/java/org/apache/fineract/module/service/TestDefaultConfiguration.java
 
b/fineract-provider/src/test/java/org/apache/fineract/module/service/TestDefaultConfiguration.java
new file mode 100644
index 0000000..5f1bd24
--- /dev/null
+++ 
b/fineract-provider/src/test/java/org/apache/fineract/module/service/TestDefaultConfiguration.java
@@ -0,0 +1,84 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fineract.module.service;
+
+import static org.mockito.Mockito.mock;
+
+import org.apache.fineract.infrastructure.core.config.FineractProperties;
+import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
+import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
+import 
org.apache.fineract.infrastructure.core.service.RoutingDataSourceServiceFactory;
+import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
+import org.apache.fineract.portfolio.group.domain.GroupRepository;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
+import 
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
+import org.apache.fineract.portfolio.note.domain.NoteRepository;
+import 
org.apache.fineract.portfolio.note.serialization.NoteCommandFromApiJsonDeserializer;
+import 
org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+
+@EnableConfigurationProperties({ FineractProperties.class })
+public class TestDefaultConfiguration {
+    // NOTE: unfortunately an abastract base class that contains all these 
mock functions won't work
+
+    @Bean
+    public FromJsonHelper fromJsonHelper() {
+        return mock(FromJsonHelper.class);
+    }
+
+    @Bean
+    public RoutingDataSourceServiceFactory routingDataSourceServiceFactory() {
+        return mock(RoutingDataSourceServiceFactory.class);
+    }
+
+    @Bean
+    public RoutingDataSource routingDataSource() {
+        return mock(RoutingDataSource.class);
+    }
+
+    @Bean
+    public NoteRepository noteRepository() {
+        return mock(NoteRepository.class);
+    }
+
+    @Bean
+    public ClientRepositoryWrapper clientRepository() {
+        return mock(ClientRepositoryWrapper.class);
+    }
+
+    @Bean
+    public GroupRepository groupRepository() {
+        return mock(GroupRepository.class);
+    }
+
+    @Bean
+    public LoanRepositoryWrapper loanRepository() {
+        return mock(LoanRepositoryWrapper.class);
+    }
+
+    @Bean
+    public LoanTransactionRepository loanTransactionRepository() {
+        return mock(LoanTransactionRepository.class);
+    }
+
+    @Bean
+    public NoteCommandFromApiJsonDeserializer 
fromApiJsonDeserializer(FromJsonHelper fromJsonHelper) {
+        return new NoteCommandFromApiJsonDeserializer(fromJsonHelper);
+    }
+}
diff --git 
a/fineract-provider/src/test/java/org/apache/fineract/module/service/TestOverrideConfiguration.java
 
b/fineract-provider/src/test/java/org/apache/fineract/module/service/TestOverrideConfiguration.java
new file mode 100644
index 0000000..dfc0544
--- /dev/null
+++ 
b/fineract-provider/src/test/java/org/apache/fineract/module/service/TestOverrideConfiguration.java
@@ -0,0 +1,83 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fineract.module.service;
+
+import static org.mockito.Mockito.mock;
+
+import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
+import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
+import 
org.apache.fineract.infrastructure.core.service.RoutingDataSourceServiceFactory;
+import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
+import org.apache.fineract.portfolio.group.domain.GroupRepository;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
+import 
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
+import org.apache.fineract.portfolio.note.domain.NoteRepository;
+import 
org.apache.fineract.portfolio.note.serialization.NoteCommandFromApiJsonDeserializer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+
+@ComponentScan("org.apache.fineract.module.service.custom")
+public class TestOverrideConfiguration {
+    // NOTE: unfortunately an abastract base class that contains all these 
mock functions won't work
+
+    @Bean
+    public FromJsonHelper fromJsonHelper() {
+        return mock(FromJsonHelper.class);
+    }
+
+    @Bean
+    public RoutingDataSourceServiceFactory routingDataSourceServiceFactory() {
+        return mock(RoutingDataSourceServiceFactory.class);
+    }
+
+    @Bean
+    public RoutingDataSource routingDataSource() {
+        return mock(RoutingDataSource.class);
+    }
+
+    @Bean
+    public NoteRepository noteRepository() {
+        return mock(NoteRepository.class);
+    }
+
+    @Bean
+    public ClientRepositoryWrapper clientRepository() {
+        return mock(ClientRepositoryWrapper.class);
+    }
+
+    @Bean
+    public GroupRepository groupRepository() {
+        return mock(GroupRepository.class);
+    }
+
+    @Bean
+    public LoanRepositoryWrapper loanRepository() {
+        return mock(LoanRepositoryWrapper.class);
+    }
+
+    @Bean
+    public LoanTransactionRepository loanTransactionRepository() {
+        return mock(LoanTransactionRepository.class);
+    }
+
+    @Bean
+    public NoteCommandFromApiJsonDeserializer 
fromApiJsonDeserializer(FromJsonHelper fromJsonHelper) {
+        return new NoteCommandFromApiJsonDeserializer(fromJsonHelper);
+    }
+}
diff --git a/settings.gradle 
b/fineract-provider/src/test/java/org/apache/fineract/module/service/custom/CustomNoteReadPlatformService.java
similarity index 56%
copy from settings.gradle
copy to 
fineract-provider/src/test/java/org/apache/fineract/module/service/custom/CustomNoteReadPlatformService.java
index 0a304eb..7d4e5c0 100644
--- a/settings.gradle
+++ 
b/fineract-provider/src/test/java/org/apache/fineract/module/service/custom/CustomNoteReadPlatformService.java
@@ -16,11 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-rootProject.name='fineract'
-include ':fineract-provider'
-include ':fineract-war'
-include ':integration-tests'
-include ':twofactor-tests'
-include ':oauth2-tests'
-include ':fineract-client'
-include ':fineract-doc'
+package org.apache.fineract.module.service.custom;
+
+import java.util.Collection;
+import org.apache.fineract.portfolio.note.data.NoteData;
+import org.apache.fineract.portfolio.note.service.NoteReadPlatformService;
+import org.springframework.stereotype.Service;
+
+@Service
+public class CustomNoteReadPlatformService implements NoteReadPlatformService {
+
+    @Override
+    public NoteData retrieveNote(Long noteId, Long resourceId, Integer 
noteTypeId) {
+        return null;
+    }
+
+    @Override
+    public Collection<NoteData> retrieveNotesByResource(Long resourceId, 
Integer noteTypeId) {
+        return null;
+    }
+}
diff --git 
a/fineract-provider/src/test/java/org/apache/fineract/module/service/custom/CustomNoteWritePlatformService.java
 
b/fineract-provider/src/test/java/org/apache/fineract/module/service/custom/CustomNoteWritePlatformService.java
new file mode 100644
index 0000000..ecc82db
--- /dev/null
+++ 
b/fineract-provider/src/test/java/org/apache/fineract/module/service/custom/CustomNoteWritePlatformService.java
@@ -0,0 +1,49 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fineract.module.service.custom;
+
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import org.apache.fineract.portfolio.client.domain.Client;
+import org.apache.fineract.portfolio.note.service.NoteWritePlatformService;
+import org.springframework.stereotype.Service;
+
+@Service
+public class CustomNoteWritePlatformService implements 
NoteWritePlatformService {
+
+    @Override
+    public CommandProcessingResult createNote(JsonCommand command) {
+        return null;
+    }
+
+    @Override
+    public CommandProcessingResult updateNote(JsonCommand command) {
+        return null;
+    }
+
+    @Override
+    public CommandProcessingResult deleteNote(JsonCommand command) {
+        return null;
+    }
+
+    @Override
+    public void createAndPersistClientNote(Client client, JsonCommand command) 
{
+
+    }
+}
diff --git a/fineract-provider/src/test/resources/cucumber.properties 
b/fineract-provider/src/test/resources/cucumber.properties
index d3b2786..a745f74 100644
--- a/fineract-provider/src/test/resources/cucumber.properties
+++ b/fineract-provider/src/test/resources/cucumber.properties
@@ -18,3 +18,4 @@
 #
 
 cucumber.publish.quiet=true
+cucumber.glue=org.apache.fineract
diff --git 
a/fineract-provider/src/test/resources/features/module/modules.example.feature 
b/fineract-provider/src/test/resources/features/module/modules.example.feature
new file mode 100644
index 0000000..ad2be04
--- /dev/null
+++ 
b/fineract-provider/src/test/resources/features/module/modules.example.feature
@@ -0,0 +1,12 @@
+Feature: Example Modules
+
+  @modules
+  Scenario Outline: Verify that the dummy service returns the correct message
+    Given A dummy service configuration <configurationClass>
+    When The user gets the dummy service message
+    Then The dummy service message should match <message>
+
+    Examples:
+      | configurationClass                                          | message  
             |
+      | org.apache.fineract.module.example.TestDefaultConfiguration | Hello: 
DEFAULT DUMMY! |
+      | org.apache.fineract.module.example.TestFooConfiguration     | Hello: 
FOO!           |
\ No newline at end of file
diff --git 
a/fineract-provider/src/test/resources/features/module/modules.service.feature 
b/fineract-provider/src/test/resources/features/module/modules.service.feature
new file mode 100644
index 0000000..6aee6ba
--- /dev/null
+++ 
b/fineract-provider/src/test/resources/features/module/modules.service.feature
@@ -0,0 +1,14 @@
+Feature: Service Modules
+
+  @modules
+  Scenario Outline: Verify that the dummy service returns the correct message
+    Given An auto configuration <autoConfigurationClass> and a service 
configuration <configurationClass>
+    When The user retrieves the service of interface class <interfaceClass>
+    Then The service class should match <serviceClass>
+
+    Examples:
+      | autoConfigurationClass                                           | 
configurationClass                                           | interfaceClass   
                                                   | serviceClass               
                                                          |
+      | org.apache.fineract.portfolio.note.starter.NoteAutoConfiguration | 
org.apache.fineract.module.service.TestDefaultConfiguration  | 
org.apache.fineract.portfolio.note.service.NoteReadPlatformService  | 
org.apache.fineract.portfolio.note.service.NoteReadPlatformServiceImpl          
     |
+      | org.apache.fineract.portfolio.note.starter.NoteAutoConfiguration | 
org.apache.fineract.module.service.TestDefaultConfiguration  | 
org.apache.fineract.portfolio.note.service.NoteWritePlatformService | 
org.apache.fineract.portfolio.note.service.NoteWritePlatformServiceJpaRepositoryImpl
 |
+      | org.apache.fineract.portfolio.note.starter.NoteAutoConfiguration | 
org.apache.fineract.module.service.TestOverrideConfiguration | 
org.apache.fineract.portfolio.note.service.NoteReadPlatformService  | 
org.apache.fineract.module.service.custom.CustomNoteReadPlatformService         
     |
+      | org.apache.fineract.portfolio.note.starter.NoteAutoConfiguration | 
org.apache.fineract.module.service.TestOverrideConfiguration | 
org.apache.fineract.portfolio.note.service.NoteWritePlatformService | 
org.apache.fineract.module.service.custom.CustomNoteWritePlatformService        
     |
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index 11fe8a7..89f430e 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -16,6 +16,6 @@
 # specific language governing permissions and limitations
 # under the License.
 #
-org.gradle.jvmargs=-Xmx2g --add-exports 
jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports 
jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED --add-exports 
jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED --add-exports 
jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED --add-exports 
jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED 
--add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED 
--add-opens=java.base/java.lang=ALL-UNNAMED 
--add-opens=java.base/java.lang.invoke=ALL-UN [...]
+org.gradle.jvmargs=-Xmx2g --add-exports 
jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports 
jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED --add-exports 
jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED --add-exports 
jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED --add-exports 
jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED 
--add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED 
--add-opens=java.base/java.lang=ALL-UNNAMED 
--add-opens=java.base/java.lang.invoke=ALL-UN [...]
 buildType=BUILD
 org.gradle.caching=true
diff --git a/integration-tests/build.gradle b/integration-tests/build.gradle
index f395cf9..1217e8e 100644
--- a/integration-tests/build.gradle
+++ b/integration-tests/build.gradle
@@ -28,6 +28,9 @@ configurations {
 
 apply from: 'dependencies.gradle'
 
+// enable when all tests are migrated
+tasks.cucumber.onlyIf {false}
+
 cargo {
     containerId "tomcat9x"
 
@@ -39,6 +42,7 @@ cargo {
 
     local {
         logLevel = 'medium'
+        // outputFile = file('build/output.log')
         installer {
             installConfiguration = configurations.tomcat
             downloadDir = file("$buildDir/download")
diff --git a/integration-tests/src/test/resources/cucumber.properties 
b/integration-tests/src/test/resources/cucumber.properties
index d3b2786..a745f74 100644
--- a/integration-tests/src/test/resources/cucumber.properties
+++ b/integration-tests/src/test/resources/cucumber.properties
@@ -18,3 +18,4 @@
 #
 
 cucumber.publish.quiet=true
+cucumber.glue=org.apache.fineract
diff --git a/settings.gradle b/module/build.gradle
similarity index 79%
copy from settings.gradle
copy to module/build.gradle
index 0a304eb..d145498 100644
--- a/settings.gradle
+++ b/module/build.gradle
@@ -16,11 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-rootProject.name='fineract'
-include ':fineract-provider'
-include ':fineract-war'
-include ':integration-tests'
-include ':twofactor-tests'
-include ':oauth2-tests'
-include ':fineract-client'
-include ':fineract-doc'
+description = 'Fineract Module'
diff --git a/settings.gradle b/module/dummy/build.gradle
similarity index 79%
copy from settings.gradle
copy to module/dummy/build.gradle
index 0a304eb..016d5b2 100644
--- a/settings.gradle
+++ b/module/dummy/build.gradle
@@ -16,11 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-rootProject.name='fineract'
-include ':fineract-provider'
-include ':fineract-war'
-include ':integration-tests'
-include ':twofactor-tests'
-include ':oauth2-tests'
-include ':fineract-client'
-include ':fineract-doc'
+description = 'Fineract Module: Dummy'
diff --git a/settings.gradle b/module/dummy/core/build.gradle
similarity index 79%
copy from settings.gradle
copy to module/dummy/core/build.gradle
index 0a304eb..bd83b90 100644
--- a/settings.gradle
+++ b/module/dummy/core/build.gradle
@@ -16,11 +16,8 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-rootProject.name='fineract'
-include ':fineract-provider'
-include ':fineract-war'
-include ':integration-tests'
-include ':twofactor-tests'
-include ':oauth2-tests'
-include ':fineract-client'
-include ':fineract-doc'
+description = 'Fineract Module: Dummy Core'
+
+group = 'org.apache.fineract.dummy.core'
+
+apply from: 'dependencies.gradle'
diff --git a/settings.gradle b/module/dummy/core/dependencies.gradle
similarity index 79%
copy from settings.gradle
copy to module/dummy/core/dependencies.gradle
index 0a304eb..e819cc7 100644
--- a/settings.gradle
+++ b/module/dummy/core/dependencies.gradle
@@ -16,11 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-rootProject.name='fineract'
-include ':fineract-provider'
-include ':fineract-war'
-include ':integration-tests'
-include ':twofactor-tests'
-include ':oauth2-tests'
-include ':fineract-client'
-include ':fineract-doc'
+
+dependencies {
+    implementation('org.springframework:spring-context')
+}
diff --git a/settings.gradle 
b/module/dummy/core/src/main/java/org/apache/fineract/dummy/core/data/DummyMessage.java
similarity index 70%
copy from settings.gradle
copy to 
module/dummy/core/src/main/java/org/apache/fineract/dummy/core/data/DummyMessage.java
index 0a304eb..67e4350 100644
--- a/settings.gradle
+++ 
b/module/dummy/core/src/main/java/org/apache/fineract/dummy/core/data/DummyMessage.java
@@ -16,11 +16,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-rootProject.name='fineract'
-include ':fineract-provider'
-include ':fineract-war'
-include ':integration-tests'
-include ':twofactor-tests'
-include ':oauth2-tests'
-include ':fineract-client'
-include ':fineract-doc'
+package org.apache.fineract.dummy.core.data;
+
+public class DummyMessage {
+    private String message;
+
+    public DummyMessage(String message) {
+        this.message = message;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+}
diff --git a/settings.gradle 
b/module/dummy/core/src/main/java/org/apache/fineract/dummy/core/service/DummyService.java
similarity index 79%
copy from settings.gradle
copy to 
module/dummy/core/src/main/java/org/apache/fineract/dummy/core/service/DummyService.java
index 0a304eb..f0ae2a6 100644
--- a/settings.gradle
+++ 
b/module/dummy/core/src/main/java/org/apache/fineract/dummy/core/service/DummyService.java
@@ -16,11 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-rootProject.name='fineract'
-include ':fineract-provider'
-include ':fineract-war'
-include ':integration-tests'
-include ':twofactor-tests'
-include ':oauth2-tests'
-include ':fineract-client'
-include ':fineract-doc'
+package org.apache.fineract.dummy.core.service;
+
+import org.apache.fineract.dummy.core.data.DummyMessage;
+
+public interface DummyService {
+    DummyMessage getMessage();
+}
diff --git a/settings.gradle b/module/dummy/service/build.gradle
similarity index 79%
copy from settings.gradle
copy to module/dummy/service/build.gradle
index 0a304eb..8e59db8 100644
--- a/settings.gradle
+++ b/module/dummy/service/build.gradle
@@ -16,11 +16,8 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-rootProject.name='fineract'
-include ':fineract-provider'
-include ':fineract-war'
-include ':integration-tests'
-include ':twofactor-tests'
-include ':oauth2-tests'
-include ':fineract-client'
-include ':fineract-doc'
+description = 'Fineract Module: Dummy Service'
+
+group = 'org.apache.fineract.dummy.service'
+
+apply from: 'dependencies.gradle'
diff --git a/settings.gradle b/module/dummy/service/dependencies.gradle
similarity index 79%
copy from settings.gradle
copy to module/dummy/service/dependencies.gradle
index 0a304eb..517ab7d 100644
--- a/settings.gradle
+++ b/module/dummy/service/dependencies.gradle
@@ -16,11 +16,8 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-rootProject.name='fineract'
-include ':fineract-provider'
-include ':fineract-war'
-include ':integration-tests'
-include ':twofactor-tests'
-include ':oauth2-tests'
-include ':fineract-client'
-include ':fineract-doc'
+
+dependencies {
+    implementation(project(':module:dummy:core'),
+            'org.springframework:spring-context')
+}
diff --git a/settings.gradle 
b/module/dummy/service/src/main/java/org/apache/fineract/dummy/service/DummyServiceImpl.java
similarity index 70%
copy from settings.gradle
copy to 
module/dummy/service/src/main/java/org/apache/fineract/dummy/service/DummyServiceImpl.java
index 0a304eb..02eb36d 100644
--- a/settings.gradle
+++ 
b/module/dummy/service/src/main/java/org/apache/fineract/dummy/service/DummyServiceImpl.java
@@ -16,11 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-rootProject.name='fineract'
-include ':fineract-provider'
-include ':fineract-war'
-include ':integration-tests'
-include ':twofactor-tests'
-include ':oauth2-tests'
-include ':fineract-client'
-include ':fineract-doc'
+package org.apache.fineract.dummy.service;
+
+import org.apache.fineract.dummy.core.data.DummyMessage;
+import org.apache.fineract.dummy.core.service.DummyService;
+
+public class DummyServiceImpl implements DummyService {
+    @Override
+    public DummyMessage getMessage() {
+        return new DummyMessage("Hello: DEFAULT DUMMY!");
+    }
+}
diff --git a/settings.gradle b/module/dummy/starter/build.gradle
similarity index 79%
copy from settings.gradle
copy to module/dummy/starter/build.gradle
index 0a304eb..ab64be9 100644
--- a/settings.gradle
+++ b/module/dummy/starter/build.gradle
@@ -16,11 +16,8 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-rootProject.name='fineract'
-include ':fineract-provider'
-include ':fineract-war'
-include ':integration-tests'
-include ':twofactor-tests'
-include ':oauth2-tests'
-include ':fineract-client'
-include ':fineract-doc'
+description = 'Fineract Module: Dummy Starter'
+
+group = 'org.apache.fineract.dummy.starter'
+
+apply from: 'dependencies.gradle'
diff --git a/settings.gradle b/module/dummy/starter/dependencies.gradle
similarity index 79%
copy from settings.gradle
copy to module/dummy/starter/dependencies.gradle
index 0a304eb..4c8348e 100644
--- a/settings.gradle
+++ b/module/dummy/starter/dependencies.gradle
@@ -16,11 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-rootProject.name='fineract'
-include ':fineract-provider'
-include ':fineract-war'
-include ':integration-tests'
-include ':twofactor-tests'
-include ':oauth2-tests'
-include ':fineract-client'
-include ':fineract-doc'
+
+dependencies {
+    implementation(project(':module:dummy:core'),
+            project(':module:dummy:service'),
+            'org.springframework.boot:spring-boot-starter')
+}
diff --git a/settings.gradle 
b/module/dummy/starter/src/main/java/org/apache/fineract/dummy/starter/DummyAutoConfiguration.java
similarity index 59%
copy from settings.gradle
copy to 
module/dummy/starter/src/main/java/org/apache/fineract/dummy/starter/DummyAutoConfiguration.java
index 0a304eb..1dc7427 100644
--- a/settings.gradle
+++ 
b/module/dummy/starter/src/main/java/org/apache/fineract/dummy/starter/DummyAutoConfiguration.java
@@ -16,11 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-rootProject.name='fineract'
-include ':fineract-provider'
-include ':fineract-war'
-include ':integration-tests'
-include ':twofactor-tests'
-include ':oauth2-tests'
-include ':fineract-client'
-include ':fineract-doc'
+package org.apache.fineract.dummy.starter;
+
+import org.apache.fineract.dummy.core.service.DummyService;
+import org.apache.fineract.dummy.service.DummyServiceImpl;
+import 
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ConditionalOnMissingBean(DummyService.class)
+public class DummyAutoConfiguration {
+    @Bean
+    public DummyService dummyService() {
+        return new DummyServiceImpl();
+    }
+}
diff --git a/module/dummy/starter/src/main/resources/META-INF/spring.factories 
b/module/dummy/starter/src/main/resources/META-INF/spring.factories
new file mode 100644
index 0000000..5dcbd56
--- /dev/null
+++ b/module/dummy/starter/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,2 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+org.apache.fineract.dummy.starter.DummyAutoConfiguration
\ No newline at end of file
diff --git a/oauth2-tests/build.gradle b/oauth2-tests/build.gradle
index 1a89ab7..eebd32d 100644
--- a/oauth2-tests/build.gradle
+++ b/oauth2-tests/build.gradle
@@ -28,6 +28,9 @@ configurations {
 
 apply from: 'dependencies.gradle'
 
+// enable when all tests are migrated
+tasks.cucumber.onlyIf {false}
+
 cargo {
     containerId "tomcat9x"
 
@@ -38,6 +41,8 @@ cargo {
     }
 
     local {
+        // logLevel = 'medium'
+        // outputFile = file('build/output.log')
         installer {
             installConfiguration = configurations.tomcat
             downloadDir = file("$buildDir/download")
diff --git a/oauth2-tests/dependencies.gradle b/oauth2-tests/dependencies.gradle
index e8088f6..dc085d4 100644
--- a/oauth2-tests/dependencies.gradle
+++ b/oauth2-tests/dependencies.gradle
@@ -26,12 +26,6 @@ dependencies {
             'org.junit.jupiter:junit-jupiter-api',
             'org.bouncycastle:bcpkix-jdk15to18',
             'org.bouncycastle:bcprov-jdk15to18',
-            'io.cucumber:cucumber-core',
-            'io.cucumber:cucumber-java',
-            'io.cucumber:cucumber-java8',
-            'io.cucumber:cucumber-junit-platform-engine',
-            'io.cucumber:cucumber-spring',
-            'com.intuit.karate:karate-junit5',
             )
     testImplementation ('io.rest-assured:rest-assured') {
         exclude group: 'commons-logging'
diff --git a/fineract-client/src/test/resources/cucumber.properties 
b/oauth2-tests/src/test/resources/cucumber.properties
similarity index 95%
copy from fineract-client/src/test/resources/cucumber.properties
copy to oauth2-tests/src/test/resources/cucumber.properties
index d3b2786..a745f74 100644
--- a/fineract-client/src/test/resources/cucumber.properties
+++ b/oauth2-tests/src/test/resources/cucumber.properties
@@ -18,3 +18,4 @@
 #
 
 cucumber.publish.quiet=true
+cucumber.glue=org.apache.fineract
diff --git a/settings.gradle b/settings.gradle
index 0a304eb..4fb8b3b 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -17,6 +17,10 @@
  * under the License.
  */
 rootProject.name='fineract'
+include ':module:dummy:core'
+include ':module:dummy:service'
+include ':module:dummy:starter'
+include ':custom:foo:service'
 include ':fineract-provider'
 include ':fineract-war'
 include ':integration-tests'
diff --git a/twofactor-tests/build.gradle b/twofactor-tests/build.gradle
index a83febb..272fa0f 100644
--- a/twofactor-tests/build.gradle
+++ b/twofactor-tests/build.gradle
@@ -28,6 +28,9 @@ configurations {
 
 apply from: 'dependencies.gradle'
 
+// enable when all tests are migrated
+tasks.cucumber.onlyIf {false}
+
 cargo {
     containerId "tomcat9x"
 
@@ -38,6 +41,8 @@ cargo {
     }
 
     local {
+        // logLevel = 'medium'
+        // outputFile = file('build/output.log')
         installer {
             installConfiguration = configurations.tomcat
             downloadDir = file("$buildDir/download")
diff --git a/twofactor-tests/dependencies.gradle 
b/twofactor-tests/dependencies.gradle
index 190bfff..85cb0c6 100644
--- a/twofactor-tests/dependencies.gradle
+++ b/twofactor-tests/dependencies.gradle
@@ -24,15 +24,9 @@ dependencies {
     testImplementation( 
files("$rootDir/fineract-provider/build/classes/java/main/"),
             project(path: ':fineract-provider', configuration: 
'runtimeElements'),
             'org.junit.jupiter:junit-jupiter-api',
+            'com.icegreen:greenmail-junit5',
             'org.bouncycastle:bcpkix-jdk15to18',
             'org.bouncycastle:bcprov-jdk15to18',
-            'io.cucumber:cucumber-core',
-            'io.cucumber:cucumber-java',
-            'io.cucumber:cucumber-java8',
-            'io.cucumber:cucumber-junit-platform-engine',
-            'io.cucumber:cucumber-spring',
-            'com.icegreen:greenmail-junit5',
-            'com.intuit.karate:karate-junit5',
             )
     testImplementation ('io.rest-assured:rest-assured') {
         exclude group: 'commons-logging'
diff --git a/fineract-client/src/test/resources/cucumber.properties 
b/twofactor-tests/src/test/resources/cucumber.properties
similarity index 95%
copy from fineract-client/src/test/resources/cucumber.properties
copy to twofactor-tests/src/test/resources/cucumber.properties
index d3b2786..a745f74 100644
--- a/fineract-client/src/test/resources/cucumber.properties
+++ b/twofactor-tests/src/test/resources/cucumber.properties
@@ -18,3 +18,4 @@
 #
 
 cucumber.publish.quiet=true
+cucumber.glue=org.apache.fineract

Reply via email to