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:43 UTC
[camel-k] 01/03: initial support for spring boot
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)
}