You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2024/02/02 11:33:33 UTC
(camel) 01/13: CAMEL-20378: Languages should be thread-safe and be configured only via properties array, all in the same way.
This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch lang2
in repository https://gitbox.apache.org/repos/asf/camel.git
commit c3205f090cd8c1d8e09713cc6e0287b135b2c036
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Feb 2 09:50:14 2024 +0100
CAMEL-20378: Languages should be thread-safe and be configured only via properties array, all in the same way.
---
.../camel/language/tokenizer/TokenizeLanguage.java | 210 +++------------------
.../org/apache/camel/builder/ExpressionClause.java | 4 +-
.../org/apache/camel/language/TokenizerTest.java | 37 ++--
.../org/apache/camel/support/CustomizersTest.java | 114 -----------
.../camel/support/SingleInputLanguageSupport.java | 1 +
.../ROOT/pages/camel-4x-upgrade-guide-4_4.adoc | 6 +
6 files changed, 48 insertions(+), 324 deletions(-)
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 9456066bc54..6c246662ab6 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,15 +16,11 @@
*/
package org.apache.camel.language.tokenizer;
-import org.apache.camel.CamelContext;
import org.apache.camel.Expression;
import org.apache.camel.Predicate;
-import org.apache.camel.spi.PropertyConfigurer;
import org.apache.camel.support.ExpressionToPredicateAdapter;
-import org.apache.camel.support.SingleInputLanguageSupport;
+import org.apache.camel.support.LanguageSupport;
import org.apache.camel.support.builder.ExpressionBuilder;
-import org.apache.camel.support.component.PropertyConfigurerSupport;
-import org.apache.camel.util.ObjectHelper;
/**
* A language for tokenizer expressions.
@@ -39,89 +35,42 @@ import org.apache.camel.util.ObjectHelper;
* <tt>token</tt> and <tt>endToken</tt>. And the <tt>xml</tt> mode supports the <tt>inheritNamespaceTagName</tt> option.
*/
@org.apache.camel.spi.annotations.Language("tokenize")
-public class TokenizeLanguage extends SingleInputLanguageSupport implements PropertyConfigurer {
+public class TokenizeLanguage extends LanguageSupport {
- private String token;
- private String endToken;
- private String inheritNamespaceTagName;
- private boolean regex;
- private boolean xml;
- private boolean includeTokens;
- private String group;
- private String groupDelimiter;
- private boolean skipFirst;
+ @Override
+ public Predicate createPredicate(String expression) {
+ return ExpressionToPredicateAdapter.toPredicate(createExpression(expression));
+ }
@Override
- public boolean configure(CamelContext camelContext, Object target, String name, Object value, boolean ignoreCase) {
- if (target != this) {
- throw new IllegalStateException("Can only configure our own instance !");
- }
- switch (ignoreCase ? name.toLowerCase() : name) {
- case "token":
- setToken(PropertyConfigurerSupport.property(camelContext, String.class, value));
- return true;
- case "endtoken":
- case "endToken":
- setEndToken(PropertyConfigurerSupport.property(camelContext, String.class, value));
- return true;
- case "inheritnamespacetagname":
- case "inheritNamespaceTagName":
- setInheritNamespaceTagName(PropertyConfigurerSupport.property(camelContext, String.class, value));
- return true;
- case "headername":
- case "headerName":
- setHeaderName(PropertyConfigurerSupport.property(camelContext, String.class, value));
- return true;
- case "propertyname":
- case "propertyName":
- setPropertyName(PropertyConfigurerSupport.property(camelContext, String.class, value));
- return true;
- case "variablename":
- case "variableName":
- setVariableName(PropertyConfigurerSupport.property(camelContext, String.class, value));
- return true;
- case "regex":
- setRegex(PropertyConfigurerSupport.property(camelContext, Boolean.class, value));
- return true;
- case "xml":
- setXml(PropertyConfigurerSupport.property(camelContext, Boolean.class, value));
- return true;
- case "includetokens":
- case "includeTokens":
- setIncludeTokens(PropertyConfigurerSupport.property(camelContext, Boolean.class, value));
- return true;
- case "group":
- setGroup(PropertyConfigurerSupport.property(camelContext, String.class, value));
- return true;
- case "groupdelimiter":
- case "groupDelimiter":
- setGroupDelimiter(PropertyConfigurerSupport.property(camelContext, String.class, value));
- return true;
- case "skipfirst":
- case "skipFirst":
- setSkipFirst(PropertyConfigurerSupport.property(camelContext, Boolean.class, value));
- return true;
- default:
- return false;
- }
+ public Expression createExpression(String expression) {
+ return createExpression(expression, null);
}
@Override
- public Predicate createPredicate(String expression) {
- return ExpressionToPredicateAdapter.toPredicate(createExpression(expression));
+ public Predicate createPredicate(String expression, Object[] properties) {
+ return ExpressionToPredicateAdapter.toPredicate(createExpression(expression, properties));
}
- /**
- * Creates a tokenize expression.
- */
- public Expression createExpression() {
- ObjectHelper.notNull(token, "token");
+ @Override
+ public Expression createExpression(String expression, Object[] properties) {
+ String token = property(String.class, properties, 0, expression);
+ String endToken = property(String.class, properties, 1, null);
+ String inheritNamespaceTagName = property(String.class, properties, 2, null);
+ String headerName = property(String.class, properties, 3, null);
+ String groupDelimiter = property(String.class, properties, 4, null);
+ boolean regex = property(boolean.class, properties, 5, false);
+ boolean xml = property(boolean.class, properties, 6, false);
+ boolean includeTokens = property(boolean.class, properties, 7, false);
+ String group = property(String.class, properties, 8, null);
+ boolean skipFirst = property(boolean.class, properties, 9, false);
+ String propertyName = property(String.class, properties, 10, null);
+ String variableName = property(String.class, properties, 11, null);
- // validate some invalid combinations
if (endToken != null && inheritNamespaceTagName != null) {
throw new IllegalArgumentException("Cannot have both xml and pair tokenizer enabled.");
}
- if (isXml() && (endToken != null || includeTokens)) {
+ if (xml && (endToken != null || includeTokens)) {
throw new IllegalArgumentException("Cannot have both xml and pair tokenizer enabled.");
}
if (endToken == null && includeTokens) {
@@ -129,7 +78,7 @@ public class TokenizeLanguage extends SingleInputLanguageSupport implements Prop
}
Expression answer = null;
- if (isXml()) {
+ if (xml) {
answer = ExpressionBuilder.tokenizeXMLExpression(token, inheritNamespaceTagName);
} else if (endToken != null) {
answer = ExpressionBuilder.tokenizePairExpression(token, endToken, includeTokens);
@@ -138,7 +87,7 @@ public class TokenizeLanguage extends SingleInputLanguageSupport implements Prop
if (answer == null) {
// use the regular tokenizer
final Expression exp
- = ExpressionBuilder.singleInputExpression(getVariableName(), getHeaderName(), getPropertyName());
+ = ExpressionBuilder.singleInputExpression(variableName, headerName, propertyName);
if (regex) {
answer = ExpressionBuilder.regexTokenizeExpression(exp, token);
} else {
@@ -152,7 +101,7 @@ public class TokenizeLanguage extends SingleInputLanguageSupport implements Prop
// if group then wrap answer in group expression
if (group != null) {
- if (isXml()) {
+ if (xml) {
answer = ExpressionBuilder.groupXmlIteratorExpression(answer, group);
} else {
String delim = groupDelimiter != null ? groupDelimiter : token;
@@ -164,110 +113,7 @@ public class TokenizeLanguage extends SingleInputLanguageSupport implements Prop
answer.init(getCamelContext());
}
return answer;
- }
-
- @Override
- public Expression createExpression(String expression) {
- if (ObjectHelper.isNotEmpty(expression)) {
- this.token = expression;
- }
- return createExpression();
- }
-
- @Override
- public Predicate createPredicate(String expression, Object[] properties) {
- return ExpressionToPredicateAdapter.toPredicate(createExpression(expression, properties));
- }
-
- @Override
- public Expression createExpression(String expression, Object[] properties) {
- TokenizeLanguage answer = new TokenizeLanguage();
- answer.setToken(property(String.class, properties, 0, token));
- answer.setEndToken(property(String.class, properties, 1, endToken));
- answer.setInheritNamespaceTagName(
- property(String.class, properties, 2, inheritNamespaceTagName));
- answer.setHeaderName(property(String.class, properties, 3, getHeaderName()));
- answer.setGroupDelimiter(property(String.class, properties, 4, groupDelimiter));
- answer.setRegex(property(boolean.class, properties, 5, regex));
- answer.setXml(property(boolean.class, properties, 6, xml));
- answer.setIncludeTokens(property(boolean.class, properties, 7, includeTokens));
- answer.setGroup(property(String.class, properties, 8, group));
- answer.setSkipFirst(property(boolean.class, properties, 9, skipFirst));
- answer.setPropertyName(property(String.class, properties, 10, getPropertyName()));
- answer.setVariableName(property(String.class, properties, 11, getVariableName()));
- return answer.createExpression(expression);
- }
-
- public String getToken() {
- return token;
- }
-
- public void setToken(String token) {
- this.token = token;
- }
-
- public String getEndToken() {
- return endToken;
- }
-
- public void setEndToken(String endToken) {
- this.endToken = endToken;
- }
-
- public boolean isRegex() {
- return regex;
- }
-
- public void setRegex(boolean regex) {
- this.regex = regex;
- }
-
- public String getInheritNamespaceTagName() {
- return inheritNamespaceTagName;
- }
-
- public void setInheritNamespaceTagName(String inheritNamespaceTagName) {
- this.inheritNamespaceTagName = inheritNamespaceTagName;
- }
-
- public boolean isXml() {
- return xml;
- }
-
- public void setXml(boolean xml) {
- this.xml = xml;
- }
-
- public boolean isIncludeTokens() {
- return includeTokens;
- }
-
- public void setIncludeTokens(boolean includeTokens) {
- this.includeTokens = includeTokens;
- }
-
- public String getGroup() {
- return group;
- }
-
- public void setGroup(String group) {
- this.group = "0".equals(group) ? null : group;
- }
-
- public String getGroupDelimiter() {
- return groupDelimiter;
- }
-
- public void setGroupDelimiter(String groupDelimiter) {
- this.groupDelimiter = groupDelimiter;
- }
-
- public boolean isSkipFirst() {
- return skipFirst;
- }
- public void setSkipFirst(boolean skipFirst) {
- this.skipFirst = skipFirst;
}
}
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/ExpressionClause.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/ExpressionClause.java
index 68f944bf094..9a4e468b23e 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/builder/ExpressionClause.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/ExpressionClause.java
@@ -882,7 +882,7 @@ public class ExpressionClause<T> implements Expression, Predicate {
* @return the builder to continue processing the DSL
*/
public T tokenizeXML(String tagName) {
- return tokenizeXML(tagName, null);
+ return delegate.tokenizeXMLPair(tagName, null, null);
}
/**
@@ -904,7 +904,7 @@ public class ExpressionClause<T> implements Expression, Predicate {
* @return the builder to continue processing the DSL
*/
public T tokenizeXML(String tagName, String inheritNamespaceTagName) {
- return tokenizeXML(tagName, inheritNamespaceTagName, 0);
+ return delegate.tokenizeXMLPair(tagName, inheritNamespaceTagName, null);
}
/**
diff --git a/core/camel-core/src/test/java/org/apache/camel/language/TokenizerTest.java b/core/camel-core/src/test/java/org/apache/camel/language/TokenizerTest.java
index 2e4f055e929..b0b99a9474f 100644
--- a/core/camel-core/src/test/java/org/apache/camel/language/TokenizerTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/language/TokenizerTest.java
@@ -25,9 +25,7 @@ import org.apache.camel.language.tokenizer.TokenizeLanguage;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
public class TokenizerTest extends ExchangeTestSupport {
@@ -37,9 +35,8 @@ public class TokenizerTest extends ExchangeTestSupport {
Expression tokenize(String token, boolean regex) {
TokenizeLanguage language = new TokenizeLanguage();
- language.setToken(token);
- language.setRegex(regex);
- return language.createExpression(null);
+ language.setCamelContext(context);
+ return language.createExpression(null, new Object[] { token, null, null, null, null, regex });
}
Expression tokenize(String headerName, String token) {
@@ -48,26 +45,21 @@ public class TokenizerTest extends ExchangeTestSupport {
Expression tokenize(String headerName, String token, boolean regex) {
TokenizeLanguage language = new TokenizeLanguage();
- language.setHeaderName(headerName);
- language.setToken(token);
- language.setRegex(regex);
- return language.createExpression(null);
+ language.setCamelContext(context);
+ return language.createExpression(null, new Object[] { token, null, null, headerName });
}
Expression tokenizePair(String startToken, String endToken, boolean includeTokens) {
TokenizeLanguage language = new TokenizeLanguage();
- language.setToken(startToken);
- language.setEndToken(endToken);
- language.setIncludeTokens(includeTokens);
- return language.createExpression(null);
+ language.setCamelContext(context);
+ return language.createExpression(null,
+ new Object[] { startToken, endToken, null, null, null, null, null, includeTokens });
}
Expression tokenizeXML(String tagName, String inheritNamespaceTagName) {
TokenizeLanguage language = new TokenizeLanguage();
- language.setToken(tagName);
- language.setInheritNamespaceTagName(inheritNamespaceTagName);
- language.setXml(true);
- return language.createExpression(null);
+ language.setCamelContext(context);
+ return language.createExpression(null, new Object[] { tagName, null, inheritNamespaceTagName, null, null, null, true });
}
@Override
@@ -145,10 +137,8 @@ public class TokenizerTest extends ExchangeTestSupport {
@Test
public void testTokenizeManualConfiguration() throws Exception {
TokenizeLanguage lan = new TokenizeLanguage();
- lan.setHeaderName("names");
- lan.setRegex(false);
- lan.setToken(",");
- Expression exp = lan.createExpression();
+ lan.setCamelContext(context);
+ Expression exp = lan.createExpression(null, new Object[] { ",", null, null, "names" });
exp.init(context);
List<?> names = exp.evaluate(exchange, List.class);
@@ -157,11 +147,6 @@ public class TokenizerTest extends ExchangeTestSupport {
assertEquals("Claus", names.get(0));
assertEquals("James", names.get(1));
assertEquals("Willem", names.get(2));
-
- assertEquals("names", lan.getHeaderName());
- assertEquals(",", lan.getToken());
- assertFalse(lan.isRegex());
- assertTrue(lan.isSingleton());
}
@Test
diff --git a/core/camel-core/src/test/java/org/apache/camel/support/CustomizersTest.java b/core/camel-core/src/test/java/org/apache/camel/support/CustomizersTest.java
index ec590239e92..88d7a37d9de 100644
--- a/core/camel-core/src/test/java/org/apache/camel/support/CustomizersTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/support/CustomizersTest.java
@@ -25,13 +25,10 @@ import java.util.stream.Stream;
import org.apache.camel.Exchange;
import org.apache.camel.component.log.LogComponent;
import org.apache.camel.impl.DefaultCamelContext;
-import org.apache.camel.language.tokenizer.TokenizeLanguage;
import org.apache.camel.spi.ComponentCustomizer;
import org.apache.camel.spi.DataFormat;
import org.apache.camel.spi.DataFormatCustomizer;
import org.apache.camel.spi.DataFormatFactory;
-import org.apache.camel.spi.Language;
-import org.apache.camel.spi.LanguageCustomizer;
import org.apache.camel.support.processor.DefaultExchangeFormatter;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
@@ -305,117 +302,6 @@ public class CustomizersTest {
assertEquals(1, ((MyDataFormat) df1).getId());
}
- // *****************************
- //
- // Language
- //
- // *****************************
-
- @Test
- public void testLanguageCustomizationFromRegistry() {
- AtomicInteger counter = new AtomicInteger();
-
- DefaultCamelContext context = new DefaultCamelContext();
- context.getCamelContextExtension().getRegistry().bind(
- "tokenize",
- new TokenizeLanguage());
- context.getCamelContextExtension().getRegistry().bind(
- "tokenize-customizer",
- LanguageCustomizer.forType(TokenizeLanguage.class,
- target -> target.setGroup(Integer.toString(counter.incrementAndGet()))));
-
- Language l1 = context.resolveLanguage("tokenize");
- assertTrue(l1 instanceof TokenizeLanguage);
- assertEquals("1", ((TokenizeLanguage) l1).getGroup());
-
- Language l2 = context.resolveLanguage("tokenize");
- assertTrue(l2 instanceof TokenizeLanguage);
- assertEquals("1", ((TokenizeLanguage) l2).getGroup());
-
- // as the language is resolved via the registry, then the instance is the same
- // even if it is not a singleton
- assertSame(l1, l2);
- }
-
- @Test
- public void testLanguageCustomizationFromResource() {
- AtomicInteger counter = new AtomicInteger();
-
- DefaultCamelContext context = new DefaultCamelContext();
- context.getCamelContextExtension().getRegistry().bind(
- "tokenize-customizer",
- LanguageCustomizer.forType(TokenizeLanguage.class,
- target -> target.setGroup(Integer.toString(counter.incrementAndGet()))));
-
- // singleton language so its customized once
- Language l1 = context.resolveLanguage("tokenize");
- assertTrue(l1 instanceof TokenizeLanguage);
- assertEquals("1", ((TokenizeLanguage) l1).getGroup());
-
- Language l2 = context.resolveLanguage("tokenize");
- assertTrue(l2 instanceof TokenizeLanguage);
- assertEquals("1", ((TokenizeLanguage) l2).getGroup());
-
- assertSame(l1, l2);
- }
-
- @Test
- public void testLanguageCustomizationFromResourceWithFilter() {
- AtomicInteger counter = new AtomicInteger();
-
- DefaultCamelContext context = new DefaultCamelContext();
- context.getCamelContextExtension().getRegistry().bind(
- "customizer-filter",
- LanguageCustomizer.Policy.none());
- context.getCamelContextExtension().getRegistry().bind(
- "tokenize-customizer",
- LanguageCustomizer.forType(TokenizeLanguage.class,
- target -> target.setGroup(Integer.toString(counter.incrementAndGet()))));
-
- // singleton language so its customized once
- Language l1 = context.resolveLanguage("tokenize");
- assertTrue(l1 instanceof TokenizeLanguage);
- assertNull(((TokenizeLanguage) l1).getGroup());
-
- Language l2 = context.resolveLanguage("tokenize");
- assertTrue(l2 instanceof TokenizeLanguage);
- assertNull(((TokenizeLanguage) l2).getGroup());
-
- assertSame(l1, l2);
- }
-
- @ParameterizedTest
- @MethodSource("disableLanguageCustomizationProperties")
- public void testLanguageCustomizationDisabledByProperty(Properties initialProperties) {
- DefaultCamelContext context = new DefaultCamelContext();
- context.getPropertiesComponent().setInitialProperties(initialProperties);
-
- context.getCamelContextExtension().getRegistry().bind(
- "customizer-filter",
- new CustomizersSupport.LanguageCustomizationEnabledPolicy());
- context.getCamelContextExtension().getRegistry().bind(
- "tokenize-customizer",
- LanguageCustomizer.forType(TokenizeLanguage.class, target -> target.setGroup("something")));
-
- assertNotEquals("something", ((TokenizeLanguage) context.resolveLanguage("tokenize")).getGroup());
- }
-
- @ParameterizedTest
- @MethodSource("enableLanguageCustomizationProperties")
- public void testLanguageCustomizationEnabledByProperty(Properties initialProperties) {
- DefaultCamelContext context = new DefaultCamelContext();
- context.getPropertiesComponent().setInitialProperties(initialProperties);
-
- context.getCamelContextExtension().getRegistry().bind(
- "customizer-filter",
- new CustomizersSupport.LanguageCustomizationEnabledPolicy());
- context.getCamelContextExtension().getRegistry().bind(
- "tokenize-customizer",
- LanguageCustomizer.forType(TokenizeLanguage.class, target -> target.setGroup("something")));
-
- assertEquals("something", ((TokenizeLanguage) context.resolveLanguage("tokenize")).getGroup());
- }
-
// *****************************
//
// Model
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/SingleInputLanguageSupport.java b/core/camel-support/src/main/java/org/apache/camel/support/SingleInputLanguageSupport.java
index eabffb5a5a7..4b84833105d 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/SingleInputLanguageSupport.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/SingleInputLanguageSupport.java
@@ -21,6 +21,7 @@ import org.apache.camel.spi.Language;
/**
* Base class for {@link Language} implementations that support different sources of input data.
*/
+@Deprecated
public abstract class SingleInputLanguageSupport extends LanguageSupport {
private String variableName;
diff --git a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_4.adoc b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_4.adoc
index f2e2e1b353c..127c4768f2d 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_4.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_4.adoc
@@ -21,6 +21,12 @@ Durations and some time-related information were consolidated in a new internal
The `lookup` method in `org.apache.camel.component.properties.PropertiesLookup` now has a 2nd parameter for the default value.
+==== Languages
+
+The way languages are created and configured by Camel has been refactored to be aligned and avoid a thread-safety issues
+when using Java DSL. All the setter/getter on the `Language` classes has been removed (such as `TokenizeLanguage`) as the options are configured in the DSL
+in a consistent and thread-safe manner.
+
==== WireTap EIP
The copied exchange is no longer having exchange property CORRELATION_ID set that links to the original exchange.