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 a4723cc09f2 18913: simple language - Add join function that for
example can be used in camel-http to build multi-value query
a4723cc09f2 is described below
commit a4723cc09f21310cf71f66538bffa995a12e5b7f
Author: Claus Ibsen <[email protected]>
AuthorDate: Fri Jan 13 13:01:29 2023 +0100
18913: simple language - Add join function that for example can be used in
camel-http to build multi-value query
---
.../camel/component/http/HttpSetHeaderIdsTest.java | 81 ++++++++++++++++++++++
.../modules/languages/pages/simple-language.adoc | 6 ++
.../language/simple/SimpleExpressionBuilder.java | 31 +++++++++
.../simple/ast/SimpleFunctionExpression.java | 28 ++++++++
.../apache/camel/language/simple/SimpleTest.java | 26 +++++++
.../camel/support/builder/ExpressionBuilder.java | 47 +++++++++++++
6 files changed, 219 insertions(+)
diff --git
a/components/camel-http/src/test/java/org/apache/camel/component/http/HttpSetHeaderIdsTest.java
b/components/camel-http/src/test/java/org/apache/camel/component/http/HttpSetHeaderIdsTest.java
new file mode 100644
index 00000000000..09349ed2376
--- /dev/null
+++
b/components/camel-http/src/test/java/org/apache/camel/component/http/HttpSetHeaderIdsTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.component.http;
+
+import java.util.List;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.bootstrap.HttpServer;
+import org.apache.http.impl.bootstrap.ServerBootstrap;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class HttpSetHeaderIdsTest extends BaseHttpTest {
+
+ private HttpServer localServer;
+
+ @BeforeEach
+ @Override
+ public void setUp() throws Exception {
+ localServer =
ServerBootstrap.bootstrap().setHttpProcessor(getBasicHttpProcessor())
+
.setConnectionReuseStrategy(getConnectionReuseStrategy()).setResponseFactory(getHttpResponseFactory())
+
.setExpectationVerifier(getHttpExpectationVerifier()).setSslContext(getSSLContext())
+ .registerHandler("/myids", (httpRequest, httpResponse,
httpContext) -> {
+ Assertions.assertNull(httpRequest.getFirstHeader("ids"));
+ String u = httpRequest.getRequestLine().getUri();
+ httpResponse.setEntity(new StringEntity(u));
+ }).create();
+ localServer.start();
+
+ super.setUp();
+ }
+
+ @AfterEach
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+
+ if (localServer != null) {
+ localServer.stop();
+ }
+ }
+
+ @Override
+ protected RoutesBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:myids")
+ .setHeader(Exchange.HTTP_QUERY,
simple("${join(&,id=,${header.ids})}"))
+ .removeHeader("ids")
+ .to("http://localhost:" + localServer.getLocalPort() +
"/myids");
+ }
+ };
+ }
+
+ @Test
+ public void testIds() throws Exception {
+ String o = fluentTemplate.to("direct:myids").withHeader("ids",
List.of(1, 2, 3)).request(String.class);
+ Assertions.assertEquals("/myids?id=1&id=2&id=3", o);
+ }
+
+}
diff --git
a/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-language.adoc
b/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-language.adoc
index 7023b95e8a5..ad3df916128 100644
---
a/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-language.adoc
+++
b/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-language.adoc
@@ -213,6 +213,12 @@ similar to the collate method in Groovy.
the first number of items. This can be used with the
Splitter EIP to split a message body and skip the first N number of items.
+|join(separator,prefix,exp) | String | The join function iterates the message
body (by default) and joins
+the data into a string. The separator is by default a comma. The prefix is
optional.
+
+The join uses the message body as source by default. It is possible to refer
to another
+source (simple language) such as a header via the exp parameter. For example
`join('&','id=','$\{header.ids}')`.
+
|messageHistory |String |The message history of the current exchange how it has
been routed. This is similar to the route stack-trace message history
the error handler logs in case of an unhandled exception.
diff --git
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleExpressionBuilder.java
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleExpressionBuilder.java
index 14a1139d588..eec05382c10 100644
---
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleExpressionBuilder.java
+++
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleExpressionBuilder.java
@@ -185,6 +185,37 @@ public final class SimpleExpressionBuilder {
};
}
+ /**
+ * Joins together the values from the expression
+ */
+ public static Expression joinExpression(final String expression, final
String separator, final String prefix) {
+ return new ExpressionAdapter() {
+ private Expression exp;
+
+ @Override
+ public void init(CamelContext context) {
+ exp =
context.resolveLanguage("simple").createExpression(expression);
+ exp.init(context);
+ exp = ExpressionBuilder.joinExpression(exp, separator, prefix);
+ exp.init(context);
+ }
+
+ @Override
+ public Object evaluate(Exchange exchange) {
+ return exp.evaluate(exchange, Object.class);
+ }
+
+ @Override
+ public String toString() {
+ if (prefix != null) {
+ return "join(" + expression + "," + separator + "," +
prefix + ")";
+ } else {
+ return "join(" + expression + "," + separator + ")";
+ }
+ }
+ };
+ }
+
/**
* Returns a random number between min and max (exclusive)
*/
diff --git
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
index 27388e08b55..c7e0a032822 100644
---
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
+++
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
@@ -32,6 +32,7 @@ import org.apache.camel.support.builder.ExpressionBuilder;
import org.apache.camel.util.ObjectHelper;
import org.apache.camel.util.OgnlHelper;
import org.apache.camel.util.StringHelper;
+import org.apache.camel.util.StringQuoteHelper;
import org.apache.camel.util.URISupport;
/**
@@ -545,6 +546,33 @@ public class SimpleFunctionExpression extends
LiteralExpression {
return SimpleExpressionBuilder.collateExpression(exp, num);
}
+ // join function
+ remainder = ifStartsWithReturnRemainder("join(", function);
+ if (remainder != null) {
+ String values = StringHelper.before(remainder, ")");
+ String separator = ",";
+ String prefix = null;
+ String exp = "${body}";
+ if (ObjectHelper.isNotEmpty(values)) {
+ String[] tokens = StringQuoteHelper.splitSafeQuote(values,
',', false);
+ if (tokens.length > 3) {
+ throw new SimpleParserException(
+ "Valid syntax:
${join(separator,prefix,expression)} was: " + function, token.getIndex());
+ }
+ if (tokens.length == 3) {
+ separator = tokens[0];
+ prefix = tokens[1];
+ exp = tokens[2];
+ } else if (tokens.length == 2) {
+ separator = tokens[0];
+ prefix = tokens[1];
+ } else {
+ separator = tokens[0];
+ }
+ }
+ return SimpleExpressionBuilder.joinExpression(exp, separator,
prefix);
+ }
+
// messageHistory function
remainder = ifStartsWithReturnRemainder("messageHistory", function);
if (remainder != null) {
diff --git
a/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java
b/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java
index 57fcbf88bf3..7466326bf11 100644
---
a/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java
+++
b/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java
@@ -1845,6 +1845,32 @@ public class SimpleTest extends LanguageTestSupport {
assertEquals("G", chunk3.get(0));
}
+ @Test
+ public void testJoinBody() throws Exception {
+ List<Object> data = new ArrayList<>();
+ data.add("A");
+ data.add("B");
+ data.add("C");
+ exchange.getIn().setBody(data);
+
+ assertExpression("${join()}", "A,B,C");
+ assertExpression("${join(;)}", "A;B;C");
+ assertExpression("${join(' ')}", "A B C");
+ assertExpression("${join(',','id=')}", "id=A,id=B,id=C");
+ assertExpression("${join(&,id=)}", "id=A&id=B&id=C");
+ }
+
+ @Test
+ public void testJoinHeader() throws Exception {
+ List<Object> data = new ArrayList<>();
+ data.add("A");
+ data.add("B");
+ data.add("C");
+ exchange.getIn().setHeader("id", data);
+
+ assertExpression("${join('&','id=','${header.id}')}",
"id=A&id=B&id=C");
+ }
+
@Test
public void testRandomExpression() throws Exception {
int min = 1;
diff --git
a/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java
b/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java
index 2d8a08ec715..96de5b5e1c4 100644
---
a/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java
+++
b/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java
@@ -1439,6 +1439,53 @@ public class ExpressionBuilder {
};
}
+ public static Expression joinExpression(final Expression expression, final
String separator, final String prefix) {
+ return new ExpressionAdapter() {
+ private TypeConverter converter;
+
+ @Override
+ public Object evaluate(Exchange exchange) {
+ // evaluate expression as iterator
+ Iterator<?> it = expression.evaluate(exchange, Iterator.class);
+ ObjectHelper.notNull(it, "expression: " + expression + "
evaluated on " + exchange + " must return an java.util.Iterator");
+
+ StringBuilder sb = new StringBuilder();
+ while (it.hasNext()) {
+ Object o = it.next();
+ if (o != null) {
+ String s = converter.tryConvertTo(String.class,
exchange, o);
+ if (s != null) {
+ if (sb.length() > 0) {
+ sb.append(separator);
+ }
+ if (prefix != null) {
+ sb.append(prefix);
+ }
+ sb.append(s);
+ }
+ }
+ }
+
+ return sb.toString();
+ }
+
+ @Override
+ public void init(CamelContext context) {
+ expression.init(context);
+ converter = context.getTypeConverter();
+ }
+
+ @Override
+ public String toString() {
+ if (prefix != null) {
+ return "join(" + expression + "," + separator + "," +
prefix + ")";
+ } else {
+ return "join(" + expression + "," + separator + ")";
+ }
+ }
+ };
+ }
+
/**
* Returns a sort expression which will sort the expression with the given
comparator.
* <p/>