Skip to content

Commit

Permalink
fix(apache#3844): Add service discovery for Kamelet data type converter
Browse files Browse the repository at this point in the history
- Enable service discovery for data type converter resources in order to enable factory finder mechanism when resolving data type implementations
- Add proper quarkus-maven-plugin build time properties for quarkus.camel.* properties
- Fixes the way camel-quarkus build time properties are set (set properties on the quarkus-maven-plugin instead of using generic Maven system properties)
- Explicitly add quarkus.camel.service.discovery.include-patterns for data type converter resources in order to enable lazy loading of Kamelets data type implementations

Relates to apache#1980
  • Loading branch information
christophd committed Dec 20, 2022
1 parent 67aad9b commit 7b33c38
Show file tree
Hide file tree
Showing 8 changed files with 194 additions and 39 deletions.
7 changes: 6 additions & 1 deletion pkg/apis/camel/v1/maven_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,9 @@ type Server struct {
Configuration Properties `xml:"configuration,omitempty" json:"configuration,omitempty"`
}

type Properties map[string]string
type StringOrProperties struct {
Value string `xml:",chardata" json:"-"`
Properties map[string]string `xml:"properties,omitempty" json:"properties,omitempty"`
}

type Properties map[string]StringOrProperties
41 changes: 35 additions & 6 deletions pkg/apis/camel/v1/maven_types_support.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ limitations under the License.

package v1

import "encoding/xml"
import (
"encoding/xml"
)

func (in *MavenArtifact) GetDependencyID() string {
switch {
Expand All @@ -35,23 +37,50 @@ type propertiesEntry struct {

func (m Properties) AddAll(properties map[string]string) {
for k, v := range properties {
m[k] = v
m.Add(k, v)
}
}

func (m Properties) Add(key string, value string) {
m[key] = StringOrProperties{Value: value}
}

func (m Properties) AddProperties(key string, properties map[string]string) {
m[key] = StringOrProperties{Properties: properties}
}

func (m Properties) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
if len(m) == 0 {
return nil
}

err := e.EncodeToken(start)
if err != nil {
if err := e.EncodeToken(start); err != nil {
return err
}

for k, v := range m {
if err := e.Encode(propertiesEntry{XMLName: xml.Name{Local: k}, Value: v}); err != nil {
return err
if v.Value != "" {
if err := e.Encode(propertiesEntry{XMLName: xml.Name{Local: k}, Value: v.Value}); err != nil {
return err
}
}

if len(v.Properties) > 0 {
nestedPropertyStart := xml.StartElement{Name: xml.Name{Local: k}}
if err := e.EncodeToken(nestedPropertyStart); err != nil {
return err
}

for key, value := range v.Properties {
if err := e.Encode(propertiesEntry{XMLName: xml.Name{Local: key}, Value: value}); err != nil {
return err
}
}

if err := e.EncodeToken(nestedPropertyStart.End()); err != nil {
return err
}

}
}

Expand Down
101 changes: 101 additions & 0 deletions pkg/apis/camel/v1/maven_types_support_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
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 v1

import (
"bytes"
"encoding/xml"
"strings"
"testing"

"github.com/stretchr/testify/assert"
)

func TestMarshalEmptyProperties(t *testing.T) {
buf := new(bytes.Buffer)
e := xml.NewEncoder(buf)

err := Properties{}.MarshalXML(e, xml.StartElement{
Name: xml.Name{Local: "root"},
})

assert.NoError(t, err)

err = e.Flush()

assert.NoError(t, err)
assert.Equal(t, "", buf.String())
}

func TestMarshalProperties(t *testing.T) {
buf := new(bytes.Buffer)
e := xml.NewEncoder(buf)

properties := Properties{}
properties.Add("v1", "foo")
properties.Add("v2", "bar")

err := properties.MarshalXML(e, xml.StartElement{
Name: xml.Name{Local: "root"},
})

assert.NoError(t, err)

err = e.Flush()

assert.NoError(t, err)

result := buf.String()
assert.True(t, strings.HasPrefix(result, "<root>"))
assert.True(t, strings.HasSuffix(result, "</root>"))
assert.Contains(t, result, "<v1>foo</v1>")
assert.Contains(t, result, "<v2>bar</v2>")
}

func TestMarshalNestedProperties(t *testing.T) {
buf := new(bytes.Buffer)
e := xml.NewEncoder(buf)

properties := Properties{}
properties.Add("v1", "foo")
properties.AddProperties("props", map[string]string{
"prop1": "foo",
"prop2": "baz",
})
properties.Add("v2", "bar")

err := properties.MarshalXML(e, xml.StartElement{
Name: xml.Name{Local: "root"},
})

assert.NoError(t, err)

err = e.Flush()

assert.NoError(t, err)

result := buf.String()
assert.True(t, strings.HasPrefix(result, "<root>"))
assert.True(t, strings.HasSuffix(result, "</root>"))
assert.Contains(t, result, "<v1>foo</v1>")
assert.Contains(t, result, "<props>")
assert.Contains(t, result, "</props>")
assert.Contains(t, result, "<prop1>foo</prop1>")
assert.Contains(t, result, "<prop2>baz</prop2>")
assert.Contains(t, result, "<v2>bar</v2>")
}
8 changes: 4 additions & 4 deletions pkg/builder/project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,8 +452,8 @@ func TestInjectServersIntoDefaultMavenSettings(t *testing.T) {
ID: "image-repository",
Username: "jpoth",
Password: "changeit",
Configuration: map[string]string{
"allowInsecureRegistries": "false",
Configuration: v1.Properties{
"allowInsecureRegistries": v1.StringOrProperties{Value: "false"},
},
},
}
Expand All @@ -478,8 +478,8 @@ func TestInjectServersIntoCustomMavenSettings(t *testing.T) {
ID: "image-repository",
Username: "jpoth",
Password: "changeit",
Configuration: map[string]string{
"allowInsecureRegistries": "false",
Configuration: v1.Properties{
"allowInsecureRegistries": v1.StringOrProperties{Value: "false"},
},
},
}
Expand Down
50 changes: 34 additions & 16 deletions pkg/builder/quarkus.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,9 @@ func loadCamelQuarkusCatalog(ctx *builderContext) error {

func generateQuarkusProject(ctx *builderContext) error {
p := GenerateQuarkusProjectCommon(
ctx.Build.Runtime.Metadata["camel-quarkus.version"],
ctx.Build.Runtime.Version,
ctx.Build.Runtime.Metadata["quarkus.version"])

// Add all the properties from the build configuration
p.Properties.AddAll(ctx.Build.Maven.Properties)
ctx.Build.Runtime.Metadata["quarkus.version"],
ctx.Build.Maven.Properties)

// Add Maven build extensions
p.Build.Extensions = ctx.Build.Maven.Extension
Expand All @@ -96,23 +93,14 @@ func generateQuarkusProject(ctx *builderContext) error {
return nil
}

func GenerateQuarkusProjectCommon(camelQuarkusVersion string, runtimeVersion string, quarkusVersion string) maven.Project {
func GenerateQuarkusProjectCommon(runtimeVersion string, quarkusVersion string, buildTimeProperties map[string]string) maven.Project {
p := maven.NewProjectWithGAV("org.apache.camel.k.integration", "camel-k-integration", defaults.Version)
p.DependencyManagement = &maven.DependencyManagement{Dependencies: make([]maven.Dependency, 0)}
p.Dependencies = make([]maven.Dependency, 0)
p.Build = &maven.Build{Plugins: make([]maven.Plugin, 0)}

// camel-quarkus does route discovery at startup, but we don't want
// this to happen as routes are loaded at runtime and looking for
// routes at build time may try to load camel-k-runtime routes builder
// proxies which in some case may fail.
p.Properties["quarkus.camel.routes-discovery.enabled"] = "false"

// disable quarkus banner
p.Properties["quarkus.banner.enabled"] = "false"

// set fast-jar packaging by default, since it gives some startup time improvements
p.Properties["quarkus.package.type"] = "fast-jar"
p.Properties.Add("quarkus.package.type", "fast-jar")

// DependencyManagement
p.DependencyManagement.Dependencies = append(p.DependencyManagement.Dependencies,
Expand All @@ -125,6 +113,34 @@ func GenerateQuarkusProjectCommon(camelQuarkusVersion string, runtimeVersion str
},
)

// Add all the properties from the build configuration
p.Properties.AddAll(buildTimeProperties)

// Quarkus build time properties
buildProperties := make(map[string]string)

// disable quarkus banner
buildProperties["quarkus.banner.enabled"] = "false"

// camel-quarkus does route discovery at startup, but we don't want
// this to happen as routes are loaded at runtime and looking for
// routes at build time may try to load camel-k-runtime routes builder
// proxies which in some case may fail.
buildProperties["quarkus.camel.routes-discovery.enabled"] = "false"

// required for Kamelets utils to resolve data type converters at runtime
buildProperties["quarkus.camel.service.discovery.include-patterns"] = "META-INF/services/org/apache/camel/datatype/converter/*"

// copy all user defined quarkus.camel build time properties to the quarkus-maven-plugin build properties
for key, value := range buildTimeProperties {
if strings.HasPrefix(key, "quarkus.camel.") {
buildProperties[key] = value
}
}

configuration := v1.Properties{}
configuration.AddProperties("properties", buildProperties)

// Plugins
p.Build.Plugins = append(p.Build.Plugins,
maven.Plugin{
Expand All @@ -133,9 +149,11 @@ func GenerateQuarkusProjectCommon(camelQuarkusVersion string, runtimeVersion str
Version: quarkusVersion,
Executions: []maven.Execution{
{
ID: "build-integration",
Goals: []string{
"build",
},
Configuration: configuration,
},
},
},
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/local/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,9 @@ func getTopLevelDependencies(ctx context.Context, catalog *camel.RuntimeCatalog,

func getTransitiveDependencies(ctx context.Context, catalog *camel.RuntimeCatalog, dependencies []string, repositories []string) ([]string, error) {
project := builder.GenerateQuarkusProjectCommon(
catalog.GetCamelQuarkusVersion(),
defaults.DefaultRuntimeVersion,
catalog.GetQuarkusVersion(),
make(map[string]string),
)

if err := camel.ManageIntegrationDependencies(&project, dependencies, catalog); err != nil {
Expand Down
18 changes: 10 additions & 8 deletions pkg/util/camel/camel_dependencies.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,20 +213,22 @@ func addRegistryMavenDependency(project *maven.Project, dependency string) error
if isClasspath {
outputDirectory = "src/main/resources"
}

properties := v1.Properties{}
properties.Add("outputDirectory", filepath.Join(outputDirectory, filepath.Dir(outputFileRelativePath)))
properties.Add("outputFileName", filepath.Base(outputFileRelativePath))
properties.Add("groupId", gav.GroupID)
properties.Add("artifactId", gav.ArtifactID)
properties.Add("version", gav.Version)
properties.Add("type", gav.Type)

exec := maven.Execution{
ID: fmt.Sprint(len(plugin.Executions)),
Phase: "validate",
Goals: []string{
"artifact",
},
Configuration: map[string]string{
"outputDirectory": filepath.Join(outputDirectory, filepath.Dir(outputFileRelativePath)),
"outputFileName": filepath.Base(outputFileRelativePath),
"groupId": gav.GroupID,
"artifactId": gav.ArtifactID,
"version": gav.Version,
"type": gav.Type,
},
Configuration: properties,
}
plugin.Executions = append(plugin.Executions, exec)

Expand Down
6 changes: 3 additions & 3 deletions pkg/util/maven/maven_project.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ func NewProjectWithGAV(group string, artifact string, version string) Project {
p.GroupID = group
p.ArtifactID = artifact
p.Version = version
p.Properties = make(map[string]string)
p.Properties["project.build.sourceEncoding"] = "UTF-8"
p.Properties = v1.Properties{}
p.Properties.Add("project.build.sourceEncoding", "UTF-8")

return p
}
Expand Down Expand Up @@ -167,7 +167,7 @@ func NewDependency(groupID string, artifactID string, version string) Dependency
// The repository can be customized by appending @param to the repository
// URL, e.g.:
//
// http://my-nexus:8081/repository/publicc@id=my-repo@snapshots
// http://my-nexus:8081/repository/publicc@id=my-repo@snapshots
//
// That enables snapshots and sets the repository id to `my-repo`.
func NewRepository(repo string) v1.Repository {
Expand Down

0 comments on commit 7b33c38

Please sign in to comment.