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

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

commit acf77559fb63c2244d0b1959bc185fe7e39d083e
Author: Christoph Deppisch <[email protected]>
AuthorDate: Mon Jan 9 15:21:16 2023 +0100

    fix(#3844): Add service discovery for Kamelet data type converter
    
    - 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 https://github.com/apache/camel-k/issues/1980
---
 docs/modules/ROOT/partials/apis/camel-k-crds.adoc |  34 ++++++
 pkg/apis/camel/v1/maven_types.go                  |   6 +
 pkg/apis/camel/v1/maven_types_support.go          |  62 +++++++++-
 pkg/apis/camel/v1/maven_types_support_test.go     | 142 ++++++++++++++++++++++
 pkg/apis/camel/v1/zz_generated.deepcopy.go        |  43 +++++++
 pkg/builder/project_test.go                       |   4 +-
 pkg/builder/quarkus.go                            |  50 +++++---
 pkg/cmd/local/local.go                            |   2 +-
 pkg/util/camel/camel_dependencies.go              |  18 +--
 pkg/util/defaults/defaults.go                     |   2 +-
 pkg/util/maven/maven_project.go                   |   7 +-
 pkg/util/maven/maven_types.go                     |   8 +-
 12 files changed, 341 insertions(+), 37 deletions(-)

diff --git a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc 
b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
index 122776fcb..0db42b568 100644
--- a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
+++ b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
@@ -2423,6 +2423,12 @@ See 
https://maven.apache.org/ref/3.8.4/maven-embedder/cli.html.
 
 |===
 
+[#_camel_apache_org_v1_PluginProperties]
+=== 
PluginProperties(`map[string]github.com/apache/camel-k/pkg/apis/camel/v1.StringOrProperties`
 alias)
+
+
+
+
 [#_camel_apache_org_v1_PodSpec]
 === PodSpec
 
@@ -2547,6 +2553,7 @@ the specification
 *Appears on:*
 
 * <<#_camel_apache_org_v1_Server, Server>>
+* <<#_camel_apache_org_v1_StringOrProperties, StringOrProperties>>
 
 
 
@@ -3073,6 +3080,33 @@ SpectrumTask is used to configure Spectrum
 
 
 
+|===
+
+[#_camel_apache_org_v1_StringOrProperties]
+=== StringOrProperties
+
+
+
+[cols="2,2a",options="header"]
+|===
+|Field
+|Description
+
+|`-` +
+string
+|
+
+
+
+
+|`properties` +
+*xref:#_camel_apache_org_v1_Properties[Properties]*
+|
+
+
+
+
+
 |===
 
 [#_camel_apache_org_v1_Task]
diff --git a/pkg/apis/camel/v1/maven_types.go b/pkg/apis/camel/v1/maven_types.go
index 1d55cb3fd..378d7cfc4 100644
--- a/pkg/apis/camel/v1/maven_types.go
+++ b/pkg/apis/camel/v1/maven_types.go
@@ -96,4 +96,10 @@ type Server struct {
        Configuration Properties `xml:"configuration,omitempty" 
json:"configuration,omitempty"`
 }
 
+type StringOrProperties struct {
+       Value      string     `xml:",chardata" json:"-"`
+       Properties Properties `xml:"properties,omitempty" 
json:"properties,omitempty"`
+}
+
 type Properties map[string]string
+type PluginProperties map[string]StringOrProperties
diff --git a/pkg/apis/camel/v1/maven_types_support.go 
b/pkg/apis/camel/v1/maven_types_support.go
index d4777bffc..5ba46f595 100644
--- a/pkg/apis/camel/v1/maven_types_support.go
+++ b/pkg/apis/camel/v1/maven_types_support.go
@@ -17,7 +17,9 @@ limitations under the License.
 
 package v1
 
-import "encoding/xml"
+import (
+       "encoding/xml"
+)
 
 func (in *MavenArtifact) GetDependencyID() string {
        switch {
@@ -35,10 +37,14 @@ 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] = value
+}
+
 func (m Properties) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
        if len(m) == 0 {
                return nil
@@ -57,3 +63,55 @@ func (m Properties) MarshalXML(e *xml.Encoder, start 
xml.StartElement) error {
 
        return e.EncodeToken(start.End())
 }
+
+func (m PluginProperties) AddAll(properties map[string]string) {
+       for k, v := range properties {
+               m.Add(k, v)
+       }
+}
+
+func (m PluginProperties) Add(key string, value string) {
+       m[key] = StringOrProperties{Value: value}
+}
+
+func (m PluginProperties) AddProperties(key string, properties 
map[string]string) {
+       m[key] = StringOrProperties{Properties: properties}
+}
+
+func (m PluginProperties) MarshalXML(e *xml.Encoder, start xml.StartElement) 
error {
+       if len(m) == 0 {
+               return nil
+       }
+
+       if err := e.EncodeToken(start); err != nil {
+               return err
+       }
+
+       for k, v := range m {
+               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
+                       }
+
+               }
+       }
+
+       return e.EncodeToken(start.End())
+}
diff --git a/pkg/apis/camel/v1/maven_types_support_test.go 
b/pkg/apis/camel/v1/maven_types_support_test.go
new file mode 100644
index 000000000..979e6f7e5
--- /dev/null
+++ b/pkg/apis/camel/v1/maven_types_support_test.go
@@ -0,0 +1,142 @@
+/*
+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 TestMarshalEmptyPluginProperties(t *testing.T) {
+       buf := new(bytes.Buffer)
+       e := xml.NewEncoder(buf)
+
+       err := PluginProperties{}.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 TestMarshalPluginProperties(t *testing.T) {
+       buf := new(bytes.Buffer)
+       e := xml.NewEncoder(buf)
+
+       properties := PluginProperties{}
+       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 TestMarshalPluginPropertiesWithNestedProps(t *testing.T) {
+       buf := new(bytes.Buffer)
+       e := xml.NewEncoder(buf)
+
+       properties := PluginProperties{}
+       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>")
+}
diff --git a/pkg/apis/camel/v1/zz_generated.deepcopy.go 
b/pkg/apis/camel/v1/zz_generated.deepcopy.go
index 7aa25d965..a6082a6c2 100644
--- a/pkg/apis/camel/v1/zz_generated.deepcopy.go
+++ b/pkg/apis/camel/v1/zz_generated.deepcopy.go
@@ -1304,6 +1304,27 @@ func (in *MavenSpec) DeepCopy() *MavenSpec {
        return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
+func (in PluginProperties) DeepCopyInto(out *PluginProperties) {
+       {
+               in := &in
+               *out = make(PluginProperties, len(*in))
+               for key, val := range *in {
+                       (*out)[key] = *val.DeepCopy()
+               }
+       }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new PluginProperties.
+func (in PluginProperties) DeepCopy() PluginProperties {
+       if in == nil {
+               return nil
+       }
+       out := new(PluginProperties)
+       in.DeepCopyInto(out)
+       return *out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
 func (in *PodSpec) DeepCopyInto(out *PodSpec) {
        *out = *in
@@ -1623,6 +1644,28 @@ func (in *SpectrumTask) DeepCopy() *SpectrumTask {
        return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
+func (in *StringOrProperties) DeepCopyInto(out *StringOrProperties) {
+       *out = *in
+       if in.Properties != nil {
+               in, out := &in.Properties, &out.Properties
+               *out = make(Properties, len(*in))
+               for key, val := range *in {
+                       (*out)[key] = val
+               }
+       }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new StringOrProperties.
+func (in *StringOrProperties) DeepCopy() *StringOrProperties {
+       if in == nil {
+               return nil
+       }
+       out := new(StringOrProperties)
+       in.DeepCopyInto(out)
+       return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
 func (in *Task) DeepCopyInto(out *Task) {
        *out = *in
diff --git a/pkg/builder/project_test.go b/pkg/builder/project_test.go
index 15bd9f212..a529f058d 100644
--- a/pkg/builder/project_test.go
+++ b/pkg/builder/project_test.go
@@ -452,7 +452,7 @@ func TestInjectServersIntoDefaultMavenSettings(t 
*testing.T) {
                        ID:       "image-repository",
                        Username: "jpoth",
                        Password: "changeit",
-                       Configuration: map[string]string{
+                       Configuration: v1.Properties{
                                "allowInsecureRegistries": "false",
                        },
                },
@@ -478,7 +478,7 @@ func TestInjectServersIntoCustomMavenSettings(t *testing.T) 
{
                        ID:       "image-repository",
                        Username: "jpoth",
                        Password: "changeit",
-                       Configuration: map[string]string{
+                       Configuration: v1.Properties{
                                "allowInsecureRegistries": "false",
                        },
                },
diff --git a/pkg/builder/quarkus.go b/pkg/builder/quarkus.go
index f5ad3ef79..91d6bfa33 100644
--- a/pkg/builder/quarkus.go
+++ b/pkg/builder/quarkus.go
@@ -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
@@ -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,
@@ -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.PluginProperties{}
+       configuration.AddProperties("properties", buildProperties)
+
        // Plugins
        p.Build.Plugins = append(p.Build.Plugins,
                maven.Plugin{
@@ -133,9 +149,11 @@ func GenerateQuarkusProjectCommon(camelQuarkusVersion 
string, runtimeVersion str
                        Version:    quarkusVersion,
                        Executions: []maven.Execution{
                                {
+                                       ID: "build-integration",
                                        Goals: []string{
                                                "build",
                                        },
+                                       Configuration: configuration,
                                },
                        },
                },
diff --git a/pkg/cmd/local/local.go b/pkg/cmd/local/local.go
index 0032e0eee..b1513a855 100644
--- a/pkg/cmd/local/local.go
+++ b/pkg/cmd/local/local.go
@@ -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 {
diff --git a/pkg/util/camel/camel_dependencies.go 
b/pkg/util/camel/camel_dependencies.go
index 7ef91d326..a3b65b003 100644
--- a/pkg/util/camel/camel_dependencies.go
+++ b/pkg/util/camel/camel_dependencies.go
@@ -213,20 +213,22 @@ func addRegistryMavenDependency(project *maven.Project, 
dependency string) error
        if isClasspath {
                outputDirectory = "src/main/resources"
        }
+
+       properties := v1.PluginProperties{}
+       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)
 
diff --git a/pkg/util/defaults/defaults.go b/pkg/util/defaults/defaults.go
index 3297388a4..f2a39043d 100644
--- a/pkg/util/defaults/defaults.go
+++ b/pkg/util/defaults/defaults.go
@@ -47,5 +47,5 @@ const (
        installDefaultKamelets = true
 )
 
-//GitCommit must be provided during application build
+// GitCommit must be provided during application build
 var GitCommit string
diff --git a/pkg/util/maven/maven_project.go b/pkg/util/maven/maven_project.go
index f73eb0d01..9bb125d19 100644
--- a/pkg/util/maven/maven_project.go
+++ b/pkg/util/maven/maven_project.go
@@ -40,8 +40,9 @@ 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{
+               "project.build.sourceEncoding": "UTF-8",
+       }
 
        return p
 }
@@ -167,7 +168,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 {
diff --git a/pkg/util/maven/maven_types.go b/pkg/util/maven/maven_types.go
index b033a66b4..df8ed5d0a 100644
--- a/pkg/util/maven/maven_types.go
+++ b/pkg/util/maven/maven_types.go
@@ -45,10 +45,10 @@ type Plugin struct {
 }
 
 type Execution struct {
-       ID            string        `xml:"id,omitempty"`
-       Phase         string        `xml:"phase,omitempty"`
-       Goals         []string      `xml:"goals>goal,omitempty"`
-       Configuration v1.Properties `xml:"configuration,omitempty"`
+       ID            string              `xml:"id,omitempty"`
+       Phase         string              `xml:"phase,omitempty"`
+       Goals         []string            `xml:"goals>goal,omitempty"`
+       Configuration v1.PluginProperties `xml:"configuration,omitempty"`
 }
 
 // Settings models a Maven settings.

Reply via email to