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 7a8ecca4236 CAMEL-20378: Languages should be thread-safe and be
configured only via properties array, all in the same way. (#13004)
7a8ecca4236 is described below
commit 7a8ecca42363837330ede7ad1d9b94c971ea80c6
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Feb 5 11:43:02 2024 +0100
CAMEL-20378: Languages should be thread-safe and be configured only via
properties array, all in the same way. (#13004)
---
.../language/xtokenizer/XMLTokenizeLanguage.java | 41 +++++++++-
.../camel/language/tokenizer/TokenizeLanguage.java | 32 ++++++++
.../camel/language/TokenizeLanguageTest.java | 7 +-
.../apache/camel/support/IteratorConvertTo.java | 93 ++++++++++++++++++++++
4 files changed, 167 insertions(+), 6 deletions(-)
diff --git
a/components/camel-stax/src/main/java/org/apache/camel/language/xtokenizer/XMLTokenizeLanguage.java
b/components/camel-stax/src/main/java/org/apache/camel/language/xtokenizer/XMLTokenizeLanguage.java
index d87499136be..5d41314788d 100644
---
a/components/camel-stax/src/main/java/org/apache/camel/language/xtokenizer/XMLTokenizeLanguage.java
+++
b/components/camel-stax/src/main/java/org/apache/camel/language/xtokenizer/XMLTokenizeLanguage.java
@@ -16,10 +16,15 @@
*/
package org.apache.camel.language.xtokenizer;
+import java.util.Iterator;
import java.util.Map;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
import org.apache.camel.Expression;
import org.apache.camel.spi.annotations.Language;
+import org.apache.camel.support.ExpressionAdapter;
+import org.apache.camel.support.IteratorConvertTo;
import org.apache.camel.support.SingleInputTypedLanguageSupport;
import org.apache.camel.support.builder.Namespaces;
@@ -45,9 +50,11 @@ public class XMLTokenizeLanguage extends
SingleInputTypedLanguageSupport {
@Override
public Expression createExpression(Expression source, String expression,
Object[] properties) {
+ Class<?> type = property(Class.class, properties, 0, null);
Character mode = property(Character.class, properties, 4, "i");
- XMLTokenExpressionIterator answer = new
XMLTokenExpressionIterator(source, expression, mode);
- answer.setGroup(property(int.class, properties, 5, 1));
+
+ XMLTokenExpressionIterator xml = new
XMLTokenExpressionIterator(source, expression, mode);
+ xml.setGroup(property(int.class, properties, 5, 1));
Object obj = properties[6];
if (obj != null) {
Namespaces ns;
@@ -60,8 +67,36 @@ public class XMLTokenizeLanguage extends
SingleInputTypedLanguageSupport {
throw new IllegalArgumentException(
"Namespaces is not instance of java.util.Map or " +
Namespaces.class.getName());
}
- answer.setNamespaces(ns.getNamespaces());
+ xml.setNamespaces(ns.getNamespaces());
+ }
+ Expression answer = xml;
+
+ if (type != null && type != Object.class) {
+ // wrap iterator in a converter
+ final Expression delegate = xml;
+ answer = new ExpressionAdapter() {
+ @Override
+ public Object evaluate(Exchange exchange) {
+ Object value = delegate.evaluate(exchange, Object.class);
+ if (value instanceof Iterator<?> it) {
+ value = new IteratorConvertTo(exchange, it, type);
+ }
+ return value;
+ }
+
+ @Override
+ public void init(CamelContext context) {
+ super.init(context);
+ delegate.init(context);
+ }
+
+ @Override
+ public String toString() {
+ return delegate.toString();
+ }
+ };
}
+
if (getCamelContext() != null) {
answer.init(getCamelContext());
}
diff --git
a/core/camel-core-languages/src/main/java/org/apache/camel/language/tokenizer/TokenizeLanguage.java
b/core/camel-core-languages/src/main/java/org/apache/camel/language/tokenizer/TokenizeLanguage.java
index ca9c7c5286b..ad2986db362 100644
---
a/core/camel-core-languages/src/main/java/org/apache/camel/language/tokenizer/TokenizeLanguage.java
+++
b/core/camel-core-languages/src/main/java/org/apache/camel/language/tokenizer/TokenizeLanguage.java
@@ -16,7 +16,13 @@
*/
package org.apache.camel.language.tokenizer;
+import java.util.Iterator;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
import org.apache.camel.Expression;
+import org.apache.camel.support.ExpressionAdapter;
+import org.apache.camel.support.IteratorConvertTo;
import org.apache.camel.support.SingleInputTypedLanguageSupport;
import org.apache.camel.support.builder.ExpressionBuilder;
@@ -94,6 +100,32 @@ public class TokenizeLanguage extends
SingleInputTypedLanguageSupport {
}
}
+ if (type != null && type != Object.class) {
+ // wrap iterator in a converter
+ final Expression delegate = answer;
+ answer = new ExpressionAdapter() {
+ @Override
+ public Object evaluate(Exchange exchange) {
+ Object value = delegate.evaluate(exchange, Object.class);
+ if (value instanceof Iterator<?> it) {
+ value = new IteratorConvertTo(exchange, it, type);
+ }
+ return value;
+ }
+
+ @Override
+ public void init(CamelContext context) {
+ super.init(context);
+ delegate.init(context);
+ }
+
+ @Override
+ public String toString() {
+ return delegate.toString();
+ }
+ };
+ }
+
if (getCamelContext() != null) {
answer.init(getCamelContext());
}
diff --git
a/core/camel-core/src/test/java/org/apache/camel/language/TokenizeLanguageTest.java
b/core/camel-core/src/test/java/org/apache/camel/language/TokenizeLanguageTest.java
index 7818da28363..e8709be396e 100644
---
a/core/camel-core/src/test/java/org/apache/camel/language/TokenizeLanguageTest.java
+++
b/core/camel-core/src/test/java/org/apache/camel/language/TokenizeLanguageTest.java
@@ -16,8 +16,9 @@
*/
package org.apache.camel.language;
+import java.util.Iterator;
+
import org.apache.camel.model.language.TokenizerExpression;
-import org.apache.camel.util.Scanner;
/**
* Ensures that the "tokenize" language is compliant with the single input
expectations.
@@ -30,7 +31,7 @@ class TokenizeLanguageTest extends
AbstractSingleInputTypedLanguageTest<Tokenize
@Override
protected TestContext testWithTypeContext() {
- return new TestContext("1\n", "1", String.class);
+ return new TestContext("1\n", 1, Integer.class);
}
@Override
@@ -46,7 +47,7 @@ class TokenizeLanguageTest extends
AbstractSingleInputTypedLanguageTest<Tokenize
@Override
protected void assertBodyReceived(Object expected, Object body) {
// uses an scanner, so we need to walk it to get the body
- if (body instanceof Scanner it) {
+ if (body instanceof Iterator it) {
body = it.next();
}
super.assertBodyReceived(expected, body);
diff --git
a/core/camel-support/src/main/java/org/apache/camel/support/IteratorConvertTo.java
b/core/camel-support/src/main/java/org/apache/camel/support/IteratorConvertTo.java
new file mode 100644
index 00000000000..269a4973571
--- /dev/null
+++
b/core/camel-support/src/main/java/org/apache/camel/support/IteratorConvertTo.java
@@ -0,0 +1,93 @@
+/*
+ * 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.support;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.Iterator;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.TypeConverter;
+import org.apache.camel.util.IOHelper;
+
+/**
+ * Wraps an {@link Iterator} so its returned values are automatically
converted to a given type.
+ */
+public final class IteratorConvertTo implements Iterator<Object>, Closeable {
+
+ private final Exchange exchange;
+ private final TypeConverter converter;
+ private final Iterator<?> it;
+ private final Class<?> type;
+ private boolean closed;
+
+ /**
+ * Creates the convert iterator.
+ *
+ * @param exchange the exchange
+ * @param it the iterator to wrap
+ * @param type the type to convert to
+ */
+ public IteratorConvertTo(Exchange exchange, Iterator<?> it, Class<?> type)
{
+ this.exchange = exchange;
+ this.converter = exchange.getContext().getTypeConverter();
+ this.it = it;
+ this.type = type;
+ }
+
+ @Override
+ public void close() throws IOException {
+ try {
+ IOHelper.closeIterator(it);
+ } finally {
+ // we are now closed
+ closed = true;
+ }
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (closed) {
+ return false;
+ }
+
+ boolean answer = it.hasNext();
+ if (!answer) {
+ // auto close
+ try {
+ close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ return answer;
+ }
+
+ @Override
+ public Object next() {
+ Object next = it.next();
+ if (next != null) {
+ next = converter.convertTo(type, exchange, next);
+ }
+ return next;
+ }
+
+ @Override
+ public void remove() {
+ it.remove();
+ }
+}