git.net

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GitHub] nicolaferraro closed pull request #293: Re-add missing commits


nicolaferraro closed pull request #293: Re-add missing commits
URL: https://github.com/apache/camel-k/pull/293
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/pkg/client/cmd/install.go b/pkg/client/cmd/install.go
index 5b86a8b3..0de2ed21 100644
--- a/pkg/client/cmd/install.go
+++ b/pkg/client/cmd/install.go
@@ -19,8 +19,10 @@ package cmd
 
 import (
 	"fmt"
+	"time"
 
 	"github.com/apache/camel-k/pkg/install"
+	"github.com/operator-framework/operator-sdk/pkg/k8sclient"
 	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
 	k8serrors "k8s.io/apimachinery/pkg/api/errors"
@@ -56,6 +58,9 @@ type installCmdOptions struct {
 }
 
 func (o *installCmdOptions) install(cmd *cobra.Command, args []string) error {
+	// Let's use a fast refresh period when running with the CLI
+	k8sclient.ResetCacheEvery(8 * time.Second)
+
 	err := install.SetupClusterwideResources()
 	if err != nil && k8serrors.IsForbidden(err) {
 		fmt.Println("Current user is not authorized to create cluster-wide objects like custom resource definitions or cluster roles: ", err)
diff --git a/pkg/client/cmd/root.go b/pkg/client/cmd/root.go
index c69f0630..203876a1 100644
--- a/pkg/client/cmd/root.go
+++ b/pkg/client/cmd/root.go
@@ -19,9 +19,6 @@ package cmd
 
 import (
 	"context"
-	"time"
-
-	"github.com/operator-framework/operator-sdk/pkg/k8sclient"
 
 	"github.com/apache/camel-k/pkg/util/kubernetes"
 	"github.com/pkg/errors"
@@ -63,9 +60,6 @@ func NewKamelCommand(ctx context.Context) (*cobra.Command, error) {
 				}
 			}
 
-			// Let's use a fast refresh period when running with the CLI
-			k8sclient.ResetCacheEvery(2 * time.Second)
-
 			// Initialize the Kubernetes client to allow using the operator-sdk
 			return kubernetes.InitKubeClient(options.KubeConfig)
 		},
diff --git a/pkg/install/operator.go b/pkg/install/operator.go
index 3af6a0e9..147bbb52 100644
--- a/pkg/install/operator.go
+++ b/pkg/install/operator.go
@@ -87,7 +87,7 @@ func installKnative(namespace string) error {
 
 // Platform installs the platform custom resource
 func Platform(namespace string, registry string, organization string, pushSecret string) error {
-	if err := waitForPlatformCRDAvailable(namespace, 15*time.Second); err != nil {
+	if err := waitForPlatformCRDAvailable(namespace, 25*time.Second); err != nil {
 		return err
 	}
 	isOpenshift, err := openshift.IsOpenShift()
diff --git a/pkg/trait/builder.go b/pkg/trait/builder.go
index fd11fa2f..0cb22fcb 100644
--- a/pkg/trait/builder.go
+++ b/pkg/trait/builder.go
@@ -18,12 +18,13 @@ limitations under the License.
 package trait
 
 import (
+	"regexp"
+
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 	"github.com/apache/camel-k/pkg/builder"
 	"github.com/apache/camel-k/pkg/builder/kaniko"
 	"github.com/apache/camel-k/pkg/builder/s2i"
 	"github.com/apache/camel-k/pkg/platform"
-	"regexp"
 )
 
 const (
@@ -103,5 +104,4 @@ func (t *builderTrait) ReplaceHost(ctx *builder.Context) error {
 func getImageWithOpenShiftHost(image string) string {
 	pattern := regexp.MustCompile(`^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+([:/].*)`)
 	return pattern.ReplaceAllString(image, openshiftDockerRegistryHost+"$1")
-	return image
 }
diff --git a/pkg/trait/builder_test.go b/pkg/trait/builder_test.go
index cb9147f0..bf863301 100644
--- a/pkg/trait/builder_test.go
+++ b/pkg/trait/builder_test.go
@@ -20,6 +20,8 @@ package trait
 import (
 	"testing"
 
+	"k8s.io/api/core/v1"
+
 	"github.com/apache/camel-k/pkg/builder"
 
 	"github.com/apache/camel-k/pkg/util/kubernetes"
@@ -136,7 +138,7 @@ func createBuilderTestEnv(cluster v1alpha1.IntegrationPlatformCluster, strategy
 				},
 			},
 		},
-		EnvVars:        make(map[string]string),
+		EnvVars:        make([]v1.EnvVar, 0),
 		ExecutedTraits: make([]Trait, 0),
 		Resources:      kubernetes.NewCollection(),
 	}
@@ -150,4 +152,4 @@ func TestIPReplacement(t *testing.T) {
 	assert.Equal(t, "10.0.2.3.4/camel-k", getImageWithOpenShiftHost("10.0.2.3.4/camel-k"))
 	assert.Equal(t, "gcr.io/camel-k/camel-k:latest", getImageWithOpenShiftHost("gcr.io/camel-k/camel-k:latest"))
 	assert.Equal(t, "docker.io/camel-k:latest", getImageWithOpenShiftHost("docker.io/camel-k:latest"))
-}
\ No newline at end of file
+}
diff --git a/pkg/trait/catalog.go b/pkg/trait/catalog.go
index 6ab0ae23..0fd56689 100644
--- a/pkg/trait/catalog.go
+++ b/pkg/trait/catalog.go
@@ -86,8 +86,8 @@ func (c *Catalog) traitsFor(environment *Environment) []Trait {
 			c.tDependencies,
 			c.tBuilder,
 			c.tSpringBoot,
-			c.tDeployment,
 			c.tEnvironment,
+			c.tDeployment,
 			c.tService,
 			c.tRoute,
 			c.tOwner,
@@ -98,8 +98,8 @@ func (c *Catalog) traitsFor(environment *Environment) []Trait {
 			c.tDependencies,
 			c.tBuilder,
 			c.tSpringBoot,
-			c.tDeployment,
 			c.tEnvironment,
+			c.tDeployment,
 			c.tService,
 			c.tIngress,
 			c.tOwner,
@@ -110,9 +110,9 @@ func (c *Catalog) traitsFor(environment *Environment) []Trait {
 			c.tDependencies,
 			c.tBuilder,
 			c.tSpringBoot,
+			c.tEnvironment,
 			c.tKnative,
 			c.tDeployment,
-			c.tEnvironment,
 			c.tIstio,
 			c.tOwner,
 		}
diff --git a/pkg/trait/debug.go b/pkg/trait/debug.go
index b78bcc6e..51f5161f 100644
--- a/pkg/trait/debug.go
+++ b/pkg/trait/debug.go
@@ -19,6 +19,7 @@ package trait
 
 import (
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+	"github.com/apache/camel-k/pkg/util/envvar"
 )
 
 type debugTrait struct {
@@ -43,7 +44,7 @@ func (t *debugTrait) Configure(e *Environment) (bool, error) {
 
 func (t *debugTrait) Apply(e *Environment) error {
 	// this is all that's needed as long as the base image is `fabric8/s2i-java` look into builder/builder.go
-	e.EnvVars["JAVA_DEBUG"] = True
+	envvar.SetVal(&e.EnvVars, "JAVA_DEBUG", True)
 
 	return nil
 }
diff --git a/pkg/trait/debug_test.go b/pkg/trait/debug_test.go
index 6c24d82d..8283c08e 100644
--- a/pkg/trait/debug_test.go
+++ b/pkg/trait/debug_test.go
@@ -20,6 +20,10 @@ package trait
 import (
 	"testing"
 
+	"github.com/apache/camel-k/pkg/util/envvar"
+
+	"k8s.io/api/core/v1"
+
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 	"github.com/stretchr/testify/assert"
 )
@@ -40,7 +44,8 @@ func TestDebugTraitApplicability(t *testing.T) {
 				},
 			},
 		},
-		EnvVars: make(map[string]string)}
+		EnvVars: make([]v1.EnvVar, 0),
+	}
 
 	trait := newDebugTrait()
 
@@ -56,7 +61,7 @@ func TestDebugTraitApplicability(t *testing.T) {
 }
 
 func TestApplyDebugTrait(t *testing.T) {
-	env := Environment{
+	environment := Environment{
 		Integration: &v1alpha1.Integration{
 			Status: v1alpha1.IntegrationStatus{
 				Phase: v1alpha1.IntegrationPhaseDeploying,
@@ -71,10 +76,12 @@ func TestApplyDebugTrait(t *testing.T) {
 				},
 			},
 		},
-		EnvVars: make(map[string]string)}
+		EnvVars: make([]v1.EnvVar, 0),
+	}
 
 	trait := newDebugTrait()
 
-	assert.Nil(t, trait.Apply(&env))
-	assert.Equal(t, True, env.EnvVars["JAVA_DEBUG"])
+	assert.Nil(t, trait.Apply(&environment))
+	assert.NotNil(t, envvar.Get(environment.EnvVars, "JAVA_DEBUG"))
+	assert.Equal(t, True, envvar.Get(environment.EnvVars, "JAVA_DEBUG").Value)
 }
diff --git a/pkg/trait/deployment.go b/pkg/trait/deployment.go
index 7e8d01fe..6b334852 100644
--- a/pkg/trait/deployment.go
+++ b/pkg/trait/deployment.go
@@ -23,6 +23,8 @@ import (
 	"strconv"
 	"strings"
 
+	"github.com/apache/camel-k/pkg/util/envvar"
+
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 	appsv1 "k8s.io/api/apps/v1"
 	corev1 "k8s.io/api/core/v1"
@@ -96,7 +98,11 @@ func (t *deploymentTrait) getConfigMapsFor(e *Environment) []runtime.Object {
 
 	// combine properties of integration with context, integration
 	// properties have the priority
-	properties := CombineConfigurationAsMap("property", e.Context, e.Integration)
+	properties := ""
+
+	VisitKeyValConfigurations("property", e.Context, e.Integration, func(key string, val string) {
+		properties += fmt.Sprintf("%s=%s\n", key, val)
+	})
 
 	maps = append(
 		maps,
@@ -113,7 +119,7 @@ func (t *deploymentTrait) getConfigMapsFor(e *Environment) []runtime.Object {
 				},
 			},
 			Data: map[string]string{
-				"properties": PropertiesString(properties),
+				"properties": properties,
 			},
 		},
 	)
@@ -194,28 +200,32 @@ func (t *deploymentTrait) getSources(e *Environment) []string {
 func (t *deploymentTrait) getDeploymentFor(e *Environment) *appsv1.Deployment {
 	sources := t.getSources(e)
 
+	environment := make([]corev1.EnvVar, 0)
+
 	// combine Environment of integration with context, integration
 	// Environment has the priority
-	environment := CombineConfigurationAsMap("env", e.Context, e.Integration)
+	VisitKeyValConfigurations("env", e.Context, e.Integration, func(key string, value string) {
+		envvar.SetVal(&environment, key, value)
+	})
 
 	// set env vars needed by the runtime
-	environment["JAVA_MAIN_CLASS"] = "org.apache.camel.k.jvm.Application"
+	envvar.SetVal(&environment, "JAVA_MAIN_CLASS", "org.apache.camel.k.jvm.Application")
 
 	// camel-k runtime
-	environment["CAMEL_K_ROUTES"] = strings.Join(sources, ",")
-	environment["CAMEL_K_CONF"] = "/etc/camel/conf/application.properties"
-	environment["CAMEL_K_CONF_D"] = "/etc/camel/conf.d"
+	envvar.SetVal(&environment, "CAMEL_K_ROUTES", strings.Join(sources, ","))
+	envvar.SetVal(&environment, "CAMEL_K_CONF", "/etc/camel/conf/application.properties")
+	envvar.SetVal(&environment, "CAMEL_K_CONF_D", "/etc/camel/conf.d")
 
 	// add a dummy env var to trigger deployment if everything but the code
 	// has been changed
-	environment["CAMEL_K_DIGEST"] = e.Integration.Status.Digest
+	envvar.SetVal(&environment, "CAMEL_K_DIGEST", e.Integration.Status.Digest)
 
 	// optimizations
-	environment["AB_JOLOKIA_OFF"] = True
+	envvar.SetVal(&environment, "AB_JOLOKIA_OFF", True)
 
 	// add env vars from traits
-	for k, v := range e.EnvVars {
-		environment[k] = v
+	for _, envVar := range e.EnvVars {
+		envvar.SetVar(&environment, envVar)
 	}
 
 	labels := map[string]string{
@@ -248,7 +258,7 @@ func (t *deploymentTrait) getDeploymentFor(e *Environment) *appsv1.Deployment {
 						{
 							Name:  e.Integration.Name,
 							Image: e.Integration.Status.Image,
-							Env:   EnvironmentAsEnvVarSlice(environment),
+							Env:   environment,
 						},
 					},
 				},
@@ -329,8 +339,7 @@ func (t *deploymentTrait) getDeploymentFor(e *Environment) *appsv1.Deployment {
 	// Volumes :: Additional ConfigMaps
 	//
 
-	cmList := CombineConfigurationAsSlice("configmap", e.Context, e.Integration)
-	for _, cmName := range cmList {
+	VisitConfigurations("configmap", e.Context, e.Integration, func(cmName string) {
 		cnt++
 
 		vols = append(vols, corev1.Volume{
@@ -348,14 +357,13 @@ func (t *deploymentTrait) getDeploymentFor(e *Environment) *appsv1.Deployment {
 			Name:      "integration-cm-" + cmName,
 			MountPath: fmt.Sprintf("/etc/camel/conf.d/%03d_%s", cnt, cmName),
 		})
-	}
+	})
 
 	//
 	// Volumes :: Additional Secrets
 	//
 
-	secretList := CombineConfigurationAsSlice("secret", e.Context, e.Integration)
-	for _, secretName := range secretList {
+	VisitConfigurations("secret", e.Context, e.Integration, func(secretName string) {
 		cnt++
 
 		vols = append(vols, corev1.Volume{
@@ -371,7 +379,7 @@ func (t *deploymentTrait) getDeploymentFor(e *Environment) *appsv1.Deployment {
 			Name:      "integration-secret-" + secretName,
 			MountPath: fmt.Sprintf("/etc/camel/conf.d/%03d_%s", cnt, secretName),
 		})
-	}
+	})
 
 	//
 	// Volumes
diff --git a/pkg/trait/environment.go b/pkg/trait/environment.go
index f97ee134..67fd522e 100644
--- a/pkg/trait/environment.go
+++ b/pkg/trait/environment.go
@@ -19,8 +19,8 @@ package trait
 
 import (
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
-	appsv1 "k8s.io/api/apps/v1"
-	"k8s.io/api/core/v1"
+	"github.com/apache/camel-k/pkg/util/envvar"
+	"github.com/apache/camel-k/version"
 )
 
 type environmentTrait struct {
@@ -29,8 +29,9 @@ type environmentTrait struct {
 }
 
 const (
-	envVarNamespace = "NAMESPACE"
-	envVarPodName   = "POD_NAME"
+	envVarNamespace     = "NAMESPACE"
+	envVarPodName       = "POD_NAME"
+	envVarCamelKVersion = "CAMEL_K_VERSION"
 )
 
 func newEnvironmentTrait() *environmentTrait {
@@ -51,28 +52,11 @@ func (t *environmentTrait) Configure(e *Environment) (bool, error) {
 }
 
 func (t *environmentTrait) Apply(e *Environment) error {
+	envvar.SetVal(&e.EnvVars, envVarCamelKVersion, version.Version)
+
 	if t.ContainerMeta {
-		e.Resources.VisitDeployment(func(deployment *appsv1.Deployment) {
-			for i := 0; i < len(deployment.Spec.Template.Spec.Containers); i++ {
-				c := &deployment.Spec.Template.Spec.Containers[i]
-				c.Env = append(c.Env, v1.EnvVar{
-					Name: envVarNamespace,
-					ValueFrom: &v1.EnvVarSource{
-						FieldRef: &v1.ObjectFieldSelector{
-							FieldPath: "metadata.namespace",
-						},
-					},
-				})
-				c.Env = append(c.Env, v1.EnvVar{
-					Name: envVarPodName,
-					ValueFrom: &v1.EnvVarSource{
-						FieldRef: &v1.ObjectFieldSelector{
-							FieldPath: "metadata.name",
-						},
-					},
-				})
-			}
-		})
+		envvar.SetValFrom(&e.EnvVars, envVarNamespace, "metadata.namespace")
+		envvar.SetValFrom(&e.EnvVars, envVarPodName, "metadata.name")
 	}
 
 	return nil
diff --git a/pkg/trait/environment_test.go b/pkg/trait/environment_test.go
index 12fdd316..430bef2a 100644
--- a/pkg/trait/environment_test.go
+++ b/pkg/trait/environment_test.go
@@ -20,6 +20,8 @@ package trait
 import (
 	"testing"
 
+	corev1 "k8s.io/api/core/v1"
+
 	"github.com/apache/camel-k/pkg/util/kubernetes"
 
 	"k8s.io/api/apps/v1"
@@ -44,7 +46,7 @@ func TestDefaultEnvironment(t *testing.T) {
 				Cluster: v1alpha1.IntegrationPlatformClusterOpenShift,
 			},
 		},
-		EnvVars:        make(map[string]string),
+		EnvVars:        make([]corev1.EnvVar, 0),
 		ExecutedTraits: make([]Trait, 0),
 		Resources:      kubernetes.NewCollection(),
 	}
@@ -55,6 +57,7 @@ func TestDefaultEnvironment(t *testing.T) {
 
 	ns := false
 	name := false
+	ck := false
 
 	env.Resources.VisitDeployment(func(deployment *v1.Deployment) {
 		for _, e := range deployment.Spec.Template.Spec.Containers[0].Env {
@@ -64,11 +67,15 @@ func TestDefaultEnvironment(t *testing.T) {
 			if e.Name == envVarPodName {
 				name = true
 			}
+			if e.Name == envVarCamelKVersion {
+				ck = true
+			}
 		}
 	})
 
 	assert.True(t, ns)
 	assert.True(t, name)
+	assert.True(t, ck)
 }
 
 func TestEnabledContainerMetaDataEnvVars(t *testing.T) {
@@ -94,7 +101,7 @@ func TestEnabledContainerMetaDataEnvVars(t *testing.T) {
 				Cluster: v1alpha1.IntegrationPlatformClusterOpenShift,
 			},
 		},
-		EnvVars:        make(map[string]string),
+		EnvVars:        make([]corev1.EnvVar, 0),
 		ExecutedTraits: make([]Trait, 0),
 		Resources:      kubernetes.NewCollection(),
 	}
@@ -105,6 +112,7 @@ func TestEnabledContainerMetaDataEnvVars(t *testing.T) {
 
 	ns := false
 	name := false
+	ck := false
 
 	env.Resources.VisitDeployment(func(deployment *v1.Deployment) {
 		for _, e := range deployment.Spec.Template.Spec.Containers[0].Env {
@@ -114,11 +122,15 @@ func TestEnabledContainerMetaDataEnvVars(t *testing.T) {
 			if e.Name == envVarPodName {
 				name = true
 			}
+			if e.Name == envVarCamelKVersion {
+				ck = true
+			}
 		}
 	})
 
 	assert.True(t, ns)
 	assert.True(t, name)
+	assert.True(t, ck)
 }
 
 func TestDisabledContainerMetaDataEnvVars(t *testing.T) {
@@ -144,7 +156,7 @@ func TestDisabledContainerMetaDataEnvVars(t *testing.T) {
 				Cluster: v1alpha1.IntegrationPlatformClusterOpenShift,
 			},
 		},
-		EnvVars:        make(map[string]string),
+		EnvVars:        make([]corev1.EnvVar, 0),
 		ExecutedTraits: make([]Trait, 0),
 		Resources:      kubernetes.NewCollection(),
 	}
@@ -155,6 +167,7 @@ func TestDisabledContainerMetaDataEnvVars(t *testing.T) {
 
 	ns := false
 	name := false
+	ck := false
 
 	env.Resources.VisitDeployment(func(deployment *v1.Deployment) {
 		for _, e := range deployment.Spec.Template.Spec.Containers[0].Env {
@@ -164,9 +177,13 @@ func TestDisabledContainerMetaDataEnvVars(t *testing.T) {
 			if e.Name == envVarPodName {
 				name = true
 			}
+			if e.Name == envVarCamelKVersion {
+				ck = true
+			}
 		}
 	})
 
 	assert.False(t, ns)
 	assert.False(t, name)
+	assert.True(t, ck)
 }
diff --git a/pkg/trait/knative.go b/pkg/trait/knative.go
index 93e16a0a..b31ef07c 100644
--- a/pkg/trait/knative.go
+++ b/pkg/trait/knative.go
@@ -21,6 +21,8 @@ import (
 	"encoding/json"
 	"fmt"
 
+	"github.com/apache/camel-k/pkg/util/envvar"
+
 	"strconv"
 	"strings"
 
@@ -110,23 +112,33 @@ func (t *knativeTrait) prepareEnvVars(e *Environment) error {
 	if err != nil {
 		return err
 	}
-	e.EnvVars["CAMEL_KNATIVE_CONFIGURATION"] = conf
+
+	envvar.SetVal(&e.EnvVars, "CAMEL_KNATIVE_CONFIGURATION", conf)
+
 	return nil
 }
 
 func (t *knativeTrait) getServiceFor(e *Environment) *serving.Service {
 	// combine properties of integration with context, integration
 	// properties have the priority
-	properties := CombineConfigurationAsMap("property", e.Context, e.Integration)
+	properties := ""
+
+	VisitKeyValConfigurations("property", e.Context, e.Integration, func(key string, val string) {
+		properties += fmt.Sprintf("%s=%s\n", key, val)
+	})
+
+	environment := make([]corev1.EnvVar, 0)
 
 	// combine Environment of integration with context, integration
 	// Environment has the priority
-	environment := CombineConfigurationAsMap("env", e.Context, e.Integration)
+	VisitKeyValConfigurations("env", e.Context, e.Integration, func(key string, value string) {
+		envvar.SetVal(&environment, key, value)
+	})
 
 	sources := make([]string, 0, len(e.Integration.Spec.Sources))
 	for i, s := range e.Integration.Spec.Sources {
-		envName := fmt.Sprintf("KAMEL_K_ROUTE_%03d", i)
-		environment[envName] = s.Content
+		envName := fmt.Sprintf("CAMEL_K_ROUTE_%03d", i)
+		envvar.SetVal(&environment, envName, s.Content)
 
 		params := make([]string, 0)
 		if s.Language != "" {
@@ -145,23 +157,23 @@ func (t *knativeTrait) getServiceFor(e *Environment) *serving.Service {
 	}
 
 	// set env vars needed by the runtime
-	environment["JAVA_MAIN_CLASS"] = "org.apache.camel.k.jvm.Application"
+	envvar.SetVal(&environment, "JAVA_MAIN_CLASS", "org.apache.camel.k.jvm.Application")
 
 	// camel-k runtime
-	environment["CAMEL_K_ROUTES"] = strings.Join(sources, ",")
-	environment["CAMEL_K_CONF"] = "env:CAMEL_K_PROPERTIES"
-	environment["CAMEL_K_PROPERTIES"] = PropertiesString(properties)
+	envvar.SetVal(&environment, "CAMEL_K_ROUTES", strings.Join(sources, ","))
+	envvar.SetVal(&environment, "CAMEL_K_CONF", "env:CAMEL_K_PROPERTIES")
+	envvar.SetVal(&environment, "CAMEL_K_PROPERTIES", properties)
 
 	// add a dummy env var to trigger deployment if everything but the code
 	// has been changed
-	environment["CAMEL_K_DIGEST"] = e.Integration.Status.Digest
+	envvar.SetVal(&environment, "CAMEL_K_DIGEST", e.Integration.Status.Digest)
 
 	// optimizations
-	environment["AB_JOLOKIA_OFF"] = True
+	envvar.SetVal(&environment, "AB_JOLOKIA_OFF", True)
 
 	// add env vars from traits
-	for k, v := range e.EnvVars {
-		environment[k] = v
+	for _, envVar := range e.EnvVars {
+		envvar.SetVar(&environment, envVar)
 	}
 
 	labels := map[string]string{
@@ -200,7 +212,7 @@ func (t *knativeTrait) getServiceFor(e *Environment) *serving.Service {
 						Spec: serving.RevisionSpec{
 							Container: corev1.Container{
 								Image: e.Integration.Status.Image,
-								Env:   EnvironmentAsEnvVarSlice(environment),
+								Env:   environment,
 							},
 						},
 					},
diff --git a/pkg/trait/knative_test.go b/pkg/trait/knative_test.go
index f701c88f..4fd5c40d 100644
--- a/pkg/trait/knative_test.go
+++ b/pkg/trait/knative_test.go
@@ -20,6 +20,10 @@ package trait
 import (
 	"testing"
 
+	"github.com/apache/camel-k/pkg/util/envvar"
+
+	"k8s.io/api/core/v1"
+
 	"github.com/apache/camel-k/pkg/util"
 
 	"github.com/apache/camel-k/pkg/util/kubernetes"
@@ -33,7 +37,7 @@ import (
 func TestKnativeTraitWithCompressedSources(t *testing.T) {
 	content := "H4sIAAAAAAAA/+JKK8rP1VAvycxNLbIqyUzOVtfkUlBQUNAryddQz8lPt8rMS8tX1+QCAAAA//8BAAD//3wZ4pUoAAAA"
 
-	env := Environment{
+	environment := Environment{
 		Integration: &v1alpha1.Integration{
 			ObjectMeta: metav1.ObjectMeta{
 				Name:      "test",
@@ -63,33 +67,33 @@ func TestKnativeTraitWithCompressedSources(t *testing.T) {
 				},
 			},
 		},
-		EnvVars:        make(map[string]string),
+		EnvVars:        make([]v1.EnvVar, 0),
 		ExecutedTraits: make([]Trait, 0),
 		Resources:      kubernetes.NewCollection(),
 	}
 
-	err := NewCatalog().apply(&env)
+	err := NewCatalog().apply(&environment)
 
 	assert.Nil(t, err)
-	assert.NotEmpty(t, env.ExecutedTraits)
-	assert.NotNil(t, env.GetTrait(ID("knative")))
-	assert.NotNil(t, env.EnvVars["KAMEL_KNATIVE_CONFIGURATION"])
+	assert.NotEmpty(t, environment.ExecutedTraits)
+	assert.NotNil(t, environment.GetTrait(ID("knative")))
+	assert.NotNil(t, envvar.Get(environment.EnvVars, "CAMEL_KNATIVE_CONFIGURATION"))
 
 	services := 0
-	env.Resources.VisitKnativeService(func(service *serving.Service) {
+	environment.Resources.VisitKnativeService(func(service *serving.Service) {
 		services++
 
 		vars := service.Spec.RunLatest.Configuration.RevisionTemplate.Spec.Container.Env
 
 		routes := util.LookupEnvVar(vars, "CAMEL_K_ROUTES")
 		assert.NotNil(t, routes)
-		assert.Equal(t, "env:KAMEL_K_ROUTE_000?language=js&compression=true", routes.Value)
+		assert.Equal(t, "env:CAMEL_K_ROUTE_000?language=js&compression=true", routes.Value)
 
-		route := util.LookupEnvVar(vars, "KAMEL_K_ROUTE_000")
+		route := util.LookupEnvVar(vars, "CAMEL_K_ROUTE_000")
 		assert.NotNil(t, route)
 		assert.Equal(t, content, route.Value)
 	})
 
 	assert.True(t, services > 0)
-	assert.True(t, env.Resources.Size() > 0)
+	assert.True(t, environment.Resources.Size() > 0)
 }
diff --git a/pkg/trait/springboot.go b/pkg/trait/springboot.go
index 116c6844..f8d87b91 100644
--- a/pkg/trait/springboot.go
+++ b/pkg/trait/springboot.go
@@ -21,6 +21,8 @@ import (
 	"sort"
 	"strings"
 
+	"github.com/apache/camel-k/pkg/util/envvar"
+
 	"github.com/operator-framework/operator-sdk/pkg/sdk"
 	"github.com/pkg/errors"
 
@@ -75,8 +77,8 @@ func (t *springBootTrait) Apply(e *Environment) error {
 
 	if e.Integration != nil && e.Integration.Status.Phase == v1alpha1.IntegrationPhaseDeploying {
 		// Override env vars
-		e.EnvVars["JAVA_MAIN_CLASS"] = "org.springframework.boot.loader.PropertiesLauncher"
-		e.EnvVars["LOADER_PATH"] = "/deployments/dependencies/"
+		envvar.SetVal(&e.EnvVars, "JAVA_MAIN_CLASS", "org.springframework.boot.loader.PropertiesLauncher")
+		envvar.SetVal(&e.EnvVars, "LOADER_PATH", "/deployments/dependencies/")
 
 		if e.Integration.Spec.Context != "" {
 			name := e.Integration.Spec.Context
@@ -96,8 +98,8 @@ func (t *springBootTrait) Apply(e *Environment) error {
 				deps = append(deps, artifact.Target)
 			}
 
-			e.EnvVars["LOADER_HOME"] = "/deployments"
-			e.EnvVars["LOADER_PATH"] = strings.Join(deps, ",")
+			envvar.SetVal(&e.EnvVars, "LOADER_HOME", "/deployments")
+			envvar.SetVal(&e.EnvVars, "LOADER_PATH", strings.Join(deps, ","))
 		}
 	}
 
diff --git a/pkg/trait/trait.go b/pkg/trait/trait.go
index 6684319f..fdc54285 100644
--- a/pkg/trait/trait.go
+++ b/pkg/trait/trait.go
@@ -22,6 +22,7 @@ import (
 	"github.com/apache/camel-k/pkg/platform"
 	"github.com/apache/camel-k/pkg/util/kubernetes"
 	"github.com/pkg/errors"
+	"k8s.io/api/core/v1"
 )
 
 // True --
@@ -75,6 +76,6 @@ func newEnvironment(integration *v1alpha1.Integration, ctx *v1alpha1.Integration
 		Integration:    integration,
 		ExecutedTraits: make([]Trait, 0),
 		Resources:      kubernetes.NewCollection(),
-		EnvVars:        make(map[string]string),
+		EnvVars:        make([]v1.EnvVar, 0),
 	}, nil
 }
diff --git a/pkg/trait/trait_test.go b/pkg/trait/trait_test.go
index b48bd374..6c9b89af 100644
--- a/pkg/trait/trait_test.go
+++ b/pkg/trait/trait_test.go
@@ -192,7 +192,7 @@ func createTestEnv(cluster v1alpha1.IntegrationPlatformCluster, script string) *
 				Cluster: cluster,
 			},
 		},
-		EnvVars:        make(map[string]string),
+		EnvVars:        make([]corev1.EnvVar, 0),
 		ExecutedTraits: make([]Trait, 0),
 		Resources:      kubernetes.NewCollection(),
 	}
diff --git a/pkg/trait/types.go b/pkg/trait/types.go
index a81f2f40..bbba5acc 100644
--- a/pkg/trait/types.go
+++ b/pkg/trait/types.go
@@ -22,6 +22,7 @@ import (
 	"github.com/apache/camel-k/pkg/builder"
 	"github.com/apache/camel-k/pkg/platform"
 	"github.com/apache/camel-k/pkg/util/kubernetes"
+	"k8s.io/api/core/v1"
 )
 
 // Identifiable represent an identifiable type
@@ -67,7 +68,7 @@ type Environment struct {
 	Steps          []builder.Step
 	BuildDir       string
 	ExecutedTraits []Trait
-	EnvVars        map[string]string
+	EnvVars        []v1.EnvVar
 }
 
 // GetTrait --
diff --git a/pkg/trait/util.go b/pkg/trait/util.go
index afb8f239..ad6e1d32 100644
--- a/pkg/trait/util.go
+++ b/pkg/trait/util.go
@@ -18,12 +18,10 @@ limitations under the License.
 package trait
 
 import (
-	"fmt"
 	"strings"
 
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 	"github.com/operator-framework/operator-sdk/pkg/sdk"
-	"k8s.io/api/core/v1"
 )
 
 // GetIntegrationContext retrieves the context set on the integration
@@ -38,39 +36,19 @@ func GetIntegrationContext(integration *v1alpha1.Integration) (*v1alpha1.Integra
 	return &ctx, err
 }
 
-// PropertiesString --
-func PropertiesString(m map[string]string) string {
-	properties := ""
-	for k, v := range m {
-		properties += fmt.Sprintf("%s=%s\n", k, v)
-	}
-
-	return properties
-}
-
-// EnvironmentAsEnvVarSlice --
-func EnvironmentAsEnvVarSlice(m map[string]string) []v1.EnvVar {
-	env := make([]v1.EnvVar, 0, len(m))
-
-	for k, v := range m {
-		env = append(env, v1.EnvVar{Name: k, Value: v})
-	}
-
-	return env
-}
+// VisitConfigurations --
+func VisitConfigurations(
+	configurationType string,
+	context *v1alpha1.IntegrationContext,
+	integration *v1alpha1.Integration,
+	consumer func(string)) {
 
-// CombineConfigurationAsMap --
-func CombineConfigurationAsMap(configurationType string, context *v1alpha1.IntegrationContext, integration *v1alpha1.Integration) map[string]string {
-	result := make(map[string]string)
 	if context != nil {
 		// Add context properties first so integrations can
 		// override it
 		for _, c := range context.Spec.Configuration {
 			if c.Type == configurationType {
-				pair := strings.Split(c.Value, "=")
-				if len(pair) == 2 {
-					result[pair[0]] = pair[1]
-				}
+				consumer(c.Value)
 			}
 		}
 	}
@@ -78,40 +56,40 @@ func CombineConfigurationAsMap(configurationType string, context *v1alpha1.Integ
 	if integration != nil {
 		for _, c := range integration.Spec.Configuration {
 			if c.Type == configurationType {
-				pair := strings.Split(c.Value, "=")
-				if len(pair) == 2 {
-					result[pair[0]] = pair[1]
-				}
+				consumer(c.Value)
 			}
 		}
 	}
-
-	return result
 }
 
-// CombineConfigurationAsSlice --
-func CombineConfigurationAsSlice(configurationType string, context *v1alpha1.IntegrationContext, integration *v1alpha1.Integration) []string {
-	result := make(map[string]bool)
+// VisitKeyValConfigurations --
+func VisitKeyValConfigurations(
+	configurationType string,
+	context *v1alpha1.IntegrationContext,
+	integration *v1alpha1.Integration,
+	consumer func(string, string)) {
+
 	if context != nil {
 		// Add context properties first so integrations can
 		// override it
 		for _, c := range context.Spec.Configuration {
 			if c.Type == configurationType {
-				result[c.Value] = true
+				pair := strings.Split(c.Value, "=")
+				if len(pair) == 2 {
+					consumer(pair[0], pair[1])
+				}
 			}
 		}
 	}
 
-	for _, c := range integration.Spec.Configuration {
-		if c.Type == configurationType {
-			result[c.Value] = true
+	if integration != nil {
+		for _, c := range integration.Spec.Configuration {
+			if c.Type == configurationType {
+				pair := strings.Split(c.Value, "=")
+				if len(pair) == 2 {
+					consumer(pair[0], pair[1])
+				}
+			}
 		}
 	}
-
-	keys := make([]string, 0, len(result))
-	for k := range result {
-		keys = append(keys, k)
-	}
-
-	return keys
 }
diff --git a/pkg/util/envvar/envvar.go b/pkg/util/envvar/envvar.go
new file mode 100644
index 00000000..68f6ba7e
--- /dev/null
+++ b/pkg/util/envvar/envvar.go
@@ -0,0 +1,87 @@
+/*
+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 envvar
+
+import "k8s.io/api/core/v1"
+
+// Get --
+func Get(vars []v1.EnvVar, name string) *v1.EnvVar {
+	for i := 0; i < len(vars); i++ {
+		if vars[i].Name == name {
+			return &vars[i]
+		}
+	}
+
+	return nil
+}
+
+// SetVal --
+func SetVal(vars *[]v1.EnvVar, name string, value string) {
+	envVar := Get(*vars, name)
+
+	if envVar != nil {
+		envVar.Value = value
+		envVar.ValueFrom = nil
+	} else {
+		*vars = append(*vars, v1.EnvVar{
+			Name:  name,
+			Value: value,
+		})
+	}
+}
+
+// SetVar --
+func SetVar(vars *[]v1.EnvVar, newEnvVar v1.EnvVar) {
+	envVar := Get(*vars, newEnvVar.Name)
+
+	if envVar != nil {
+		envVar.Value = newEnvVar.Value
+		envVar.ValueFrom = nil
+
+		if newEnvVar.ValueFrom != nil {
+			from := *newEnvVar.ValueFrom
+			envVar.ValueFrom = &from
+		}
+
+	} else {
+		*vars = append(*vars, newEnvVar)
+	}
+}
+
+// SetValFrom --
+func SetValFrom(vars *[]v1.EnvVar, name string, path string) {
+	envVar := Get(*vars, name)
+
+	if envVar != nil {
+		envVar.Value = ""
+		envVar.ValueFrom = &v1.EnvVarSource{
+			FieldRef: &v1.ObjectFieldSelector{
+				FieldPath: path,
+			},
+		}
+	} else {
+		*vars = append(*vars, v1.EnvVar{
+			Name: name,
+			ValueFrom: &v1.EnvVarSource{
+				FieldRef: &v1.ObjectFieldSelector{
+					FieldPath: path,
+				},
+			},
+		})
+	}
+}
diff --git a/pkg/util/envvar/envvar_test.go b/pkg/util/envvar/envvar_test.go
new file mode 100644
index 00000000..8d98c493
--- /dev/null
+++ b/pkg/util/envvar/envvar_test.go
@@ -0,0 +1,103 @@
+/*
+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 envvar
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+
+	"k8s.io/api/core/v1"
+)
+
+func TestGetEnvVar(t *testing.T) {
+	vars := []v1.EnvVar{
+		{
+			Name:  "MyEnv",
+			Value: "MyValue",
+		},
+	}
+
+	ev := Get(vars, "MyEnv")
+
+	assert.NotNil(t, ev)
+	assert.Equal(t, "MyValue", ev.Value)
+	assert.Nil(t, ev.ValueFrom)
+
+	assert.Nil(t, Get(vars, "NotMyEnv"))
+}
+
+func TestModifyEnvVar(t *testing.T) {
+	vars := []v1.EnvVar{
+		{
+			Name:  "MyEnv",
+			Value: "MyValue",
+		},
+	}
+
+	ev := Get(vars, "MyEnv")
+	assert.NotNil(t, ev)
+	assert.Equal(t, "MyValue", ev.Value)
+
+	ev.Value = "MyNewValue"
+
+	ev = Get(vars, "MyEnv")
+	assert.NotNil(t, ev)
+	assert.Equal(t, "MyNewValue", ev.Value)
+}
+
+func TestSetEnvVar(t *testing.T) {
+	vars := []v1.EnvVar{
+		{
+			Name:  "MyEnv",
+			Value: "MyValue",
+		},
+	}
+
+	ev := Get(vars, "MyEnv")
+	assert.NotNil(t, ev)
+	assert.Equal(t, "MyValue", ev.Value)
+	assert.Nil(t, ev.ValueFrom)
+
+	SetVal(&vars, "MyEnv", "MyNewValue")
+
+	ev = Get(vars, "MyEnv")
+	assert.NotNil(t, ev)
+	assert.Equal(t, "MyNewValue", ev.Value)
+	assert.Nil(t, ev.ValueFrom)
+
+	SetVal(&vars, "MyNewEnv", "MyNewNewValue")
+
+	ev = Get(vars, "MyEnv")
+	assert.NotNil(t, ev)
+	assert.Equal(t, "MyNewValue", ev.Value)
+	assert.Nil(t, ev.ValueFrom)
+
+	ev = Get(vars, "MyNewEnv")
+	assert.NotNil(t, ev)
+	assert.Equal(t, "MyNewNewValue", ev.Value)
+	assert.Nil(t, ev.ValueFrom)
+
+	SetValFrom(&vars, "MyNewEnv", "metadata.namespace")
+
+	ev = Get(vars, "MyNewEnv")
+	assert.NotNil(t, ev)
+	assert.Equal(t, "", ev.Value)
+	assert.NotNil(t, ev.ValueFrom)
+	assert.Equal(t, "metadata.namespace", ev.ValueFrom.FieldRef.FieldPath)
+}
diff --git a/runtime/.maven-versions-rules.xml b/runtime/.maven-versions-rules.xml
new file mode 100644
index 00000000..44e512be
--- /dev/null
+++ b/runtime/.maven-versions-rules.xml
@@ -0,0 +1,39 @@
+<?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.
+
+-->
+<ruleset xmlns="http://mojo.codehaus.org/versions-maven-plugin/rule/2.0.0"; 
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
+        comparisonMethod="maven" 
+        xsi:schemaLocation="http://mojo.codehaus.org/versions-maven-plugin/rule/2.0.0 http://mojo.codehaus.org/versions-maven-plugin/xsd/rule-2.0.0.xsd";>
+
+    <ignoreVersions>
+        <!-- Ignore Alpha's, Beta's, release candidates and milestones -->
+        <ignoreVersion type="regex">(?i).*Alpha(?:-?\d+)?</ignoreVersion>
+        <ignoreVersion type="regex">(?i).*a(?:-?\d+)?</ignoreVersion>
+        <ignoreVersion type="regex">(?i).*Beta(?:-?\d+)?</ignoreVersion>
+        <ignoreVersion type="regex">(?i).*-B(?:-?\d+)?</ignoreVersion>
+        <ignoreVersion type="regex">(?i).*RC(?:-?\d+)?</ignoreVersion>
+        <ignoreVersion type="regex">(?i).*CR(?:-?\d+)?</ignoreVersion>
+        <ignoreVersion type="regex">(?i).*M(?:-?\d+)?</ignoreVersion>
+    </ignoreVersions>
+
+    <rules>
+    </rules>
+    
+</ruleset>
\ No newline at end of file
diff --git a/runtime/camel-k-runtime-core/pom.xml b/runtime/camel-k-runtime-core/pom.xml
new file mode 100644
index 00000000..35774928
--- /dev/null
+++ b/runtime/camel-k-runtime-core/pom.xml
@@ -0,0 +1,82 @@
+<?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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <parent>
+        <groupId>org.apache.camel.k</groupId>
+        <artifactId>camel-k-runtime-parent</artifactId>
+        <version>0.1.1-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>camel-k-runtime-core</artifactId>
+
+    <dependencies>
+
+        <!-- ****************************** -->
+        <!--                                -->
+        <!-- RUNTIME                        -->
+        <!--                                -->
+        <!-- ****************************** -->
+
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>${slf4j.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>${commons-lang.version}</version>
+        </dependency>
+
+        <!-- ****************************** -->
+        <!--                                -->
+        <!-- TESTS                          -->
+        <!--                                -->
+        <!-- ****************************** -->
+
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-api</artifactId>
+            <version>${junit-jupiter.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-engine</artifactId>
+            <version>${junit-jupiter.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
+            <version>${assertj.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Constants.java b/runtime/camel-k-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/camel-k-runtime-core/src/main/java/org/apache/camel/k/Constants.java
index d3cb4b7b..e00fed49 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Constants.java
+++ b/runtime/camel-k-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/camel-k-runtime-core/src/main/java/org/apache/camel/k/Language.java
similarity index 86%
rename from runtime/jvm/src/main/java/org/apache/camel/k/jvm/Language.java
rename to runtime/camel-k-runtime-core/src/main/java/org/apache/camel/k/Language.java
index d041faa0..c338bd60 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Language.java
+++ b/runtime/camel-k-runtime-core/src/main/java/org/apache/camel/k/Language.java
@@ -14,45 +14,59 @@
  * 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;
 import java.util.List;
 
+import org.apache.camel.util.ObjectHelper;
 import org.apache.commons.lang3.StringUtils;
 
 public enum Language {
     Unknown(
+        "unknown",
         Collections.emptyList(),
         Collections.emptyList()),
     JavaClass(
+        "java-class",
         Collections.singletonList("class"),
         Collections.singletonList("class")),
     JavaSource(
+        "java-source",
         Collections.singletonList("java"),
         Collections.singletonList("java")),
     JavaScript(
+        "js",
         Arrays.asList("js", "javascript"),
         Collections.singletonList("js")),
     Groovy(
+        "groovy",
         Collections.singletonList("groovy"),
         Collections.singletonList("groovy")),
     Xml(
+        "xml",
         Collections.singletonList("xml"),
         Collections.singletonList("xml")),
     Kotlin(
+        "kotlin",
         Arrays.asList("kotlin", "kts"),
         Collections.singletonList("kts"));
 
+    private final String id;
     private final List<String> names;
     private final List<String> extensions;
 
-    Language(List<String> names, List<String> extensions) {
+    Language(String id, List<String> names, List<String> extensions) {
+        this.id = ObjectHelper.notNull(id, "id");
         this.names = names;
         this.extensions = extensions;
     }
 
+    public String getId() {
+        return id;
+    }
+
     public List<String> getNames() {
         return names;
     }
diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RoutesLoader.java b/runtime/camel-k-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/camel-k-runtime-core/src/main/java/org/apache/camel/k/RoutesLoader.java
index faac8edb..3026b926 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RoutesLoader.java
+++ b/runtime/camel-k-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/camel-k-runtime-core/src/main/java/org/apache/camel/k/RuntimeRegistry.java
similarity index 96%
rename from runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeRegistry.java
rename to runtime/camel-k-runtime-core/src/main/java/org/apache/camel/k/RuntimeRegistry.java
index 7e13a283..895fe339 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeRegistry.java
+++ b/runtime/camel-k-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/camel-k-runtime-core/src/main/java/org/apache/camel/k/RuntimeTrait.java b/runtime/camel-k-runtime-core/src/main/java/org/apache/camel/k/RuntimeTrait.java
new file mode 100644
index 00000000..275f53a3
--- /dev/null
+++ b/runtime/camel-k-runtime-core/src/main/java/org/apache/camel/k/RuntimeTrait.java
@@ -0,0 +1,28 @@
+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
+ * 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.
+ */
+
+@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/camel-k-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/camel-k-runtime-core/src/main/java/org/apache/camel/k/Source.java
index 8b00a4b9..0726b072 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Source.java
+++ b/runtime/camel-k-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/pom.xml b/runtime/camel-k-runtime-groovy/pom.xml
similarity index 100%
rename from runtime/groovy/pom.xml
rename to runtime/camel-k-runtime-groovy/pom.xml
diff --git a/runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/GroovyRoutesLoader.groovy b/runtime/camel-k-runtime-groovy/src/main/groovy/org/apache/camel/k/groovy/GroovyRoutesLoader.groovy
similarity index 93%
rename from runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/GroovyRoutesLoader.groovy
rename to runtime/camel-k-runtime-groovy/src/main/groovy/org/apache/camel/k/groovy/GroovyRoutesLoader.groovy
index 932f5265..bb081d44 100644
--- a/runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/GroovyRoutesLoader.groovy
+++ b/runtime/camel-k-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/ComponentConfiguration.groovy b/runtime/camel-k-runtime-groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/ComponentConfiguration.groovy
similarity index 100%
rename from runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/ComponentConfiguration.groovy
rename to runtime/camel-k-runtime-groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/ComponentConfiguration.groovy
diff --git a/runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/ComponentsConfiguration.groovy b/runtime/camel-k-runtime-groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/ComponentsConfiguration.groovy
similarity index 100%
rename from runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/ComponentsConfiguration.groovy
rename to runtime/camel-k-runtime-groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/ComponentsConfiguration.groovy
diff --git a/runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/ContextConfiguration.groovy b/runtime/camel-k-runtime-groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/ContextConfiguration.groovy
similarity index 97%
rename from runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/ContextConfiguration.groovy
rename to runtime/camel-k-runtime-groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/ContextConfiguration.groovy
index 405fe8c1..d70dd04d 100644
--- a/runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/ContextConfiguration.groovy
+++ b/runtime/camel-k-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/camel-k-runtime-groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/IntegrationConfiguration.groovy
similarity index 98%
rename from runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/IntegrationConfiguration.groovy
rename to runtime/camel-k-runtime-groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/IntegrationConfiguration.groovy
index 5b07bd53..fdc860aa 100644
--- a/runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/IntegrationConfiguration.groovy
+++ b/runtime/camel-k-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/camel-k-runtime-groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/RegistryConfiguration.groovy
similarity index 96%
rename from runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/RegistryConfiguration.groovy
rename to runtime/camel-k-runtime-groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/RegistryConfiguration.groovy
index 0b7b23d8..f695ec19 100644
--- a/runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/RegistryConfiguration.groovy
+++ b/runtime/camel-k-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/groovy/org/apache/camel/k/groovy/dsl/RestConfiguration.groovy b/runtime/camel-k-runtime-groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/RestConfiguration.groovy
similarity index 100%
rename from runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/RestConfiguration.groovy
rename to runtime/camel-k-runtime-groovy/src/main/groovy/org/apache/camel/k/groovy/dsl/RestConfiguration.groovy
diff --git a/runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/extension/LogComponentExtension.groovy b/runtime/camel-k-runtime-groovy/src/main/groovy/org/apache/camel/k/groovy/extension/LogComponentExtension.groovy
similarity index 100%
rename from runtime/groovy/src/main/groovy/org/apache/camel/k/groovy/extension/LogComponentExtension.groovy
rename to runtime/camel-k-runtime-groovy/src/main/groovy/org/apache/camel/k/groovy/extension/LogComponentExtension.groovy
diff --git a/runtime/groovy/src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule b/runtime/camel-k-runtime-groovy/src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule
similarity index 100%
rename from runtime/groovy/src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule
rename to runtime/camel-k-runtime-groovy/src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule
diff --git a/runtime/camel-k-runtime-groovy/src/main/resources/META-INF/services/org/apache/camel/k/loader/groovy b/runtime/camel-k-runtime-groovy/src/main/resources/META-INF/services/org/apache/camel/k/loader/groovy
new file mode 100644
index 00000000..ba7720a4
--- /dev/null
+++ b/runtime/camel-k-runtime-groovy/src/main/resources/META-INF/services/org/apache/camel/k/loader/groovy
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.k.groovy.GroovyRoutesLoader
\ No newline at end of file
diff --git a/runtime/groovy/src/test/groovy/org/apache/camel/k/groovy/LoaderTest.groovy b/runtime/camel-k-runtime-groovy/src/test/groovy/org/apache/camel/k/groovy/LoaderTest.groovy
similarity index 88%
rename from runtime/groovy/src/test/groovy/org/apache/camel/k/groovy/LoaderTest.groovy
rename to runtime/camel-k-runtime-groovy/src/test/groovy/org/apache/camel/k/groovy/LoaderTest.groovy
index ab3779c3..0bc194ff 100644
--- a/runtime/groovy/src/test/groovy/org/apache/camel/k/groovy/LoaderTest.groovy
+++ b/runtime/camel-k-runtime-groovy/src/test/groovy/org/apache/camel/k/groovy/LoaderTest.groovy
@@ -16,9 +16,10 @@
  */
 package org.apache.camel.k.groovy
 
-import org.apache.camel.k.jvm.RoutesLoaders
+import org.apache.camel.impl.DefaultCamelContext
+import org.apache.camel.k.jvm.RuntimeSupport
 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
 
@@ -29,7 +30,7 @@ class LoaderTest extends Specification {
             def source = Source.create("classpath:routes.groovy")
 
         when:
-            def loader = RoutesLoaders.loaderFor(source)
+            def loader = RuntimeSupport.loaderFor(new DefaultCamelContext(), source)
             def builder = loader.load(new SimpleRuntimeRegistry(), source)
 
         then:
diff --git a/runtime/groovy/src/test/groovy/org/apache/camel/k/groovy/dsl/IntegrationTest.groovy b/runtime/camel-k-runtime-groovy/src/test/groovy/org/apache/camel/k/groovy/dsl/IntegrationTest.groovy
similarity index 100%
rename from runtime/groovy/src/test/groovy/org/apache/camel/k/groovy/dsl/IntegrationTest.groovy
rename to runtime/camel-k-runtime-groovy/src/test/groovy/org/apache/camel/k/groovy/dsl/IntegrationTest.groovy
diff --git a/runtime/groovy/src/test/groovy/org/apache/camel/k/groovy/dsl/extension/LogExtensionTest.groovy b/runtime/camel-k-runtime-groovy/src/test/groovy/org/apache/camel/k/groovy/dsl/extension/LogExtensionTest.groovy
similarity index 100%
rename from runtime/groovy/src/test/groovy/org/apache/camel/k/groovy/dsl/extension/LogExtensionTest.groovy
rename to runtime/camel-k-runtime-groovy/src/test/groovy/org/apache/camel/k/groovy/dsl/extension/LogExtensionTest.groovy
diff --git a/runtime/groovy/src/test/resources/log4j2-test.xml b/runtime/camel-k-runtime-groovy/src/test/resources/log4j2-test.xml
similarity index 100%
rename from runtime/groovy/src/test/resources/log4j2-test.xml
rename to runtime/camel-k-runtime-groovy/src/test/resources/log4j2-test.xml
diff --git a/runtime/groovy/src/test/resources/routes-with-bindings.groovy b/runtime/camel-k-runtime-groovy/src/test/resources/routes-with-bindings.groovy
similarity index 100%
rename from runtime/groovy/src/test/resources/routes-with-bindings.groovy
rename to runtime/camel-k-runtime-groovy/src/test/resources/routes-with-bindings.groovy
diff --git a/runtime/groovy/src/test/resources/routes-with-component-configuration.groovy b/runtime/camel-k-runtime-groovy/src/test/resources/routes-with-component-configuration.groovy
similarity index 100%
rename from runtime/groovy/src/test/resources/routes-with-component-configuration.groovy
rename to runtime/camel-k-runtime-groovy/src/test/resources/routes-with-component-configuration.groovy
diff --git a/runtime/groovy/src/test/resources/routes-with-rest.groovy b/runtime/camel-k-runtime-groovy/src/test/resources/routes-with-rest.groovy
similarity index 100%
rename from runtime/groovy/src/test/resources/routes-with-rest.groovy
rename to runtime/camel-k-runtime-groovy/src/test/resources/routes-with-rest.groovy
diff --git a/runtime/groovy/src/test/resources/routes.groovy b/runtime/camel-k-runtime-groovy/src/test/resources/routes.groovy
similarity index 100%
rename from runtime/groovy/src/test/resources/routes.groovy
rename to runtime/camel-k-runtime-groovy/src/test/resources/routes.groovy
diff --git a/runtime/jvm/pom.xml b/runtime/camel-k-runtime-jvm/pom.xml
similarity index 90%
rename from runtime/jvm/pom.xml
rename to runtime/camel-k-runtime-jvm/pom.xml
index b02dc3cd..aa486034 100644
--- a/runtime/jvm/pom.xml
+++ b/runtime/camel-k-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/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/Application.java
similarity index 83%
rename from runtime/jvm/src/main/java/org/apache/camel/k/jvm/Application.java
rename to runtime/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/Application.java
index 917b5660..682609cd 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Application.java
+++ b/runtime/camel-k-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 static void main(String[] args) throws Exception {
     // *******************************
 
     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 void onComponentAdd(String name, Component component) {
                     //
                     //     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/Runtime.java b/runtime/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/Runtime.java
similarity index 94%
rename from runtime/jvm/src/main/java/org/apache/camel/k/jvm/Runtime.java
rename to runtime/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/Runtime.java
index 1e05e70b..3923e85a 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Runtime.java
+++ b/runtime/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/Runtime.java
@@ -27,6 +27,9 @@
 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;
@@ -44,7 +47,7 @@ public Runtime() {
     public void load(String[] routes) throws Exception {
         for (String route: routes) {
             final Source source = Source.create(route);
-            final RoutesLoader loader = RoutesLoaders.loaderFor(source);
+            final RoutesLoader loader = RuntimeSupport.loaderFor(getCamelContext(), source);
             final RouteBuilder builder = loader.load(registry, source);
 
             if (builder == null) {
diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeSupport.java b/runtime/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/RuntimeSupport.java
similarity index 72%
rename from runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeSupport.java
rename to runtime/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/RuntimeSupport.java
index 936e4d15..b3192b66 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeSupport.java
+++ b/runtime/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/RuntimeSupport.java
@@ -28,6 +28,14 @@
 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.RoutesLoader;
+import org.apache.camel.k.RuntimeTrait;
+import org.apache.camel.k.Source;
+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 +110,29 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
         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 +154,17 @@ public static void configureLogging() {
         );
     }
 
+    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)
@@ -140,4 +182,18 @@ public static void bindProperties(Properties properties, Object target, String p
                 }
             );
     }
+
+    public static RoutesLoader loaderFor(CamelContext context, Source source) {
+        final FactoryFinder finder;
+        final RoutesLoader loader;
+
+        try {
+            finder = context.getFactoryFinder(Constants.ROUTES_LOADER_RESOURCE_PATH);
+            loader = (RoutesLoader)finder.newInstance(source.getLanguage().getId());
+        } catch (NoFactoryAvailableException e) {
+            throw new IllegalArgumentException("Unable to find loader for: " + source, e);
+        }
+
+        return loader;
+    }
 }
diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/SimpleRuntimeRegistry.java b/runtime/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/SimpleRuntimeRegistry.java
similarity index 98%
rename from runtime/jvm/src/main/java/org/apache/camel/k/jvm/SimpleRuntimeRegistry.java
rename to runtime/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/SimpleRuntimeRegistry.java
index 1035b9c4..c62175fe 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/SimpleRuntimeRegistry.java
+++ b/runtime/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/SimpleRuntimeRegistry.java
@@ -24,6 +24,7 @@
 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/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/URIResolver.java
similarity index 97%
rename from runtime/jvm/src/main/java/org/apache/camel/k/jvm/URIResolver.java
rename to runtime/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/URIResolver.java
index c7ec4fea..30bee2ea 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/URIResolver.java
+++ b/runtime/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/URIResolver.java
@@ -24,6 +24,8 @@
 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/java/org/apache/camel/k/jvm/dsl/Components.java b/runtime/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/dsl/Components.java
similarity index 100%
rename from runtime/jvm/src/main/java/org/apache/camel/k/jvm/dsl/Components.java
rename to runtime/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/dsl/Components.java
diff --git a/runtime/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/loader/JavaClassLoader.java b/runtime/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/loader/JavaClassLoader.java
new file mode 100644
index 00000000..bf73a827
--- /dev/null
+++ b/runtime/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/loader/JavaClassLoader.java
@@ -0,0 +1,34 @@
+package org.apache.camel.k.jvm.loader;
+
+import java.util.Collections;
+import java.util.List;
+
+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.commons.lang3.StringUtils;
+
+public class JavaClassLoader implements RoutesLoader {
+    @Override
+    public List<Language> getSupportedLanguages() {
+        return Collections.singletonList(Language.JavaClass);
+    }
+
+    @Override
+    public RouteBuilder load(RuntimeRegistry registry, Source source) throws Exception {
+        String path = source.getLocation();
+        path = StringUtils.removeStart(path, Constants.SCHEME_CLASSPATH);
+        path = StringUtils.removeEnd(path, ".class");
+
+        Class<?> type = Class.forName(path);
+
+        if (!RouteBuilder.class.isAssignableFrom(type)) {
+            throw new IllegalStateException("The class provided (" + path + ") is not a org.apache.camel.builder.RouteBuilder");
+        }
+
+        return (RouteBuilder)type.newInstance();
+    }
+}
diff --git a/runtime/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/loader/JavaScriptLoader.java b/runtime/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/loader/JavaScriptLoader.java
new file mode 100644
index 00000000..650a4d1f
--- /dev/null
+++ b/runtime/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/loader/JavaScriptLoader.java
@@ -0,0 +1,58 @@
+package org.apache.camel.k.jvm.loader;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import javax.script.Bindings;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.SimpleBindings;
+
+import org.apache.camel.CamelContext;
+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.URIResolver;
+import org.apache.camel.k.jvm.dsl.Components;
+import org.apache.camel.model.RouteDefinition;
+import org.apache.camel.model.rest.RestConfigurationDefinition;
+import org.apache.camel.model.rest.RestDefinition;
+
+public class JavaScriptLoader implements RoutesLoader {
+    @Override
+    public List<Language> getSupportedLanguages() {
+        return Collections.singletonList(Language.JavaScript);
+    }
+
+    @Override
+    public RouteBuilder load(RuntimeRegistry registry, Source source) throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                final CamelContext context = getContext();
+                final ScriptEngineManager manager = new ScriptEngineManager();
+                final ScriptEngine engine = manager.getEngineByName("nashorn");
+                final Bindings bindings = new SimpleBindings();
+
+                // Exposed to the underlying script, but maybe better to have
+                // a nice dsl
+                bindings.put("builder", this);
+                bindings.put("context", context);
+                bindings.put("components", new Components(context));
+                bindings.put("registry", registry);
+                bindings.put("from", (Function<String, RouteDefinition>) uri -> from(uri));
+                bindings.put("rest", (Supplier<RestDefinition>) () -> rest());
+                bindings.put("restConfiguration", (Supplier<RestConfigurationDefinition>) () -> restConfiguration());
+
+                try (InputStream is = URIResolver.resolve(context, source)) {
+                    engine.eval(new InputStreamReader(is), bindings);
+                }
+            }
+        };
+    }
+}
diff --git a/runtime/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/loader/JavaSourceLoader.java b/runtime/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/loader/JavaSourceLoader.java
new file mode 100644
index 00000000..767a6d4a
--- /dev/null
+++ b/runtime/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/loader/JavaSourceLoader.java
@@ -0,0 +1,45 @@
+package org.apache.camel.k.jvm.loader;
+
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.List;
+
+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.URIResolver;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.joor.Reflect;
+
+public class JavaSourceLoader implements RoutesLoader {
+    @Override
+    public List<Language> getSupportedLanguages() {
+        return Collections.singletonList(Language.JavaSource);
+    }
+
+    @Override
+    public RouteBuilder load(RuntimeRegistry registry, Source source) throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                try (InputStream is = URIResolver.resolve(getContext(), source)) {
+                    String name = StringUtils.substringAfter(source.getLocation(), ":");
+                    name = StringUtils.removeEnd(name, ".java");
+
+                    if (name.contains("/")) {
+                        name = StringUtils.substringAfterLast(name, "/");
+                    }
+
+                    // Wrap routes builder
+                    includeRoutes(
+                        Reflect.compile(name, IOUtils.toString(is, StandardCharsets.UTF_8)).create().get()
+                    );
+                }
+            }
+        };
+    }
+}
diff --git a/runtime/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/loader/XmlLoader.java b/runtime/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/loader/XmlLoader.java
new file mode 100644
index 00000000..7532f141
--- /dev/null
+++ b/runtime/camel-k-runtime-jvm/src/main/java/org/apache/camel/k/jvm/loader/XmlLoader.java
@@ -0,0 +1,50 @@
+package org.apache.camel.k.jvm.loader;
+
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.List;
+import javax.xml.bind.UnmarshalException;
+
+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.URIResolver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class XmlLoader implements RoutesLoader {
+    private static final Logger LOGGER = LoggerFactory.getLogger(XmlLoader.class);
+
+    @Override
+    public List<Language> getSupportedLanguages() {
+        return Collections.singletonList(Language.Xml);
+    }
+
+    @Override
+    public RouteBuilder load(RuntimeRegistry registry, Source source) throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                try (InputStream is = URIResolver.resolve(getContext(), source)) {
+                    try {
+                        setRouteCollection(
+                            getContext().loadRoutesDefinition(is)
+                        );
+                    } catch (UnmarshalException e) {
+                        LOGGER.debug("Unable to load RoutesDefinition: {}", e.getMessage());
+                    }
+
+                    try {
+                        setRestCollection(
+                            getContext().loadRestsDefinition(is)
+                        );
+                    } catch (UnmarshalException e) {
+                        LOGGER.debug("Unable to load RestsDefinition: {}", e.getMessage());
+                    }
+                }
+            }
+        };
+    }
+}
diff --git a/runtime/camel-k-runtime-jvm/src/main/resources/META-INF/services/org/apache/camel/k/loader/java-class b/runtime/camel-k-runtime-jvm/src/main/resources/META-INF/services/org/apache/camel/k/loader/java-class
new file mode 100644
index 00000000..2d85f95e
--- /dev/null
+++ b/runtime/camel-k-runtime-jvm/src/main/resources/META-INF/services/org/apache/camel/k/loader/java-class
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.k.jvm.loader.JavaClassLoader
\ No newline at end of file
diff --git a/runtime/camel-k-runtime-jvm/src/main/resources/META-INF/services/org/apache/camel/k/loader/java-source b/runtime/camel-k-runtime-jvm/src/main/resources/META-INF/services/org/apache/camel/k/loader/java-source
new file mode 100644
index 00000000..3bf82972
--- /dev/null
+++ b/runtime/camel-k-runtime-jvm/src/main/resources/META-INF/services/org/apache/camel/k/loader/java-source
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.k.jvm.loader.JavaSourceLoader
\ No newline at end of file
diff --git a/runtime/camel-k-runtime-jvm/src/main/resources/META-INF/services/org/apache/camel/k/loader/js b/runtime/camel-k-runtime-jvm/src/main/resources/META-INF/services/org/apache/camel/k/loader/js
new file mode 100644
index 00000000..45227e82
--- /dev/null
+++ b/runtime/camel-k-runtime-jvm/src/main/resources/META-INF/services/org/apache/camel/k/loader/js
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.k.jvm.loader.JavaScriptLoader
\ No newline at end of file
diff --git a/runtime/camel-k-runtime-jvm/src/main/resources/META-INF/services/org/apache/camel/k/loader/xml b/runtime/camel-k-runtime-jvm/src/main/resources/META-INF/services/org/apache/camel/k/loader/xml
new file mode 100644
index 00000000..e30ce1eb
--- /dev/null
+++ b/runtime/camel-k-runtime-jvm/src/main/resources/META-INF/services/org/apache/camel/k/loader/xml
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.k.jvm.loader.XmlLoader
\ No newline at end of file
diff --git a/runtime/jvm/src/main/resources/log4j2.properties b/runtime/camel-k-runtime-jvm/src/main/resources/log4j2.properties
similarity index 100%
rename from runtime/jvm/src/main/resources/log4j2.properties
rename to runtime/camel-k-runtime-jvm/src/main/resources/log4j2.properties
diff --git a/runtime/jvm/src/test/java/org/apache/camel/k/jvm/PropertiesTest.java b/runtime/camel-k-runtime-jvm/src/test/java/org/apache/camel/k/jvm/PropertiesTest.java
similarity index 55%
rename from runtime/jvm/src/test/java/org/apache/camel/k/jvm/PropertiesTest.java
rename to runtime/camel-k-runtime-jvm/src/test/java/org/apache/camel/k/jvm/PropertiesTest.java
index 6ae83242..43e0d9c2 100644
--- a/runtime/jvm/src/test/java/org/apache/camel/k/jvm/PropertiesTest.java
+++ b/runtime/camel-k-runtime-jvm/src/test/java/org/apache/camel/k/jvm/PropertiesTest.java
@@ -19,12 +19,11 @@
 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 void testLoadProperties() throws Exception {
         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 void testSystemProperties() throws Exception {
             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 void testComponentConfiguration() throws Exception {
             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 void testContextConfiguration() throws Exception {
             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 void afterStart(MainSupport main) {
             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/camel-k-runtime-jvm/src/test/java/org/apache/camel/k/jvm/RoutesLoadersTest.java
similarity index 82%
rename from runtime/jvm/src/test/java/org/apache/camel/k/jvm/RoutesLoadersTest.java
rename to runtime/camel-k-runtime-jvm/src/test/java/org/apache/camel/k/jvm/RoutesLoadersTest.java
index d12539ca..cc3b7c3b 100644
--- a/runtime/jvm/src/test/java/org/apache/camel/k/jvm/RoutesLoadersTest.java
+++ b/runtime/camel-k-runtime-jvm/src/test/java/org/apache/camel/k/jvm/RoutesLoadersTest.java
@@ -19,6 +19,13 @@
 import java.util.List;
 
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.k.RoutesLoader;
+import org.apache.camel.k.Source;
+import org.apache.camel.k.jvm.loader.JavaClassLoader;
+import org.apache.camel.k.jvm.loader.JavaScriptLoader;
+import org.apache.camel.k.jvm.loader.JavaSourceLoader;
+import org.apache.camel.k.jvm.loader.XmlLoader;
 import org.apache.camel.model.ProcessDefinition;
 import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.model.SetBodyDefinition;
@@ -33,10 +40,10 @@
     @Test
     public void testLoadClass() throws Exception {
         Source source = Source.create("classpath:" + MyRoutes.class.getName() + ".class");
-        RoutesLoader loader = RoutesLoaders.loaderFor(source);
+        RoutesLoader loader = RuntimeSupport.loaderFor(new DefaultCamelContext(), source);
         RouteBuilder builder = loader.load(new SimpleRuntimeRegistry(), source);
 
-        assertThat(loader).isInstanceOf(RoutesLoaders.JavaClass.class);
+        assertThat(loader).isInstanceOf(JavaClassLoader.class);
         assertThat(builder).isNotNull();
 
         builder.configure();
@@ -50,10 +57,10 @@ public void testLoadClass() throws Exception {
     @Test
     public void testLoadJava() throws Exception {
         Source source = Source.create("classpath:MyRoutes.java");
-        RoutesLoader loader = RoutesLoaders.loaderFor(source);
+        RoutesLoader loader = RuntimeSupport.loaderFor(new DefaultCamelContext(), source);
         RouteBuilder builder = loader.load(new SimpleRuntimeRegistry(), source);
 
-        assertThat(loader).isInstanceOf(RoutesLoaders.JavaSource.class);
+        assertThat(loader).isInstanceOf(JavaSourceLoader.class);
         assertThat(builder).isNotNull();
 
         builder.configure();
@@ -67,10 +74,10 @@ public void testLoadJava() throws Exception {
     @Test
     public void testLoadJavaWithNestedClass() throws Exception {
         Source source = Source.create("classpath:MyRoutesWithNestedClass.java");
-        RoutesLoader loader = RoutesLoaders.loaderFor(source);
+        RoutesLoader loader = RuntimeSupport.loaderFor(new DefaultCamelContext(), source);
         RouteBuilder builder = loader.load(new SimpleRuntimeRegistry(), source);
 
-        assertThat(loader).isInstanceOf(RoutesLoaders.JavaSource.class);
+        assertThat(loader).isInstanceOf(JavaSourceLoader.class);
         assertThat(builder).isNotNull();
 
         builder.configure();
@@ -86,10 +93,10 @@ public void testLoadJavaWithNestedClass() throws Exception {
     @Test
     public void testLoadJavaScript() throws Exception {
         Source source = Source.create("classpath:routes.js");
-        RoutesLoader loader = RoutesLoaders.loaderFor(source);
+        RoutesLoader loader = RuntimeSupport.loaderFor(new DefaultCamelContext(), source);
         RouteBuilder builder = loader.load(new SimpleRuntimeRegistry(), source);
 
-        assertThat(loader).isInstanceOf(RoutesLoaders.JavaScript.class);
+        assertThat(loader).isInstanceOf(JavaScriptLoader.class);
         assertThat(builder).isNotNull();
 
         builder.configure();
@@ -103,10 +110,10 @@ public void testLoadJavaScript() throws Exception {
     @Test
     public void testLoadCompressedRoute() throws Exception {
         Source source = Source.create("classpath:routes-compressed.js.gz.b64?language=js&compression=true");
-        RoutesLoader loader = RoutesLoaders.loaderFor(source);
+        RoutesLoader loader = RuntimeSupport.loaderFor(new DefaultCamelContext(), source);
         RouteBuilder builder = loader.load(new SimpleRuntimeRegistry(), source);
 
-        assertThat(loader).isInstanceOf(RoutesLoaders.JavaScript.class);
+        assertThat(loader).isInstanceOf(JavaScriptLoader.class);
         assertThat(builder).isNotNull();
 
         builder.configure();
@@ -120,10 +127,10 @@ public void testLoadCompressedRoute() throws Exception {
     @Test
     public void testLoadJavaScriptWithCustomExtension() throws Exception {
         Source source = Source.create("classpath:routes.mytype?language=js");
-        RoutesLoader loader = RoutesLoaders.loaderFor(source);
+        RoutesLoader loader = RuntimeSupport.loaderFor(new DefaultCamelContext(), source);
         RouteBuilder builder = loader.load(new SimpleRuntimeRegistry(), source);
 
-        assertThat(loader).isInstanceOf(RoutesLoaders.JavaScript.class);
+        assertThat(loader).isInstanceOf(JavaScriptLoader.class);
         assertThat(builder).isNotNull();
 
         builder.configure();
@@ -137,10 +144,10 @@ public void testLoadJavaScriptWithCustomExtension() throws Exception {
     @Test
     public void testLoadXml() throws Exception {
         Source source = Source.create("classpath:routes.xml");
-        RoutesLoader loader = RoutesLoaders.loaderFor(source);
+        RoutesLoader loader = RuntimeSupport.loaderFor(new DefaultCamelContext(), source);
         RouteBuilder builder = loader.load(new SimpleRuntimeRegistry(), source);
 
-        assertThat(loader).isInstanceOf(RoutesLoaders.Xml.class);
+        assertThat(loader).isInstanceOf(XmlLoader.class);
         assertThat(builder).isNotNull();
 
         builder.configure();
diff --git a/runtime/jvm/src/test/java/org/apache/camel/k/jvm/RuntimeTest.java b/runtime/camel-k-runtime-jvm/src/test/java/org/apache/camel/k/jvm/RuntimeTest.java
similarity index 100%
rename from runtime/jvm/src/test/java/org/apache/camel/k/jvm/RuntimeTest.java
rename to runtime/camel-k-runtime-jvm/src/test/java/org/apache/camel/k/jvm/RuntimeTest.java
diff --git a/runtime/camel-k-runtime-jvm/src/test/java/org/apache/camel/k/jvm/RuntimeTestSupport.java b/runtime/camel-k-runtime-jvm/src/test/java/org/apache/camel/k/jvm/RuntimeTestSupport.java
new file mode 100644
index 00000000..d72ddddd
--- /dev/null
+++ b/runtime/camel-k-runtime-jvm/src/test/java/org/apache/camel/k/jvm/RuntimeTestSupport.java
@@ -0,0 +1,41 @@
+/**
+ * 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.camel.k.jvm;
+
+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;
+
+public final class RuntimeTestSupport {
+    private RuntimeTestSupport() {
+    }
+
+    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/jvm/src/test/resources/MyRoutes.java b/runtime/camel-k-runtime-jvm/src/test/resources/MyRoutes.java
similarity index 100%
rename from runtime/jvm/src/test/resources/MyRoutes.java
rename to runtime/camel-k-runtime-jvm/src/test/resources/MyRoutes.java
diff --git a/runtime/jvm/src/test/resources/MyRoutesWithNestedClass.java b/runtime/camel-k-runtime-jvm/src/test/resources/MyRoutesWithNestedClass.java
similarity index 100%
rename from runtime/jvm/src/test/resources/MyRoutesWithNestedClass.java
rename to runtime/camel-k-runtime-jvm/src/test/resources/MyRoutesWithNestedClass.java
diff --git a/runtime/jvm/src/test/resources/conf.d/001/conf.properties b/runtime/camel-k-runtime-jvm/src/test/resources/conf.d/001/conf.properties
similarity index 100%
rename from runtime/jvm/src/test/resources/conf.d/001/conf.properties
rename to runtime/camel-k-runtime-jvm/src/test/resources/conf.d/001/conf.properties
diff --git a/runtime/jvm/src/test/resources/conf.d/002/conf.properties b/runtime/camel-k-runtime-jvm/src/test/resources/conf.d/002/conf.properties
similarity index 100%
rename from runtime/jvm/src/test/resources/conf.d/002/conf.properties
rename to runtime/camel-k-runtime-jvm/src/test/resources/conf.d/002/conf.properties
diff --git a/runtime/jvm/src/test/resources/conf.properties b/runtime/camel-k-runtime-jvm/src/test/resources/conf.properties
similarity index 100%
rename from runtime/jvm/src/test/resources/conf.properties
rename to runtime/camel-k-runtime-jvm/src/test/resources/conf.properties
diff --git a/runtime/jvm/src/test/resources/log4j2-test.xml b/runtime/camel-k-runtime-jvm/src/test/resources/log4j2-test.xml
similarity index 100%
rename from runtime/jvm/src/test/resources/log4j2-test.xml
rename to runtime/camel-k-runtime-jvm/src/test/resources/log4j2-test.xml
diff --git a/runtime/jvm/src/test/resources/r1.js b/runtime/camel-k-runtime-jvm/src/test/resources/r1.js
similarity index 100%
rename from runtime/jvm/src/test/resources/r1.js
rename to runtime/camel-k-runtime-jvm/src/test/resources/r1.js
diff --git a/runtime/jvm/src/test/resources/r2.mytype b/runtime/camel-k-runtime-jvm/src/test/resources/r2.mytype
similarity index 100%
rename from runtime/jvm/src/test/resources/r2.mytype
rename to runtime/camel-k-runtime-jvm/src/test/resources/r2.mytype
diff --git a/runtime/jvm/src/test/resources/routes-compressed.js.gz.b64 b/runtime/camel-k-runtime-jvm/src/test/resources/routes-compressed.js.gz.b64
similarity index 100%
rename from runtime/jvm/src/test/resources/routes-compressed.js.gz.b64
rename to runtime/camel-k-runtime-jvm/src/test/resources/routes-compressed.js.gz.b64
diff --git a/runtime/jvm/src/test/resources/routes.js b/runtime/camel-k-runtime-jvm/src/test/resources/routes.js
similarity index 100%
rename from runtime/jvm/src/test/resources/routes.js
rename to runtime/camel-k-runtime-jvm/src/test/resources/routes.js
diff --git a/runtime/jvm/src/test/resources/routes.mytype b/runtime/camel-k-runtime-jvm/src/test/resources/routes.mytype
similarity index 100%
rename from runtime/jvm/src/test/resources/routes.mytype
rename to runtime/camel-k-runtime-jvm/src/test/resources/routes.mytype
diff --git a/runtime/jvm/src/test/resources/routes.xml b/runtime/camel-k-runtime-jvm/src/test/resources/routes.xml
similarity index 100%
rename from runtime/jvm/src/test/resources/routes.xml
rename to runtime/camel-k-runtime-jvm/src/test/resources/routes.xml
diff --git a/runtime/kotlin/pom.xml b/runtime/camel-k-runtime-kotlin/pom.xml
similarity index 100%
rename from runtime/kotlin/pom.xml
rename to runtime/camel-k-runtime-kotlin/pom.xml
diff --git a/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/KotlinRoutesLoader.kt b/runtime/camel-k-runtime-kotlin/src/main/kotlin/org/apache/camel/k/kotlin/KotlinRoutesLoader.kt
similarity index 96%
rename from runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/KotlinRoutesLoader.kt
rename to runtime/camel-k-runtime-kotlin/src/main/kotlin/org/apache/camel/k/kotlin/KotlinRoutesLoader.kt
index fba85d60..79025393 100644
--- a/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/KotlinRoutesLoader.kt
+++ b/runtime/camel-k-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/ComponentsConfiguration.kt b/runtime/camel-k-runtime-kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/ComponentsConfiguration.kt
similarity index 100%
rename from runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/ComponentsConfiguration.kt
rename to runtime/camel-k-runtime-kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/ComponentsConfiguration.kt
diff --git a/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/ContextConfiguration.kt b/runtime/camel-k-runtime-kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/ContextConfiguration.kt
similarity index 96%
rename from runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/ContextConfiguration.kt
rename to runtime/camel-k-runtime-kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/ContextConfiguration.kt
index 618d1c79..9dbf77f2 100644
--- a/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/ContextConfiguration.kt
+++ b/runtime/camel-k-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/camel-k-runtime-kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/IntegrationConfiguration.kt
similarity index 97%
rename from runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/IntegrationConfiguration.kt
rename to runtime/camel-k-runtime-kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/IntegrationConfiguration.kt
index 52d20f4b..926ad3ac 100644
--- a/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/IntegrationConfiguration.kt
+++ b/runtime/camel-k-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/camel-k-runtime-kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/RegistryConfiguration.kt
similarity index 95%
rename from runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/RegistryConfiguration.kt
rename to runtime/camel-k-runtime-kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/RegistryConfiguration.kt
index f15f71ab..b3abc957 100644
--- a/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/RegistryConfiguration.kt
+++ b/runtime/camel-k-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/kotlin/org/apache/camel/k/kotlin/dsl/RestConfiguration.kt b/runtime/camel-k-runtime-kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/RestConfiguration.kt
similarity index 100%
rename from runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/RestConfiguration.kt
rename to runtime/camel-k-runtime-kotlin/src/main/kotlin/org/apache/camel/k/kotlin/dsl/RestConfiguration.kt
diff --git a/runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/extension/LogComponentExtensions.kt b/runtime/camel-k-runtime-kotlin/src/main/kotlin/org/apache/camel/k/kotlin/extension/LogComponentExtensions.kt
similarity index 100%
rename from runtime/kotlin/src/main/kotlin/org/apache/camel/k/kotlin/extension/LogComponentExtensions.kt
rename to runtime/camel-k-runtime-kotlin/src/main/kotlin/org/apache/camel/k/kotlin/extension/LogComponentExtensions.kt
diff --git a/runtime/camel-k-runtime-kotlin/src/main/resources/META-INF/services/org/apache/camel/k/loader/kotlin b/runtime/camel-k-runtime-kotlin/src/main/resources/META-INF/services/org/apache/camel/k/loader/kotlin
new file mode 100644
index 00000000..d4bcde13
--- /dev/null
+++ b/runtime/camel-k-runtime-kotlin/src/main/resources/META-INF/services/org/apache/camel/k/loader/kotlin
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.k.kotlin.KotlinRoutesLoader
\ No newline at end of file
diff --git a/runtime/kotlin/src/test/kotlin/org/apache/camel/k/kotlin/LoaderTest.kt b/runtime/camel-k-runtime-kotlin/src/test/kotlin/org/apache/camel/k/kotlin/LoaderTest.kt
similarity index 89%
rename from runtime/kotlin/src/test/kotlin/org/apache/camel/k/kotlin/LoaderTest.kt
rename to runtime/camel-k-runtime-kotlin/src/test/kotlin/org/apache/camel/k/kotlin/LoaderTest.kt
index 0783b275..c0f86c6c 100644
--- a/runtime/kotlin/src/test/kotlin/org/apache/camel/k/kotlin/LoaderTest.kt
+++ b/runtime/camel-k-runtime-kotlin/src/test/kotlin/org/apache/camel/k/kotlin/LoaderTest.kt
@@ -16,9 +16,10 @@
  */
 package org.apache.camel.k.kotlin
 
-import org.apache.camel.k.jvm.RoutesLoaders
+import org.apache.camel.impl.DefaultCamelContext
+import org.apache.camel.k.Source
+import org.apache.camel.k.jvm.RuntimeSupport
 import org.apache.camel.k.jvm.SimpleRuntimeRegistry
-import org.apache.camel.k.jvm.Source
 import org.apache.camel.model.ProcessDefinition
 import org.apache.camel.model.ToDefinition
 import org.assertj.core.api.Assertions.assertThat
@@ -29,7 +30,7 @@ class LoaderTest {
     @Test
     fun `load route from classpath`() {
         var source = Source.create("classpath:routes.kts")
-        val loader = RoutesLoaders.loaderFor(source)
+        val loader = RuntimeSupport.loaderFor(DefaultCamelContext(), source)
         val builder = loader.load(SimpleRuntimeRegistry(), source)
 
         assertThat(loader).isInstanceOf(KotlinRoutesLoader::class.java)
diff --git a/runtime/kotlin/src/test/kotlin/org/apache/camel/k/kotlin/dsl/IntegrationTest.kt b/runtime/camel-k-runtime-kotlin/src/test/kotlin/org/apache/camel/k/kotlin/dsl/IntegrationTest.kt
similarity index 100%
rename from runtime/kotlin/src/test/kotlin/org/apache/camel/k/kotlin/dsl/IntegrationTest.kt
rename to runtime/camel-k-runtime-kotlin/src/test/kotlin/org/apache/camel/k/kotlin/dsl/IntegrationTest.kt
diff --git a/runtime/kotlin/src/test/kotlin/org/apache/camel/k/kotlin/extension/LogExtensionTest.kt b/runtime/camel-k-runtime-kotlin/src/test/kotlin/org/apache/camel/k/kotlin/extension/LogExtensionTest.kt
similarity index 100%
rename from runtime/kotlin/src/test/kotlin/org/apache/camel/k/kotlin/extension/LogExtensionTest.kt
rename to runtime/camel-k-runtime-kotlin/src/test/kotlin/org/apache/camel/k/kotlin/extension/LogExtensionTest.kt
diff --git a/runtime/kotlin/src/test/resources/log4j2-test.xml b/runtime/camel-k-runtime-kotlin/src/test/resources/log4j2-test.xml
similarity index 100%
rename from runtime/kotlin/src/test/resources/log4j2-test.xml
rename to runtime/camel-k-runtime-kotlin/src/test/resources/log4j2-test.xml
diff --git a/runtime/kotlin/src/test/resources/routes-new.kts b/runtime/camel-k-runtime-kotlin/src/test/resources/routes-new.kts
similarity index 100%
rename from runtime/kotlin/src/test/resources/routes-new.kts
rename to runtime/camel-k-runtime-kotlin/src/test/resources/routes-new.kts
diff --git a/runtime/kotlin/src/test/resources/routes-with-bindings.kts b/runtime/camel-k-runtime-kotlin/src/test/resources/routes-with-bindings.kts
similarity index 100%
rename from runtime/kotlin/src/test/resources/routes-with-bindings.kts
rename to runtime/camel-k-runtime-kotlin/src/test/resources/routes-with-bindings.kts
diff --git a/runtime/kotlin/src/test/resources/routes-with-component-configuration.kts b/runtime/camel-k-runtime-kotlin/src/test/resources/routes-with-component-configuration.kts
similarity index 100%
rename from runtime/kotlin/src/test/resources/routes-with-component-configuration.kts
rename to runtime/camel-k-runtime-kotlin/src/test/resources/routes-with-component-configuration.kts
diff --git a/runtime/kotlin/src/test/resources/routes-with-rest.kts b/runtime/camel-k-runtime-kotlin/src/test/resources/routes-with-rest.kts
similarity index 100%
rename from runtime/kotlin/src/test/resources/routes-with-rest.kts
rename to runtime/camel-k-runtime-kotlin/src/test/resources/routes-with-rest.kts
diff --git a/runtime/kotlin/src/test/resources/routes.kts b/runtime/camel-k-runtime-kotlin/src/test/resources/routes.kts
similarity index 100%
rename from runtime/kotlin/src/test/resources/routes.kts
rename to runtime/camel-k-runtime-kotlin/src/test/resources/routes.kts
diff --git a/runtime/spring-boot/pom.xml b/runtime/camel-k-runtime-spring-boot/pom.xml
similarity index 100%
rename from runtime/spring-boot/pom.xml
rename to runtime/camel-k-runtime-spring-boot/pom.xml
diff --git a/runtime/spring-boot/src/main/java/org/apache/camel/k/spring/boot/Application.java b/runtime/camel-k-runtime-spring-boot/src/main/java/org/apache/camel/k/spring/boot/Application.java
similarity index 91%
rename from runtime/spring-boot/src/main/java/org/apache/camel/k/spring/boot/Application.java
rename to runtime/camel-k-runtime-spring-boot/src/main/java/org/apache/camel/k/spring/boot/Application.java
index 0fe24ff6..427dd9ed 100644
--- a/runtime/spring-boot/src/main/java/org/apache/camel/k/spring/boot/Application.java
+++ b/runtime/camel-k-runtime-spring-boot/src/main/java/org/apache/camel/k/spring/boot/Application.java
@@ -22,12 +22,11 @@
 
 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.jvm.RoutesLoaders;
-import org.apache.camel.k.jvm.RuntimeRegistry;
+import org.apache.camel.k.RuntimeRegistry;
+import org.apache.camel.k.Constants;
+import org.apache.camel.k.RoutesLoader;
 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,10 +84,17 @@ public void beforeApplicationStart(CamelContext context) {
                     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);
-                        final RoutesLoader loader = RoutesLoaders.loaderFor(source);
+                        final RoutesLoader loader = RuntimeSupport.loaderFor(context, source);
                         final RouteBuilder builder = loader.load(registry, source);
 
                         if (builder == null) {
diff --git a/runtime/camel-knative/.gitignore b/runtime/camel-knative/.gitignore
deleted file mode 100644
index ed929831..00000000
--- a/runtime/camel-knative/.gitignore
+++ /dev/null
@@ -1,10 +0,0 @@
-target
-
-*.iml
-
-.idea
-.project
-.metadata
-.settings
-.factorypath
-.classpath
diff --git a/runtime/catalog-builder/.gitignore b/runtime/catalog-builder/.gitignore
deleted file mode 100644
index ed929831..00000000
--- a/runtime/catalog-builder/.gitignore
+++ /dev/null
@@ -1,10 +0,0 @@
-target
-
-*.iml
-
-.idea
-.project
-.metadata
-.settings
-.factorypath
-.classpath
diff --git a/runtime/dependency-lister/.gitignore b/runtime/dependency-lister/.gitignore
deleted file mode 100644
index ed929831..00000000
--- a/runtime/dependency-lister/.gitignore
+++ /dev/null
@@ -1,10 +0,0 @@
-target
-
-*.iml
-
-.idea
-.project
-.metadata
-.settings
-.factorypath
-.classpath
diff --git a/runtime/groovy/.gitignore b/runtime/groovy/.gitignore
deleted file mode 100644
index ed929831..00000000
--- a/runtime/groovy/.gitignore
+++ /dev/null
@@ -1,10 +0,0 @@
-target
-
-*.iml
-
-.idea
-.project
-.metadata
-.settings
-.factorypath
-.classpath
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.jvm.RoutesLoader
deleted file mode 100644
index db214e0e..00000000
--- a/runtime/groovy/src/main/resources/META-INF/services/org.apache.camel.k.jvm.RoutesLoader
+++ /dev/null
@@ -1 +0,0 @@
-org.apache.camel.k.groovy.GroovyRoutesLoader
\ No newline at end of file
diff --git a/runtime/jvm/.gitignore b/runtime/jvm/.gitignore
deleted file mode 100644
index ed929831..00000000
--- a/runtime/jvm/.gitignore
+++ /dev/null
@@ -1,10 +0,0 @@
-target
-
-*.iml
-
-.idea
-.project
-.metadata
-.settings
-.factorypath
-.classpath
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
deleted file mode 100644
index 5f670780..00000000
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RoutesLoaders.java
+++ /dev/null
@@ -1,179 +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.camel.k.jvm;
-
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.nio.charset.StandardCharsets;
-import java.util.Collections;
-import java.util.List;
-import java.util.ServiceLoader;
-import java.util.function.Function;
-import java.util.function.Supplier;
-import javax.script.Bindings;
-import javax.script.ScriptEngine;
-import javax.script.ScriptEngineManager;
-import javax.script.SimpleBindings;
-import javax.xml.bind.UnmarshalException;
-
-import org.apache.camel.CamelContext;
-import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.k.jvm.dsl.Components;
-import org.apache.camel.model.RouteDefinition;
-import org.apache.camel.model.rest.RestConfigurationDefinition;
-import org.apache.camel.model.rest.RestDefinition;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.joor.Reflect;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public final class RoutesLoaders {
-    private static final Logger LOGGER = LoggerFactory.getLogger(RoutesLoaders.class);
-
-    private RoutesLoaders() {
-    }
-
-    public static class JavaClass implements RoutesLoader {
-        @Override
-        public List<Language> getSupportedLanguages() {
-            return Collections.singletonList(Language.JavaClass);
-        }
-
-        @Override
-        public RouteBuilder load(RuntimeRegistry registry, Source source) throws Exception {
-            String path = source.getLocation();
-            path = StringUtils.removeStart(path, Constants.SCHEME_CLASSPATH);
-            path = StringUtils.removeEnd(path, ".class");
-
-            Class<?> type = Class.forName(path);
-
-            if (!RouteBuilder.class.isAssignableFrom(type)) {
-                throw new IllegalStateException("The class provided (" + path + ") is not a org.apache.camel.builder.RouteBuilder");
-            }
-
-            return (RouteBuilder)type.newInstance();
-        }
-    }
-
-    public static class JavaSource implements RoutesLoader {
-        @Override
-        public List<Language> getSupportedLanguages() {
-            return Collections.singletonList(Language.JavaSource);
-        }
-
-        @Override
-        public RouteBuilder load(RuntimeRegistry registry, Source source) throws Exception {
-            return new RouteBuilder() {
-                @Override
-                public void configure() throws Exception {
-                    try (InputStream is = URIResolver.resolve(getContext(), source)) {
-                        String name = StringUtils.substringAfter(source.getLocation(), ":");
-                        name = StringUtils.removeEnd(name, ".java");
-
-                        if (name.contains("/")) {
-                            name = StringUtils.substringAfterLast(name, "/");
-                        }
-
-                        // Wrap routes builder
-                        includeRoutes(
-                            Reflect.compile(name, IOUtils.toString(is, StandardCharsets.UTF_8)).create().get()
-                        );
-                    }
-                }
-            };
-        }
-    }
-
-    public static class JavaScript implements RoutesLoader {
-        @Override
-        public List<Language> getSupportedLanguages() {
-            return Collections.singletonList(Language.JavaScript);
-        }
-
-        @Override
-        public RouteBuilder load(RuntimeRegistry registry, Source source) throws Exception {
-            return new RouteBuilder() {
-                @Override
-                public void configure() throws Exception {
-                    final CamelContext context = getContext();
-                    final ScriptEngineManager manager = new ScriptEngineManager();
-                    final ScriptEngine engine = manager.getEngineByName("nashorn");
-                    final Bindings bindings = new SimpleBindings();
-
-                    // Exposed to the underlying script, but maybe better to have
-                    // a nice dsl
-                    bindings.put("builder", this);
-                    bindings.put("context", context);
-                    bindings.put("components", new Components(context));
-                    bindings.put("registry", registry);
-                    bindings.put("from", (Function<String, RouteDefinition>) uri -> from(uri));
-                    bindings.put("rest", (Supplier<RestDefinition>) () -> rest());
-                    bindings.put("restConfiguration", (Supplier<RestConfigurationDefinition>) () -> restConfiguration());
-
-                    try (InputStream is = URIResolver.resolve(context, source)) {
-                        engine.eval(new InputStreamReader(is), bindings);
-                    }
-                }
-            };
-        }
-    }
-
-    public static class Xml implements RoutesLoader {
-        @Override
-        public List<Language> getSupportedLanguages() {
-            return Collections.singletonList(Language.Xml);
-        }
-
-        @Override
-        public RouteBuilder load(RuntimeRegistry registry, Source source) throws Exception {
-            return new RouteBuilder() {
-                @Override
-                public void configure() throws Exception {
-                    try (InputStream is = URIResolver.resolve(getContext(), source)) {
-                        try {
-                            setRouteCollection(
-                                getContext().loadRoutesDefinition(is)
-                            );
-                        } catch (UnmarshalException e) {
-                            LOGGER.debug("Unable to load RoutesDefinition: {}", e.getMessage());
-                        }
-
-                        try {
-                            setRestCollection(
-                                getContext().loadRestsDefinition(is)
-                            );
-                        } catch (UnmarshalException e) {
-                            LOGGER.debug("Unable to load RestsDefinition: {}", e.getMessage());
-                        }
-                    }
-                }
-            };
-        }
-    }
-
-
-    public static RoutesLoader loaderFor(Source source) {
-        for (RoutesLoader loader: ServiceLoader.load(RoutesLoader.class)) {
-            if (loader.getSupportedLanguages().contains(source.getLanguage())) {
-                return loader;
-            }
-        }
-
-        throw new IllegalArgumentException("Unable to find loader for: " + source);
-    }
-}
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.jvm.RoutesLoader
deleted file mode 100644
index 5a579270..00000000
--- a/runtime/jvm/src/main/resources/META-INF/services/org.apache.camel.k.jvm.RoutesLoader
+++ /dev/null
@@ -1,4 +0,0 @@
-org.apache.camel.k.jvm.RoutesLoaders$JavaClass
-org.apache.camel.k.jvm.RoutesLoaders$JavaSource
-org.apache.camel.k.jvm.RoutesLoaders$JavaScript
-org.apache.camel.k.jvm.RoutesLoaders$Xml
diff --git a/runtime/kotlin/.gitignore b/runtime/kotlin/.gitignore
deleted file mode 100644
index ed929831..00000000
--- a/runtime/kotlin/.gitignore
+++ /dev/null
@@ -1,10 +0,0 @@
-target
-
-*.iml
-
-.idea
-.project
-.metadata
-.settings
-.factorypath
-.classpath
diff --git a/runtime/kotlin/src/main/resources/META-INF/services/javax.script.ScriptEngineFactory b/runtime/kotlin/src/main/resources/META-INF/services/javax.script.ScriptEngineFactory
deleted file mode 100644
index f8f59003..00000000
--- a/runtime/kotlin/src/main/resources/META-INF/services/javax.script.ScriptEngineFactory
+++ /dev/null
@@ -1 +0,0 @@
-org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngineFactory
\ No newline at end of file
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.jvm.RoutesLoader
deleted file mode 100644
index 83c3f090..00000000
--- a/runtime/kotlin/src/main/resources/META-INF/services/org.apache.camel.k.jvm.RoutesLoader
+++ /dev/null
@@ -1 +0,0 @@
-org.apache.camel.k.kotlin.KotlinRoutesLoader
\ No newline at end of file
diff --git a/runtime/pom.xml b/runtime/pom.xml
index e7f2c3aa..014e40bb 100644
--- a/runtime/pom.xml
+++ b/runtime/pom.xml
@@ -17,11 +17,8 @@
     limitations under the License.
 
 -->
-<project xmlns="http://maven.apache.org/POM/4.0.0";
-         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+<project xmlns="http://maven.apache.org/POM/4.0.0"; xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd";>
     <modelVersion>4.0.0</modelVersion>
-
     <groupId>org.apache.camel.k</groupId>
     <artifactId>camel-k-runtime-parent</artifactId>
     <version>0.1.1-SNAPSHOT</version>
@@ -29,10 +26,8 @@
 
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-
         <maven.compiler.source>1.8</maven.compiler.source>
         <maven.compiler.target>1.8</maven.compiler.target>
-
         <camel.version>2.23.0</camel.version>
         <junit.version>4.12</junit.version>
         <junit-jupiter.version>5.3.2</junit-jupiter.version>
@@ -49,11 +44,12 @@
         <spock.version>1.2-groovy-2.5</spock.version>
         <jackson.version>2.9.7</jackson.version>
         <spring-boot.version>2.1.0.RELEASE</spring-boot.version>
-
         <gmavenplus-plugin.version>1.6.1</gmavenplus-plugin.version>
         <fabric8-maven-plugin.version>3.5.40</fabric8-maven-plugin.version>
         <maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
         <maven-surefire-plugin.version>2.22.1</maven-surefire-plugin.version>
+        <versions-maven-plugin.version>2.7</versions-maven-plugin.version>
+        <directory-maven-plugin.version>0.3.1</directory-maven-plugin.version>
     </properties>
 
     <dependencyManagement>
@@ -79,7 +75,7 @@
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-compiler-plugin</artifactId>
-                    <version>3.8.0</version>
+                    <version>${maven-compiler-plugin.version}</version>
                     <configuration>
                         <source>1.8</source>
                         <target>1.8</target>
@@ -98,14 +94,53 @@
     </build>
 
     <modules>
-        <module>jvm</module>
-        <module>groovy</module>
-        <module>kotlin</module>
-        <module>spring-boot</module>
+        <module>camel-k-runtime-core</module>
+        <module>camel-k-runtime-jvm</module>
+        <module>camel-k-runtime-groovy</module>
+        <module>camel-k-runtime-kotlin</module>
+        <module>camel-k-runtime-spring-boot</module>
         <module>catalog-builder</module>
         <module>dependency-lister</module>
         <module>camel-knative-http</module>
         <module>camel-knative</module>
     </modules>
 
-</project>
+    <profiles>
+        <profile>
+            <id>deps</id>
+            <activation>
+                <activeByDefault>false</activeByDefault>
+            </activation>
+            <build>
+                <defaultGoal>initialize versions:display-dependency-updates</defaultGoal>
+                <plugins>
+                    <plugin>
+                        <groupId>org.commonjava.maven.plugins</groupId>
+                        <artifactId>directory-maven-plugin</artifactId>
+                        <version>${directory-maven-plugin.version}</version>
+                        <executions>
+                            <execution>
+                                <id>directories</id>
+                                <goals>
+                                    <goal>highest-basedir</goal>
+                                </goals>
+                                <phase>initialize</phase>
+                                <configuration>
+                                    <property>camel-k.project.root</property>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>versions-maven-plugin</artifactId>
+                        <version>${versions-maven-plugin.version}</version>
+                        <configuration>
+                            <rulesUri>file:///${camel-k.project.root}/.maven-versions-rules.xml</rulesUri>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+</project>
\ No newline at end of file
diff --git a/runtime/spring-boot/.gitignore b/runtime/spring-boot/.gitignore
deleted file mode 100644
index ed929831..00000000
--- a/runtime/spring-boot/.gitignore
+++ /dev/null
@@ -1,10 +0,0 @@
-target
-
-*.iml
-
-.idea
-.project
-.metadata
-.settings
-.factorypath
-.classpath


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@xxxxxxxxxxxxxxxx


With regards,
Apache Git Services