diff --git a/benchmark/build.gradle b/benchmark/build.gradle
index 025b8010a5a39c532916c0687a82c04af81a9da7..bae3a15ceec969d7597cb4d7a0c9de3d43d222d0 100644
--- a/benchmark/build.gradle
+++ b/benchmark/build.gradle
@@ -1,27 +1,14 @@
-apply plugin: 'application'
+plugins {
+    id 'eraser.java-application-conventions'
+}
 
 dependencies {
-    compile project(':eraser-base')
-    compile project(':feedbackloop.learner_backup')
-    compile project(':datasets')
+    implementation project(':eraser-base')
+    implementation project(':feedbackloop.learner_backup')
     implementation group: 'com.opencsv', name: 'opencsv', version: '4.1'
-    compile group: 'org.apache.httpcomponents', name: 'httpclient', version: "${apache_httpcomponents_version}"
-    compile group: 'org.apache.httpcomponents', name: 'fluent-hc', version: "${apache_httpcomponents_version}"
-    testCompile group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.11.2'
-}
-
-run {
-    mainClassName = 'de.tudresden.inf.st.eraser.benchmark.Main'
-    standardInput = System.in
-    if (project.hasProperty("appArgs")) {
-        args Eval.me(appArgs)
-    }
+    implementation group: 'org.apache.httpcomponents', name: 'httpclient', version: "${apache_httpcomponents_version}"
+    implementation group: 'org.apache.httpcomponents', name: 'fluent-hc', version: "${apache_httpcomponents_version}"
+    testImplementation group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.11.2'
 }
 
-sourceSets {
-    main {
-        java {
-            srcDir 'src/main/java'
-        }
-    }
-}
+application.mainClass = 'de.tudresden.inf.st.eraser.benchmark.Main'
diff --git a/build.gradle b/build.gradle
deleted file mode 100644
index f1f3b408f121f388615eca5d85cd3f128128f17c..0000000000000000000000000000000000000000
--- a/build.gradle
+++ /dev/null
@@ -1,46 +0,0 @@
-plugins {
-    id "com.github.ben-manes.versions" version "0.20.0"
-}
-
-allprojects  {
-	group = 'de.tudresden.inf.st'
-	version = '0.1'
-}
-
-subprojects {
-	apply plugin: 'java'
-
-	sourceCompatibility = 1.8
-	targetCompatibility = 1.8
-
-	task packageSources(type: Jar) {
-		classifier = 'sources'
-		from sourceSets.main.allSource
-	}
-
-	artifacts.archives packageSources
-	configurations {
-		testArtifacts.extendsFrom testRuntime
-	}
-
-	task testJar(type: Jar) {
-		classifier "test"
-		from sourceSets.test.output
-	}
-
-	artifacts {
-		testArtifacts testJar
-	}
-
-	repositories {
-		mavenCentral()
-	}
-
-	dependencies {
-		compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.11.2'
-		compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.11.2'
-		testCompile group: 'junit', name: 'junit', version: '4.12'
-		testCompile group: 'org.hamcrest', name: 'hamcrest-junit', version: '2.0.0.0'
-	}
-
-}
diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..95bfe53999d61b768da82463f837ec9f5254e997
--- /dev/null
+++ b/buildSrc/build.gradle
@@ -0,0 +1,11 @@
+plugins {
+    id 'groovy-gradle-plugin'
+}
+
+repositories {
+    gradlePluginPortal()
+}
+
+dependencies {
+    implementation 'com.github.ben-manes:gradle-versions-plugin:0.36.0'
+}
diff --git a/buildSrc/src/main/groovy/eraser.java-application-conventions.gradle b/buildSrc/src/main/groovy/eraser.java-application-conventions.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..fba18dcf1f122aa46fd411481ed8d5072c8cff26
--- /dev/null
+++ b/buildSrc/src/main/groovy/eraser.java-application-conventions.gradle
@@ -0,0 +1,4 @@
+plugins {
+  id 'eraser.java-common-conventions'
+  id 'application'
+}
diff --git a/buildSrc/src/main/groovy/eraser.java-common-conventions.gradle b/buildSrc/src/main/groovy/eraser.java-common-conventions.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..8639ba92b6ec0fa6ad86248e115e8b5ddcc29d75
--- /dev/null
+++ b/buildSrc/src/main/groovy/eraser.java-common-conventions.gradle
@@ -0,0 +1,24 @@
+plugins {
+  id 'java'
+  id 'idea'
+  id 'com.github.ben-manes.versions'
+}
+
+repositories {
+  mavenCentral()
+}
+
+dependencies {
+  implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.11.2'
+  implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.11.2'
+  testImplementation group: 'junit', name: 'junit', version: '4.12'
+  testImplementation group: 'org.hamcrest', name: 'hamcrest-junit', version: '2.0.0.0'
+
+  // testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.2'
+
+  // testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
+}
+
+// tasks.named('test') {
+//   useJUnitPlatform()
+// }
diff --git a/buildSrc/src/main/groovy/eraser.java-jastadd-conventions.gradle b/buildSrc/src/main/groovy/eraser.java-jastadd-conventions.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..a3cbca5362fd011dc7bfbb4277ef8c46c37c408f
--- /dev/null
+++ b/buildSrc/src/main/groovy/eraser.java-jastadd-conventions.gradle
@@ -0,0 +1,12 @@
+plugins {
+  id 'java'
+  id 'jastadd'
+}
+
+repositories {
+  mavenCentral()
+}
+
+dependencies {
+  implementation group: 'org.jastadd', name: 'jastaddgradle', version: '1.13.2'
+}
diff --git a/commons.color/build.gradle b/commons.color/build.gradle
index 30ce209c40610e390f709d9ec5a36c7324543c23..7339050832911cbad2e2b88d36875b8561a724b7 100644
--- a/commons.color/build.gradle
+++ b/commons.color/build.gradle
@@ -1,11 +1,8 @@
-dependencies {
-    compile group: 'org.apache.commons', name: 'commons-math3', version: '3.6.1'
+plugins {
+    id 'eraser.java-application-conventions'
+    id 'java-library'
 }
 
-sourceSets {
-    main {
-        java {
-            srcDir 'src/main/java'
-        }
-    }
+dependencies {
+    api group: 'org.apache.commons', name: 'commons-math3', version: '3.6.1'
 }
diff --git a/eraser-base/build.gradle b/eraser-base/build.gradle
index d7bf5cc432ae71b5c6bb7d0aedb032dcd787a2e0..4c5f412723181e1cc3e6a0a7184528e5087678bd 100644
--- a/eraser-base/build.gradle
+++ b/eraser-base/build.gradle
@@ -1,19 +1,3 @@
-apply plugin: 'jastadd'
-apply plugin: 'application'
-apply plugin: 'jacoco'
-apply plugin: 'idea'
-apply plugin: 'distribution'
-
-dependencies {
-    compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "${jackson_version}"
-    compile group: 'net.sf.beaver', name: 'beaver-rt', version: '0.9.11'
-    compile group: 'org.fusesource.mqtt-client', name: 'mqtt-client', version: '1.15'
-    compile group: 'org.influxdb', name: 'influxdb-java', version: '2.15'
-    testCompile group: 'org.testcontainers', name: 'testcontainers', version: '1.11.2'
-    testCompile group: 'org.testcontainers', name: 'influxdb', version: '1.11.2'
-    testCompile group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.11.2'
-}
-
 buildscript {
     repositories.mavenLocal()
     repositories.mavenCentral()
@@ -22,14 +6,28 @@ buildscript {
     }
 }
 
-run {
-    mainClassName = 'de.tudresden.inf.st.eraser.Main'
-    standardInput = System.in
-    if (project.hasProperty("appArgs")) {
-        args Eval.me(appArgs)
-    }
+plugins {
+    id 'eraser.java-application-conventions'
+    id 'java-library'
+    id 'com.github.ben-manes.versions'
+    id 'jacoco'
+    id 'distribution'
 }
 
+apply plugin: 'jastadd'
+
+dependencies {
+    api group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "${jackson_version}"
+    api group: 'net.sf.beaver', name: 'beaver-rt', version: '0.9.11'
+    api group: 'org.fusesource.mqtt-client', name: 'mqtt-client', version: '1.15'
+    implementation group: 'org.influxdb', name: 'influxdb-java', version: '2.15'
+    testImplementation group: 'org.testcontainers', name: 'testcontainers', version: '1.11.2'
+    testImplementation group: 'org.testcontainers', name: 'influxdb', version: '1.11.2'
+    testImplementation group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.11.2'
+}
+
+application.mainClass = 'de.tudresden.inf.st.eraser.Main'
+
 test {
     testLogging {
         events "passed", "skipped", "failed"
@@ -97,7 +95,7 @@ String[] arguments = ["libs/rd-builder.jar", "-d", "doc/"]
 def allSrcFiles = sourceSets.main.allSource.findAll { it.name.endsWith('java') }.toArray()
 def ragdocViewSrcData = '../ragdoc-view/src/data/'
 
-task ragdoc(type: JavaExec, dependsOn: assemble, overwrite: true) {
+task ragdocFixed(type: JavaExec, dependsOn: assemble) {
     group = 'documentation'
     description = 'Create ragdoc json documentation files'
     main = "-jar"
diff --git a/eraser.spark/build.gradle b/eraser.spark/build.gradle
index 5a577d15400aab9d58ac2fec4fae8589b0995020..e4012910f534331674e6fef88ecff0202d00e97c 100644
--- a/eraser.spark/build.gradle
+++ b/eraser.spark/build.gradle
@@ -1,23 +1,12 @@
 plugins {
-    id 'application'
+    id 'eraser.java-application-conventions'
     id 'io.franzbecker.gradle-lombok' version '3.0.0'
 }
 
 dependencies {
-    compile project(':eraser-base')
-    compile group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.11.2'
-    compile group: 'com.sparkjava', name: 'spark-core', version: '2.9.0'
+    implementation project(':eraser-base')
+    implementation group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.11.2'
+    implementation group: 'com.sparkjava', name: 'spark-core', version: '2.9.0'
 }
 
-run {
-    mainClassName = 'de.tudresden.inf.st.eraser.spark.Application'
-    standardInput = System.in
-}
-
-sourceSets {
-    main {
-        java {
-            srcDir 'src/main/java'
-        }
-    }
-}
+application.mainClass = 'de.tudresden.inf.st.eraser.spark.Application'
diff --git a/eraser.starter/build.gradle b/eraser.starter/build.gradle
index 78c59295cfce693d055282d6a68ccd3f7bdf4980..739e399f957a3b55b859384c45a078104e51a0bb 100644
--- a/eraser.starter/build.gradle
+++ b/eraser.starter/build.gradle
@@ -1,36 +1,25 @@
 plugins {
-    id 'java'
-    id 'application'
+    id 'eraser.java-application-conventions'
     id 'distribution'
     id 'io.github.http-builder-ng.http-plugin' version '0.1.1'
 }
 
-repositories {
-    mavenCentral()
-}
-
-sourceCompatibility = 1.8
-
 dependencies {
-    compile project(':eraser-base')
-    compile project(':eraser.spark')
-    compile project(':feedbackloop.api')
-    compile project(':feedbackloop.analyze')
-    compile project(':feedbackloop.plan')
-    compile project(':feedbackloop.execute')
-    compile project(':feedbackloop.learner_backup')
-    compile project(':datasets')
-    compile group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: "${jackson_version}"
-    compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "${jackson_version}"
-    compile group: 'net.sourceforge.argparse4j', name: 'argparse4j', version: '0.8.1'
-    //    compile project(':feedbackloop.learner')
+    implementation project(':eraser-base')
+    implementation project(':eraser.spark')
+    implementation project(':feedbackloop.api')
+    implementation project(':feedbackloop.analyze')
+    implementation project(':feedbackloop.plan')
+    implementation project(':feedbackloop.execute')
+    implementation project(':feedbackloop.learner_backup')
+    implementation group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: "${jackson_version}"
+    implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "${jackson_version}"
+    implementation group: 'net.sourceforge.argparse4j', name: 'argparse4j', version: '0.8.1'
+    //    implementation project(':feedbackloop.learner')
 
 }
 
-run {
-    mainClassName = 'de.tudresden.inf.st.eraser.starter.EraserStarter'
-    standardInput = System.in
-}
+application.mainClass = 'de.tudresden.inf.st.eraser.starter.EraserStarter'
 
 import io.github.httpbuilderng.http.HttpTask
 
@@ -46,23 +35,6 @@ task shutdown (type: HttpTask) {
     }
 }
 
-sourceSets {
-    main {
-        java {
-            srcDir 'src/main/java'
-        }
-    }
-}
-
-//distributions {
-//    main {
-//        contents {
-//            from {
-//                'src/main/resources/starter.eraser'
-//            }
-//        }
-//    }
-//}
 applicationDistribution.from("src/main/resources") {
     include "starter.eraser"
 }
diff --git a/feedbackloop.analyze/build.gradle b/feedbackloop.analyze/build.gradle
index 361f5c1429190208b8a70cbb889bf6c1cbd56993..6fb8173284f0268085bf53a8a0b6dcae071496d2 100644
--- a/feedbackloop.analyze/build.gradle
+++ b/feedbackloop.analyze/build.gradle
@@ -1,12 +1,8 @@
-dependencies {
-    compile project(':eraser-base')
-    compile project(':feedbackloop.api')
+plugins {
+    id 'eraser.java-common-conventions'
 }
 
-sourceSets {
-    main {
-        java {
-            srcDir 'src/main/java'
-        }
-    }
+dependencies {
+    implementation project(':eraser-base')
+    implementation project(':feedbackloop.api')
 }
diff --git a/feedbackloop.api/build.gradle b/feedbackloop.api/build.gradle
index ba194086c7c858a3435af764a8783f38231d2c69..f4a30208fd328727ddfb07201b16d1093f8b70df 100644
--- a/feedbackloop.api/build.gradle
+++ b/feedbackloop.api/build.gradle
@@ -1,17 +1,10 @@
 plugins {
+    id 'eraser.java-common-conventions'
     id 'io.franzbecker.gradle-lombok' version '3.0.0'
 }
 
 dependencies {
-    compile project(':eraser-base')
+    implementation project(':eraser-base')
     compile project(':commons.color')
     compile group: 'org.encog', name: 'encog-core', version: '3.4'
 }
-
-sourceSets {
-    main {
-        java {
-            srcDir 'src/main/java'
-        }
-    }
-}
diff --git a/feedbackloop.execute/build.gradle b/feedbackloop.execute/build.gradle
index 361f5c1429190208b8a70cbb889bf6c1cbd56993..6fb8173284f0268085bf53a8a0b6dcae071496d2 100644
--- a/feedbackloop.execute/build.gradle
+++ b/feedbackloop.execute/build.gradle
@@ -1,12 +1,8 @@
-dependencies {
-    compile project(':eraser-base')
-    compile project(':feedbackloop.api')
+plugins {
+    id 'eraser.java-common-conventions'
 }
 
-sourceSets {
-    main {
-        java {
-            srcDir 'src/main/java'
-        }
-    }
+dependencies {
+    implementation project(':eraser-base')
+    implementation project(':feedbackloop.api')
 }
diff --git a/feedbackloop.learner/build.gradle b/feedbackloop.learner/build.gradle
index 3ad295bf3c112d55e31fb6d185cef21ead1da66d..270a1146ccb06a983472c29b54a8ce510649ce9b 100644
--- a/feedbackloop.learner/build.gradle
+++ b/feedbackloop.learner/build.gradle
@@ -1,23 +1,11 @@
-apply plugin: 'application'
-
-dependencies {
-    compile project(':eraser-base')
-    compile project(':feedbackloop.api')
-    compile group: 'org.encog', name: 'encog-core', version: '3.4'
+plugins {
+    id 'eraser.java-application-conventions'
 }
 
-run {
-    mainClassName = 'de.tudresden.inf.st.eraser.feedbackloop.learner.Main'
-    standardInput = System.in
-    if (project.hasProperty("appArgs")) {
-        args Eval.me(appArgs)
-    }
+dependencies {
+    implementation project(':eraser-base')
+    implementation project(':feedbackloop.api')
+    implementation group: 'org.encog', name: 'encog-core', version: '3.4'
 }
 
-sourceSets {
-    main {
-        java {
-            srcDir 'src/main/java'
-        }
-    }
-}
+application.mainClass = 'de.tudresden.inf.st.eraser.feedbackloop.learner.Main'
diff --git a/feedbackloop.learner_backup/build.gradle b/feedbackloop.learner_backup/build.gradle
index 4ee3fb5d717a1f36a86b8cb31accba4e751d9ddc..b4800381bf8d804eaf716a98b09ff165dc77eae2 100644
--- a/feedbackloop.learner_backup/build.gradle
+++ b/feedbackloop.learner_backup/build.gradle
@@ -1,12 +1,12 @@
 plugins {
-    id 'application'
+    id 'eraser.java-application-conventions'
     id 'io.franzbecker.gradle-lombok' version '3.0.0'
 }
 
 dependencies {
-    compile project(':eraser-base')
-    compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "${jackson_version}"
-    compile group: 'org.encog', name: 'encog-core', version: '3.4'
+    implementation project(':eraser-base')
+    implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "${jackson_version}"
+    implementation group: 'org.encog', name: 'encog-core', version: '3.4'
     implementation group: 'com.opencsv', name: 'opencsv', version: '4.1'
     implementation group: 'commons-io', name: 'commons-io', version: '2.5'
     implementation group: 'org.apache.httpcomponents', name: 'httpclient', version: "${apache_httpcomponents_version}"
@@ -16,16 +16,4 @@ dependencies {
 //    compile group: 'com.sparkjava', name: 'spark-core', version: '2.9.0'
 }
 
-run {
-    mainClassName = 'de.tudresden.inf.st.eraser.feedbackloop.learner_backup.Main'
-    standardInput = System.in
-    if (project.hasProperty("appArgs")) {
-        args Eval.me(appArgs)
-    }
-}
-
-sourceSets.main {
-    java {
-        srcDir 'src/main/java'
-    }
-}
+application.mainClass = 'de.tudresden.inf.st.eraser.feedbackloop.learner_backup.Main'
diff --git a/feedbackloop.main/build.gradle b/feedbackloop.main/build.gradle
index 7e66daa3efddb2ef62735abc2fe6e57bab91d053..c1ff89c5aebae853e7d2716cb6b6f1b4b6c2bfd2 100644
--- a/feedbackloop.main/build.gradle
+++ b/feedbackloop.main/build.gradle
@@ -1,26 +1,14 @@
-apply plugin: 'application'
-
-dependencies {
-    compile project(':eraser-base')
-    compile project(':feedbackloop.api')
-    compile project(':feedbackloop.monitor')
-    compile project(':feedbackloop.analyze')
-    compile project(':feedbackloop.plan')
-    compile project(':feedbackloop.execute')
+plugins {
+    id 'eraser.java-application-conventions'
 }
 
-run {
-    mainClassName = 'de.tudresden.inf.st.eraser.feedbackloop.main.Main'
-    standardInput = System.in
-    if (project.hasProperty("appArgs")) {
-        args Eval.me(appArgs)
-    }
+dependencies {
+    implementation project(':eraser-base')
+    implementation project(':feedbackloop.api')
+    implementation project(':feedbackloop.monitor')
+    implementation project(':feedbackloop.analyze')
+    implementation project(':feedbackloop.plan')
+    implementation project(':feedbackloop.execute')
 }
 
-sourceSets {
-    main {
-        java {
-            srcDir 'src/main/java'
-        }
-    }
-}
+application.mainClass = 'de.tudresden.inf.st.eraser.feedbackloop.main.Main'
diff --git a/feedbackloop.monitor/build.gradle b/feedbackloop.monitor/build.gradle
index e3f4c6e283e32e73a0a54ffe1f03d019c81c6d8a..7b20211d09ea803af8c249af518cf9ae038d3036 100644
--- a/feedbackloop.monitor/build.gradle
+++ b/feedbackloop.monitor/build.gradle
@@ -1,22 +1,10 @@
-apply plugin: 'application'
-
-dependencies {
-    compile project(':eraser-base')
-    compile project(':feedbackloop.api')
+plugins {
+    id 'eraser.java-application-conventions'
 }
 
-run {
-    mainClassName = 'de.tudresden.inf.st.eraser.feedbackloop.monitor.Main'
-    standardInput = System.in
-    if (project.hasProperty("appArgs")) {
-        args Eval.me(appArgs)
-    }
+dependencies {
+    implementation project(':eraser-base')
+    implementation project(':feedbackloop.api')
 }
 
-sourceSets {
-    main {
-        java {
-            srcDir 'src/main/java'
-        }
-    }
-}
+application.mainClass = 'de.tudresden.inf.st.eraser.feedbackloop.monitor.Main'
diff --git a/feedbackloop.plan/build.gradle b/feedbackloop.plan/build.gradle
index 13b20cf6cff29796338f0ac62dd71723fd5ff467..f975ca22ecedf94fa809f412f5c1fd8bb46a4a11 100644
--- a/feedbackloop.plan/build.gradle
+++ b/feedbackloop.plan/build.gradle
@@ -1,22 +1,10 @@
-apply plugin: 'application'
+plugins {
+    id 'eraser.java-application-conventions'
+}
 
 dependencies {
-    compile project(':eraser-base')
+    implementation project(':eraser-base')
     compile project(':feedbackloop.api')
 }
 
-run {
-    mainClassName = 'de.tudresden.inf.st.eraser.feedbackloop.plan.Main'
-    standardInput = System.in
-    if (project.hasProperty("appArgs")) {
-        args Eval.me(appArgs)
-    }
-}
-
-sourceSets {
-    main {
-        java {
-            srcDir 'src/main/java'
-        }
-    }
-}
+application.mainClass = 'de.tudresden.inf.st.eraser.feedbackloop.plan.Main'
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 01b8bf6b1f99cad9213fc495b33ad5bbab8efd20..457aad0d98108420a977756b7145c93c8910b076 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 030ec1f8a437a05e86702c10632c66340d98ba0f..4d9ca1649142b0c20144adce78e2472e2da01c30 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
-#Tue May 07 14:40:56 CEST 2019
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
diff --git a/gradlew b/gradlew
index cccdd3d517fc5249beaefa600691cf150f2fa3e6..af6708ff229fda75da4f7cc4da4747217bac4d53 100755
--- a/gradlew
+++ b/gradlew
@@ -28,7 +28,7 @@ APP_NAME="Gradle"
 APP_BASE_NAME=`basename "$0"`
 
 # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
+DEFAULT_JVM_OPTS='"-Xmx64m"'
 
 # Use the maximum available, or set MAX_FD != -1 to use that value.
 MAX_FD="maximum"
diff --git a/gradlew.bat b/gradlew.bat
index e95643d6a2ca62258464e83c72f5156dc941c609..0f8d5937c4ad18feb44a19e55ad1e37cc159260f 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -14,7 +14,7 @@ set APP_BASE_NAME=%~n0
 set APP_HOME=%DIRNAME%
 
 @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
+set DEFAULT_JVM_OPTS="-Xmx64m"
 
 @rem Find java.exe
 if defined JAVA_HOME goto findJavaFromJavaHome
diff --git a/integration/build.gradle b/integration/build.gradle
index 219d9424d1b27114d05fc74ff704f6e7ce02937b..1317bea5f88fd9341768b1cfef08dd925ecbfc93 100644
--- a/integration/build.gradle
+++ b/integration/build.gradle
@@ -1,14 +1,10 @@
-apply plugin: 'application'
-
-run {
-    mainClassName = 'de.tudresden.inf.st.eraser.integration.IntegrationMain'
-    standardInput = System.in
-    if (project.hasProperty("appArgs")) {
-        args Eval.me(appArgs)
-    }
+plugins {
+    id 'eraser.java-application-conventions'
 }
 
 dependencies {
-    compile project(':eraser-base')
-    compile project(':openhab-mock')
+    implementation project(':eraser-base')
+    implementation group: 'com.opencsv', name: 'opencsv', version: '3.8'
 }
+
+application.mainClass = 'de.tudresden.inf.st.eraser.integration.IntegrationMain'
diff --git a/integration/src/main/java/de/tudresden/inf/st/eraser/integration/IntegrationMain.java b/integration/src/main/java/de/tudresden/inf/st/eraser/integration/IntegrationMain.java
index 05884c80d68bf27980465038960da9d5fe7adf66..61c7d67b77f0630894436a26e74e6f8e6557a3ca 100644
--- a/integration/src/main/java/de/tudresden/inf/st/eraser/integration/IntegrationMain.java
+++ b/integration/src/main/java/de/tudresden/inf/st/eraser/integration/IntegrationMain.java
@@ -5,8 +5,8 @@ import de.tudresden.inf.st.eraser.Main;
 import de.tudresden.inf.st.eraser.deserializer.ASTNodeDeserializer;
 import de.tudresden.inf.st.eraser.jastadd.model.*;
 import de.tudresden.inf.st.eraser.openhab2.mqtt.MQTTUpdater;
-import de.tudresden.inf.st.eraser.openhab_mock.MockMain;
 import de.tudresden.inf.st.eraser.serializer.JsonSerializer;
+import org.fusesource.mqtt.client.QoS;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
@@ -41,7 +41,7 @@ public class IntegrationMain {
       // read in csv
       String filename = "/data1.csv";
 //      Path csvContent = Paths.get("src", "main", "resources", filename);
-      InputStream inputStream = MockMain.class.getResourceAsStream(filename);
+      InputStream inputStream = IntegrationMain.class.getResourceAsStream(filename);
       String host = "localhost";
       MqttRoot mqttRoot = new MqttRoot();
       mqttRoot.setHostByName(host);
@@ -64,7 +64,7 @@ public class IntegrationMain {
           String message = line[3];
           // TODO replay messages in real time, i.e., with delay between messages
           try {
-            sender.publish(topic, message, MockMain.getQoSEnum(qos));
+            sender.publish(topic, message, getQoSEnum(qos));
           } catch (Exception e) {
             // abort the whole operation
             throw new RuntimeException(e);
@@ -126,4 +126,13 @@ public class IntegrationMain {
     return ASTNodeDeserializer.read(inputStream);
   }
 
+  public static QoS getQoSEnum(String qos) {
+    switch(qos) {
+      case "0": return QoS.AT_MOST_ONCE;
+      case "1": return QoS.AT_LEAST_ONCE;
+      case "2": return QoS.EXACTLY_ONCE;
+      default: throw new IllegalArgumentException("Invalid QoS: " + qos);
+    }
+  }
+
 }
diff --git a/integration_test/build.gradle b/integration_test/build.gradle
index 955056f2e34dbd32af7c1167f717d268db0088c0..7e3f7749884765aa9d3ff7137a65bda9c5a345fc 100644
--- a/integration_test/build.gradle
+++ b/integration_test/build.gradle
@@ -1,24 +1,12 @@
-apply plugin: 'application'
-
-dependencies {
-    testCompile project(':eraser-base')
-    testCompile group: 'org.apache.httpcomponents', name: 'httpclient', version: "${apache_httpcomponents_version}"
-    testCompile group: 'org.apache.httpcomponents', name: 'fluent-hc', version: "${apache_httpcomponents_version}"
-    testCompile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "${jackson_version}"
+plugins {
+    id 'eraser.java-application-conventions'
 }
 
-run {
-    mainClassName = 'de.tudresden.inf.st.eraser.integration_test.Main'
-    standardInput = System.in
-    if (project.hasProperty("appArgs")) {
-        args Eval.me(appArgs)
-    }
+dependencies {
+    implementation project(':eraser-base')
+    testImplementation group: 'org.apache.httpcomponents', name: 'httpclient', version: "${apache_httpcomponents_version}"
+    testImplementation group: 'org.apache.httpcomponents', name: 'fluent-hc', version: "${apache_httpcomponents_version}"
+    testImplementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "${jackson_version}"
 }
 
-sourceSets {
-    main {
-        java {
-            srcDir 'src/main/java'
-        }
-    }
-}
+application.mainClass = 'de.tudresden.inf.st.eraser.integration_test.Main'
diff --git a/project-template/build.gradle b/project-template/build.gradle
index 3bae16225ca01a6fea919d36be3a383c6a62507f..4c719170028a0bc82e806ef5dd56fc08cba627e2 100644
--- a/project-template/build.gradle
+++ b/project-template/build.gradle
@@ -1,21 +1,9 @@
-apply plugin: 'application'
-
-dependencies {
-    compile project(':eraser-base')
+plugins {
+    id 'eraser.java-application-conventions'
 }
 
-run {
-    mainClassName = 'de.tudresden.inf.st.eraser.projectName.Main'
-    standardInput = System.in
-    if (project.hasProperty("appArgs")) {
-        args Eval.me(appArgs)
-    }
+dependencies {
+    implementation project(':eraser-base')
 }
 
-sourceSets {
-    main {
-        java {
-            srcDir 'src/main/java'
-        }
-    }
-}
+application.mainClass
diff --git a/settings.gradle b/settings.gradle
index 3dd742cc3db674b63a4f2a43a1651ecf773747ae..7a1998d518bc44ca122f597f2a6da1099867aab3 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,7 +1,6 @@
 rootProject.name = 'eraser'
 
 include ':eraser-base'
-include 'openhab-mock'
 include 'integration'
 include ':benchmark'
 include ':commons.color'
@@ -15,4 +14,3 @@ include ':feedbackloop.learner'
 include ':eraser.spark'
 include ':eraser.starter'
 include ':feedbackloop.learner_backup'
-include ':datasets'
diff --git a/skywriter-hue-integration/build.gradle b/skywriter-hue-integration/build.gradle
index 410a39b582bd8ea9316289b95c1f7f0083de6576..77d03a565cbd09eda8fd17563c92b7207c9487db 100644
--- a/skywriter-hue-integration/build.gradle
+++ b/skywriter-hue-integration/build.gradle
@@ -1,22 +1,10 @@
-apply plugin: 'application'
-
-dependencies {
-    compile project(':eraser-base')
-    compile project(':commons.color')
+plugins {
+    id 'eraser.java-application-conventions'
 }
 
-run {
-    mainClassName = 'de.tudresden.inf.st.eraser.skywriter_hue_integration.Main'
-    standardInput = System.in
-    if (project.hasProperty("appArgs")) {
-        args Eval.me(appArgs)
-    }
+dependencies {
+    implementation project(':eraser-base')
+    implementation project(':commons.color')
 }
 
-sourceSets {
-    main {
-        java {
-            srcDir 'src/main/java'
-        }
-    }
-}
+application.mainClass = 'de.tudresden.inf.st.eraser.skywriter_hue_integration.Main'