You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by nf...@apache.org on 2018/11/26 10:27:42 UTC

[camel-k] branch master updated (ba28129 -> 03bcfd8)

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

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


    from ba28129  initial support for custom maven repositories
     new e096565  initial support for spring boot
     new 965c71b  spring-boot: fix issue with best base image selection
     new 03bcfd8  fix issue with owned resources

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 ... platform-integration-context-spring-boot.yaml} |   9 +-
 deploy/resources.go                                |  22 +++
 pkg/apis/camel/v1alpha1/types.go                   |   1 +
 pkg/builder/builder.go                             |  11 +-
 pkg/builder/builder_steps.go                       |  46 +++---
 pkg/builder/builder_types.go                       |  29 ++--
 .../springboot/dependencies.go}                    |  25 +--
 pkg/builder/springboot/generator.go                | 161 +++++++++++++++++++
 .../springboot/initializer.go}                     |  18 ++-
 pkg/stub/action/integration/build.go               |   1 +
 pkg/stub/action/platform/create.go                 |   1 +
 pkg/trait/catalog.go                               |  39 +++--
 pkg/trait/deployment.go                            |   5 +
 pkg/trait/springboot.go                            | 103 +++++++++++++
 pkg/trait/trait.go                                 |   1 +
 pkg/trait/types.go                                 |   1 +
 pkg/util/maven/maven_project.go                    |  24 ++-
 pkg/util/tar/appender.go                           |  32 ++++
 runtime/examples/hello.xml                         |   6 +-
 .../org/apache/camel/k/groovy/LoaderTest.groovy    |   5 +-
 .../java/org/apache/camel/k/jvm/Application.java   |   4 -
 .../main/java/org/apache/camel/k/jvm/Runtime.java  |   4 +-
 .../org/apache/camel/k/jvm/RuntimeRegistry.java    |  83 +---------
 .../org/apache/camel/k/jvm/RuntimeSupport.java     |   9 +-
 ...imeRegistry.java => SimpleRuntimeRegistry.java} |   4 +-
 .../org/apache/camel/k/jvm/RoutesLoadersTest.java  |  10 +-
 .../kotlin/org/apache/camel/k/kotlin/LoaderTest.kt |   4 +-
 runtime/pom.xml                                    |   2 +
 runtime/{kotlin => spring-boot-example}/.gitignore |   0
 runtime/spring-boot-example/pom.xml                |  90 +++++++++++
 runtime/{kotlin => spring-boot}/.gitignore         |   0
 runtime/{groovy => spring-boot}/pom.xml            |  65 ++++----
 .../apache/camel/k/spring/boot/Application.java    | 170 +++++++++++++++++++++
 test/build_manager_integration_test.go             |   1 -
 34 files changed, 784 insertions(+), 202 deletions(-)
 copy deploy/{platform-integration-context-jvm.yaml => platform-integration-context-spring-boot.yaml} (68%)
 copy pkg/{client/cmd/context.go => builder/springboot/dependencies.go} (65%)
 create mode 100644 pkg/builder/springboot/generator.go
 copy pkg/{util/camel/catalog_test.go => builder/springboot/initializer.go} (69%)
 create mode 100644 pkg/trait/springboot.go
 copy runtime/jvm/src/main/java/org/apache/camel/k/jvm/{RuntimeRegistry.java => SimpleRuntimeRegistry.java} (96%)
 copy runtime/{kotlin => spring-boot-example}/.gitignore (100%)
 create mode 100644 runtime/spring-boot-example/pom.xml
 copy runtime/{kotlin => spring-boot}/.gitignore (100%)
 copy runtime/{groovy => spring-boot}/pom.xml (69%)
 create mode 100644 runtime/spring-boot/src/main/java/org/apache/camel/k/spring/boot/Application.java


[camel-k] 01/03: initial support for spring boot

Posted by nf...@apache.org.
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 e0965651f0b54b80629f93c9b8d0b5da2c74deaf
Author: lburgazzoli <lb...@gmail.com>
AuthorDate: Fri Nov 23 22:04:42 2018 +0100

    initial support for spring boot
---
 pkg/apis/camel/v1alpha1/types.go                   |   1 +
 pkg/builder/builder.go                             |  11 +-
 pkg/builder/builder_steps.go                       |  40 +++--
 pkg/builder/builder_types.go                       |  29 ++--
 pkg/builder/springboot/dependencies.go             |  37 +++++
 pkg/builder/springboot/generator.go                | 161 +++++++++++++++++++
 pkg/builder/springboot/initializer.go              |  34 +++++
 pkg/stub/action/integration/build.go               |   1 +
 pkg/trait/catalog.go                               |  33 +++-
 pkg/trait/deployment.go                            |   5 +
 pkg/trait/springboot.go                            | 103 +++++++++++++
 pkg/trait/trait.go                                 |   1 +
 pkg/trait/types.go                                 |   1 +
 pkg/util/maven/maven_project.go                    |  24 ++-
 pkg/util/tar/appender.go                           |  32 ++++
 runtime/examples/hello.xml                         |   6 +-
 .../org/apache/camel/k/groovy/LoaderTest.groovy    |   5 +-
 .../java/org/apache/camel/k/jvm/Application.java   |   4 -
 .../main/java/org/apache/camel/k/jvm/Runtime.java  |   4 +-
 .../org/apache/camel/k/jvm/RuntimeRegistry.java    |  83 +---------
 .../org/apache/camel/k/jvm/RuntimeSupport.java     |   9 +-
 ...imeRegistry.java => SimpleRuntimeRegistry.java} |   4 +-
 .../org/apache/camel/k/jvm/RoutesLoadersTest.java  |  10 +-
 .../kotlin/org/apache/camel/k/kotlin/LoaderTest.kt |   4 +-
 runtime/pom.xml                                    |   2 +
 runtime/spring-boot-example/.gitignore             |  10 ++
 runtime/spring-boot-example/pom.xml                |  90 +++++++++++
 runtime/spring-boot/.gitignore                     |  10 ++
 runtime/spring-boot/pom.xml                        | 123 +++++++++++++++
 .../apache/camel/k/spring/boot/Application.java    | 170 +++++++++++++++++++++
 test/build_manager_integration_test.go             |   1 -
 31 files changed, 904 insertions(+), 144 deletions(-)

diff --git a/pkg/apis/camel/v1alpha1/types.go b/pkg/apis/camel/v1alpha1/types.go
index acb2270..901c001 100644
--- a/pkg/apis/camel/v1alpha1/types.go
+++ b/pkg/apis/camel/v1alpha1/types.go
@@ -286,4 +286,5 @@ const (
 type Artifact struct {
 	ID       string `json:"id" yaml:"id"`
 	Location string `json:"location,omitempty" yaml:"location,omitempty"`
+	Target   string `json:"target,omitempty" yaml:"target,omitempty"`
 }
diff --git a/pkg/builder/builder.go b/pkg/builder/builder.go
index 1e120f6..a04f3d8 100644
--- a/pkg/builder/builder.go
+++ b/pkg/builder/builder.go
@@ -141,10 +141,12 @@ func (b *defaultBuilder) submit(request Request) {
 	b.request.Store(request.Meta.Name, r)
 
 	c := Context{
-		C:         b.ctx,
-		Path:      builderPath,
-		Namespace: b.namespace,
-		Request:   request,
+		C:                b.ctx,
+		Path:             builderPath,
+		Namespace:        b.namespace,
+		Request:          request,
+		ComputeClasspath: true,
+		Image:            "fabric8/s2i-java:2.3", // TODO: externalize
 	}
 
 	// Sort steps by phase
@@ -152,6 +154,7 @@ func (b *defaultBuilder) submit(request Request) {
 		return request.Steps[i].Phase() < request.Steps[j].Phase()
 	})
 
+	b.log.Infof("steps: %v", request.Steps)
 	for _, step := range request.Steps {
 		if c.Error != nil {
 			break
diff --git a/pkg/builder/builder_steps.go b/pkg/builder/builder_steps.go
index b29e81e..f0eaa58 100644
--- a/pkg/builder/builder_steps.go
+++ b/pkg/builder/builder_steps.go
@@ -154,6 +154,7 @@ func ComputeDependencies(ctx *Context) error {
 		ctx.Artifacts = append(ctx.Artifacts, v1alpha1.Artifact{
 			ID:       e.ID,
 			Location: e.Location,
+			Target:   "dependencies",
 		})
 	}
 
@@ -166,7 +167,7 @@ type ArtifactsSelector func([]v1alpha1.Artifact) (string, []v1alpha1.Artifact, e
 // StandardPackager --
 func StandardPackager(ctx *Context) error {
 	return packager(ctx, func(libraries []v1alpha1.Artifact) (string, []v1alpha1.Artifact, error) {
-		return "fabric8/s2i-java:2.3", libraries, nil
+		return ctx.Image, libraries, nil
 	})
 }
 
@@ -191,15 +192,19 @@ func IncrementalPackager(ctx *Context) error {
 		}
 
 		// return default selection
-		return "fabric8/s2i-java:2.3", libraries, nil
+		return ctx.Image, libraries, nil
 	})
 }
 
+// ClassPathPackager --
 func packager(ctx *Context, selector ArtifactsSelector) error {
 	imageName, selectedArtifacts, err := selector(ctx.Artifacts)
 	if err != nil {
 		return err
 	}
+	if imageName == "" {
+		imageName = ctx.Image
+	}
 
 	tarFileName := path.Join(ctx.Path, "package", "occi.tar")
 	tarFileDir := path.Dir(tarFileName)
@@ -215,38 +220,43 @@ func packager(ctx *Context, selector ArtifactsSelector) error {
 	}
 	defer tarAppender.Close()
 
-	tarDir := "dependencies/"
 	for _, entry := range selectedArtifacts {
 		gav, err := maven.ParseGAV(entry.ID)
 		if err != nil {
 			return err
 		}
 
-		tarPath := path.Join(tarDir, gav.GroupID)
-		_, err = tarAppender.AddFile(entry.Location, tarPath)
+		_, fileName := path.Split(entry.Location)
+
+		_, err = tarAppender.AddFileWithName(gav.GroupID+"."+fileName, entry.Location, entry.Target)
 		if err != nil {
 			return err
 		}
 	}
 
-	cp := ""
-	for _, entry := range ctx.Artifacts {
-		gav, err := maven.ParseGAV(entry.ID)
+	if ctx.ComputeClasspath {
+		cp := ""
+		for _, entry := range ctx.Artifacts {
+			gav, err := maven.ParseGAV(entry.ID)
+			if err != nil {
+				return nil
+			}
+			_, fileName := path.Split(entry.Location)
+			cp += path.Join(entry.Target, gav.GroupID+"."+fileName) + "\n"
+		}
+
+		err = tarAppender.AppendData([]byte(cp), "classpath")
 		if err != nil {
-			return nil
+			return err
 		}
-		tarPath := path.Join(tarDir, gav.GroupID)
-		_, fileName := path.Split(entry.Location)
-		fileName = path.Join(tarPath, fileName)
-		cp += fileName + "\n"
 	}
 
-	err = tarAppender.AppendData([]byte(cp), "classpath")
+	err = tarAppender.AppendData([]byte(""), "marker")
 	if err != nil {
 		return err
 	}
 
-	ctx.Image = imageName //"fabric8/s2i-java:2.3"
+	ctx.Image = imageName
 	ctx.Archive = tarFileName
 
 	return nil
diff --git a/pkg/builder/builder_types.go b/pkg/builder/builder_types.go
index e23dfc0..a81f879 100644
--- a/pkg/builder/builder_types.go
+++ b/pkg/builder/builder_types.go
@@ -31,6 +31,8 @@ import (
 )
 
 const (
+	// IntiPhase --
+	IntiPhase int32 = 0
 	// ProjectGenerationPhase --
 	ProjectGenerationPhase int32 = 10
 	// ProjectBuildPhase --
@@ -59,7 +61,7 @@ type Step interface {
 type stepWrapper struct {
 	id    string
 	phase int32
-	task  func(*Context) error
+	task  StepTask
 }
 
 func (s *stepWrapper) String() string {
@@ -78,8 +80,11 @@ func (s *stepWrapper) Execute(ctx *Context) error {
 	return s.task(ctx)
 }
 
+// StepTask ---
+type StepTask func(*Context) error
+
 // NewStep --
-func NewStep(ID string, phase int32, task func(*Context) error) Step {
+func NewStep(ID string, phase int32, task StepTask) Step {
 	s := stepWrapper{
 		id:    ID,
 		phase: phase,
@@ -123,15 +128,17 @@ type Result struct {
 
 // Context --
 type Context struct {
-	C         context.Context
-	Request   Request
-	Image     string
-	Error     error
-	Namespace string
-	Project   maven.Project
-	Path      string
-	Artifacts []v1alpha1.Artifact
-	Archive   string
+	C                context.Context
+	Request          Request
+	Image            string
+	Error            error
+	Namespace        string
+	Project          maven.Project
+	Path             string
+	Artifacts        []v1alpha1.Artifact
+	Archive          string
+	ComputeClasspath bool
+	MainClass        string
 }
 
 // PublishedImage --
diff --git a/pkg/builder/springboot/dependencies.go b/pkg/builder/springboot/dependencies.go
new file mode 100644
index 0000000..6c3aec1
--- /dev/null
+++ b/pkg/builder/springboot/dependencies.go
@@ -0,0 +1,37 @@
+/*
+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 springboot
+
+import (
+	"strings"
+
+	"github.com/apache/camel-k/pkg/builder"
+)
+
+// ComputeDependencies --
+func ComputeDependencies(ctx *builder.Context) error {
+	for i := 0; i < len(ctx.Artifacts); i++ {
+		if strings.HasPrefix(ctx.Artifacts[i].ID, "org.apache.camel.k:camel-k-runtime-spring-boot:") {
+			// Don't set a target so the jar will be copied to the
+			// deployment root
+			ctx.Artifacts[i].Target = ""
+		}
+	}
+
+	return nil
+}
diff --git a/pkg/builder/springboot/generator.go b/pkg/builder/springboot/generator.go
new file mode 100644
index 0000000..b812046
--- /dev/null
+++ b/pkg/builder/springboot/generator.go
@@ -0,0 +1,161 @@
+/*
+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 springboot
+
+import (
+	"encoding/xml"
+	"fmt"
+	"strings"
+
+	"github.com/apache/camel-k/pkg/builder"
+	"github.com/apache/camel-k/pkg/util/maven"
+	"github.com/apache/camel-k/version"
+)
+
+// GenerateProject --
+func GenerateProject(ctx *builder.Context) error {
+	ctx.Project = maven.Project{
+		XMLName:           xml.Name{Local: "project"},
+		XMLNs:             "http://maven.apache.org/POM/4.0.0",
+		XMLNsXsi:          "http://www.w3.org/2001/XMLSchema-instance",
+		XsiSchemaLocation: "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd",
+		ModelVersion:      "4.0.0",
+		GroupID:           "org.apache.camel.k.integration",
+		ArtifactID:        "camel-k-integration",
+		Version:           version.Version,
+		DependencyManagement: maven.DependencyManagement{
+			Dependencies: maven.Dependencies{
+				Dependencies: []maven.Dependency{
+					{
+						//TODO: camel version should be retrieved from an external request or provided as static version
+						GroupID:    "org.apache.camel",
+						ArtifactID: "camel-bom",
+						Version:    "2.22.2",
+						Type:       "pom",
+						Scope:      "import",
+					},
+				},
+			},
+		},
+		Dependencies: maven.Dependencies{
+			Dependencies: make([]maven.Dependency, 0),
+		},
+	}
+
+	//
+	// set-up dependencies
+	//
+
+	deps := &ctx.Project.Dependencies
+
+	//
+	// common
+	//
+
+	deps.Add(maven.Dependency{
+		GroupID:    "org.apache.camel.k",
+		ArtifactID: "camel-k-runtime-spring-boot",
+		Version:    version.Version,
+		Exclusions: &maven.Exclusions{
+			Exclusions: []maven.Exclusion{
+				{
+					GroupID:    "org.apache.camel",
+					ArtifactID: "*",
+				},
+				{
+					GroupID:    "org.apache.camel.k",
+					ArtifactID: "*",
+				},
+				{
+					GroupID:    "org.springframework.boot",
+					ArtifactID: "*",
+				},
+			},
+		},
+	})
+
+	//
+	// others
+	//
+
+	for _, d := range ctx.Request.Dependencies {
+		if strings.HasPrefix(d, "camel:") {
+			if d == "camel:core" {
+				continue
+			}
+
+			artifactID := strings.TrimPrefix(d, "camel:")
+
+			if !strings.HasPrefix(artifactID, "camel-") {
+				artifactID = "camel-" + artifactID
+			}
+
+			deps.Add(maven.Dependency{
+				GroupID:    "org.apache.camel",
+				ArtifactID: artifactID + "-starter",
+				Version:    "2.22.2",
+				Exclusions: &maven.Exclusions{
+					Exclusions: []maven.Exclusion{
+						{
+							GroupID:    "com.sun.xml.bind",
+							ArtifactID: "*",
+						},
+						{
+							GroupID:    "org.apache.camel",
+							ArtifactID: "camel-core",
+						},
+						{
+							GroupID:    "org.apache.camel",
+							ArtifactID: "camel-core-starter",
+						},
+						{
+							GroupID:    "org.apache.camel",
+							ArtifactID: "camel-spring-boot-starter",
+						},
+						{
+							GroupID:    "org.springframework.boot",
+							ArtifactID: "spring-boot-starter",
+						},
+					},
+				},
+			})
+		} else if strings.HasPrefix(d, "mvn:") {
+			mid := strings.TrimPrefix(d, "mvn:")
+			gav := strings.Replace(mid, "/", ":", -1)
+
+			deps.AddEncodedGAV(gav)
+		} else if strings.HasPrefix(d, "runtime:") {
+			if d == "runtime:jvm" {
+				// common
+				continue
+			}
+			if d == "runtime:spring-boot" {
+				// common
+				continue
+			}
+
+			artifactID := strings.Replace(d, "runtime:", "camel-k-runtime-", 1)
+
+			deps.AddGAV("org.apache.camel.k", artifactID, version.Version)
+		} else {
+			return fmt.Errorf("unknown dependency type: %s", d)
+		}
+	}
+
+	return nil
+}
diff --git a/pkg/builder/springboot/initializer.go b/pkg/builder/springboot/initializer.go
new file mode 100644
index 0000000..de40ea6
--- /dev/null
+++ b/pkg/builder/springboot/initializer.go
@@ -0,0 +1,34 @@
+/*
+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 springboot
+
+import (
+	"github.com/apache/camel-k/pkg/builder"
+)
+
+// Initialize --
+func Initialize(ctx *builder.Context) error {
+	// set the base image
+	//ctx.Image = "kamel-k/s2i-boot:" + version.Version
+
+	// no need to compute classpath as we do use spring boot own
+	// loader: PropertiesLauncher
+	ctx.ComputeClasspath = false
+
+	return nil
+}
diff --git a/pkg/stub/action/integration/build.go b/pkg/stub/action/integration/build.go
index 02387ce..e4660c8 100644
--- a/pkg/stub/action/integration/build.go
+++ b/pkg/stub/action/integration/build.go
@@ -119,6 +119,7 @@ func (action *buildAction) Handle(integration *v1alpha1.Integration) error {
 	platformCtx.Spec = v1alpha1.IntegrationContextSpec{
 		Dependencies: integration.Spec.Dependencies,
 		Repositories: integration.Spec.Repositories,
+		Traits:       integration.Spec.Traits,
 	}
 
 	if err := sdk.Create(&platformCtx); err != nil {
diff --git a/pkg/trait/catalog.go b/pkg/trait/catalog.go
index 9db06ab..3eba945 100644
--- a/pkg/trait/catalog.go
+++ b/pkg/trait/catalog.go
@@ -21,6 +21,8 @@ import (
 	"reflect"
 	"strings"
 
+	"github.com/sirupsen/logrus"
+
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 	"github.com/apache/camel-k/pkg/platform"
 	"github.com/fatih/structs"
@@ -36,6 +38,7 @@ type Catalog struct {
 	tIngress      Trait
 	tOwner        Trait
 	tBuilder      Trait
+	tSpringBoot   Trait
 }
 
 // NewCatalog creates a new trait Catalog
@@ -49,6 +52,7 @@ func NewCatalog() *Catalog {
 		tIngress:      newIngressTrait(),
 		tOwner:        newOwnerTrait(),
 		tBuilder:      newBuilderTrait(),
+		tSpringBoot:   newSpringBootTrait(),
 	}
 }
 
@@ -62,6 +66,7 @@ func (c *Catalog) allTraits() []Trait {
 		c.tIngress,
 		c.tOwner,
 		c.tBuilder,
+		c.tSpringBoot,
 	}
 }
 
@@ -78,20 +83,22 @@ func (c *Catalog) traitsFor(environment *Environment) []Trait {
 	case v1alpha1.TraitProfileOpenShift:
 		return []Trait{
 			c.tDependencies,
-			c.tDeployment,
 			c.tService,
 			c.tRoute,
 			c.tOwner,
 			c.tBuilder,
+			c.tSpringBoot,
+			c.tDeployment,
 		}
 	case v1alpha1.TraitProfileKubernetes:
 		return []Trait{
 			c.tDependencies,
-			c.tDeployment,
 			c.tService,
 			c.tIngress,
 			c.tOwner,
 			c.tBuilder,
+			c.tSpringBoot,
+			c.tDeployment,
 		}
 	case v1alpha1.TraitProfileKnative:
 		return []Trait{
@@ -99,6 +106,7 @@ func (c *Catalog) traitsFor(environment *Environment) []Trait {
 			c.tKnative,
 			c.tOwner,
 			c.tBuilder,
+			c.tSpringBoot,
 		}
 	}
 
@@ -108,6 +116,7 @@ func (c *Catalog) traitsFor(environment *Environment) []Trait {
 func (c *Catalog) apply(environment *Environment) error {
 	c.configure(environment)
 	traits := c.traitsFor(environment)
+
 	for _, trait := range traits {
 		if !trait.appliesTo(environment) {
 			continue
@@ -119,6 +128,7 @@ func (c *Catalog) apply(environment *Environment) error {
 			}
 		}
 		if trait.IsEnabled() {
+			logrus.Infof("apply trait: %s", trait.ID())
 			if err := trait.apply(environment); err != nil {
 				return err
 			}
@@ -139,13 +149,20 @@ func (c *Catalog) GetTrait(id string) Trait {
 }
 
 func (c *Catalog) configure(env *Environment) {
-	if env.Integration == nil || env.Integration.Spec.Traits == nil {
-		return
+	if env.Context != nil && env.Context.Spec.Traits != nil {
+		for id, traitSpec := range env.Context.Spec.Traits {
+			catTrait := c.GetTrait(id)
+			if catTrait != nil {
+				traitSpec.Decode(catTrait)
+			}
+		}
 	}
-	for id, traitSpec := range env.Integration.Spec.Traits {
-		catTrait := c.GetTrait(id)
-		if catTrait != nil {
-			traitSpec.Decode(catTrait)
+	if env.Integration != nil && env.Integration.Spec.Traits != nil {
+		for id, traitSpec := range env.Integration.Spec.Traits {
+			catTrait := c.GetTrait(id)
+			if catTrait != nil {
+				traitSpec.Decode(catTrait)
+			}
 		}
 	}
 }
diff --git a/pkg/trait/deployment.go b/pkg/trait/deployment.go
index bc3f121..8411e3a 100644
--- a/pkg/trait/deployment.go
+++ b/pkg/trait/deployment.go
@@ -146,6 +146,11 @@ func getDeploymentFor(e *Environment) *appsv1.Deployment {
 	// optimizations
 	environment["AB_JOLOKIA_OFF"] = "true"
 
+	// add env vars from traits
+	for k, v := range e.EnvVars {
+		environment[k] = v
+	}
+
 	labels := map[string]string{
 		"camel.apache.org/integration": e.Integration.Name,
 	}
diff --git a/pkg/trait/springboot.go b/pkg/trait/springboot.go
new file mode 100644
index 0000000..7069d67
--- /dev/null
+++ b/pkg/trait/springboot.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 trait
+
+import (
+	"sort"
+
+	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+	"github.com/apache/camel-k/pkg/builder"
+	"github.com/apache/camel-k/pkg/builder/springboot"
+	"github.com/apache/camel-k/pkg/util"
+)
+
+type springBootTrait struct {
+	BaseTrait `property:",squash"`
+}
+
+func newSpringBootTrait() *springBootTrait {
+	return &springBootTrait{
+		BaseTrait: newBaseTrait("springboot"),
+	}
+}
+
+// IsAuto determines if we should apply automatic configuration
+func (trait *springBootTrait) IsAuto() bool {
+	return false
+}
+
+// IsEnabled is used to determine if the trait needs to be executed
+func (trait *springBootTrait) IsEnabled() bool {
+	if trait.Enabled == nil {
+		return false
+	}
+	return *trait.Enabled
+}
+
+func (trait *springBootTrait) appliesTo(e *Environment) bool {
+	if e.Context != nil && e.Context.Status.Phase == v1alpha1.IntegrationContextPhaseBuilding {
+		return true
+	}
+	if e.Integration != nil && e.Integration.Status.Phase == v1alpha1.IntegrationPhaseDeploying {
+		return true
+	}
+	if e.Integration != nil && e.Integration.Status.Phase == "" {
+		return true
+	}
+
+	return false
+}
+
+func (trait *springBootTrait) apply(e *Environment) error {
+
+	//
+	// Integration
+	//
+
+	if e.Integration != nil && e.Integration.Status.Phase == "" {
+		util.StringSliceUniqueAdd(&e.Integration.Spec.Dependencies, "runtime:spring-boot")
+
+		// sort the dependencies to get always the same list if they don't change
+		sort.Strings(e.Integration.Spec.Dependencies)
+	}
+
+	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/"
+	}
+
+	//
+	// Integration Context
+	//
+
+	if e.Context != nil && e.Context.Status.Phase == v1alpha1.IntegrationContextPhaseBuilding {
+		// add custom initialization logic
+		e.Steps = append(e.Steps, builder.NewStep("initialize/spring-boot", builder.IntiPhase, springboot.Initialize))
+		e.Steps = append(e.Steps, builder.NewStep("build/compute-boot-dependencies", builder.ProjectBuildPhase+1, springboot.ComputeDependencies))
+
+		// replace project generator
+		for i := 0; i < len(e.Steps); i++ {
+			if e.Steps[i].Phase() == builder.ProjectGenerationPhase {
+				e.Steps[i] = builder.NewStep("generate/spring-boot", builder.ProjectGenerationPhase, springboot.GenerateProject)
+			}
+		}
+	}
+
+	return nil
+}
diff --git a/pkg/trait/trait.go b/pkg/trait/trait.go
index 1ab5f9e..042b4d5 100644
--- a/pkg/trait/trait.go
+++ b/pkg/trait/trait.go
@@ -72,5 +72,6 @@ func newEnvironment(integration *v1alpha1.Integration, ctx *v1alpha1.Integration
 		Integration:    integration,
 		ExecutedTraits: make([]ID, 0),
 		Resources:      kubernetes.NewCollection(),
+		EnvVars:        make(map[string]string),
 	}, nil
 }
diff --git a/pkg/trait/types.go b/pkg/trait/types.go
index 8c1d09a..6b87029 100644
--- a/pkg/trait/types.go
+++ b/pkg/trait/types.go
@@ -100,6 +100,7 @@ type Environment struct {
 	Resources      *kubernetes.Collection
 	Steps          []builder.Step
 	ExecutedTraits []ID
+	EnvVars        map[string]string
 }
 
 // IntegrationInPhase --
diff --git a/pkg/util/maven/maven_project.go b/pkg/util/maven/maven_project.go
index 5c7ec5d..57603a1 100644
--- a/pkg/util/maven/maven_project.go
+++ b/pkg/util/maven/maven_project.go
@@ -73,14 +73,26 @@ func (deps *Dependencies) AddEncodedGAV(gav string) {
 	}
 }
 
-// Dependency represent a maven's dependency
-type Dependency struct {
+// Exclusion represent a maven's dependency exlucsion
+type Exclusion struct {
 	GroupID    string `xml:"groupId"`
 	ArtifactID string `xml:"artifactId"`
-	Version    string `xml:"version,omitempty"`
-	Type       string `xml:"type,omitempty"`
-	Classifier string `xml:"classifier,omitempty"`
-	Scope      string `xml:"scope,omitempty"`
+}
+
+// Exclusions --
+type Exclusions struct {
+	Exclusions []Exclusion `xml:"exclusion"`
+}
+
+// Dependency represent a maven's dependency
+type Dependency struct {
+	GroupID    string      `xml:"groupId"`
+	ArtifactID string      `xml:"artifactId"`
+	Version    string      `xml:"version,omitempty"`
+	Type       string      `xml:"type,omitempty"`
+	Classifier string      `xml:"classifier,omitempty"`
+	Scope      string      `xml:"scope,omitempty"`
+	Exclusions *Exclusions `xml:"exclusions,omitempty"`
 }
 
 // NewDependency create an new dependency from the given gav info
diff --git a/pkg/util/tar/appender.go b/pkg/util/tar/appender.go
index 965bbc7..7ffbfad 100644
--- a/pkg/util/tar/appender.go
+++ b/pkg/util/tar/appender.go
@@ -92,6 +92,38 @@ func (t *Appender) AddFile(filePath string, tarDir string) (string, error) {
 	return fileName, nil
 }
 
+// AddFileWithName adds a file content to the tarDir, using the fiven file name.
+// It returns the full path of the file inside the tar.
+func (t *Appender) AddFileWithName(fileName string, filePath string, tarDir string) (string, error) {
+	info, err := os.Stat(filePath)
+	if err != nil {
+		return "", err
+	}
+	if tarDir != "" {
+		fileName = path.Join(tarDir, fileName)
+	}
+
+	t.writer.WriteHeader(&atar.Header{
+		Name:    fileName,
+		Size:    info.Size(),
+		Mode:    int64(info.Mode()),
+		ModTime: info.ModTime(),
+	})
+
+	file, err := os.Open(filePath)
+	if err != nil {
+		return "", err
+	}
+	defer file.Close()
+
+	_, err = io.Copy(t.writer, file)
+	if err != nil {
+		return "", errors.Wrap(err, "cannot add file to the tar archive")
+	}
+
+	return fileName, nil
+}
+
 // AppendData appends the given content to a file inside the tar, creating it if it does not exist
 func (t *Appender) AppendData(data []byte, tarPath string) error {
 	t.writer.WriteHeader(&atar.Header{
diff --git a/runtime/examples/hello.xml b/runtime/examples/hello.xml
index ff9bc8d..4c0535a 100644
--- a/runtime/examples/hello.xml
+++ b/runtime/examples/hello.xml
@@ -14,8 +14,10 @@
     limitations under the License.
 -->
 <routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-              xmlns="http://camel.apache.org/schema/spring"
-              xsi:schemaLocation="http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
+        xmlns="http://camel.apache.org/schema/spring"
+        xsi:schemaLocation="
+            http://camel.apache.org/schema/spring
+            http://camel.apache.org/schema/spring/camel-spring.xsd">
 
     <route id="hello">
         <from uri="timer:hello?period=3s"/>
diff --git a/runtime/groovy/src/test/groovy/org/apache/camel/k/groovy/LoaderTest.groovy b/runtime/groovy/src/test/groovy/org/apache/camel/k/groovy/LoaderTest.groovy
index 16b4f0f..b7c7c95 100644
--- a/runtime/groovy/src/test/groovy/org/apache/camel/k/groovy/LoaderTest.groovy
+++ b/runtime/groovy/src/test/groovy/org/apache/camel/k/groovy/LoaderTest.groovy
@@ -16,9 +16,8 @@
  */
 package org.apache.camel.k.groovy
 
-
 import org.apache.camel.k.jvm.RoutesLoaders
-import org.apache.camel.k.jvm.RuntimeRegistry
+import org.apache.camel.k.jvm.SimpleRuntimeRegistry
 import org.apache.camel.model.ToDefinition
 import spock.lang.Specification
 
@@ -30,7 +29,7 @@ class LoaderTest extends Specification {
 
         when:
             def loader = RoutesLoaders.loaderFor(resource, null)
-            def builder = loader.load(new RuntimeRegistry(), resource)
+            def builder = loader.load(new SimpleRuntimeRegistry(), resource)
 
         then:
             loader instanceof GroovyRoutesLoader
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 d26ddef..69cbc96 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
@@ -21,12 +21,8 @@ import org.apache.camel.Component;
 import org.apache.camel.main.MainListenerSupport;
 import org.apache.camel.support.LifecycleStrategySupport;
 import org.apache.camel.util.ObjectHelper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 public class Application {
-    private static final Logger LOGGER = LoggerFactory.getLogger(Application.class);
-
     static {
         //
         // Load properties as system properties so they are accessible through
diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Runtime.java b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Runtime.java
index d4a755c..ffa71a0 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Runtime.java
+++ b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Runtime.java
@@ -36,7 +36,7 @@ public final class Runtime extends MainSupport {
     private static final Logger LOGGER = LoggerFactory.getLogger(Runtime.class);
 
     private final ConcurrentMap<String, CamelContext> contextMap;
-    private final RuntimeRegistry registry = new RuntimeRegistry();
+    private final RuntimeRegistry registry = new SimpleRuntimeRegistry();
 
     public Runtime() {
         this.contextMap = new ConcurrentHashMap<>();
@@ -53,7 +53,7 @@ public final class Runtime extends MainSupport {
             final RoutesLoader loader = RoutesLoaders.loaderFor(location, language);
             final RouteBuilder builder = loader.load(registry, location);
 
-            if (routes == null) {
+            if (builder == null) {
                 throw new IllegalStateException("Unable to load route from: " + route);
             }
 
diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeRegistry.java b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeRegistry.java
index 8fc7589..3b41e2b 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeRegistry.java
+++ b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeRegistry.java
@@ -16,85 +16,12 @@
  */
 package org.apache.camel.k.jvm;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.stream.Collectors;
-
-import org.apache.camel.NoSuchBeanException;
 import org.apache.camel.spi.Registry;
 
-public class RuntimeRegistry implements Registry {
-    private final ConcurrentMap<String, Object> registry;
-
-    public RuntimeRegistry() {
-        this.registry = new ConcurrentHashMap<>();
-    }
-
-    public void bind(String name, Object bean) {
-        this.registry.put(name, bean);
-    }
-
-    @Override
-    public Object lookupByName(String name) {
-        return registry.get(name);
-    }
-
-    @Override
-    public <T> T lookupByNameAndType(String name, Class<T> type) {
-        final Object answer = lookupByName(name);
-
-        if (answer != null) {
-            try {
-                return type.cast(answer);
-            } catch (Throwable t) {
-                throw new NoSuchBeanException(
-                    name,
-                    "Found bean: " + name + " in RuntimeRegistry: " + this + " of type: " + answer.getClass().getName() + " expected type was: " + type,
-                    t
-                );
-            }
-        }
-
-        return null;
-    }
-
-    @Override
-    public <T> Map<String, T> findByTypeWithName(Class<T> type) {
-        final Map<String, T> result = new HashMap<>();
-
-        registry.entrySet().stream()
-            .filter(entry -> type.isInstance(entry.getValue()))
-            .forEach(entry -> result.put(entry.getKey(), type.cast(entry.getValue())));
-
-        return result;
-    }
-
-    @Override
-    public <T> Set<T> findByType(Class<T> type) {
-        return registry.values().stream()
-            .filter(type::isInstance)
-            .map(type::cast)
-            .collect(Collectors.toSet());
-    }
-
-    @SuppressWarnings("deprecation")
-    @Override
-    public Object lookup(String name) {
-        return lookupByName(name);
-    }
-
-    @SuppressWarnings("deprecation")
-    @Override
-    public <T> T lookup(String name, Class<T> type) {
-        return lookupByNameAndType(name, type);
-    }
+public interface RuntimeRegistry extends Registry {
 
-    @SuppressWarnings("deprecation")
-    @Override
-    public <T> Map<String, T> lookupByType(Class<T> type) {
-        return findByTypeWithName(type);
-    }
+    /**
+     *
+     */
+    void bind(String name, Object bean);
 }
diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeSupport.java b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeSupport.java
index 8b4db47..423ee08 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeSupport.java
+++ b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeSupport.java
@@ -41,7 +41,7 @@ public final class RuntimeSupport {
     private RuntimeSupport() {
     }
 
-    public static void configureSystemProperties() {
+    public static Properties loadProperties() {
         final String conf = System.getenv(Constants.ENV_CAMEL_K_CONF);
         final String confd = System.getenv(Constants.ENV_CAMEL_K_CONF_D);
         final Properties properties = new Properties();
@@ -94,6 +94,13 @@ public final class RuntimeSupport {
             }
         }
 
+        return properties;
+    }
+
+    public static void configureSystemProperties() {
+        final Properties properties = loadProperties();
+
+        // TODO: sensitive info, maybe better to use properties component ...
         System.getProperties().putAll(properties);
     }
 
diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeRegistry.java b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/SimpleRuntimeRegistry.java
similarity index 96%
copy from runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeRegistry.java
copy to runtime/jvm/src/main/java/org/apache/camel/k/jvm/SimpleRuntimeRegistry.java
index 8fc7589..f09b331 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/RuntimeRegistry.java
+++ b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/SimpleRuntimeRegistry.java
@@ -26,10 +26,10 @@ import java.util.stream.Collectors;
 import org.apache.camel.NoSuchBeanException;
 import org.apache.camel.spi.Registry;
 
-public class RuntimeRegistry implements Registry {
+public class SimpleRuntimeRegistry implements RuntimeRegistry {
     private final ConcurrentMap<String, Object> registry;
 
-    public RuntimeRegistry() {
+    public SimpleRuntimeRegistry() {
         this.registry = new ConcurrentHashMap<>();
     }
 
diff --git a/runtime/jvm/src/test/java/org/apache/camel/k/jvm/RoutesLoadersTest.java b/runtime/jvm/src/test/java/org/apache/camel/k/jvm/RoutesLoadersTest.java
index 328aaf3..069520a 100644
--- a/runtime/jvm/src/test/java/org/apache/camel/k/jvm/RoutesLoadersTest.java
+++ b/runtime/jvm/src/test/java/org/apache/camel/k/jvm/RoutesLoadersTest.java
@@ -32,7 +32,7 @@ public class RoutesLoadersTest {
     public void testLoadClass() throws Exception {
         String resource = "classpath:" + MyRoutes.class.getName() + ".class";
         RoutesLoader loader = RoutesLoaders.loaderFor(resource, null);
-        RouteBuilder builder = loader.load(new RuntimeRegistry(), resource);
+        RouteBuilder builder = loader.load(new SimpleRuntimeRegistry(), resource);
 
         assertThat(loader).isInstanceOf(RoutesLoaders.JavaClass.class);
         assertThat(builder).isNotNull();
@@ -49,7 +49,7 @@ public class RoutesLoadersTest {
     public void testLoadJava() throws Exception {
         String resource = "classpath:MyRoutes.java";
         RoutesLoader loader = RoutesLoaders.loaderFor(resource, null);
-        RouteBuilder builder = loader.load(new RuntimeRegistry(), resource);
+        RouteBuilder builder = loader.load(new SimpleRuntimeRegistry(), resource);
 
         assertThat(loader).isInstanceOf(RoutesLoaders.JavaSource.class);
         assertThat(builder).isNotNull();
@@ -66,7 +66,7 @@ public class RoutesLoadersTest {
     public void testLoadJavaScript() throws Exception {
         String resource = "classpath:routes.js";
         RoutesLoader loader = RoutesLoaders.loaderFor(resource, null);
-        RouteBuilder builder = loader.load(new RuntimeRegistry(), resource);
+        RouteBuilder builder = loader.load(new SimpleRuntimeRegistry(), resource);
 
         assertThat(loader).isInstanceOf(RoutesLoaders.JavaScript.class);
         assertThat(builder).isNotNull();
@@ -83,7 +83,7 @@ public class RoutesLoadersTest {
     public void testLoadJavaScriptWithCustomExtension() throws Exception {
         String resource = "classpath:routes.mytype";
         RoutesLoader loader = RoutesLoaders.loaderFor(resource, "js");
-        RouteBuilder builder = loader.load(new RuntimeRegistry(), resource);
+        RouteBuilder builder = loader.load(new SimpleRuntimeRegistry(), resource);
 
         assertThat(loader).isInstanceOf(RoutesLoaders.JavaScript.class);
         assertThat(builder).isNotNull();
@@ -100,7 +100,7 @@ public class RoutesLoadersTest {
     public void testLoadXml() throws Exception {
         String resource = "classpath:routes.xml";
         RoutesLoader loader = RoutesLoaders.loaderFor(resource, null);
-        RouteBuilder builder = loader.load(new RuntimeRegistry(), resource);
+        RouteBuilder builder = loader.load(new SimpleRuntimeRegistry(), resource);
 
         assertThat(loader).isInstanceOf(RoutesLoaders.Xml.class);
         assertThat(builder).isNotNull();
diff --git a/runtime/kotlin/src/test/kotlin/org/apache/camel/k/kotlin/LoaderTest.kt b/runtime/kotlin/src/test/kotlin/org/apache/camel/k/kotlin/LoaderTest.kt
index da4ab18..00dfcea 100644
--- a/runtime/kotlin/src/test/kotlin/org/apache/camel/k/kotlin/LoaderTest.kt
+++ b/runtime/kotlin/src/test/kotlin/org/apache/camel/k/kotlin/LoaderTest.kt
@@ -17,7 +17,7 @@
 package org.apache.camel.k.kotlin
 
 import org.apache.camel.k.jvm.RoutesLoaders
-import org.apache.camel.k.jvm.RuntimeRegistry
+import org.apache.camel.k.jvm.SimpleRuntimeRegistry
 import org.apache.camel.model.ProcessDefinition
 import org.apache.camel.model.ToDefinition
 import org.assertj.core.api.Assertions.assertThat
@@ -29,7 +29,7 @@ class LoaderTest {
     fun `load route from classpath`() {
         val resource = "classpath:routes.kts"
         val loader = RoutesLoaders.loaderFor(resource, null)
-        val builder = loader.load(RuntimeRegistry(), resource)
+        val builder = loader.load(SimpleRuntimeRegistry(), resource)
 
         assertThat(loader).isInstanceOf(KotlinRoutesLoader::class.java)
         assertThat(builder).isNotNull()
diff --git a/runtime/pom.xml b/runtime/pom.xml
index 3ddf47c..3be5314 100644
--- a/runtime/pom.xml
+++ b/runtime/pom.xml
@@ -48,6 +48,7 @@
         <snakeyaml.version>1.23</snakeyaml.version>
         <spock.version>1.0-groovy-2.4</spock.version>
         <jackson.version>2.9.7</jackson.version>
+        <spring-boot.version>2.0.3.RELEASE</spring-boot.version>
 
         <gmavenplus-plugin.version>1.6.1</gmavenplus-plugin.version>
         <fabric8-maven-plugin.version>3.5.40</fabric8-maven-plugin.version>
@@ -100,6 +101,7 @@
         <module>jvm</module>
         <module>groovy</module>
         <module>kotlin</module>
+        <module>spring-boot</module>
         <module>catalog-builder</module>
         <module>dependency-lister</module>
         <module>camel-knative-http</module>
diff --git a/runtime/spring-boot-example/.gitignore b/runtime/spring-boot-example/.gitignore
new file mode 100644
index 0000000..ed92983
--- /dev/null
+++ b/runtime/spring-boot-example/.gitignore
@@ -0,0 +1,10 @@
+target
+
+*.iml
+
+.idea
+.project
+.metadata
+.settings
+.factorypath
+.classpath
diff --git a/runtime/spring-boot-example/pom.xml b/runtime/spring-boot-example/pom.xml
new file mode 100644
index 0000000..4e98e33
--- /dev/null
+++ b/runtime/spring-boot-example/pom.xml
@@ -0,0 +1,90 @@
+<?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.0.6-SNAPSHOT</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>camel-k-runtime-spring-boot-example</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.camel.k</groupId>
+            <artifactId>camel-k-runtime-spring-boot</artifactId>
+            <version>${project.version}</version>
+           <exclusions>
+                <exclusion>
+                    <groupId>org.apache.camel</groupId>
+                    <artifactId>*</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.camel.k</groupId>
+                    <artifactId>*</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>*</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-dns-starter</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.sun.xml.bind</groupId>
+                    <artifactId>*</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.camel</groupId>
+                    <artifactId>camel-core</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.camel</groupId>
+                    <artifactId>camel-core-starter</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.camel</groupId>
+                    <artifactId>camel-spring-boot-starter</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.camel.k</groupId>
+                <artifactId>camel-k-runtime-dependency-lister</artifactId>
+                <version>${project.version}</version>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/runtime/spring-boot/.gitignore b/runtime/spring-boot/.gitignore
new file mode 100644
index 0000000..ed92983
--- /dev/null
+++ b/runtime/spring-boot/.gitignore
@@ -0,0 +1,10 @@
+target
+
+*.iml
+
+.idea
+.project
+.metadata
+.settings
+.factorypath
+.classpath
diff --git a/runtime/spring-boot/pom.xml b/runtime/spring-boot/pom.xml
new file mode 100644
index 0000000..1e822ff
--- /dev/null
+++ b/runtime/spring-boot/pom.xml
@@ -0,0 +1,123 @@
+<?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.0.6-SNAPSHOT</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>camel-k-runtime-spring-boot</artifactId>
+
+    <properties>
+        <jar_file>${project.build.directory}/${project.build.finalName}.jar</jar_file>
+    </properties>
+
+    <dependencies>
+
+        <!-- ****************************** -->
+        <!--                                -->
+        <!-- RUNTIME                        -->
+        <!--                                -->
+        <!-- ****************************** -->
+
+        <dependency>
+            <groupId>org.apache.camel.k</groupId>
+            <artifactId>camel-k-runtime-jvm</artifactId>
+            <version>${project.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.logging.log4j</groupId>
+                    <artifactId>log4j-core</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.logging.log4j</groupId>
+                    <artifactId>log4j-slf4j-impl</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-spring-boot-starter</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-logging</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-log4j2</artifactId>
+            <version>${spring-boot.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>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>${spring-boot.version}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <mainClass>org.apache.camel.k.spring.boot.Application</mainClass>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/runtime/spring-boot/src/main/java/org/apache/camel/k/spring/boot/Application.java b/runtime/spring-boot/src/main/java/org/apache/camel/k/spring/boot/Application.java
new file mode 100644
index 0000000..9ff694c
--- /dev/null
+++ b/runtime/spring-boot/src/main/java/org/apache/camel/k/spring/boot/Application.java
@@ -0,0 +1,170 @@
+/**
+ * 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.spring.boot;
+
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.k.jvm.Constants;
+import org.apache.camel.k.jvm.RoutesLoader;
+import org.apache.camel.k.jvm.RoutesLoaders;
+import org.apache.camel.k.jvm.RuntimeRegistry;
+import org.apache.camel.k.jvm.RuntimeSupport;
+import org.apache.camel.spi.Registry;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.URISupport;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
+
+@SpringBootApplication
+public class Application {
+    private static final Logger LOGGER = LoggerFactory.getLogger(Application.class);
+
+    public static void main(String[] args) {
+        SpringApplication.run(Application.class, args);
+    }
+
+    // *****************************
+    //
+    // Beans
+    //
+    // *****************************
+
+    @Bean
+    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
+        // load properties using default behaviour
+        final Properties properties = RuntimeSupport.loadProperties();
+
+        // set spring boot specific properties
+        properties.put("camel.springboot.main-run-controller", "true");
+        properties.put("camel.springboot.name", "camel-1");
+        properties.put("camel.springboot.streamCachingEnabled", "true");
+        properties.put("camel.springboot.xml-routes", "false");
+        properties.put("camel.springboot.xml-rests", "false");
+        properties.put("camel.springboot.jmx-enabled", "false");
+
+        // set loaded properties as default properties
+        PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
+        configurer.setProperties(properties);
+
+        return configurer;
+    }
+
+    @Bean
+    public RouteBuilder routes(ConfigurableApplicationContext applicationContext) throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                final CamelContext context = getContext();
+                final RuntimeRegistry registry = new RuntimeApplicationContextRegistry(applicationContext, context.getRegistry());
+                final String routes = System.getenv(Constants.ENV_CAMEL_K_ROUTES);
+
+                if (ObjectHelper.isEmpty(routes)) {
+                    throw new IllegalStateException("No valid routes found in " + Constants.ENV_CAMEL_K_ROUTES + " environment variable");
+                }
+
+                for (String route: routes.split(",")) {
+                    // determine location and language
+                    final String location = StringUtils.substringBefore(route, "?");
+                    final String query = StringUtils.substringAfter(route, "?");
+                    final String language = (String) URISupport.parseQuery(query).get("language");
+
+                    // load routes
+                    final RoutesLoader loader = RoutesLoaders.loaderFor(location, language);
+                    final RouteBuilder builder = loader.load(registry, location);
+
+                    if (builder == null) {
+                        throw new IllegalStateException("Unable to load route from: " + route);
+                    }
+
+                    LOGGER.info("Routes: {}", route);
+
+                    context.addRoutes(builder);
+                }
+            }
+        };
+    }
+
+    // *****************************
+    //
+    // Registry
+    //
+    // *****************************
+
+    private static class RuntimeApplicationContextRegistry implements RuntimeRegistry {
+        private final ConfigurableApplicationContext applicationContext;
+        private final Registry registry;
+
+        public RuntimeApplicationContextRegistry(ConfigurableApplicationContext applicationContext, Registry registry) {
+            this.applicationContext = applicationContext;
+            this.registry = registry;
+        }
+
+        @Override
+        public Object lookupByName(String name) {
+            return registry.lookupByName(name);
+        }
+
+        @Override
+        public <T> T lookupByNameAndType(String name, Class<T> type) {
+            return registry.lookupByNameAndType(name, type);
+        }
+
+        @Override
+        public <T> Map<String, T> findByTypeWithName(Class<T> type) {
+            return registry.findByTypeWithName(type);
+        }
+
+        @Override
+        public <T> Set<T> findByType(Class<T> type) {
+            return registry.findByType(type);
+        }
+
+        @SuppressWarnings("deprecation")
+        @Override
+        public Object lookup(String name) {
+            return registry.lookup(name);
+        }
+
+        @SuppressWarnings("deprecation")
+        @Override
+        public <T> T lookup(String name, Class<T> type) {
+            return registry.lookup(name, type);
+        }
+
+        @SuppressWarnings("deprecation")
+        @Override
+        public <T> Map<String, T> lookupByType(Class<T> type) {
+            return registry.lookupByType(type);
+        }
+
+        @Override
+        public void bind(String name, Object bean) {
+            applicationContext.getBeanFactory().registerSingleton(name, bean);
+        }
+    }
+
+}
diff --git a/test/build_manager_integration_test.go b/test/build_manager_integration_test.go
index 09bc0e7..1e8a10c 100644
--- a/test/build_manager_integration_test.go
+++ b/test/build_manager_integration_test.go
@@ -107,5 +107,4 @@ func TestBuildManagerFailedBuild(t *testing.T) {
 
 	assert.Equal(t, builder.StatusError, result.Status)
 	assert.NotEqual(t, builder.StatusCompleted, result.Status)
-	assert.Empty(t, result.Image)
 }


[camel-k] 02/03: spring-boot: fix issue with best base image selection

Posted by nf...@apache.org.
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 965c71bcdc40a66ae66d70b37b8773b97e54a901
Author: lburgazzoli <lb...@gmail.com>
AuthorDate: Sun Nov 25 00:29:56 2018 +0100

    spring-boot: fix issue with best base image selection
---
 .../platform-integration-context-spring-boot.yaml  | 18 ++++++++++++++++++
 deploy/resources.go                                | 22 ++++++++++++++++++++++
 pkg/builder/builder_steps.go                       |  8 ++------
 pkg/stub/action/platform/create.go                 |  1 +
 4 files changed, 43 insertions(+), 6 deletions(-)

diff --git a/deploy/platform-integration-context-spring-boot.yaml b/deploy/platform-integration-context-spring-boot.yaml
new file mode 100644
index 0000000..e52d9f7
--- /dev/null
+++ b/deploy/platform-integration-context-spring-boot.yaml
@@ -0,0 +1,18 @@
+apiVersion: camel.apache.org/v1alpha1
+kind: IntegrationContext
+metadata:
+  name: spring-boot
+  labels:
+    app: "camel-k"
+    camel.apache.org/context.created.by.kind: Operator
+    camel.apache.org/context.created.by.name: jvm
+    camel.apache.org/context.type: platform
+spec:
+  dependencies:
+    - runtime:jvm
+    - runtime:spring-boot
+    - camel:core
+  traits:
+    springboot:
+      configuration:
+        enabled: "true"
diff --git a/deploy/resources.go b/deploy/resources.go
index d67602b..223d55b 100644
--- a/deploy/resources.go
+++ b/deploy/resources.go
@@ -2681,6 +2681,28 @@ spec:
     - runtime:kotlin
     - camel:core
 `
+	Resources["platform-integration-context-spring-boot.yaml"] =
+		`
+apiVersion: camel.apache.org/v1alpha1
+kind: IntegrationContext
+metadata:
+  name: spring-boot
+  labels:
+    app: "camel-k"
+    camel.apache.org/context.created.by.kind: Operator
+    camel.apache.org/context.created.by.name: jvm
+    camel.apache.org/context.type: platform
+spec:
+  dependencies:
+    - runtime:jvm
+    - runtime:spring-boot
+    - camel:core
+  traits:
+    springboot:
+      configuration:
+        enabled: "true"
+
+`
 	Resources["user-cluster-role.yaml"] =
 		`
 kind: ClusterRole
diff --git a/pkg/builder/builder_steps.go b/pkg/builder/builder_steps.go
index f0eaa58..e0c34e7 100644
--- a/pkg/builder/builder_steps.go
+++ b/pkg/builder/builder_steps.go
@@ -251,11 +251,6 @@ func packager(ctx *Context, selector ArtifactsSelector) error {
 		}
 	}
 
-	err = tarAppender.AppendData([]byte(""), "marker")
-	if err != nil {
-		return err
-	}
-
 	ctx.Image = imageName
 	ctx.Archive = tarFileName
 
@@ -309,7 +304,8 @@ func FindBestImage(images []PublishedImage, entries []v1alpha1.Artifact) (*Publi
 		}
 		numCommonLibs := len(common)
 		surplus := len(image.Classpath) - numCommonLibs
-		if surplus >= numCommonLibs/3 {
+
+		if numCommonLibs != len(image.Classpath) && surplus >= numCommonLibs/3 {
 			// Heuristic approach: if there are too many unrelated libraries, just use the base image
 			continue
 		}
diff --git a/pkg/stub/action/platform/create.go b/pkg/stub/action/platform/create.go
index 0933e2f..5f8ea2f 100644
--- a/pkg/stub/action/platform/create.go
+++ b/pkg/stub/action/platform/create.go
@@ -28,6 +28,7 @@ var resources = []string{
 	"platform-integration-context-jvm.yaml",
 	"platform-integration-context-groovy.yaml",
 	"platform-integration-context-kotlin.yaml",
+	"platform-integration-context-spring-boot.yaml",
 }
 
 // NewCreateAction returns a action that creates resources needed by the platform


[camel-k] 03/03: fix issue with owned resources

Posted by nf...@apache.org.
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 03bcfd872e4e55866f9ef2ff4a6df40f66938d4d
Author: lburgazzoli <lb...@gmail.com>
AuthorDate: Sun Nov 25 00:36:02 2018 +0100

    fix issue with owned resources
---
 pkg/trait/catalog.go | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/pkg/trait/catalog.go b/pkg/trait/catalog.go
index 3eba945..4684202 100644
--- a/pkg/trait/catalog.go
+++ b/pkg/trait/catalog.go
@@ -85,28 +85,28 @@ func (c *Catalog) traitsFor(environment *Environment) []Trait {
 			c.tDependencies,
 			c.tService,
 			c.tRoute,
-			c.tOwner,
 			c.tBuilder,
 			c.tSpringBoot,
 			c.tDeployment,
+			c.tOwner,
 		}
 	case v1alpha1.TraitProfileKubernetes:
 		return []Trait{
 			c.tDependencies,
 			c.tService,
 			c.tIngress,
-			c.tOwner,
 			c.tBuilder,
 			c.tSpringBoot,
 			c.tDeployment,
+			c.tOwner,
 		}
 	case v1alpha1.TraitProfileKnative:
 		return []Trait{
 			c.tDependencies,
 			c.tKnative,
-			c.tOwner,
 			c.tBuilder,
 			c.tSpringBoot,
+			c.tOwner,
 		}
 	}