This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push: new 4605a0ebcc1 CAMEL-19977: camel-core - Java DSL - Add support for using Java 17 te… (#11689) 4605a0ebcc1 is described below commit 4605a0ebcc1391024e7272b3910dfd45c2820152 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Wed Oct 11 14:55:43 2023 +0200 CAMEL-19977: camel-core - Java DSL - Add support for using Java 17 te… (#11689) * CAMEL-19977: camel-core - Java DSL - Add support for using Java 17 text blocks for long URIs which contains line breaks that need to change URI back into a single line for noramlization in Camel. --- .../camel/parser/helper/CamelJavaParserHelper.java | 6 +++ .../helper/CamelJavaRestDslParserHelper.java | 3 ++ .../parser/helper/CamelJavaTreeParserHelper.java | 3 ++ .../parser/java/MyJava17TextBlockRouteBuilder.java | 34 ++++++++++++ ...erJava17TextBlockRouteBuilderConfigureTest.java | 57 ++++++++++++++++++++ .../camel/impl/engine/AbstractCamelContext.java | 4 +- .../camel/processor/UriAsJava17TextBlockTest.java | 61 ++++++++++++++++++++++ .../java/org/apache/camel/util/URISupport.java | 18 +++++++ 8 files changed, 185 insertions(+), 1 deletion(-) diff --git a/catalog/camel-route-parser/src/main/java/org/apache/camel/parser/helper/CamelJavaParserHelper.java b/catalog/camel-route-parser/src/main/java/org/apache/camel/parser/helper/CamelJavaParserHelper.java index e5b49996521..8aab7812d02 100644 --- a/catalog/camel-route-parser/src/main/java/org/apache/camel/parser/helper/CamelJavaParserHelper.java +++ b/catalog/camel-route-parser/src/main/java/org/apache/camel/parser/helper/CamelJavaParserHelper.java @@ -25,6 +25,7 @@ import org.apache.camel.parser.RouteBuilderParser; import org.apache.camel.parser.roaster.AnonymousMethodSource; import org.apache.camel.parser.roaster.StatementFieldSource; import org.apache.camel.tooling.util.Strings; +import org.apache.camel.util.URISupport; import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.ASTNode; import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.AnonymousClassDeclaration; import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.Block; @@ -47,6 +48,7 @@ import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.SimpleType; import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.SingleMemberAnnotation; import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.Statement; import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.StringLiteral; +import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.TextBlock; import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.Type; import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.VariableDeclaration; import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.VariableDeclarationFragment; @@ -342,6 +344,8 @@ public final class CamelJavaParserHelper { boolean fields) { if (strings) { String uri = getLiteralValue(clazz, block, (Expression) arg); + // java 17 text block + uri = URISupport.textBlockToSingleLine(uri); if (!Strings.isNullOrEmpty(uri)) { int position = ((Expression) arg).getStartPosition(); int len = ((Expression) arg).getLength(); @@ -591,6 +595,8 @@ public final class CamelJavaParserHelper { return String.valueOf(booleanLiteral.booleanValue()); } else if (expression instanceof NumberLiteral numberLiteral) { return numberLiteral.getToken(); + } else if (expression instanceof TextBlock textBlock) { + return textBlock.getLiteralValue(); } // if it's a method invocation then add a dummy value assuming the method invocation will return a valid response diff --git a/catalog/camel-route-parser/src/main/java/org/apache/camel/parser/helper/CamelJavaRestDslParserHelper.java b/catalog/camel-route-parser/src/main/java/org/apache/camel/parser/helper/CamelJavaRestDslParserHelper.java index 8a821682cc4..dc3c7711d57 100644 --- a/catalog/camel-route-parser/src/main/java/org/apache/camel/parser/helper/CamelJavaRestDslParserHelper.java +++ b/catalog/camel-route-parser/src/main/java/org/apache/camel/parser/helper/CamelJavaRestDslParserHelper.java @@ -44,6 +44,7 @@ import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.QualifiedName; import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.SimpleName; import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.SingleMemberAnnotation; import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.StringLiteral; +import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.TextBlock; import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.Type; import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.VariableDeclarationStatement; @@ -503,6 +504,8 @@ public final class CamelJavaRestDslParserHelper { return String.valueOf(((BooleanLiteral) expression).booleanValue()); } else if (expression instanceof NumberLiteral) { return ((NumberLiteral) expression).getToken(); + } else if (expression instanceof TextBlock textBlock) { + return textBlock.getLiteralValue(); } // if it's a method invocation then add a dummy value assuming the method invocation will return a valid response diff --git a/catalog/camel-route-parser/src/main/java/org/apache/camel/parser/helper/CamelJavaTreeParserHelper.java b/catalog/camel-route-parser/src/main/java/org/apache/camel/parser/helper/CamelJavaTreeParserHelper.java index 77beae5fd7f..b6c9e6cba04 100644 --- a/catalog/camel-route-parser/src/main/java/org/apache/camel/parser/helper/CamelJavaTreeParserHelper.java +++ b/catalog/camel-route-parser/src/main/java/org/apache/camel/parser/helper/CamelJavaTreeParserHelper.java @@ -45,6 +45,7 @@ import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.QualifiedName; import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.SimpleName; import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.SingleMemberAnnotation; import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.StringLiteral; +import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.TextBlock; import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.Type; import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.VariableDeclarationStatement; @@ -345,6 +346,8 @@ public final class CamelJavaTreeParserHelper { return String.valueOf(((BooleanLiteral) expression).booleanValue()); } else if (expression instanceof NumberLiteral) { return ((NumberLiteral) expression).getToken(); + } else if (expression instanceof TextBlock textBlock) { + return textBlock.getLiteralValue(); } // if it's a method invocation then add a dummy value assuming the method invocation will return a valid response diff --git a/catalog/camel-route-parser/src/test/java/org/apache/camel/parser/java/MyJava17TextBlockRouteBuilder.java b/catalog/camel-route-parser/src/test/java/org/apache/camel/parser/java/MyJava17TextBlockRouteBuilder.java new file mode 100644 index 00000000000..c45e369aab0 --- /dev/null +++ b/catalog/camel-route-parser/src/test/java/org/apache/camel/parser/java/MyJava17TextBlockRouteBuilder.java @@ -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 org.apache.camel.parser.java; + +import org.apache.camel.builder.RouteBuilder; + +public class MyJava17TextBlockRouteBuilder extends RouteBuilder { + + @Override + public void configure() { + from("timer:foo") + .toD(""" + file:output + ?fileExist=Append + &chmod=777 + &allowNullBody=true + """) + .to("log:b"); + } +} diff --git a/catalog/camel-route-parser/src/test/java/org/apache/camel/parser/java/RoasterJava17TextBlockRouteBuilderConfigureTest.java b/catalog/camel-route-parser/src/test/java/org/apache/camel/parser/java/RoasterJava17TextBlockRouteBuilderConfigureTest.java new file mode 100644 index 00000000000..df44b01309b --- /dev/null +++ b/catalog/camel-route-parser/src/test/java/org/apache/camel/parser/java/RoasterJava17TextBlockRouteBuilderConfigureTest.java @@ -0,0 +1,57 @@ +/* + * 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.parser.java; + +import java.io.File; +import java.util.List; + +import org.apache.camel.parser.ParserResult; +import org.apache.camel.parser.helper.CamelJavaParserHelper; +import org.jboss.forge.roaster.Roaster; +import org.jboss.forge.roaster.model.source.JavaClassSource; +import org.jboss.forge.roaster.model.source.MethodSource; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class RoasterJava17TextBlockRouteBuilderConfigureTest { + + private static final Logger LOG = LoggerFactory.getLogger(RoasterJava17TextBlockRouteBuilderConfigureTest.class); + + @Test + void parse() throws Exception { + JavaClassSource clazz = (JavaClassSource) Roaster + .parse(new File("src/test/java/org/apache/camel/parser/java/MyJava17TextBlockRouteBuilder.java")); + MethodSource<JavaClassSource> method = clazz.getMethod("configure"); + + List<ParserResult> list = CamelJavaParserHelper.parseCamelConsumerUris(method, true, false); + for (ParserResult result : list) { + LOG.info("Consumer: {}", result.getElement()); + } + assertEquals("timer:foo", list.get(0).getElement()); + + list = CamelJavaParserHelper.parseCamelProducerUris(method, true, false); + for (ParserResult result : list) { + LOG.info("Producer: {}", result.getElement()); + } + assertEquals("file:output?fileExist=Append&chmod=777&allowNullBody=true", list.get(0).getElement()); + assertEquals("log:b", list.get(1).getElement()); + } + +} diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java index 7a771fd0425..027bcf6d89c 100644 --- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java +++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java @@ -775,8 +775,10 @@ public abstract class AbstractCamelContext extends BaseService LOG.trace("Getting endpoint with uri: {} and parameters: {}", uri, parameters); - // in case path has property placeholders then try to let property component resolve those if (!normalized) { + // java 17 text blocks to single line uri + uri = URISupport.textBlockToSingleLine(uri); + // in case path has property placeholders then try to let property component resolve those uri = EndpointHelper.resolveEndpointUriPropertyPlaceholders(this, uri); } diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/UriAsJava17TextBlockTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/UriAsJava17TextBlockTest.java new file mode 100644 index 00000000000..b92c20f752f --- /dev/null +++ b/core/camel-core/src/test/java/org/apache/camel/processor/UriAsJava17TextBlockTest.java @@ -0,0 +1,61 @@ +/* + * 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.processor; + +import org.apache.camel.ContextTestSupport; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class UriAsJava17TextBlockTest extends ContextTestSupport { + + @Test + public void testUriTestBlock() throws Exception { + assertEquals(1, context.getRoutesSize()); + + MockEndpoint mock = getMockEndpoint("mock:result?retainFirst=123&failFast=false&resultWaitTime=5000"); + mock.expectedBodiesReceived("Hello World"); + + template.sendBody("direct:start", "Hello World"); + + assertMockEndpointsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from( + """ + direct:start? + block=false& + timeout=1234 + """) + .to("log:foo") + .to("log:bar") + .to(""" + mock:result + ?retainFirst=123 + &failFast=false + &resultWaitTime=5000"""); + } + }; + } +} diff --git a/core/camel-util/src/main/java/org/apache/camel/util/URISupport.java b/core/camel-util/src/main/java/org/apache/camel/util/URISupport.java index 4e2da8fff68..6945893da7f 100644 --- a/core/camel-util/src/main/java/org/apache/camel/util/URISupport.java +++ b/core/camel-util/src/main/java/org/apache/camel/util/URISupport.java @@ -43,6 +43,10 @@ public final class URISupport { public static final char[] RAW_TOKEN_START = { '(', '{' }; public static final char[] RAW_TOKEN_END = { ')', '}' }; + // Java 17 text blocks have new lines with optional white space + private static final String TEXT_BLOCK_MARKER = System.lineSeparator(); + private static final Pattern TEXT_BLOCK_PATTERN = Pattern.compile("\n\\s*"); + // Match any key-value pair in the URI query string whose key contains // "passphrase" or "password" or secret key (case-insensitive). // First capture group is the key, second is the value. @@ -86,6 +90,15 @@ public final class URISupport { return sanitized; } + public static String textBlockToSingleLine(String uri) { + // text blocks + if (uri != null && uri.contains(TEXT_BLOCK_MARKER)) { + uri = TEXT_BLOCK_PATTERN.matcher(uri).replaceAll(""); + uri = uri.trim(); + } + return uri; + } + /** * Removes detected sensitive information (such as passwords) from the <em>path part</em> of an URI (that is, the * part without the query parameters or component prefix) and returns the result. @@ -612,6 +625,8 @@ public final class URISupport { * @throws URISyntaxException is thrown if syntax error in the input uri */ public static URI normalizeUriAsURI(String uri) throws URISyntaxException { + // java 17 text blocks to single line uri + uri = URISupport.textBlockToSingleLine(uri); return new URI(UnsafeUriCharactersEncoder.encode(uri, true)); } @@ -620,6 +635,9 @@ public final class URISupport { * values, or other unsafe URL characters, or have authority user/password, etc. */ private static String doComplexNormalizeUri(String uri) throws URISyntaxException { + // java 17 text blocks to single line uri + uri = URISupport.textBlockToSingleLine(uri); + URI u = new URI(UnsafeUriCharactersEncoder.encode(uri, true)); String scheme = u.getScheme(); String path = u.getSchemeSpecificPart();