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

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

commit 3676bb5175a33b094a216d3b9bb8ddb8135f5129
Author: lburgazzoli <lburgazz...@gmail.com>
AuthorDate: Thu Sep 13 16:07:28 2018 +0200

    Support for properties #62
---
 pkg/apis/camel/v1alpha1/types.go                   | 43 ++++++++++++----
 pkg/apis/camel/v1alpha1/types_support.go           |  2 +
 pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go   |  5 ++
 pkg/client/cmd/context_create.go                   |  2 +-
 pkg/client/cmd/run.go                              | 43 ++++++++++------
 pkg/stub/action/integration/build.go               | 35 +++++++------
 pkg/stub/action/integration/deploy.go              | 58 ++++++++++++++++------
 pkg/stub/action/integration/util.go                | 56 +++++++++++++++++++++
 runtime/examples/props.js                          |  9 ++++
 .../java/org/apache/camel/k/jvm/Application.java   |  7 +++
 .../main/java/org/apache/camel/k/jvm/Routes.java   |  1 +
 11 files changed, 199 insertions(+), 62 deletions(-)

diff --git a/pkg/apis/camel/v1alpha1/types.go b/pkg/apis/camel/v1alpha1/types.go
index 72da35a..e59a3e6 100644
--- a/pkg/apis/camel/v1alpha1/types.go
+++ b/pkg/apis/camel/v1alpha1/types.go
@@ -23,6 +23,7 @@ import (
 
 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 
+// IntegrationList --
 type IntegrationList struct {
        metav1.TypeMeta `json:",inline"`
        metav1.ListMeta `json:"metadata"`
@@ -31,6 +32,7 @@ type IntegrationList struct {
 
 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 
+// Integration --
 type Integration struct {
        metav1.TypeMeta   `json:",inline"`
        metav1.ObjectMeta `json:"metadata"`
@@ -38,36 +40,49 @@ type Integration struct {
        Status            IntegrationStatus `json:"status,omitempty"`
 }
 
+// IntegrationSpec --
 type IntegrationSpec struct {
-       Replicas     *int32     `json:"replicas,omitempty"`
-       Source       SourceSpec `json:"source,omitempty"`
-       Context      string     `json:"context,omitempty"`
-       Dependencies []string   `json:"dependencies,omitempty"`
+       Replicas     *int32         `json:"replicas,omitempty"`
+       Source       SourceSpec     `json:"source,omitempty"`
+       Context      string         `json:"context,omitempty"`
+       Dependencies []string       `json:"dependencies,omitempty"`
+       Properties   []PropertySpec `json:"properties,omitempty"`
 }
 
+// SourceSpec --
 type SourceSpec struct {
        Name     string `json:"name,omitempty"`
        Content  string `json:"content,omitempty"`
        Language string `json:"language,omitempty"`
 }
 
+// IntegrationStatus --
 type IntegrationStatus struct {
        Phase  IntegrationPhase `json:"phase,omitempty"`
        Digest string           `json:"digest,omitempty"`
        Image  string           `json:"image,omitempty"`
 }
 
+// IntegrationPhase --
 type IntegrationPhase string
 
 const (
-       IntegrationPhaseBuilding  IntegrationPhase = "Building"
+       // IntegrationKind --
+       IntegrationKind string = "Integration"
+
+       // IntegrationPhaseBuilding --
+       IntegrationPhaseBuilding IntegrationPhase = "Building"
+       // IntegrationPhaseDeploying --
        IntegrationPhaseDeploying IntegrationPhase = "Deploying"
-       IntegrationPhaseRunning   IntegrationPhase = "Running"
-       IntegrationPhaseError     IntegrationPhase = "Error"
+       // IntegrationPhaseRunning --
+       IntegrationPhaseRunning IntegrationPhase = "Running"
+       // IntegrationPhaseError --
+       IntegrationPhaseError IntegrationPhase = "Error"
 )
 
 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 
+// IntegrationContextList --
 type IntegrationContextList struct {
        metav1.TypeMeta `json:",inline"`
        metav1.ListMeta `json:"metadata"`
@@ -76,6 +91,7 @@ type IntegrationContextList struct {
 
 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 
+// IntegrationContext --
 type IntegrationContext struct {
        metav1.TypeMeta   `json:",inline"`
        metav1.ObjectMeta `json:"metadata"`
@@ -83,28 +99,33 @@ type IntegrationContext struct {
        Status            IntegrationContextStatus `json:"status,omitempty"`
 }
 
+// IntegrationContextSpec --
 type IntegrationContextSpec struct {
        Dependencies []string          `json:"dependencies,omitempty"`
        Properties   []PropertySpec    `json:"properties,omitempty"`
        Environment  []EnvironmentSpec `json:"environment,omitempty"`
 }
 
+// PropertySpec --
 type PropertySpec struct {
-       Name  string
-       Value string
+       Name  string `json:"name"`
+       Value string `json:"value"`
 }
 
+// EnvironmentSpec --
 type EnvironmentSpec struct {
-       Name  string
-       Value string
+       Name  string `json:"name"`
+       Value string `json:"value"`
 }
 
+// IntegrationContextStatus --
 type IntegrationContextStatus struct {
        Phase  IntegrationContextPhase `json:"phase,omitempty"`
        Image  string                  `json:"image,omitempty"`
        Digest string                  `json:"digest,omitempty"`
 }
 
+// IntegrationContextPhase --
 type IntegrationContextPhase string
 
 const (
diff --git a/pkg/apis/camel/v1alpha1/types_support.go 
b/pkg/apis/camel/v1alpha1/types_support.go
index fe93a18..b1cd02e 100644
--- a/pkg/apis/camel/v1alpha1/types_support.go
+++ b/pkg/apis/camel/v1alpha1/types_support.go
@@ -43,6 +43,7 @@ func (spec EnvironmentSpec) String() string {
 //
 // **********************************
 
+// NewIntegrationContext --
 func NewIntegrationContext(namespace string, name string) IntegrationContext {
        return IntegrationContext{
                TypeMeta: metav1.TypeMeta{
@@ -56,6 +57,7 @@ func NewIntegrationContext(namespace string, name string) 
IntegrationContext {
        }
 }
 
+// NewIntegrationContextList --
 func NewIntegrationContextList() IntegrationContextList {
        return IntegrationContextList{
                TypeMeta: metav1.TypeMeta{
diff --git a/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go 
b/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go
index 826918a..1da7ad7 100644
--- a/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go
+++ b/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go
@@ -224,6 +224,11 @@ func (in *IntegrationSpec) DeepCopyInto(out 
*IntegrationSpec) {
                *out = make([]string, len(*in))
                copy(*out, *in)
        }
+       if in.Properties != nil {
+               in, out := &in.Properties, &out.Properties
+               *out = make([]PropertySpec, len(*in))
+               copy(*out, *in)
+       }
        return
 }
 
diff --git a/pkg/client/cmd/context_create.go b/pkg/client/cmd/context_create.go
index de2c1a5..75b63d7 100644
--- a/pkg/client/cmd/context_create.go
+++ b/pkg/client/cmd/context_create.go
@@ -89,7 +89,7 @@ func (command *contextCreateCommand) run(cmd *cobra.Command, 
args []string) erro
        for _, item := range command.properties {
                pair := strings.Split(item, "=")
                if len(pair) == 2 {
-                       ctx.Spec.Environment = append(ctx.Spec.Environment, 
v1alpha1.EnvironmentSpec{Name: pair[0], Value: pair[1]})
+                       ctx.Spec.Properties = append(ctx.Spec.Properties, 
v1alpha1.PropertySpec{Name: pair[0], Value: pair[1]})
                }
        }
 
diff --git a/pkg/client/cmd/run.go b/pkg/client/cmd/run.go
index 312f49b..ff66631 100644
--- a/pkg/client/cmd/run.go
+++ b/pkg/client/cmd/run.go
@@ -34,17 +34,9 @@ import (
        "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
-type RunCmdOptions struct {
-       *RootCmdOptions
-       IntegrationContext string
-       Language           string
-       IntegrationName    string
-       Dependencies       []string
-       Wait               bool
-}
-
+// NewCmdRun --
 func NewCmdRun(rootCmdOptions *RootCmdOptions) *cobra.Command {
-       options := RunCmdOptions{
+       options := runCmdOptions{
                RootCmdOptions: rootCmdOptions,
        }
 
@@ -61,11 +53,22 @@ func NewCmdRun(rootCmdOptions *RootCmdOptions) 
*cobra.Command {
        cmd.Flags().StringSliceVarP(&options.Dependencies, "dependency", "d", 
nil, "The integration dependency")
        cmd.Flags().BoolVarP(&options.Wait, "wait", "w", false, "Waits for the 
integration to be running")
        cmd.Flags().StringVarP(&options.IntegrationContext, "context", "x", "", 
"The contex used to run the integration")
+       cmd.Flags().StringSliceVarP(&options.Properties, "property", "p", nil, 
"Add a system property")
 
        return &cmd
 }
 
-func (*RunCmdOptions) validateArgs(cmd *cobra.Command, args []string) error {
+type runCmdOptions struct {
+       *RootCmdOptions
+       IntegrationContext string
+       Language           string
+       IntegrationName    string
+       Dependencies       []string
+       Properties         []string
+       Wait               bool
+}
+
+func (*runCmdOptions) validateArgs(cmd *cobra.Command, args []string) error {
        if len(args) != 1 {
                return errors.New("accepts 1 arg, received " + 
strconv.Itoa(len(args)))
        }
@@ -78,7 +81,7 @@ func (*RunCmdOptions) validateArgs(cmd *cobra.Command, args 
[]string) error {
        return nil
 }
 
-func (o *RunCmdOptions) run(cmd *cobra.Command, args []string) error {
+func (o *runCmdOptions) run(cmd *cobra.Command, args []string) error {
        integration, err := o.createIntegration(cmd, args)
        if err != nil {
                return err
@@ -92,7 +95,7 @@ func (o *RunCmdOptions) run(cmd *cobra.Command, args 
[]string) error {
        return nil
 }
 
-func (o *RunCmdOptions) waitForIntegrationReady(integration 
*v1alpha1.Integration) error {
+func (o *runCmdOptions) waitForIntegrationReady(integration 
*v1alpha1.Integration) error {
        // Block this goroutine until the integration is in a final status
        changes, err := watch.WatchStateChanges(o.Context, integration)
        if err != nil {
@@ -130,7 +133,7 @@ watcher:
        return nil
 }
 
-func (o *RunCmdOptions) createIntegration(cmd *cobra.Command, args []string) 
(*v1alpha1.Integration, error) {
+func (o *runCmdOptions) createIntegration(cmd *cobra.Command, args []string) 
(*v1alpha1.Integration, error) {
        code, err := o.loadCode(args[0])
        if err != nil {
                return nil, err
@@ -157,7 +160,7 @@ func (o *RunCmdOptions) createIntegration(cmd 
*cobra.Command, args []string) (*v
 
        integration := v1alpha1.Integration{
                TypeMeta: v1.TypeMeta{
-                       Kind:       "Integration",
+                       Kind:       v1alpha1.IntegrationKind,
                        APIVersion: v1alpha1.SchemeGroupVersion.String(),
                },
                ObjectMeta: v1.ObjectMeta{
@@ -175,6 +178,14 @@ func (o *RunCmdOptions) createIntegration(cmd 
*cobra.Command, args []string) (*v
                },
        }
 
+       integration.Spec.Properties = make([]v1alpha1.PropertySpec, 0)
+       for _, item := range o.Properties {
+               pair := strings.Split(item, "=")
+               if len(pair) == 2 {
+                       integration.Spec.Properties = 
append(integration.Spec.Properties, v1alpha1.PropertySpec{Name: pair[0], Value: 
pair[1]})
+               }
+       }
+
        existed := false
        err = sdk.Create(&integration)
        if err != nil && k8serrors.IsAlreadyExists(err) {
@@ -200,7 +211,7 @@ func (o *RunCmdOptions) createIntegration(cmd 
*cobra.Command, args []string) (*v
        return &integration, nil
 }
 
-func (*RunCmdOptions) loadCode(fileName string) (string, error) {
+func (*runCmdOptions) loadCode(fileName string) (string, error) {
        content, err := ioutil.ReadFile(fileName)
        if err != nil {
                return "", err
diff --git a/pkg/stub/action/integration/build.go 
b/pkg/stub/action/integration/build.go
index f98930e..ba24358 100644
--- a/pkg/stub/action/integration/build.go
+++ b/pkg/stub/action/integration/build.go
@@ -24,38 +24,37 @@ import (
        "github.com/apache/camel-k/pkg/build"
        "github.com/apache/camel-k/pkg/build/api"
        "github.com/operator-framework/operator-sdk/pkg/sdk"
-       "github.com/pkg/errors"
        "github.com/sirupsen/logrus"
 )
 
-type BuildAction struct {
-       buildManager *build.Manager
-}
-
+// NewBuildAction create an action that handles integration build
 func NewBuildAction(ctx context.Context, namespace string) IntegrationAction {
-       return &BuildAction{
+       return &buildAction{
                buildManager: build.NewManager(ctx, namespace),
        }
 }
 
-func (b *BuildAction) Name() string {
+type buildAction struct {
+       buildManager *build.Manager
+}
+
+func (action *buildAction) Name() string {
        return "build"
 }
 
-func (b *BuildAction) CanHandle(integration *v1alpha1.Integration) bool {
+func (action *buildAction) CanHandle(integration *v1alpha1.Integration) bool {
        return integration.Status.Phase == v1alpha1.IntegrationPhaseBuilding
 }
 
-func (b *BuildAction) Handle(integration *v1alpha1.Integration) error {
-       if integration.Spec.Context != "" {
-               name := integration.Spec.Context
-               ctx := v1alpha1.NewIntegrationContext(integration.Namespace, 
name)
+func (action *buildAction) Handle(integration *v1alpha1.Integration) error {
+       ctx, err := LookupContextForIntegration(integration)
+       if err != nil {
+               //TODO: we may need to add a wait strategy, i.e give up after 
some time
+               return err
+       }
 
-               if err := sdk.Get(&ctx); err != nil {
-                       //TODO: we may need to add a wait strategy, i.e give up 
after some time
-                       return errors.Wrapf(err, "unable to find integration 
context %s, %s", ctx.Name, err)
-               }
 
+       if ctx != nil {
                if ctx.Status.Phase == v1alpha1.IntegrationContextPhaseReady {
                        target := integration.DeepCopy()
                        target.Status.Image = ctx.Status.Image
@@ -70,9 +69,9 @@ func (b *BuildAction) Handle(integration 
*v1alpha1.Integration) error {
                Name:      integration.Name,
                Qualifier: integration.Status.Digest,
        }
-       buildResult := b.buildManager.Get(buildIdentifier)
+       buildResult := action.buildManager.Get(buildIdentifier)
        if buildResult.Status == api.BuildStatusNotRequested {
-               b.buildManager.Start(api.BuildSource{
+               action.buildManager.Start(api.BuildSource{
                        Identifier: buildIdentifier,
                        Code: api.Code{
                                Name:     integration.Spec.Source.Name,
diff --git a/pkg/stub/action/integration/deploy.go 
b/pkg/stub/action/integration/deploy.go
index 3403928..9acd9d8 100644
--- a/pkg/stub/action/integration/deploy.go
+++ b/pkg/stub/action/integration/deploy.go
@@ -29,22 +29,23 @@ import (
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
-type DeployAction struct {
+// NewDeployAction create an action that handles integration deploy
+func NewDeployAction() IntegrationAction {
+       return &deployAction{}
 }
 
-func NewDeployAction() IntegrationAction {
-       return &DeployAction{}
+type deployAction struct {
 }
 
-func (b *DeployAction) Name() string {
+func (action *deployAction) Name() string {
        return "deploy"
 }
 
-func (a *DeployAction) CanHandle(integration *v1alpha1.Integration) bool {
+func (action *deployAction) CanHandle(integration *v1alpha1.Integration) bool {
        return integration.Status.Phase == v1alpha1.IntegrationPhaseDeploying
 }
 
-func (a *DeployAction) Handle(integration *v1alpha1.Integration) error {
+func (action *deployAction) Handle(integration *v1alpha1.Integration) error {
        if err := createOrUpdateConfigMap(integration); err != nil {
                return err
        }
@@ -61,11 +62,20 @@ func (a *DeployAction) Handle(integration 
*v1alpha1.Integration) error {
 //
 // **********************************
 
-func getConfigMapFor(integration *v1alpha1.Integration) *corev1.ConfigMap {
+func getConfigMapFor(integration *v1alpha1.Integration) (*corev1.ConfigMap, 
error) {
        controller := true
        blockOwnerDeletion := true
 
-       return &corev1.ConfigMap{
+       ctx, err := LookupContextForIntegration(integration)
+       if err != nil {
+               return nil, err
+       }
+
+       // combine properties of integration with context, integration
+       // properties have the priority
+       properties := CombinePropertiesAsMap(ctx, integration)
+
+       cm := corev1.ConfigMap{
                TypeMeta: metav1.TypeMeta{
                        Kind:       "ConfigMap",
                        APIVersion: "v1",
@@ -91,14 +101,20 @@ func getConfigMapFor(integration *v1alpha1.Integration) 
*corev1.ConfigMap {
                },
                Data: map[string]string{
                        "integration": integration.Spec.Source.Content,
+                       "properties":  PropertiesString(properties),
                },
        }
+
+       return &cm, nil
 }
 
 func createOrUpdateConfigMap(integration *v1alpha1.Integration) error {
-       cm := getConfigMapFor(integration)
+       cm, err := getConfigMapFor(integration)
+       if err != nil {
+               return err
+       }
 
-       err := sdk.Create(cm)
+       err = sdk.Create(cm)
        if err != nil && k8serrors.IsAlreadyExists(err) {
                err = sdk.Update(cm)
        }
@@ -115,7 +131,7 @@ func createOrUpdateConfigMap(integration 
*v1alpha1.Integration) error {
 //
 // **********************************
 
-func getDeploymentFor(integration *v1alpha1.Integration) *appsv1.Deployment {
+func getDeploymentFor(integration *v1alpha1.Integration) (*appsv1.Deployment, 
error) {
        controller := true
        blockOwnerDeletion := true
        integrationName := strings.TrimPrefix(integration.Spec.Source.Name, "/")
@@ -160,7 +176,7 @@ func getDeploymentFor(integration *v1alpha1.Integration) 
*appsv1.Deployment {
                                                        Image: 
integration.Status.Image,
                                                        VolumeMounts: 
[]corev1.VolumeMount{
                                                                {
-                                                                       Name:   
   "integration",
+                                                                       Name:   
   "integration-volume",
                                                                        
MountPath: "/etc/camel",
                                                                },
                                                        },
@@ -177,12 +193,16 @@ func getDeploymentFor(integration *v1alpha1.Integration) 
*appsv1.Deployment {
                                                                        Name:  
"CAMEL_K_ROUTES_LANGUAGE",
                                                                        Value: 
integration.Spec.Source.Language,
                                                                },
+                                                               {
+                                                                       Name:  
"CAMEL_K_PROPERTIES",
+                                                                       Value: 
"file:/etc/camel/application.properties",
+                                                               },
                                                        },
                                                },
                                        },
                                        Volumes: []corev1.Volume{
                                                {
-                                                       Name: "integration",
+                                                       Name: 
"integration-volume",
                                                        VolumeSource: 
corev1.VolumeSource{
                                                                ConfigMap: 
&corev1.ConfigMapVolumeSource{
                                                                        
LocalObjectReference: corev1.LocalObjectReference{
@@ -192,6 +212,9 @@ func getDeploymentFor(integration *v1alpha1.Integration) 
*appsv1.Deployment {
                                                                                
{
                                                                                
        Key:  "integration",
                                                                                
        Path: integrationName,
+                                                                               
}, {
+                                                                               
        Key:  "properties",
+                                                                               
        Path: "application.properties",
                                                                                
},
                                                                        },
                                                                },
@@ -203,13 +226,16 @@ func getDeploymentFor(integration *v1alpha1.Integration) 
*appsv1.Deployment {
                },
        }
 
-       return &deployment
+       return &deployment, nil
 }
 
 func createOrUpdateDeployment(integration *v1alpha1.Integration) error {
-       deployment := getDeploymentFor(integration)
+       deployment, err := getDeploymentFor(integration)
+       if err != nil {
+               return err
+       }
 
-       err := sdk.Create(deployment)
+       err = sdk.Create(deployment)
        if err != nil && k8serrors.IsAlreadyExists(err) {
                err = sdk.Update(deployment)
        }
diff --git a/pkg/stub/action/integration/util.go 
b/pkg/stub/action/integration/util.go
new file mode 100644
index 0000000..339a996
--- /dev/null
+++ b/pkg/stub/action/integration/util.go
@@ -0,0 +1,56 @@
+package action
+
+import (
+       "fmt"
+
+       "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+       "github.com/operator-framework/operator-sdk/pkg/sdk"
+
+       "github.com/pkg/errors"
+)
+
+// LookupContextForIntegration --
+func LookupContextForIntegration(integration *v1alpha1.Integration) 
(*v1alpha1.IntegrationContext, error) {
+       if integration.Spec.Context != "" {
+               name := integration.Spec.Context
+               ctx := v1alpha1.NewIntegrationContext(integration.Namespace, 
name)
+
+               if err := sdk.Get(&ctx); err != nil {
+                       return nil, errors.Wrapf(err, "unable to find 
integration context %s, %s", ctx.Name, err)
+               }
+
+               return &ctx, nil
+       }
+
+       return nil, nil
+}
+
+// PropertiesString --
+func PropertiesString(m map[string]string) string {
+       properties := ""
+       for k, v := range m {
+               properties += fmt.Sprintf("%s=%s\n", k, v)
+       }
+
+       return properties
+}
+
+// CombinePropertiesAsMap --
+func CombinePropertiesAsMap(context *v1alpha1.IntegrationContext, integration 
*v1alpha1.Integration) map[string]string {
+       properties := make(map[string]string)
+       if context != nil {
+               // Add context properties first so integrations can
+               // override it
+               for _, p := range context.Spec.Properties {
+                       properties[p.Name] = p.Value
+               }
+       }
+
+       if integration != nil {
+               for _, p := range integration.Spec.Properties {
+                       properties[p.Name] = p.Value
+               }
+       }
+
+       return properties
+}
diff --git a/runtime/examples/props.js b/runtime/examples/props.js
new file mode 100644
index 0000000..a89b6ae
--- /dev/null
+++ b/runtime/examples/props.js
@@ -0,0 +1,9 @@
+//
+// To run this integrations use:
+//
+//     kamel run -p my.message=test-props runtime/examples/props.js
+//
+
+from('timer:props?period=1s')
+    .routeId('props')
+    .log('{{my.message}}')
\ No newline at end of file
diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Application.java 
b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Application.java
index bec284f..8a394ea 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Application.java
+++ b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Application.java
@@ -25,6 +25,7 @@ public class Application {
     public static void main(String[] args) throws Exception {
         final String resource = System.getenv(Routes.ENV_CAMEL_K_ROUTES_URI);
         final String language = 
System.getenv(Routes.ENV_CAMEL_K_ROUTES_LANGUAGE);
+        final String properties = System.getenv(Routes.ENV_CAMEL_K_PROPERTIES);
 
         if (ObjectHelper.isEmpty(resource)) {
             throw new IllegalStateException("No valid resource found in " + 
Routes.ENV_CAMEL_K_ROUTES_URI + " environment variable");
@@ -38,6 +39,12 @@ public class Application {
         }
 
         Main main = new Main();
+
+        // Load properties
+        if (ObjectHelper.isNotEmpty(properties)) {
+            main.setPropertyPlaceholderLocations(properties);
+        }
+
         main.addRouteBuilder(routes);
         main.run();
     }
diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Routes.java 
b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Routes.java
index b2c87d4..308b838 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Routes.java
+++ b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Routes.java
@@ -27,6 +27,7 @@ import org.apache.commons.lang3.StringUtils;
 public final class Routes {
     public static final String ENV_CAMEL_K_ROUTES_URI = "CAMEL_K_ROUTES_URI";
     public static final String ENV_CAMEL_K_ROUTES_LANGUAGE = 
"CAMEL_K_ROUTES_LANGUAGE";
+    public static final String ENV_CAMEL_K_PROPERTIES = "CAMEL_K_PROPERTIES";
     public static final String SCHEME_CLASSPATH = "classpath:";
     public static final String SCHEME_FILE = "file:";
 

Reply via email to