You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by nf...@apache.org on 2018/12/14 08:52:43 UTC

[camel-k] 05/08: runtime: initial support for traits #287

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

nferraro pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel-k.git

commit b4b7c22696804518f971cba0a87bca54043dd2ac
Author: lburgazzoli <lb...@gmail.com>
AuthorDate: Thu Dec 13 01:49:30 2018 +0100

    runtime: initial support for traits #287
---
 runtime/{jvm => core}/pom.xml                      |  27 +----
 .../main/java/org/apache/camel/k}/Constants.java   |   5 +-
 .../main/java/org/apache/camel/k}/Language.java    |   2 +-
 .../java/org/apache/camel/k}/RoutesLoader.java     |   2 +-
 .../java/org/apache/camel/k}/RuntimeRegistry.java  |   6 +-
 .../java/org/apache/camel/k/RuntimeTrait.java}     |  19 ++--
 .../src/main/java/org/apache/camel/k}/Source.java  |   2 +-
 .../camel/k/groovy/GroovyRoutesLoader.groovy       |   4 +
 .../camel/k/groovy/dsl/ContextConfiguration.groovy |   2 +-
 .../k/groovy/dsl/IntegrationConfiguration.groovy   |   2 +-
 .../k/groovy/dsl/RegistryConfiguration.groovy      |   2 +-
 ...outesLoader => org.apache.camel.k.RoutesLoader} |   0
 .../org/apache/camel/k/groovy/LoaderTest.groovy    |   2 +-
 runtime/jvm/pom.xml                                |  14 +--
 .../java/org/apache/camel/k/jvm/Application.java   |  23 +++--
 .../java/org/apache/camel/k/jvm/RoutesLoaders.java |   5 +
 .../main/java/org/apache/camel/k/jvm/Runtime.java  |   4 +-
 .../org/apache/camel/k/jvm/RuntimeSupport.java     |  40 ++++++++
 .../apache/camel/k/jvm/SimpleRuntimeRegistry.java  |   1 +
 .../java/org/apache/camel/k/jvm/URIResolver.java   |   2 +
 ...outesLoader => org.apache.camel.k.RoutesLoader} |   0
 .../org/apache/camel/k/jvm/PropertiesTest.java     | 110 +++++++++------------
 .../org/apache/camel/k/jvm/RoutesLoadersTest.java  |   2 +
 .../apache/camel/k/jvm/RuntimeTestSupport.java}    |  42 ++++----
 .../apache/camel/k/kotlin/KotlinRoutesLoader.kt    |   4 +
 .../camel/k/kotlin/dsl/ContextConfiguration.kt     |   2 +-
 .../camel/k/kotlin/dsl/IntegrationConfiguration.kt |   2 +-
 .../camel/k/kotlin/dsl/RegistryConfiguration.kt    |   2 +-
 ...outesLoader => org.apache.camel.k.RoutesLoader} |   0
 .../kotlin/org/apache/camel/k/kotlin/LoaderTest.kt |   2 +-
 runtime/pom.xml                                    |   5 +-
 .../apache/camel/k/spring/boot/Application.java    |  15 ++-
 32 files changed, 179 insertions(+), 171 deletions(-)

diff --git a/runtime/jvm/pom.xml b/runtime/core/pom.xml
similarity index 76%
copy from runtime/jvm/pom.xml
copy to runtime/core/pom.xml
index b02dc3c..3577492 100644
--- a/runtime/jvm/pom.xml
+++ b/runtime/core/pom.xml
@@ -27,11 +27,7 @@
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
-    <artifactId>camel-k-runtime-jvm</artifactId>
-
-    <properties>
-        <kotlin.version>1.2.71</kotlin.version>
-    </properties>
+    <artifactId>camel-k-runtime-core</artifactId>
 
     <dependencies>
 
@@ -51,27 +47,6 @@
             <version>${slf4j.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.apache.logging.log4j</groupId>
-            <artifactId>log4j-core</artifactId>
-            <version>${log4j2.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.logging.log4j</groupId>
-            <artifactId>log4j-slf4j-impl</artifactId>
-            <version>${log4j2.version}</version>
-            <scope>runtime</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.jooq</groupId>
-            <artifactId>joor-java-8</artifactId>
-            <version>${joor.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>commons-io</groupId>
-            <artifactId>commons-io</artifactId>
-            <version>${commons-io.version}</version>
-        </dependency>
-        <dependency>
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-lang3</artifactId>
             <version>${commons-lang.version}</version>
diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Constants.java b/runtime/core/src/main/java/org/apache/camel/k/Constants.java
similarity index 80%
rename from runtime/jvm/src/main/java/org/apache/camel/k/jvm/Constants.java
rename to runtime/core/src/main/java/org/apache/camel/k/Constants.java
index d3cb4b7..e00fed4 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Constants.java
+++ b/runtime/core/src/main/java/org/apache/camel/k/Constants.java
@@ -14,16 +14,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.k.jvm;
+package org.apache.camel.k;
 
 public final class Constants {
     public static final String ENV_CAMEL_K_ROUTES = "CAMEL_K_ROUTES";
     public static final String ENV_CAMEL_K_CONF = "CAMEL_K_CONF";
     public static final String ENV_CAMEL_K_CONF_D = "CAMEL_K_CONF_D";
+    public static final String ENV_CAMEL_K_TRAITS = "CAMEL_K_TRAITS";
     public static final String SCHEME_CLASSPATH = "classpath:";
     public static final String SCHEME_FILE = "file:";
     public static final String SCHEME_ENV = "env:";
     public static final String LOGGING_LEVEL_PREFIX = "logging.level.";
+    public static final String ROUTES_LOADER_RESOURCE_PATH = "META-INF/services/org/apache/camel/k/loader/";
+    public static final String RUNTIME_TRAIT_RESOURCE_PATH = "META-INF/services/org/apache/camel/k/trait/";
 
     private Constants() {
     }
diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Language.java b/runtime/core/src/main/java/org/apache/camel/k/Language.java
similarity index 98%
rename from runtime/jvm/src/main/java/org/apache/camel/k/jvm/Language.java
rename to runtime/core/src/main/java/org/apache/camel/k/Language.java
index d041faa..bfeffa5 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Language.java
+++ b/runtime/core/src/main/java/org/apache/camel/k/Language.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.k.jvm;
+package org.apache.camel.k;
 
 import java.util.Arrays;
 import java.util.Collections;
diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RoutesLoader.java b/runtime/core/src/main/java/org/apache/camel/k/RoutesLoader.java
similarity index 97%
rename from runtime/jvm/src/main/java/org/apache/camel/k/jvm/RoutesLoader.java
rename to runtime/core/src/main/java/org/apache/camel/k/RoutesLoader.java
index faac8ed..3026b92 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RoutesLoader.java
+++ b/runtime/core/src/main/java/org/apache/camel/k/RoutesLoader.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.k.jvm;
+package org.apache.camel.k;
 
 import java.util.List;
 
diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeRegistry.java b/runtime/core/src/main/java/org/apache/camel/k/RuntimeRegistry.java
similarity index 96%
copy from runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeRegistry.java
copy to runtime/core/src/main/java/org/apache/camel/k/RuntimeRegistry.java
index 7e13a28..895fe33 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeRegistry.java
+++ b/runtime/core/src/main/java/org/apache/camel/k/RuntimeRegistry.java
@@ -14,17 +14,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.k.jvm;
+package org.apache.camel.k;
 
 import java.util.Map;
 
 import org.apache.camel.spi.Registry;
 
 public interface RuntimeRegistry extends Registry {
-
-    /**
-     *
-     */
     void bind(String name, Object bean);
 
     @SuppressWarnings("deprecation")
diff --git a/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/RegistryConfiguration.kt b/runtime/core/src/main/java/org/apache/camel/k/RuntimeTrait.java
similarity index 73%
copy from runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/RegistryConfiguration.kt
copy to runtime/core/src/main/java/org/apache/camel/k/RuntimeTrait.java
index f15f71a..275f53a 100644
--- a/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/RegistryConfiguration.kt
+++ b/runtime/core/src/main/java/org/apache/camel/k/RuntimeTrait.java
@@ -1,3 +1,7 @@
+package org.apache.camel.k;
+
+import org.apache.camel.CamelContext;
+
 /**
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -6,7 +10,7 @@
  * (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
+ *      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,
@@ -14,12 +18,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.k.kotlin.dsl
-
-import org.apache.camel.k.jvm.RuntimeRegistry
 
-class RegistryConfiguration(val registry: RuntimeRegistry) {
-    fun bind(name: String, value: Any) {
-        registry.bind(name, value)
-    }
+@FunctionalInterface
+public interface RuntimeTrait {
+    /**
+     * Perform CamelContext customization.
+     */
+    void apply(CamelContext camelContext);
 }
diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Source.java b/runtime/core/src/main/java/org/apache/camel/k/Source.java
similarity index 98%
rename from runtime/jvm/src/main/java/org/apache/camel/k/jvm/Source.java
rename to runtime/core/src/main/java/org/apache/camel/k/Source.java
index 8b00a4b..0726b07 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Source.java
+++ b/runtime/core/src/main/java/org/apache/camel/k/Source.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.k.jvm;
+package org.apache.camel.k;
 
 import java.util.Map;
 
diff --git a/runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/GroovyRoutesLoader.groovy b/runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/GroovyRoutesLoader.groovy
index 932f526..bb081d4 100644
--- a/runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/GroovyRoutesLoader.groovy
+++ b/runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/GroovyRoutesLoader.groovy
@@ -18,6 +18,10 @@ package org.apache.camel.k.groovy
 
 
 import org.apache.camel.builder.RouteBuilder
+import org.apache.camel.k.Language
+import org.apache.camel.k.RoutesLoader
+import org.apache.camel.k.RuntimeRegistry
+import org.apache.camel.k.Source
 import org.apache.camel.k.groovy.dsl.IntegrationConfiguration
 import org.apache.camel.k.jvm.*
 import org.codehaus.groovy.control.CompilerConfiguration
diff --git a/runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/ContextConfiguration.groovy b/runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/ContextConfiguration.groovy
index 405fe8c..d70dd04 100644
--- a/runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/ContextConfiguration.groovy
+++ b/runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/ContextConfiguration.groovy
@@ -17,7 +17,7 @@
 package org.apache.camel.k.groovy.dsl
 
 import org.apache.camel.CamelContext
-import org.apache.camel.k.jvm.RuntimeRegistry
+import org.apache.camel.k.RuntimeRegistry
 
 class ContextConfiguration {
     private final CamelContext context
diff --git a/runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/IntegrationConfiguration.groovy b/runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/IntegrationConfiguration.groovy
index 5b07bd5..fdc860a 100644
--- a/runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/IntegrationConfiguration.groovy
+++ b/runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/IntegrationConfiguration.groovy
@@ -21,7 +21,7 @@ import org.apache.camel.Exchange
 import org.apache.camel.Predicate
 import org.apache.camel.Processor
 import org.apache.camel.builder.RouteBuilder
-import org.apache.camel.k.jvm.RuntimeRegistry
+import org.apache.camel.k.RuntimeRegistry
 import org.apache.camel.k.jvm.dsl.Components
 import org.apache.camel.model.RouteDefinition
 
diff --git a/runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/RegistryConfiguration.groovy b/runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/RegistryConfiguration.groovy
index 0b7b23d..f695ec1 100644
--- a/runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/RegistryConfiguration.groovy
+++ b/runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/RegistryConfiguration.groovy
@@ -16,7 +16,7 @@
  */
 package org.apache.camel.k.groovy.dsl
 
-import org.apache.camel.k.jvm.RuntimeRegistry
+import org.apache.camel.k.RuntimeRegistry
 
 class RegistryConfiguration {
     private final RuntimeRegistry registry
diff --git a/runtime/groovy/src/main/resources/META-INF/services/org.apache.camel.k.jvm.RoutesLoader b/runtime/groovy/src/main/resources/META-INF/services/org.apache.camel.k.RoutesLoader
similarity index 100%
rename from runtime/groovy/src/main/resources/META-INF/services/org.apache.camel.k.jvm.RoutesLoader
rename to runtime/groovy/src/main/resources/META-INF/services/org.apache.camel.k.RoutesLoader
diff --git a/runtime/groovy/src/test/groovy/org/apache/camel/k/groovy/LoaderTest.groovy b/runtime/groovy/src/test/groovy/org/apache/camel/k/groovy/LoaderTest.groovy
index ab3779c..a9c8a0a 100644
--- a/runtime/groovy/src/test/groovy/org/apache/camel/k/groovy/LoaderTest.groovy
+++ b/runtime/groovy/src/test/groovy/org/apache/camel/k/groovy/LoaderTest.groovy
@@ -18,7 +18,7 @@ package org.apache.camel.k.groovy
 
 import org.apache.camel.k.jvm.RoutesLoaders
 import org.apache.camel.k.jvm.SimpleRuntimeRegistry
-import org.apache.camel.k.jvm.Source
+import org.apache.camel.k.Source
 import org.apache.camel.model.ToDefinition
 import spock.lang.Specification
 
diff --git a/runtime/jvm/pom.xml b/runtime/jvm/pom.xml
index b02dc3c..aa48603 100644
--- a/runtime/jvm/pom.xml
+++ b/runtime/jvm/pom.xml
@@ -29,10 +29,6 @@
 
     <artifactId>camel-k-runtime-jvm</artifactId>
 
-    <properties>
-        <kotlin.version>1.2.71</kotlin.version>
-    </properties>
-
     <dependencies>
 
         <!-- ****************************** -->
@@ -42,13 +38,9 @@
         <!-- ****************************** -->
 
         <dependency>
-            <groupId>org.apache.camel</groupId>
-            <artifactId>camel-core</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-api</artifactId>
-            <version>${slf4j.version}</version>
+            <groupId>org.apache.camel.k</groupId>
+            <artifactId>camel-k-runtime-core</artifactId>
+            <version>${project.version}</version>
         </dependency>
         <dependency>
             <groupId>org.apache.logging.log4j</groupId>
diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Application.java b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Application.java
index 917b566..682609c 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Application.java
+++ b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Application.java
@@ -16,11 +16,9 @@
  */
 package org.apache.camel.k.jvm;
 
-import java.util.Properties;
-
 import org.apache.camel.CamelContext;
 import org.apache.camel.Component;
-import org.apache.camel.component.properties.PropertiesComponent;
+import org.apache.camel.k.Constants;
 import org.apache.camel.main.MainListenerSupport;
 import org.apache.camel.support.LifecycleStrategySupport;
 import org.apache.camel.util.ObjectHelper;
@@ -65,20 +63,21 @@ public class Application {
     // *******************************
 
     static class ComponentPropertiesBinder extends MainListenerSupport {
+
         @Override
         public void configure(CamelContext context) {
-            final PropertiesComponent component = context.getComponent("properties", PropertiesComponent.class);
-            final Properties properties = component.getInitialProperties();
-
-            if (properties == null) {
-                throw new IllegalStateException("PropertiesComponent has no properties");
-            }
-
             // Configure the camel context using properties in the form:
             //
             //     camel.context.${name} = ${value}
             //
-            RuntimeSupport.bindProperties(properties, context, "camel.context.");
+            RuntimeSupport.bindProperties(context, context, "camel.context.");
+
+            // Programmatically apply the camel context.
+            //
+            // This is useful to configure services such as the ClusterService,
+            // RouteController, etc
+            //
+            RuntimeSupport.configureContext(context);
 
             context.addLifecycleStrategy(new LifecycleStrategySupport() {
                 @SuppressWarnings("unchecked")
@@ -90,7 +89,7 @@ public class Application {
                     //
                     //     camel.component.${scheme}.${name} = ${value}
                     //
-                    RuntimeSupport.bindProperties(properties, component, "camel.component." + name + ".");
+                    RuntimeSupport.bindProperties(context, component, "camel.component." + name + ".");
                 }
             });
         }
diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RoutesLoaders.java b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RoutesLoaders.java
index 5f67078..5702931 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RoutesLoaders.java
+++ b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RoutesLoaders.java
@@ -32,6 +32,11 @@ import javax.xml.bind.UnmarshalException;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.k.Constants;
+import org.apache.camel.k.Language;
+import org.apache.camel.k.RoutesLoader;
+import org.apache.camel.k.RuntimeRegistry;
+import org.apache.camel.k.Source;
 import org.apache.camel.k.jvm.dsl.Components;
 import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.model.rest.RestConfigurationDefinition;
diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Runtime.java b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Runtime.java
index 1e05e70..287ba69 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Runtime.java
+++ b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Runtime.java
@@ -20,13 +20,15 @@ import java.util.Map;
 import java.util.Properties;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
-
 import org.apache.camel.CamelContext;
 import org.apache.camel.ProducerTemplate;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.properties.PropertiesComponent;
 import org.apache.camel.impl.CompositeRegistry;
 import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.k.RoutesLoader;
+import org.apache.camel.k.RuntimeRegistry;
+import org.apache.camel.k.Source;
 import org.apache.camel.main.MainSupport;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeSupport.java b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeSupport.java
index 936e4d1..d6a005c 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeSupport.java
+++ b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeSupport.java
@@ -28,6 +28,12 @@ import java.nio.file.attribute.BasicFileAttributes;
 import java.util.Objects;
 import java.util.Properties;
 
+import org.apache.camel.CamelContext;
+import org.apache.camel.NoFactoryAvailableException;
+import org.apache.camel.component.properties.PropertiesComponent;
+import org.apache.camel.k.Constants;
+import org.apache.camel.k.RuntimeTrait;
+import org.apache.camel.spi.FactoryFinder;
 import org.apache.camel.util.IntrospectionSupport;
 import org.apache.camel.util.ObjectHelper;
 import org.apache.commons.io.FilenameUtils;
@@ -102,6 +108,29 @@ public final class RuntimeSupport {
         return properties;
     }
 
+    public static void configureContext(CamelContext context) {
+        try {
+            FactoryFinder finder = context.getFactoryFinder(Constants.RUNTIME_TRAIT_RESOURCE_PATH);
+            String traitIDs = System.getenv().getOrDefault(Constants.ENV_CAMEL_K_TRAITS, "");
+
+            for (String traitId: traitIDs.split(",", -1)) {
+                RuntimeTrait trait = (RuntimeTrait)finder.newInstance(traitId);
+
+                bindProperties(context, trait, "trait." + traitId);
+
+                trait.apply(context);
+            }
+        } catch (NoFactoryAvailableException e) {
+            // ignored
+        }
+
+        context.getRegistry().findByType(RuntimeTrait.class).forEach(
+            customizer -> {
+                customizer.apply(context);
+            }
+        );
+    }
+
     public static void configureLogging() {
         final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
         final Properties properties = loadProperties();
@@ -123,6 +152,17 @@ public final class RuntimeSupport {
         );
     }
 
+    public static void bindProperties(CamelContext context, Object target, String prefix) {
+        final PropertiesComponent component = context.getComponent("properties", PropertiesComponent.class);
+        final Properties properties = component.getInitialProperties();
+
+        if (properties == null) {
+            throw new IllegalStateException("PropertiesComponent has no properties");
+        }
+
+        bindProperties(properties, target, prefix);
+    }
+
     public static void bindProperties(Properties properties, Object target, String prefix) {
         properties.entrySet().stream()
             .filter(entry -> entry.getKey() instanceof String)
diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/SimpleRuntimeRegistry.java b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/SimpleRuntimeRegistry.java
index 1035b9c..c62175f 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/SimpleRuntimeRegistry.java
+++ b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/SimpleRuntimeRegistry.java
@@ -24,6 +24,7 @@ import java.util.concurrent.ConcurrentMap;
 import java.util.stream.Collectors;
 
 import org.apache.camel.NoSuchBeanException;
+import org.apache.camel.k.RuntimeRegistry;
 
 public class SimpleRuntimeRegistry implements RuntimeRegistry {
     private final ConcurrentMap<String, Object> registry;
diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/URIResolver.java b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/URIResolver.java
index c7ec4fe..30bee2e 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/URIResolver.java
+++ b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/URIResolver.java
@@ -24,6 +24,8 @@ import java.util.Base64;
 import java.util.zip.GZIPInputStream;
 
 import org.apache.camel.CamelContext;
+import org.apache.camel.k.Constants;
+import org.apache.camel.k.Source;
 import org.apache.camel.util.ResourceHelper;
 import org.apache.camel.util.StringHelper;
 
diff --git a/runtime/jvm/src/main/resources/META-INF/services/org.apache.camel.k.jvm.RoutesLoader b/runtime/jvm/src/main/resources/META-INF/services/org.apache.camel.k.RoutesLoader
similarity index 100%
rename from runtime/jvm/src/main/resources/META-INF/services/org.apache.camel.k.jvm.RoutesLoader
rename to runtime/jvm/src/main/resources/META-INF/services/org.apache.camel.k.RoutesLoader
diff --git a/runtime/jvm/src/test/java/org/apache/camel/k/jvm/PropertiesTest.java b/runtime/jvm/src/test/java/org/apache/camel/k/jvm/PropertiesTest.java
index 6ae8324..43e0d9c 100644
--- a/runtime/jvm/src/test/java/org/apache/camel/k/jvm/PropertiesTest.java
+++ b/runtime/jvm/src/test/java/org/apache/camel/k/jvm/PropertiesTest.java
@@ -19,12 +19,11 @@ package org.apache.camel.k.jvm;
 import java.util.Properties;
 import java.util.concurrent.ThreadLocalRandom;
 
-import org.apache.camel.CamelContext;
 import org.apache.camel.component.seda.SedaComponent;
-import org.apache.camel.main.MainListenerSupport;
-import org.apache.camel.main.MainSupport;
+import org.apache.camel.k.RuntimeTrait;
 import org.junit.jupiter.api.Test;
 
+import static org.apache.camel.k.jvm.RuntimeTestSupport.afterStart;
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class PropertiesTest {
@@ -37,23 +36,13 @@ public class PropertiesTest {
         runtime.setProperties(properties);
         runtime.setDuration(5);
         runtime.addMainListener(new Application.ComponentPropertiesBinder());
-        runtime.addMainListener(new MainListenerSupport() {
-            @Override
-            public void afterStart(MainSupport main) {
-                try {
-                    CamelContext context = main.getCamelContexts().get(0);
-
-                    assertThat(context.resolvePropertyPlaceholders("{{root.key}}")).isEqualTo("root.value");
-                    assertThat(context.resolvePropertyPlaceholders("{{001.key}}")).isEqualTo("001.value");
-                    assertThat(context.resolvePropertyPlaceholders("{{002.key}}")).isEqualTo("002.value");
-                    assertThat(context.resolvePropertyPlaceholders("{{a.key}}")).isEqualTo("a.002");
-
-                    main.stop();
-                } catch (Exception e) {
-                    throw new RuntimeException(e);
-                }
-            }
-        });
+        runtime.addMainListener(afterStart((main, context) -> {
+            assertThat(context.resolvePropertyPlaceholders("{{root.key}}")).isEqualTo("root.value");
+            assertThat(context.resolvePropertyPlaceholders("{{001.key}}")).isEqualTo("001.value");
+            assertThat(context.resolvePropertyPlaceholders("{{002.key}}")).isEqualTo("002.value");
+            assertThat(context.resolvePropertyPlaceholders("{{a.key}}")).isEqualTo("a.002");
+            main.stop();
+        }));
 
         runtime.run();
     }
@@ -67,21 +56,12 @@ public class PropertiesTest {
             runtime.setProperties(System.getProperties());
             runtime.setDuration(5);
             runtime.addMainListener(new Application.ComponentPropertiesBinder());
-            runtime.addMainListener(new MainListenerSupport() {
-                @Override
-                public void afterStart(MainSupport main) {
-                    try {
-                        CamelContext context = main.getCamelContexts().get(0);
-                        String value = context.resolvePropertyPlaceholders("{{my.property}}");
-
-                        assertThat(value).isEqualTo("my.value");
-
-                        main.stop();
-                    } catch (Exception e) {
-                        throw new RuntimeException(e);
-                    }
-                }
-            });
+            runtime.addMainListener(afterStart((main, context) -> {
+                String value = context.resolvePropertyPlaceholders("{{my.property}}");
+
+                assertThat(value).isEqualTo("my.value");
+                main.stop();
+            }));
 
             runtime.run();
         } finally {
@@ -103,21 +83,11 @@ public class PropertiesTest {
             runtime.setDuration(5);
             runtime.getRegistry().bind("my-seda", new SedaComponent());
             runtime.addMainListener(new Application.ComponentPropertiesBinder());
-            runtime.addMainListener(new MainListenerSupport() {
-                @Override
-                public void afterStart(MainSupport main) {
-                    try {
-                        CamelContext context = main.getCamelContexts().get(0);
-
-                        assertThat(context.getComponent("seda", true)).hasFieldOrPropertyWithValue("queueSize", queueSize1);
-                        assertThat(context.getComponent("my-seda", true)).hasFieldOrPropertyWithValue("queueSize", queueSize2);
-
-                        main.stop();
-                    } catch (Exception e) {
-                        throw new RuntimeException(e);
-                    }
-                }
-            });
+            runtime.addMainListener(afterStart((main, context) -> {
+                assertThat(context.getComponent("seda", true)).hasFieldOrPropertyWithValue("queueSize", queueSize1);
+                assertThat(context.getComponent("my-seda", true)).hasFieldOrPropertyWithValue("queueSize", queueSize2);
+                main.stop();
+            }));
 
             runtime.run();
         } finally {
@@ -135,23 +105,12 @@ public class PropertiesTest {
             Runtime runtime = new Runtime();
             runtime.setProperties(System.getProperties());
             runtime.setDuration(5);
-            runtime.getRegistry().bind("my-seda", new SedaComponent());
             runtime.addMainListener(new Application.ComponentPropertiesBinder());
-            runtime.addMainListener(new MainListenerSupport() {
-                @Override
-                public void afterStart(MainSupport main) {
-                    try {
-                        CamelContext context = main.getCamelContexts().get(0);
-
-                        assertThat(context.isMessageHistory()).isFalse();
-                        assertThat(context.isLoadTypeConverters()).isFalse();
-
-                        main.stop();
-                    } catch (Exception e) {
-                        throw new RuntimeException(e);
-                    }
-                }
-            });
+            runtime.addMainListener(afterStart((main, context) -> {
+                assertThat(context.isMessageHistory()).isFalse();
+                assertThat(context.isLoadTypeConverters()).isFalse();
+                main.stop();
+            }));
 
             runtime.run();
         } finally {
@@ -159,4 +118,23 @@ public class PropertiesTest {
             System.getProperties().remove("camel.context.loadTypeConverters");
         }
     }
+
+    @Test
+    public void testContextTrait() throws Exception {
+        Runtime runtime = new Runtime();
+        runtime.setProperties(System.getProperties());
+        runtime.setDuration(5);
+        runtime.getRegistry().bind("c1", (RuntimeTrait) context -> {
+            context.setMessageHistory(false);
+            context.setLoadTypeConverters(false);
+        });
+        runtime.addMainListener(new Application.ComponentPropertiesBinder());
+        runtime.addMainListener(afterStart((main, context) -> {
+            assertThat(context.isMessageHistory()).isFalse();
+            assertThat(context.isLoadTypeConverters()).isFalse();
+            main.stop();
+        }));
+
+        runtime.run();
+    }
 }
diff --git a/runtime/jvm/src/test/java/org/apache/camel/k/jvm/RoutesLoadersTest.java b/runtime/jvm/src/test/java/org/apache/camel/k/jvm/RoutesLoadersTest.java
index d12539c..cd32327 100644
--- a/runtime/jvm/src/test/java/org/apache/camel/k/jvm/RoutesLoadersTest.java
+++ b/runtime/jvm/src/test/java/org/apache/camel/k/jvm/RoutesLoadersTest.java
@@ -19,6 +19,8 @@ package org.apache.camel.k.jvm;
 import java.util.List;
 
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.k.RoutesLoader;
+import org.apache.camel.k.Source;
 import org.apache.camel.model.ProcessDefinition;
 import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.model.SetBodyDefinition;
diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeRegistry.java b/runtime/jvm/src/test/java/org/apache/camel/k/jvm/RuntimeTestSupport.java
similarity index 52%
rename from runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeRegistry.java
rename to runtime/jvm/src/test/java/org/apache/camel/k/jvm/RuntimeTestSupport.java
index 7e13a28..d72dddd 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeRegistry.java
+++ b/runtime/jvm/src/test/java/org/apache/camel/k/jvm/RuntimeTestSupport.java
@@ -16,32 +16,26 @@
  */
 package org.apache.camel.k.jvm;
 
-import java.util.Map;
+import org.apache.camel.CamelContext;
+import org.apache.camel.main.MainListener;
+import org.apache.camel.main.MainListenerSupport;
+import org.apache.camel.main.MainSupport;
+import org.apache.camel.util.function.ThrowingBiConsumer;
 
-import org.apache.camel.spi.Registry;
-
-public interface RuntimeRegistry extends Registry {
-
-    /**
-     *
-     */
-    void bind(String name, Object bean);
-
-    @SuppressWarnings("deprecation")
-    @Override
-    default public Object lookup(String name) {
-        return lookupByName(name);
-    }
-
-    @SuppressWarnings("deprecation")
-    @Override
-    default public <T> T lookup(String name, Class<T> type) {
-        return lookupByNameAndType(name, type);
+public final class RuntimeTestSupport {
+    private RuntimeTestSupport() {
     }
 
-    @SuppressWarnings("deprecation")
-    @Override
-    default public <T> Map<String, T> lookupByType(Class<T> type) {
-        return findByTypeWithName(type);
+    public static MainListener afterStart(ThrowingBiConsumer<MainSupport, CamelContext, Exception> consumer) {
+        return new MainListenerSupport() {
+            @Override
+            public void afterStart(MainSupport main) {
+                try {
+                    consumer.accept(main, main.getCamelContexts().get(0));
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        };
     }
 }
diff --git a/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/KotlinRoutesLoader.kt b/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/KotlinRoutesLoader.kt
index fba85d6..7902539 100644
--- a/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/KotlinRoutesLoader.kt
+++ b/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/KotlinRoutesLoader.kt
@@ -17,6 +17,10 @@
 package org.apache.camel.k.kotlin
 
 import org.apache.camel.builder.RouteBuilder
+import org.apache.camel.k.Language
+import org.apache.camel.k.RoutesLoader
+import org.apache.camel.k.RuntimeRegistry
+import org.apache.camel.k.Source
 import org.apache.camel.k.jvm.*
 import org.apache.camel.k.kotlin.dsl.IntegrationConfiguration
 import org.slf4j.Logger
diff --git a/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/ContextConfiguration.kt b/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/ContextConfiguration.kt
index 618d1c7..9dbf77f 100644
--- a/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/ContextConfiguration.kt
+++ b/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/ContextConfiguration.kt
@@ -17,7 +17,7 @@
 package org.apache.camel.k.kotlin.dsl
 
 import org.apache.camel.CamelContext
-import org.apache.camel.k.jvm.RuntimeRegistry
+import org.apache.camel.k.RuntimeRegistry
 
 class ContextConfiguration (val registry: RuntimeRegistry, val context: CamelContext) {
 
diff --git a/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/IntegrationConfiguration.kt b/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/IntegrationConfiguration.kt
index 52d20f4..926ad3a 100644
--- a/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/IntegrationConfiguration.kt
+++ b/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/IntegrationConfiguration.kt
@@ -20,7 +20,7 @@ import org.apache.camel.Exchange
 import org.apache.camel.Predicate
 import org.apache.camel.Processor
 import org.apache.camel.builder.RouteBuilder
-import org.apache.camel.k.jvm.RuntimeRegistry
+import org.apache.camel.k.RuntimeRegistry
 import org.apache.camel.model.RouteDefinition
 
 abstract class IntegrationConfiguration(
diff --git a/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/RegistryConfiguration.kt b/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/RegistryConfiguration.kt
index f15f71a..b3abc95 100644
--- a/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/RegistryConfiguration.kt
+++ b/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/RegistryConfiguration.kt
@@ -16,7 +16,7 @@
  */
 package org.apache.camel.k.kotlin.dsl
 
-import org.apache.camel.k.jvm.RuntimeRegistry
+import org.apache.camel.k.RuntimeRegistry
 
 class RegistryConfiguration(val registry: RuntimeRegistry) {
     fun bind(name: String, value: Any) {
diff --git a/runtime/kotlin/src/main/resources/META-INF/services/org.apache.camel.k.jvm.RoutesLoader b/runtime/kotlin/src/main/resources/META-INF/services/org.apache.camel.k.RoutesLoader
similarity index 100%
rename from runtime/kotlin/src/main/resources/META-INF/services/org.apache.camel.k.jvm.RoutesLoader
rename to runtime/kotlin/src/main/resources/META-INF/services/org.apache.camel.k.RoutesLoader
diff --git a/runtime/kotlin/src/test/kotlin/org/apache/camel/k/kotlin/LoaderTest.kt b/runtime/kotlin/src/test/kotlin/org/apache/camel/k/kotlin/LoaderTest.kt
index 0783b27..c9fb931 100644
--- a/runtime/kotlin/src/test/kotlin/org/apache/camel/k/kotlin/LoaderTest.kt
+++ b/runtime/kotlin/src/test/kotlin/org/apache/camel/k/kotlin/LoaderTest.kt
@@ -18,7 +18,7 @@ package org.apache.camel.k.kotlin
 
 import org.apache.camel.k.jvm.RoutesLoaders
 import org.apache.camel.k.jvm.SimpleRuntimeRegistry
-import org.apache.camel.k.jvm.Source
+import org.apache.camel.k.Source
 import org.apache.camel.model.ProcessDefinition
 import org.apache.camel.model.ToDefinition
 import org.assertj.core.api.Assertions.assertThat
diff --git a/runtime/pom.xml b/runtime/pom.xml
index 7e421b9..460135c 100644
--- a/runtime/pom.xml
+++ b/runtime/pom.xml
@@ -23,7 +23,7 @@
     <artifactId>camel-k-runtime-parent</artifactId>
     <version>0.1.1-SNAPSHOT</version>
     <packaging>pom</packaging>
-    
+
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <maven.compiler.source>1.8</maven.compiler.source>
@@ -92,8 +92,9 @@
             </plugins>
         </pluginManagement>
     </build>
-    
+
     <modules>
+        <module>core</module>
         <module>jvm</module>
         <module>groovy</module>
         <module>kotlin</module>
diff --git a/runtime/spring-boot/src/main/java/org/apache/camel/k/spring/boot/Application.java b/runtime/spring-boot/src/main/java/org/apache/camel/k/spring/boot/Application.java
index 0fe24ff..eaf7c2b 100644
--- a/runtime/spring-boot/src/main/java/org/apache/camel/k/spring/boot/Application.java
+++ b/runtime/spring-boot/src/main/java/org/apache/camel/k/spring/boot/Application.java
@@ -22,12 +22,12 @@ import java.util.Set;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.k.jvm.Constants;
-import org.apache.camel.k.jvm.RoutesLoader;
+import org.apache.camel.k.RuntimeRegistry;
+import org.apache.camel.k.Constants;
+import org.apache.camel.k.RoutesLoader;
 import org.apache.camel.k.jvm.RoutesLoaders;
-import org.apache.camel.k.jvm.RuntimeRegistry;
 import org.apache.camel.k.jvm.RuntimeSupport;
-import org.apache.camel.k.jvm.Source;
+import org.apache.camel.k.Source;
 import org.apache.camel.spi.Registry;
 import org.apache.camel.spring.boot.CamelContextConfiguration;
 import org.apache.camel.util.ObjectHelper;
@@ -85,6 +85,13 @@ public class Application {
                     throw new IllegalStateException("No valid routes found in " + Constants.ENV_CAMEL_K_ROUTES + " environment variable");
                 }
 
+                // Programmatically apply the camel context.
+                //
+                // This is useful to configure services such as the ClusterService,
+                // RouteController, etc
+                //
+                RuntimeSupport.configureContext( context);
+
                 try {
                     for (String route : routes.split(",")) {
                         final Source source = Source.create(route);