diff --git a/examples/RestWithUndertow.java b/examples/RestDSL.java similarity index 84% rename from examples/RestWithUndertow.java rename to examples/RestDSL.java index 63090a624e..10cff73882 100644 --- a/examples/RestWithUndertow.java +++ b/examples/RestDSL.java @@ -18,15 +18,14 @@ // // To run this integrations use: // -// kamel run --name=rest-with-undertow --dependency=camel-rest --dependency=camel-undertow examples/RestWithUndertow.java +// kamel run examples/RestDSL.java // import org.apache.camel.Exchange; -public class RestWithUndertow extends org.apache.camel.builder.RouteBuilder { +public class RestDSL extends org.apache.camel.builder.RouteBuilder { @Override public void configure() throws Exception { restConfiguration() - .component("undertow") .host("0.0.0.0") .port("8080"); diff --git a/pkg/metadata/http.go b/pkg/metadata/http.go deleted file mode 100644 index be568083c4..0000000000 --- a/pkg/metadata/http.go +++ /dev/null @@ -1,102 +0,0 @@ -/* -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 metadata - -import ( - "regexp" - "strings" - - "github.com/apache/camel-k/pkg/util/camel" - - v1 "github.com/apache/camel-k/pkg/apis/camel/v1" -) - -var restIndicator = regexp.MustCompile(`.*rest\s*\([^)]*\).*`) -var xmlRestIndicator = regexp.MustCompile(`.*<\s*rest\s+[^>]*>.*`) - -// requiresHTTPService returns true if the integration needs to expose itself through HTTP -func requiresHTTPService(catalog *camel.RuntimeCatalog, source v1.SourceSpec, fromURIs []string) bool { - if hasRestIndicator(source) { - return true - } - return containsHTTPURIs(catalog, fromURIs) -} - -// hasOnlyPassiveEndpoints returns true if the integration has no endpoint that needs to remain always active -func hasOnlyPassiveEndpoints(catalog *camel.RuntimeCatalog, _ v1.SourceSpec, fromURIs []string) bool { - passivePlusHTTP := make(map[string]bool) - catalog.VisitSchemes(func(id string, scheme v1.CamelScheme) bool { - if scheme.HTTP || scheme.Passive { - passivePlusHTTP[id] = true - } - - return true - }) - - return containsOnlyURIsIn(fromURIs, passivePlusHTTP) -} - -func containsHTTPURIs(catalog *camel.RuntimeCatalog, fromURI []string) bool { - for _, uri := range fromURI { - prefix := getURIPrefix(uri) - scheme, ok := catalog.GetScheme(prefix) - - if !ok { - // scheme dees not exists - continue - } - - if scheme.HTTP { - return true - } - } - - return false -} - -func containsOnlyURIsIn(fromURI []string, allowed map[string]bool) bool { - for _, uri := range fromURI { - prefix := getURIPrefix(uri) - if enabled, ok := allowed[prefix]; !ok || !enabled { - return false - } - } - return true -} - -func getURIPrefix(uri string) string { - parts := strings.SplitN(uri, ":", 2) - if len(parts) > 0 { - return parts[0] - } - return "" -} - -func hasRestIndicator(source v1.SourceSpec) bool { - pat := getRestIndicatorRegexpsForLanguage(source.InferLanguage()) - return pat.MatchString(source.Content) -} - -func getRestIndicatorRegexpsForLanguage(language v1.Language) *regexp.Regexp { - switch language { - case v1.LanguageXML: - return xmlRestIndicator - default: - return restIndicator - } -} diff --git a/pkg/metadata/metadata.go b/pkg/metadata/metadata.go index 9f9b53ea55..2c8dd8e882 100644 --- a/pkg/metadata/metadata.go +++ b/pkg/metadata/metadata.go @@ -31,17 +31,19 @@ import ( // ExtractAll returns metadata information from all listed source codes func ExtractAll(catalog *camel.RuntimeCatalog, sources []v1.SourceSpec) IntegrationMetadata { // neutral metadata - meta := NewIntegrationMetadata() + meta := src.NewMetadata() meta.PassiveEndpoints = true - meta.RequiresHTTPService = false + meta.ExposesHTTPServices = false for _, source := range sources { - meta = merge(meta, Extract(catalog, source)) + meta = merge(meta, Extract(catalog, source).Metadata) + } + return IntegrationMetadata{ + Metadata: meta, } - return meta } -func merge(m1 IntegrationMetadata, m2 IntegrationMetadata) IntegrationMetadata { +func merge(m1 src.Metadata, m2 src.Metadata) src.Metadata { d := strset.Union(m1.Dependencies, m2.Dependencies) f := make([]string, 0, len(m1.FromURIs)+len(m2.FromURIs)) @@ -52,13 +54,11 @@ func merge(m1 IntegrationMetadata, m2 IntegrationMetadata) IntegrationMetadata { t = append(t, m1.ToURIs...) t = append(t, m2.ToURIs...) - return IntegrationMetadata{ - Metadata: src.Metadata{ - FromURIs: f, - ToURIs: t, - Dependencies: d, - }, - RequiresHTTPService: m1.RequiresHTTPService || m2.RequiresHTTPService, + return src.Metadata{ + FromURIs: f, + ToURIs: t, + Dependencies: d, + ExposesHTTPServices: m1.ExposesHTTPServices || m2.ExposesHTTPServices, PassiveEndpoints: m1.PassiveEndpoints && m2.PassiveEndpoints, } } @@ -73,15 +73,16 @@ func Extract(catalog *camel.RuntimeCatalog, source v1.SourceSpec) IntegrationMet language := source.InferLanguage() - m := NewIntegrationMetadata() + meta := src.NewMetadata() + meta.PassiveEndpoints = true + meta.ExposesHTTPServices = false // TODO: handle error - _ = src.InspectorForLanguage(catalog, language).Extract(source, &m.Metadata) + _ = src.InspectorForLanguage(catalog, language).Extract(source, &meta) - m.RequiresHTTPService = requiresHTTPService(catalog, source, m.FromURIs) - m.PassiveEndpoints = hasOnlyPassiveEndpoints(catalog, source, m.FromURIs) - - return m + return IntegrationMetadata{ + Metadata: meta, + } } // Each -- diff --git a/pkg/metadata/metadata_dependencies_test.go b/pkg/metadata/metadata_dependencies_test.go index 1a96276716..fe5c0e9900 100644 --- a/pkg/metadata/metadata_dependencies_test.go +++ b/pkg/metadata/metadata_dependencies_test.go @@ -48,7 +48,17 @@ func TestDependenciesJavaSource(t *testing.T) { meta := Extract(catalog, code) - assert.ElementsMatch(t, []string{"camel:activemq", "camel:amqp", "camel:log", "camel:telegram", "camel:timer", "camel:twitter"}, meta.Dependencies.List()) + assert.ElementsMatch( + t, + []string{ + "camel:activemq", + "camel:amqp", + "camel:log", + "camel:telegram", + "camel:timer", + "camel:twitter", + }, + meta.Dependencies.List()) } func TestDependenciesJavaScript(t *testing.T) { @@ -72,7 +82,16 @@ func TestDependenciesJavaScript(t *testing.T) { meta := Extract(catalog, code) - assert.ElementsMatch(t, []string{"camel:activemq", "camel:amqp", "camel:log", "camel:telegram", "camel:timer"}, meta.Dependencies.List()) + assert.ElementsMatch( + t, + []string{ + "camel:activemq", + "camel:amqp", + "camel:log", + "camel:telegram", + "camel:timer", + }, + meta.Dependencies.List()) } func TestDependenciesGroovy(t *testing.T) { @@ -98,7 +117,17 @@ func TestDependenciesGroovy(t *testing.T) { meta := Extract(catalog, code) - assert.ElementsMatch(t, []string{"camel:activemq", "camel:amqp", "camel:log", "camel:telegram", "camel:timer", "camel:twitter"}, meta.Dependencies.List()) + assert.ElementsMatch( + t, + []string{ + "camel:activemq", + "camel:amqp", + "camel:log", + "camel:telegram", + "camel:timer", + "camel:twitter", + }, + meta.Dependencies.List()) } func TestDependencies(t *testing.T) { @@ -180,7 +209,14 @@ func TestJacksonDependency(t *testing.T) { meta := Extract(catalog, code) - assert.ElementsMatch(t, []string{"camel:http", "camel:jackson", "camel:log"}, meta.Dependencies.List()) + assert.ElementsMatch( + t, + []string{ + "camel:http", + "camel:jackson", + "camel:log", + }, + meta.Dependencies.List()) } func TestJacksonImplicitDependency(t *testing.T) { @@ -201,7 +237,14 @@ func TestJacksonImplicitDependency(t *testing.T) { meta := Extract(catalog, code) - assert.ElementsMatch(t, []string{"camel:http", "camel:jackson", "camel:log"}, meta.Dependencies.List()) + assert.ElementsMatch( + t, + []string{ + "camel:http", + "camel:jackson", + "camel:log", + }, + meta.Dependencies.List()) } func TestLanguageDependencies(t *testing.T) { @@ -227,8 +270,19 @@ func TestLanguageDependencies(t *testing.T) { assert.Nil(t, err) meta := Extract(catalog, code) - assert.ElementsMatch(t, []string{"camel:direct", "camel:ognl", "camel:saxon", "camel:xpath", - "camel:jsonpath", "camel:groovy", "camel:jaxp", "camel:mvel"}, meta.Dependencies.List()) + assert.ElementsMatch( + t, + []string{ + "camel:direct", + "camel:ognl", + "camel:saxon", + "camel:xpath", + "camel:jsonpath", + "camel:groovy", + "camel:xml-jaxp", + "camel:mvel", + }, + meta.Dependencies.List()) } func TestLanguageDependenciesTransformExpression(t *testing.T) { @@ -250,7 +304,15 @@ func TestLanguageDependenciesTransformExpression(t *testing.T) { assert.Nil(t, err) meta := Extract(catalog, code) - assert.ElementsMatch(t, []string{"camel:direct", "camel:ognl", "camel:xpath", "camel:jsonpath"}, meta.Dependencies.List()) + assert.ElementsMatch( + t, + []string{ + "camel:direct", + "camel:ognl", + "camel:xpath", + "camel:jsonpath", + }, + meta.Dependencies.List()) } func TestHystrixDependency(t *testing.T) { @@ -273,7 +335,13 @@ func TestHystrixDependency(t *testing.T) { meta := Extract(catalog, code) - assert.ElementsMatch(t, []string{"camel:http", "camel:hystrix", "camel:log"}, meta.Dependencies.List()) + assert.ElementsMatch(t, + []string{ + "camel:http", + "camel:hystrix", + "camel:log", + }, + meta.Dependencies.List()) } func TestRestDependency(t *testing.T) { @@ -296,7 +364,16 @@ func TestRestDependency(t *testing.T) { meta := Extract(catalog, code) - assert.ElementsMatch(t, []string{"camel:http", "camel:rest", "camel:direct", "camel:log"}, meta.Dependencies.List()) + assert.ElementsMatch( + t, + []string{ + "camel:http", + "camel:direct", + "camel:log", + "mvn:org.apache.camel/camel-rest", + "mvn:org.apache.camel/camel-undertow", + }, + meta.Dependencies.List()) } func TestRestWithPathDependency(t *testing.T) { @@ -319,7 +396,15 @@ func TestRestWithPathDependency(t *testing.T) { meta := Extract(catalog, code) - assert.ElementsMatch(t, []string{"camel:http", "camel:rest", "camel:direct", "camel:log"}, meta.Dependencies.List()) + assert.ElementsMatch( + t, []string{ + "camel:http", + "camel:direct", + "camel:log", + "mvn:org.apache.camel/camel-rest", + "mvn:org.apache.camel/camel-undertow", + }, + meta.Dependencies.List()) } func TestRestConfigurationDependency(t *testing.T) { @@ -341,10 +426,17 @@ func TestRestConfigurationDependency(t *testing.T) { meta := Extract(catalog, code) - assert.ElementsMatch(t, []string{"camel:http", "camel:rest", "camel:log"}, meta.Dependencies.List()) + assert.ElementsMatch( + t, []string{ + "camel:http", + "camel:log", + "mvn:org.apache.camel/camel-rest", + "mvn:org.apache.camel/camel-undertow", + }, + meta.Dependencies.List()) } -func TestRestClosureDependency(t *testing.T) { +func TestRestClosureDependencyGroovy(t *testing.T) { code := v1.SourceSpec{ DataSpec: v1.DataSpec{ Name: "Request.groovy", @@ -363,7 +455,45 @@ func TestRestClosureDependency(t *testing.T) { meta := Extract(catalog, code) - assert.ElementsMatch(t, []string{"camel:http", "camel:rest", "camel:log"}, meta.Dependencies.List()) + assert.ElementsMatch( + t, + []string{ + "camel:http", + "camel:log", + "mvn:org.apache.camel/camel-rest", + "mvn:org.apache.camel/camel-undertow", + }, + meta.Dependencies.List()) +} + +func TestRestClosureDependencyKotlin(t *testing.T) { + code := v1.SourceSpec{ + DataSpec: v1.DataSpec{ + Name: "Request.groovy", + Content: ` + rest { + } + from("http:test") + .to("log:info") + `, + }, + Language: v1.LanguageKotlin, + } + + catalog, err := camel.DefaultCatalog() + assert.Nil(t, err) + + meta := Extract(catalog, code) + + assert.ElementsMatch( + t, + []string{ + "camel:http", + "camel:log", + "mvn:org.apache.camel/camel-rest", + "mvn:org.apache.camel/camel-undertow", + }, + meta.Dependencies.List()) } func TestXMLHystrixDependency(t *testing.T) { @@ -389,7 +519,15 @@ func TestXMLHystrixDependency(t *testing.T) { meta := Extract(catalog, code) - assert.ElementsMatch(t, []string{"camel:direct", "camel:hystrix", "camel:kafka", "camel:log"}, meta.Dependencies.List()) + assert.ElementsMatch( + t, + []string{ + "camel:direct", + "camel:hystrix", + "camel:kafka", + "camel:log", + }, + meta.Dependencies.List()) } func TestXMLRestDependency(t *testing.T) { @@ -419,7 +557,14 @@ func TestXMLRestDependency(t *testing.T) { meta := Extract(catalog, code) - assert.ElementsMatch(t, []string{"camel:direct", "camel:rest", "camel:mock"}, meta.Dependencies.List()) + assert.ElementsMatch( + t, + []string{ + "camel:direct", + "camel:rest", + "camel:mock", + }, + meta.Dependencies.List()) } func TestXMLLanguageDependencies(t *testing.T) { @@ -556,7 +701,13 @@ func TestYAMLHystrixDependency(t *testing.T) { meta := Extract(catalog, code) - assert.ElementsMatch(t, []string{"camel:direct", "camel:hystrix"}, meta.Dependencies.List()) + assert.ElementsMatch( + t, + []string{ + "camel:direct", + "camel:hystrix", + }, + meta.Dependencies.List()) } func TestYAMLLanguageDependencies(t *testing.T) { diff --git a/pkg/metadata/metadata_http_test.go b/pkg/metadata/metadata_http_test.go index e89365ebdf..97b4aeab22 100644 --- a/pkg/metadata/metadata_http_test.go +++ b/pkg/metadata/metadata_http_test.go @@ -44,7 +44,7 @@ func TestHttpJavaSource(t *testing.T) { meta := Extract(catalog, code) - assert.True(t, meta.RequiresHTTPService) + assert.True(t, meta.ExposesHTTPServices) assert.False(t, meta.PassiveEndpoints) } @@ -67,7 +67,7 @@ func TestHttpOnlyJavaSource(t *testing.T) { meta := Extract(catalog, code) - assert.True(t, meta.RequiresHTTPService) + assert.True(t, meta.ExposesHTTPServices) assert.True(t, meta.PassiveEndpoints) } @@ -88,7 +88,7 @@ func TestHttpOnlyJavaSourceRest(t *testing.T) { meta := Extract(catalog, code) - assert.True(t, meta.RequiresHTTPService) + assert.True(t, meta.ExposesHTTPServices) assert.True(t, meta.PassiveEndpoints) } @@ -109,7 +109,7 @@ func TestHttpOnlyJavaSourceRest2(t *testing.T) { meta := Extract(catalog, code) - assert.True(t, meta.RequiresHTTPService) + assert.True(t, meta.ExposesHTTPServices) assert.True(t, meta.PassiveEndpoints) } @@ -131,7 +131,7 @@ func TestNoHttpGroovySource(t *testing.T) { meta := Extract(catalog, code) - assert.False(t, meta.RequiresHTTPService) + assert.False(t, meta.ExposesHTTPServices) assert.False(t, meta.PassiveEndpoints) } @@ -153,7 +153,7 @@ func TestHttpOnlyGroovySource(t *testing.T) { meta := Extract(catalog, code) - assert.True(t, meta.RequiresHTTPService) + assert.True(t, meta.ExposesHTTPServices) assert.True(t, meta.PassiveEndpoints) } @@ -175,7 +175,7 @@ func TestHttpXMLSource(t *testing.T) { meta := Extract(catalog, code) - assert.True(t, meta.RequiresHTTPService) + assert.True(t, meta.ExposesHTTPServices) assert.False(t, meta.PassiveEndpoints) } @@ -198,7 +198,7 @@ func TestHttpOnlyXMLSource(t *testing.T) { meta := Extract(catalog, code) - assert.True(t, meta.RequiresHTTPService) + assert.True(t, meta.ExposesHTTPServices) assert.True(t, meta.PassiveEndpoints) } @@ -232,7 +232,7 @@ func TestMultilangHTTPOnlySource(t *testing.T) { meta := ExtractAll(catalog, codes) - assert.True(t, meta.RequiresHTTPService) + assert.True(t, meta.ExposesHTTPServices) assert.True(t, meta.PassiveEndpoints) } @@ -268,6 +268,6 @@ func TestMultilangHTTPSource(t *testing.T) { meta := ExtractAll(catalog, codes) - assert.True(t, meta.RequiresHTTPService) + assert.True(t, meta.ExposesHTTPServices) assert.False(t, meta.PassiveEndpoints) } diff --git a/pkg/metadata/types.go b/pkg/metadata/types.go index 934da277c0..66565cf6e3 100644 --- a/pkg/metadata/types.go +++ b/pkg/metadata/types.go @@ -19,26 +19,9 @@ package metadata import ( "github.com/apache/camel-k/pkg/util/source" - "github.com/scylladb/go-set/strset" ) // IntegrationMetadata contains aggregate metadata about all Camel routes in a integrations type IntegrationMetadata struct { source.Metadata - // RequiresHTTPService indicates if the integration needs to be invoked through HTTP - RequiresHTTPService bool - // PassiveEndpoints indicates that the integration contains only passive endpoints that are activated from - // external calls, including HTTP (useful to determine if the integration can scale to 0) - PassiveEndpoints bool -} - -// NewIntegrationMetadata -- -func NewIntegrationMetadata() IntegrationMetadata { - return IntegrationMetadata{ - Metadata: source.Metadata{ - FromURIs: make([]string, 0), - ToURIs: make([]string, 0), - Dependencies: strset.New(), - }, - } } diff --git a/pkg/trait/knative_service.go b/pkg/trait/knative_service.go index 9c9e671e14..8a46b92092 100644 --- a/pkg/trait/knative_service.go +++ b/pkg/trait/knative_service.go @@ -158,7 +158,7 @@ func (t *knativeServiceTrait) Configure(e *Environment) (bool, error) { } meta := metadata.ExtractAll(e.CamelCatalog, sources) - if !meta.RequiresHTTPService || !meta.PassiveEndpoints { + if !meta.ExposesHTTPServices || !meta.PassiveEndpoints { single := 1 t.MinScale = &single } @@ -256,7 +256,7 @@ func (t *knativeServiceTrait) SelectControllerStrategy(e *Environment) (*Control } meta := metadata.ExtractAll(e.CamelCatalog, sources) - if meta.RequiresHTTPService { + if meta.ExposesHTTPServices { return &knativeServiceStrategy, nil } return nil, nil diff --git a/pkg/trait/service.go b/pkg/trait/service.go index 6257e9e1cf..882cd48d79 100644 --- a/pkg/trait/service.go +++ b/pkg/trait/service.go @@ -88,7 +88,7 @@ func (t *serviceTrait) Configure(e *Environment) (bool, error) { } meta := metadata.ExtractAll(e.CamelCatalog, sources) - if !meta.RequiresHTTPService { + if !meta.ExposesHTTPServices { e.Integration.Status.SetCondition( v1.IntegrationConditionServiceAvailable, corev1.ConditionFalse, diff --git a/pkg/util/source/inspector.go b/pkg/util/source/inspector.go index 934525c9cb..a8b690a63b 100644 --- a/pkg/util/source/inspector.go +++ b/pkg/util/source/inspector.go @@ -18,6 +18,7 @@ limitations under the License. package source import ( + "fmt" "regexp" "strings" @@ -26,6 +27,8 @@ import ( "github.com/apache/camel-k/pkg/util/camel" ) +type catalog2deps func(*camel.RuntimeCatalog) []string + var ( singleQuotedFrom = regexp.MustCompile(`from\s*\(\s*'([a-zA-Z0-9-]+:[^']+)'`) doubleQuotedFrom = regexp.MustCompile(`from\s*\(\s*"([a-zA-Z0-9-]+:[^"]+)"`) @@ -41,8 +44,8 @@ var ( jsonLanguageRegexp = regexp.MustCompile(`.*\.json\(\).*`) circuitBreakerRegexp = regexp.MustCompile(`.*\.circuitBreaker\(\).*`) restConfigurationRegexp = regexp.MustCompile(`.*restConfiguration\(\).*`) - restRegexp = regexp.MustCompile(`.*rest\(("[a-zA-Z0-9-/]+")*\).*`) - restXMLRegexp = regexp.MustCompile(`^\s*rest\s*{.*`) + restRegexp = regexp.MustCompile(`.*rest\s*\([^)]*\).*`) + restClosureRegexp = regexp.MustCompile(`.*rest\s*{\s*`) groovyLanguageRegexp = regexp.MustCompile(`.*\.groovy\s*\(.*\).*`) jsonPathLanguageRegexp = regexp.MustCompile(`.*\.?(jsonpath|jsonpathWriteAsString)\s*\(.*\).*`) ognlRegexp = regexp.MustCompile(`.*\.ognl\s*\(.*\).*`) @@ -51,27 +54,91 @@ var ( xpathRegexp = regexp.MustCompile(`.*\.?xpath\s*\(.*\).*`) xtokenizeRegexp = regexp.MustCompile(`.*\.xtokenize\s*\(.*\).*`) - sourceDependencies = struct { - main map[*regexp.Regexp]string - quarkus map[*regexp.Regexp]string - }{ - main: map[*regexp.Regexp]string{ - jsonLibraryRegexp: "camel:jackson", - jsonLanguageRegexp: "camel:jackson", - circuitBreakerRegexp: "camel:hystrix", - restConfigurationRegexp: "camel:rest", - restRegexp: "camel:rest", - restXMLRegexp: "camel:rest", - groovyLanguageRegexp: "camel:groovy", - jsonPathLanguageRegexp: "camel:jsonpath", - ognlRegexp: "camel:ognl", - mvelRegexp: "camel:mvel", - xqueryRegexp: "camel:saxon", - xpathRegexp: "camel:xpath", - xtokenizeRegexp: "camel:jaxp", + sourceDependencies = map[*regexp.Regexp]catalog2deps{ + jsonLibraryRegexp: func(_ *camel.RuntimeCatalog) []string { + return []string{"camel:jackson"} + }, + jsonLanguageRegexp: func(_ *camel.RuntimeCatalog) []string { + return []string{"camel:jackson"} + }, + circuitBreakerRegexp: func(_ *camel.RuntimeCatalog) []string { + return []string{"camel:hystrix"} + }, + restConfigurationRegexp: func(catalog *camel.RuntimeCatalog) []string { + deps := make([]string, 0) + if c, ok := catalog.CamelCatalogSpec.Runtime.Capabilities["rest"]; ok { + for _, d := range c.Dependencies { + deps = append(deps, fmt.Sprintf("mvn:%s/%s", d.GroupID, d.ArtifactID)) + } + } + return deps + }, + restRegexp: func(catalog *camel.RuntimeCatalog) []string { + deps := make([]string, 0) + if c, ok := catalog.CamelCatalogSpec.Runtime.Capabilities["rest"]; ok { + for _, d := range c.Dependencies { + deps = append(deps, fmt.Sprintf("mvn:%s/%s", d.GroupID, d.ArtifactID)) + } + } + return deps + }, + restClosureRegexp: func(catalog *camel.RuntimeCatalog) []string { + deps := make([]string, 0) + if c, ok := catalog.CamelCatalogSpec.Runtime.Capabilities["rest"]; ok { + for _, d := range c.Dependencies { + deps = append(deps, fmt.Sprintf("mvn:%s/%s", d.GroupID, d.ArtifactID)) + } + } + return deps + }, + groovyLanguageRegexp: func(catalog *camel.RuntimeCatalog) []string { + if dependency, ok := catalog.GetLanguageDependency("groovy"); ok { + return []string{dependency} + } + + return []string{} + }, + jsonPathLanguageRegexp: func(catalog *camel.RuntimeCatalog) []string { + if dependency, ok := catalog.GetLanguageDependency("jsonpath"); ok { + return []string{dependency} + } + + return []string{} + }, + ognlRegexp: func(catalog *camel.RuntimeCatalog) []string { + if dependency, ok := catalog.GetLanguageDependency("ognl"); ok { + return []string{dependency} + } + + return []string{} + }, + mvelRegexp: func(catalog *camel.RuntimeCatalog) []string { + if dependency, ok := catalog.GetLanguageDependency("mvel"); ok { + return []string{dependency} + } + + return []string{} + }, + xqueryRegexp: func(catalog *camel.RuntimeCatalog) []string { + if dependency, ok := catalog.GetLanguageDependency("xquery"); ok { + return []string{dependency} + } + + return []string{} + }, + xpathRegexp: func(catalog *camel.RuntimeCatalog) []string { + if dependency, ok := catalog.GetLanguageDependency("xpath"); ok { + return []string{dependency} + } + + return []string{} }, - quarkus: map[*regexp.Regexp]string{ - xtokenizeRegexp: "camel-quarkus:core-xml", + xtokenizeRegexp: func(catalog *camel.RuntimeCatalog) []string { + if dependency, ok := catalog.GetLanguageDependency("xtokenize"); ok { + return []string{dependency} + } + + return []string{} }, } ) @@ -143,14 +210,12 @@ func (i *baseInspector) discoverDependencies(source v1.SourceSpec, meta *Metadat } } - for pattern, dep := range sourceDependencies.main { - if i.catalog.Runtime.Provider == v1.RuntimeProviderQuarkus { - // Check whether quarkus has its own artifact that differs from the standard one - if _, ok := sourceDependencies.quarkus[pattern]; ok { - dep = sourceDependencies.quarkus[pattern] - } + for pattern, supplier := range sourceDependencies { + if !pattern.MatchString(source.Content) { + continue } - if pattern.MatchString(source.Content) { + + for _, dep := range supplier(i.catalog) { i.addDependency(dep, meta) } } @@ -192,3 +257,53 @@ func (i *baseInspector) decodeComponent(uri string) string { } return "" } + +// hasOnlyPassiveEndpoints returns true if the source has no endpoint that needs to remain always active +func (i *baseInspector) hasOnlyPassiveEndpoints(fromURIs []string) bool { + passivePlusHTTP := make(map[string]bool) + i.catalog.VisitSchemes(func(id string, scheme v1.CamelScheme) bool { + if scheme.HTTP || scheme.Passive { + passivePlusHTTP[id] = true + } + + return true + }) + + return i.containsOnlyURIsIn(fromURIs, passivePlusHTTP) +} + +func (i *baseInspector) containsOnlyURIsIn(fromURI []string, allowed map[string]bool) bool { + for _, uri := range fromURI { + prefix := i.getURIPrefix(uri) + if enabled, ok := allowed[prefix]; !ok || !enabled { + return false + } + } + return true +} + +func (i *baseInspector) getURIPrefix(uri string) string { + parts := strings.SplitN(uri, ":", 2) + if len(parts) > 0 { + return parts[0] + } + return "" +} + +func (i *baseInspector) containsHTTPURIs(fromURI []string) bool { + for _, uri := range fromURI { + prefix := i.getURIPrefix(uri) + scheme, ok := i.catalog.GetScheme(prefix) + + if !ok { + // scheme does not exists + continue + } + + if scheme.HTTP { + return true + } + } + + return false +} diff --git a/pkg/util/source/inspector_groovy.go b/pkg/util/source/inspector_groovy.go index 8ec882335a..a37bfc087e 100644 --- a/pkg/util/source/inspector_groovy.go +++ b/pkg/util/source/inspector_groovy.go @@ -49,5 +49,10 @@ func (i GroovyInspector) Extract(source v1.SourceSpec, meta *Metadata) error { i.discoverDependencies(source, meta) + hasRest := restRegexp.MatchString(source.Content) || restClosureRegexp.MatchString(source.Content) + + meta.ExposesHTTPServices = hasRest || i.containsHTTPURIs(meta.FromURIs) + meta.PassiveEndpoints = i.hasOnlyPassiveEndpoints(meta.FromURIs) + return nil } diff --git a/pkg/util/source/inspector_java_script.go b/pkg/util/source/inspector_java_script.go index 60e68f3b57..f79dd3a7fd 100644 --- a/pkg/util/source/inspector_java_script.go +++ b/pkg/util/source/inspector_java_script.go @@ -49,5 +49,8 @@ func (i JavaScriptInspector) Extract(source v1.SourceSpec, meta *Metadata) error i.discoverDependencies(source, meta) + meta.ExposesHTTPServices = restRegexp.MatchString(source.Content) || i.containsHTTPURIs(meta.FromURIs) + meta.PassiveEndpoints = i.hasOnlyPassiveEndpoints(meta.FromURIs) + return nil } diff --git a/pkg/util/source/inspector_java_source.go b/pkg/util/source/inspector_java_source.go index 7b79198e33..32bd0b044a 100644 --- a/pkg/util/source/inspector_java_source.go +++ b/pkg/util/source/inspector_java_source.go @@ -45,5 +45,8 @@ func (i JavaSourceInspector) Extract(source v1.SourceSpec, meta *Metadata) error i.discoverDependencies(source, meta) + meta.ExposesHTTPServices = restRegexp.MatchString(source.Content) || i.containsHTTPURIs(meta.FromURIs) + meta.PassiveEndpoints = i.hasOnlyPassiveEndpoints(meta.FromURIs) + return nil } diff --git a/pkg/util/source/inspector_kotlin.go b/pkg/util/source/inspector_kotlin.go index 44efd099d5..b949318b9c 100644 --- a/pkg/util/source/inspector_kotlin.go +++ b/pkg/util/source/inspector_kotlin.go @@ -45,5 +45,10 @@ func (i KotlinInspector) Extract(source v1.SourceSpec, meta *Metadata) error { i.discoverDependencies(source, meta) + hasRest := restRegexp.MatchString(source.Content) || restClosureRegexp.MatchString(source.Content) + + meta.ExposesHTTPServices = hasRest || i.containsHTTPURIs(meta.FromURIs) + meta.PassiveEndpoints = i.hasOnlyPassiveEndpoints(meta.FromURIs) + return nil } diff --git a/pkg/util/source/inspector_xml.go b/pkg/util/source/inspector_xml.go index 5ec7b99072..48777de191 100644 --- a/pkg/util/source/inspector_xml.go +++ b/pkg/util/source/inspector_xml.go @@ -45,6 +45,7 @@ func (i XMLInspector) Extract(source v1.SourceSpec, meta *Metadata) error { switch se.Name.Local { case "rest", "restConfiguration": i.addDependency("camel:rest", meta) + meta.ExposesHTTPServices = true case "circuitBreaker": i.addDependency("camel:hystrix", meta) case "language": @@ -77,5 +78,8 @@ func (i XMLInspector) Extract(source v1.SourceSpec, meta *Metadata) error { i.discoverDependencies(source, meta) + meta.ExposesHTTPServices = meta.ExposesHTTPServices || i.containsHTTPURIs(meta.FromURIs) + meta.PassiveEndpoints = i.hasOnlyPassiveEndpoints(meta.FromURIs) + return nil } diff --git a/pkg/util/source/inspector_yaml.go b/pkg/util/source/inspector_yaml.go index 06a1ce39fa..e42eb38bc6 100644 --- a/pkg/util/source/inspector_yaml.go +++ b/pkg/util/source/inspector_yaml.go @@ -49,6 +49,9 @@ func (inspector YAMLInspector) Extract(source v1.SourceSpec, meta *Metadata) err inspector.discoverDependencies(source, meta) + meta.ExposesHTTPServices = meta.ExposesHTTPServices || inspector.containsHTTPURIs(meta.FromURIs) + meta.PassiveEndpoints = inspector.hasOnlyPassiveEndpoints(meta.FromURIs) + return nil } @@ -56,6 +59,7 @@ func (inspector YAMLInspector) parseStep(key string, content interface{}, meta * switch key { case "rest": inspector.addDependency("camel:rest", meta) + meta.ExposesHTTPServices = true case "circuitBreaker": inspector.addDependency("camel:hystrix", meta) } @@ -126,6 +130,5 @@ func (inspector YAMLInspector) parseStep(key string, content interface{}, meta * meta.ToURIs = append(meta.ToURIs, maybeURI) } } - return nil } diff --git a/pkg/util/source/types.go b/pkg/util/source/types.go index 09f727a4f0..1802917440 100644 --- a/pkg/util/source/types.go +++ b/pkg/util/source/types.go @@ -27,4 +27,20 @@ type Metadata struct { ToURIs []string // All inferred dependencies required to run the integration Dependencies *strset.Set + // ExposesHTTPServices indicates if a route defined by the source is exposed + // through HTTP + ExposesHTTPServices bool + // PassiveEndpoints indicates that the source contains only passive endpoints that + // are activated from external calls, including HTTP (useful to determine if the + // integration can scale to 0) + PassiveEndpoints bool +} + +// NewMetadata -- +func NewMetadata() Metadata { + return Metadata{ + FromURIs: make([]string, 0), + ToURIs: make([]string, 0), + Dependencies: strset.New(), + } }