This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
commit ace4998312724006ba00e79745147a5ffe2edcd3 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Fri Mar 5 14:39:24 2021 +0100 CAMEL-16302: camel-core - Optional property placeholders in properties component. --- .../spi/BridgePropertyPlaceholderConfigurer.java | 12 +- .../main/java/org/apache/camel/CamelContext.java | 3 + .../org/apache/camel/ExtendedCamelContext.java | 14 ++ .../org/apache/camel/spi/PropertiesComponent.java | 20 ++ .../camel/impl/engine/AbstractCamelContext.java | 18 +- .../properties/DefaultPropertiesParser.java | 66 ++++-- .../component/properties/PropertiesComponent.java | 13 +- .../component/properties/PropertiesParser.java | 4 +- .../impl/cloud/ServiceCallProcessorFactory.java | 3 +- .../camel/impl/lw/LightweightCamelContext.java | 5 + .../impl/lw/LightweightRuntimeCamelContext.java | 7 +- .../camel/processor/SendDynamicProcessor.java | 4 +- .../org/apache/camel/reifier/AggregateReifier.java | 17 +- .../apache/camel/reifier/ClaimCheckReifier.java | 5 +- .../apache/camel/reifier/DynamicRouterReifier.java | 5 +- .../org/apache/camel/reifier/EnrichReifier.java | 5 +- .../camel/reifier/IdempotentConsumerReifier.java | 6 +- .../reifier/InterceptSendToEndpointReifier.java | 5 +- .../org/apache/camel/reifier/MulticastReifier.java | 7 +- .../apache/camel/reifier/PollEnrichReifier.java | 12 +- .../org/apache/camel/reifier/ProcessorReifier.java | 6 +- .../apache/camel/reifier/RecipientListReifier.java | 22 +- .../apache/camel/reifier/ResequenceReifier.java | 25 ++- .../apache/camel/reifier/RoutingSlipReifier.java | 5 +- .../java/org/apache/camel/reifier/SagaReifier.java | 5 +- .../org/apache/camel/reifier/SamplingReifier.java | 7 +- .../java/org/apache/camel/reifier/SortReifier.java | 5 +- .../org/apache/camel/reifier/SplitReifier.java | 13 +- .../org/apache/camel/reifier/ThreadsReifier.java | 10 +- .../org/apache/camel/reifier/ThrottleReifier.java | 2 +- .../camel/reifier/ThrowExceptionReifier.java | 5 +- .../org/apache/camel/reifier/ToDynamicReifier.java | 8 +- .../org/apache/camel/reifier/WireTapReifier.java | 10 +- .../reifier/dataformat/YAMLDataFormatReifier.java | 7 +- .../loadbalancer/FailoverLoadBalancerReifier.java | 5 +- .../transformer/CustomTransformeReifier.java | 5 +- .../core/xml/AbstractCamelEndpointFactoryBean.java | 3 +- .../OptionalPropertyPlaceholderEipTest.java | 84 ++++++++ .../OptionalPropertyPlaceholderTest.java | 228 +++++++++++++++++++++ .../builder/endpoint/AbstractEndpointBuilder.java | 19 +- .../endpoint/OptionalPropertyPlaceholderTest.java | 121 +++++++++++ .../org/apache/camel/support/EndpointHelper.java | 92 ++++++++- .../component/EndpointUriFactorySupport.java | 39 +--- .../java/org/apache/camel/util/StringHelper.java | 20 +- .../java/org/apache/camel/util/URISupport.java | 14 ++ 45 files changed, 824 insertions(+), 167 deletions(-) diff --git a/components/camel-spring/src/main/java/org/apache/camel/spring/spi/BridgePropertyPlaceholderConfigurer.java b/components/camel-spring/src/main/java/org/apache/camel/spring/spi/BridgePropertyPlaceholderConfigurer.java index 2317cb3..e97c81b 100644 --- a/components/camel-spring/src/main/java/org/apache/camel/spring/spi/BridgePropertyPlaceholderConfigurer.java +++ b/components/camel-spring/src/main/java/org/apache/camel/spring/spi/BridgePropertyPlaceholderConfigurer.java @@ -83,9 +83,10 @@ public class BridgePropertyPlaceholderConfigurer extends PropertyPlaceholderConf } @Override - public String parseUri(String text, PropertiesLookup properties, boolean fallback) throws IllegalArgumentException { + public String parseUri(String text, PropertiesLookup properties, boolean fallback, boolean keepUnresolvedOptional) + throws IllegalArgumentException { // first let Camel parse the text as it may contain Camel placeholders - String answer = parser.parseUri(text, properties, fallback); + String answer = parser.parseUri(text, properties, fallback, keepUnresolvedOptional); // then let Spring parse it to resolve any Spring placeholders if (answer != null) { @@ -172,15 +173,16 @@ public class BridgePropertyPlaceholderConfigurer extends PropertyPlaceholderConf } @Override - public String parseUri(String text, PropertiesLookup properties, boolean fallback) throws IllegalArgumentException { + public String parseUri(String text, PropertiesLookup properties, boolean fallback, boolean keepUnresolvedOptional) + throws IllegalArgumentException { String answer = null; if (delegate != null) { - answer = delegate.parseUri(text, properties, fallback); + answer = delegate.parseUri(text, properties, fallback, keepUnresolvedOptional); } if (answer != null) { text = answer; } - return parser.parseUri(text, properties, fallback); + return parser.parseUri(text, properties, fallback, keepUnresolvedOptional); } @Override diff --git a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java index 44b31ed..bbc1863 100644 --- a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java +++ b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java @@ -725,6 +725,9 @@ public interface CamelContext extends CamelContextLifecycle, RuntimeConfiguratio /** * Parses the given text and resolve any property placeholders - using {{key}}. + * <p/> + * <b>Important:</b> If resolving placeholders on an endpoint uri, then you SHOULD use + * EndpointHelper#resolveEndpointUriPropertyPlaceholders instead. * * @param text the text such as an endpoint uri or the likes * @return the text with resolved property placeholders diff --git a/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java b/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java index 114eeab..654cc52 100644 --- a/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java +++ b/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java @@ -769,4 +769,18 @@ public interface ExtendedCamelContext extends CamelContext { */ String getTestExcludeRoutes(); + /** + * Parses the given text and resolve any property placeholders - using {{key}}. + * <p/> + * <b>Important:</b> If resolving placeholders on an endpoint uri, then you SHOULD use + * EndpointHelper#resolveEndpointUriPropertyPlaceholders instead. + * + * @param text the text such as an endpoint uri or the likes + * @param keepUnresolvedOptional whether to keep placeholders that are optional and was unresolved + * @return the text with resolved property placeholders + * @throws IllegalArgumentException is thrown if property placeholders was used and there was an error resolving + * them + */ + String resolvePropertyPlaceholders(String text, boolean keepUnresolvedOptional); + } diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/PropertiesComponent.java b/core/camel-api/src/main/java/org/apache/camel/spi/PropertiesComponent.java index 83e2fd9..80dd27e 100644 --- a/core/camel-api/src/main/java/org/apache/camel/spi/PropertiesComponent.java +++ b/core/camel-api/src/main/java/org/apache/camel/spi/PropertiesComponent.java @@ -46,6 +46,16 @@ public interface PropertiesComponent extends StaticService { String SUFFIX_TOKEN = "}}"; /** + * The token for marking a placeholder as optional + */ + String OPTIONAL_TOKEN = "?"; + + /** + * The prefix and optional tokens + */ + String PREFIX_OPTIONAL_TOKEN = PREFIX_TOKEN + OPTIONAL_TOKEN; + + /** * Parses the input text and resolve all property placeholders from within the text. * * @param uri input text @@ -55,6 +65,16 @@ public interface PropertiesComponent extends StaticService { String parseUri(String uri); /** + * Parses the input text and resolve all property placeholders from within the text. + * + * @param uri input text + * @param keepUnresolvedOptional whether to keep placeholders that are optional and was unresolved + * @return text with resolved property placeholders + * @throws IllegalArgumentException is thrown if error during parsing + */ + String parseUri(String uri, boolean keepUnresolvedOptional); + + /** * Looks up the property with the given key * * @param key the name of the property 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 45a1a92..3d2d334 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 @@ -818,7 +818,7 @@ public abstract class AbstractCamelContext extends BaseService @Override public NormalizedEndpointUri normalizeUri(String uri) { try { - uri = resolvePropertyPlaceholders(uri); + uri = EndpointHelper.resolveEndpointUriPropertyPlaceholders(this, uri); uri = URISupport.normalizeUri(uri); return new NormalizedUri(uri); } catch (Exception e) { @@ -874,14 +874,9 @@ 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 + // in case path has property placeholders then try to let property component resolve those if (!normalized) { - try { - uri = resolvePropertyPlaceholders(uri); - } catch (Exception e) { - throw new ResolveEndpointFailedException(uri, e); - } + uri = EndpointHelper.resolveEndpointUriPropertyPlaceholders(this, uri); } final String rawUri = uri; @@ -1767,9 +1762,14 @@ public abstract class AbstractCamelContext extends BaseService @Override public String resolvePropertyPlaceholders(String text) { + return resolvePropertyPlaceholders(text, false); + } + + @Override + public String resolvePropertyPlaceholders(String text, boolean keepUnresolvedOptional) { if (text != null && text.contains(PropertiesComponent.PREFIX_TOKEN)) { // the parser will throw exception if property key was not found - String answer = getPropertiesComponent().parseUri(text); + String answer = getPropertiesComponent().parseUri(text, keepUnresolvedOptional); LOG.debug("Resolved text: {} -> {}", text, answer); return answer; } diff --git a/core/camel-base/src/main/java/org/apache/camel/component/properties/DefaultPropertiesParser.java b/core/camel-base/src/main/java/org/apache/camel/component/properties/DefaultPropertiesParser.java index e83b20a..9d13f56 100644 --- a/core/camel-base/src/main/java/org/apache/camel/component/properties/DefaultPropertiesParser.java +++ b/core/camel-base/src/main/java/org/apache/camel/component/properties/DefaultPropertiesParser.java @@ -25,6 +25,7 @@ import org.apache.camel.util.StringHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static org.apache.camel.spi.PropertiesComponent.OPTIONAL_TOKEN; import static org.apache.camel.spi.PropertiesComponent.PREFIX_TOKEN; import static org.apache.camel.spi.PropertiesComponent.SUFFIX_TOKEN; import static org.apache.camel.util.IOHelper.lookupEnvironmentVariable; @@ -33,6 +34,8 @@ import static org.apache.camel.util.IOHelper.lookupEnvironmentVariable; * A parser to parse a string which contains property placeholders. */ public class DefaultPropertiesParser implements PropertiesParser { + private static final String UNRESOLVED_PREFIX_TOKEN = "@@["; + private static final String UNRESOLVED_SUFFIX_TOKEN = "]@@"; private static final String GET_OR_ELSE_TOKEN = ":"; protected final Logger log = LoggerFactory.getLogger(getClass()); @@ -55,10 +58,17 @@ public class DefaultPropertiesParser implements PropertiesParser { } @Override - public String parseUri(String text, PropertiesLookup properties, boolean defaultFallbackEnabled) + public String parseUri( + String text, PropertiesLookup properties, boolean defaultFallbackEnabled, boolean keepUnresolvedOptional) throws IllegalArgumentException { - ParsingContext context = new ParsingContext(properties, defaultFallbackEnabled); - return context.parse(text); + ParsingContext context = new ParsingContext(properties, defaultFallbackEnabled, keepUnresolvedOptional); + String answer = context.parse(text); + if (keepUnresolvedOptional && answer != null && answer.contains(UNRESOLVED_PREFIX_TOKEN)) { + // replace temporary unresolved keys back to with placeholders so they are kept as-is + answer = StringHelper.replaceAll(answer, UNRESOLVED_PREFIX_TOKEN, PREFIX_TOKEN); + answer = StringHelper.replaceAll(answer, UNRESOLVED_SUFFIX_TOKEN, SUFFIX_TOKEN); + } + return answer; } @Override @@ -72,10 +82,12 @@ public class DefaultPropertiesParser implements PropertiesParser { private final class ParsingContext { private final PropertiesLookup properties; private final boolean defaultFallbackEnabled; + private final boolean keepUnresolvedOptional; - ParsingContext(PropertiesLookup properties, boolean defaultFallbackEnabled) { + ParsingContext(PropertiesLookup properties, boolean defaultFallbackEnabled, boolean keepUnresolvedOptional) { this.properties = properties; this.defaultFallbackEnabled = defaultFallbackEnabled; + this.keepUnresolvedOptional = keepUnresolvedOptional; } /** @@ -102,10 +114,15 @@ public class DefaultPropertiesParser implements PropertiesParser { String answer = input; Property property; while ((property = readProperty(answer)) != null) { - // Check for circular references if (replacedPropertyKeys.contains(property.getKey())) { - throw new IllegalArgumentException( - "Circular reference detected with key [" + property.getKey() + "] from text: " + input); + // Check for circular references (skip optional) + boolean optional = property.getKey().startsWith(OPTIONAL_TOKEN); + if (optional) { + break; + } else { + throw new IllegalArgumentException( + "Circular reference detected with key [" + property.getKey() + "] from text: " + input); + } } Set<String> newReplaced = new HashSet<>(replacedPropertyKeys); @@ -113,7 +130,18 @@ public class DefaultPropertiesParser implements PropertiesParser { String before = answer.substring(0, property.getBeginIndex()); String after = answer.substring(property.getEndIndex()); - answer = before + doParse(property.getValue(), newReplaced) + after; + String parsed = doParse(property.getValue(), newReplaced); + if (parsed != null) { + answer = before + parsed + after; + } else { + if (property.getBeginIndex() == 0 && input.length() == property.getEndIndex()) { + // its only a single placeholder which is parsed as null + answer = null; + break; + } else { + answer = before + after; + } + } } return answer; } @@ -237,6 +265,11 @@ public class DefaultPropertiesParser implements PropertiesParser { key = StringHelper.before(key, GET_OR_ELSE_TOKEN); } + boolean optional = key != null && key.startsWith(OPTIONAL_TOKEN); + if (optional) { + key = key.substring(OPTIONAL_TOKEN.length()); + } + String value = doGetPropertyValue(key); if (value == null && defaultValue != null) { log.debug("Property with key [{}] not found, using default value: {}", key, defaultValue); @@ -244,10 +277,19 @@ public class DefaultPropertiesParser implements PropertiesParser { } if (value == null) { - StringBuilder esb = new StringBuilder(); - esb.append("Property with key [").append(key).append("] "); - esb.append("not found in properties from text: ").append(input); - throw new IllegalArgumentException(esb.toString()); + if (!optional) { + StringBuilder esb = new StringBuilder(); + esb.append("Property with key [").append(key).append("] "); + esb.append("not found in properties from text: ").append(input); + throw new IllegalArgumentException(esb.toString()); + } else { + if (keepUnresolvedOptional) { + // mark the key as unresolved + return UNRESOLVED_PREFIX_TOKEN + OPTIONAL_TOKEN + key + UNRESOLVED_SUFFIX_TOKEN; + } else { + return null; + } + } } return value; diff --git a/core/camel-base/src/main/java/org/apache/camel/component/properties/PropertiesComponent.java b/core/camel-base/src/main/java/org/apache/camel/component/properties/PropertiesComponent.java index 52c5e29..0bb2868 100644 --- a/core/camel-base/src/main/java/org/apache/camel/component/properties/PropertiesComponent.java +++ b/core/camel-base/src/main/java/org/apache/camel/component/properties/PropertiesComponent.java @@ -152,13 +152,18 @@ public class PropertiesComponent extends ServiceSupport @Override public String parseUri(String uri) { - return parseUri(uri, propertiesLookup); + return parseUri(uri, false); + } + + @Override + public String parseUri(String uri, boolean keepUnresolvedOptional) { + return parseUri(uri, propertiesLookup, keepUnresolvedOptional); } @Override public Optional<String> resolveProperty(String key) { try { - String value = parseUri(key, propertiesLookup); + String value = parseUri(key, propertiesLookup, false); return Optional.of(value); } catch (IllegalArgumentException e) { // property not found @@ -243,7 +248,7 @@ public class PropertiesComponent extends ServiceSupport return prop; } - protected String parseUri(String uri, PropertiesLookup properties) { + protected String parseUri(String uri, PropertiesLookup properties, boolean keepUnresolvedOptional) { // enclose tokens if missing if (!uri.contains(PREFIX_TOKEN) && !uri.startsWith(PREFIX_TOKEN)) { uri = PREFIX_TOKEN + uri; @@ -253,7 +258,7 @@ public class PropertiesComponent extends ServiceSupport } LOG.trace("Parsing uri {}", uri); - return propertiesParser.parseUri(uri, properties, defaultFallbackEnabled); + return propertiesParser.parseUri(uri, properties, defaultFallbackEnabled, keepUnresolvedOptional); } @Override diff --git a/core/camel-base/src/main/java/org/apache/camel/component/properties/PropertiesParser.java b/core/camel-base/src/main/java/org/apache/camel/component/properties/PropertiesParser.java index 6a558da..d251640 100644 --- a/core/camel-base/src/main/java/org/apache/camel/component/properties/PropertiesParser.java +++ b/core/camel-base/src/main/java/org/apache/camel/component/properties/PropertiesParser.java @@ -27,10 +27,12 @@ public interface PropertiesParser { * @param text the text to be parsed * @param properties the properties resolved which values should be looked up * @param fallback whether to support using fallback values if a property cannot be found + * @param keepUnresolvedOptional whether to keep placeholders that are optional and was unresolved * @return the parsed text with replaced placeholders * @throws IllegalArgumentException if uri syntax is not valid or a property is not found */ - String parseUri(String text, PropertiesLookup properties, boolean fallback) throws IllegalArgumentException; + String parseUri(String text, PropertiesLookup properties, boolean fallback, boolean keepUnresolvedOptional) + throws IllegalArgumentException; /** * While parsing the uri using parseUri method each parsed property found invokes this callback. diff --git a/core/camel-cloud/src/main/java/org/apache/camel/impl/cloud/ServiceCallProcessorFactory.java b/core/camel-cloud/src/main/java/org/apache/camel/impl/cloud/ServiceCallProcessorFactory.java index 0124765..9227576 100644 --- a/core/camel-cloud/src/main/java/org/apache/camel/impl/cloud/ServiceCallProcessorFactory.java +++ b/core/camel-cloud/src/main/java/org/apache/camel/impl/cloud/ServiceCallProcessorFactory.java @@ -41,6 +41,7 @@ import org.apache.camel.model.cloud.ServiceCallConfigurationDefinition; import org.apache.camel.model.cloud.ServiceCallDefinition; import org.apache.camel.model.cloud.ServiceCallDefinitionConstants; import org.apache.camel.support.CamelContextHelper; +import org.apache.camel.support.EndpointHelper; import org.apache.camel.support.TypedProcessorFactory; import org.apache.camel.util.ObjectHelper; import org.apache.camel.util.function.Suppliers; @@ -126,7 +127,7 @@ public class ServiceCallProcessorFactory extends TypedProcessorFactory<ServiceCa endpointScheme = ThrowingHelper.applyIfNotEmpty(endpointScheme, camelContext::resolvePropertyPlaceholders, () -> ServiceCallDefinitionConstants.DEFAULT_COMPONENT); - endpointUri = ThrowingHelper.applyIfNotEmpty(endpointUri, camelContext::resolvePropertyPlaceholders, () -> null); + endpointUri = EndpointHelper.resolveEndpointUriPropertyPlaceholders(camelContext, endpointUri); ExchangePattern pattern = CamelContextHelper.parse(camelContext, ExchangePattern.class, definition.getPattern()); Expression expression = retrieveExpression(camelContext, endpointScheme); diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java index 16f4521..6101ee5 100644 --- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java +++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java @@ -640,6 +640,11 @@ public class LightweightCamelContext implements ExtendedCamelContext, CatalogCam } @Override + public String resolvePropertyPlaceholders(String text, boolean keepUnresolvedOptional) { + return getExtendedCamelContext().resolvePropertyPlaceholders(text, keepUnresolvedOptional); + } + + @Override public PropertiesComponent getPropertiesComponent() { return delegate.getPropertiesComponent(); } diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java index afed430..74af3ab 100644 --- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java +++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java @@ -914,9 +914,14 @@ public class LightweightRuntimeCamelContext implements ExtendedCamelContext, Cat @Override public String resolvePropertyPlaceholders(String text) { + return resolvePropertyPlaceholders(text, false); + } + + @Override + public String resolvePropertyPlaceholders(String text, boolean keepUnresolvedOptional) { if (text != null && text.contains(PropertiesComponent.PREFIX_TOKEN)) { // the parser will throw exception if property key was not found - return getPropertiesComponent().parseUri(text); + return getPropertiesComponent().parseUri(text, keepUnresolvedOptional); } // is the value a known field (currently we only support // constants from Exchange.class) diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/SendDynamicProcessor.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/SendDynamicProcessor.java index 9f26dee..76cdc79 100644 --- a/core/camel-core-processor/src/main/java/org/apache/camel/processor/SendDynamicProcessor.java +++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/SendDynamicProcessor.java @@ -233,7 +233,7 @@ public class SendDynamicProcessor extends AsyncProcessorSupport implements IdAwa // in case path has property placeholders then try to let property component resolve those try { - uri = exchange.getContext().resolvePropertyPlaceholders(uri); + uri = EndpointHelper.resolveEndpointUriPropertyPlaceholders(exchange.getContext(), uri); } catch (Exception e) { throw new ResolveEndpointFailedException(uri, e); } @@ -310,7 +310,7 @@ public class SendDynamicProcessor extends AsyncProcessorSupport implements IdAwa if ((isAllowOptimisedComponents() || isAutoStartupComponents()) && uri != null) { // in case path has property placeholders then try to let property component resolve those - String u = camelContext.resolvePropertyPlaceholders(uri); + String u = EndpointHelper.resolveEndpointUriPropertyPlaceholders(camelContext, uri); // find out which component it is scheme = ExchangeHelper.resolveScheme(u); } diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/AggregateReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/AggregateReifier.java index a01b4de..97c29cc 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/AggregateReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/AggregateReifier.java @@ -207,17 +207,20 @@ public class AggregateReifier extends ProcessorReifier<AggregateDefinition> { public OptimisticLockRetryPolicy createOptimisticLockRetryPolicy(OptimisticLockRetryPolicyDefinition definition) { OptimisticLockRetryPolicy policy = new OptimisticLockRetryPolicy(); - if (definition.getMaximumRetries() != null) { - policy.setMaximumRetries(parseInt(definition.getMaximumRetries())); + Integer num = parseInt(definition.getMaximumRetries()); + if (num != null) { + policy.setMaximumRetries(num); } - if (definition.getRetryDelay() != null) { - policy.setRetryDelay(parseDuration(definition.getRetryDelay())); + Long dur = parseDuration(definition.getRetryDelay()); + if (dur != null) { + policy.setRetryDelay(dur); } - if (definition.getMaximumRetryDelay() != null) { - policy.setMaximumRetryDelay(parseDuration(definition.getMaximumRetryDelay())); + dur = parseDuration(definition.getMaximumRetryDelay()); + if (dur != null) { + policy.setMaximumRetryDelay(dur); } if (definition.getExponentialBackOff() != null) { - policy.setExponentialBackOff(parseBoolean(definition.getExponentialBackOff(), false)); + policy.setExponentialBackOff(parseBoolean(definition.getExponentialBackOff(), true)); } if (definition.getRandomBackOff() != null) { policy.setRandomBackOff(parseBoolean(definition.getRandomBackOff(), false)); diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ClaimCheckReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ClaimCheckReifier.java index 47b5a14..b6a4ce8 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ClaimCheckReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ClaimCheckReifier.java @@ -109,8 +109,9 @@ public class ClaimCheckReifier extends ProcessorReifier<ClaimCheckDefinition> { private AggregationStrategy createAggregationStrategy() { AggregationStrategy strategy = definition.getAggregationStrategy(); - if (strategy == null && definition.getAggregationStrategyRef() != null) { - Object aggStrategy = lookup(parseString(definition.getAggregationStrategyRef()), Object.class); + String ref = parseString(definition.getAggregationStrategyRef()); + if (strategy == null && ref != null) { + Object aggStrategy = lookup(ref, Object.class); if (aggStrategy instanceof AggregationStrategy) { strategy = (AggregationStrategy) aggStrategy; } else if (aggStrategy != null) { diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/DynamicRouterReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/DynamicRouterReifier.java index bc760e0..c4e5169 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/DynamicRouterReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/DynamicRouterReifier.java @@ -40,8 +40,9 @@ public class DynamicRouterReifier extends ExpressionReifier<DynamicRouterDefinit if (definition.getIgnoreInvalidEndpoints() != null) { dynamicRouter.setIgnoreInvalidEndpoints(parseBoolean(definition.getIgnoreInvalidEndpoints(), false)); } - if (definition.getCacheSize() != null) { - dynamicRouter.setCacheSize(parseInt(definition.getCacheSize())); + Integer num = parseInt(definition.getCacheSize()); + if (num != null) { + dynamicRouter.setCacheSize(num); } AsyncProcessor errorHandler diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/EnrichReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/EnrichReifier.java index 2367851..ffe0387 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/EnrichReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/EnrichReifier.java @@ -41,8 +41,9 @@ public class EnrichReifier extends ExpressionReifier<EnrichDefinition> { Enricher enricher = new Enricher(exp); enricher.setShareUnitOfWork(isShareUnitOfWork); enricher.setIgnoreInvalidEndpoint(isIgnoreInvalidEndpoint); - if (definition.getCacheSize() != null) { - enricher.setCacheSize(parseInt(definition.getCacheSize())); + Integer num = parseInt(definition.getCacheSize()); + if (num != null) { + enricher.setCacheSize(num); } AggregationStrategy strategy = createAggregationStrategy(); if (strategy != null) { diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/IdempotentConsumerReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/IdempotentConsumerReifier.java index 172bf3b..8e743b8 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/IdempotentConsumerReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/IdempotentConsumerReifier.java @@ -58,9 +58,9 @@ public class IdempotentConsumerReifier extends ExpressionReifier<IdempotentConsu * @return the repository */ protected <T> IdempotentRepository resolveMessageIdRepository() { - if (definition.getMessageIdRepositoryRef() != null) { - definition.setMessageIdRepository( - mandatoryLookup(parseString(definition.getMessageIdRepositoryRef()), IdempotentRepository.class)); + String ref = parseString(definition.getMessageIdRepositoryRef()); + if (ref != null) { + definition.setMessageIdRepository(mandatoryLookup(ref, IdempotentRepository.class)); } return definition.getMessageIdRepository(); } diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/InterceptSendToEndpointReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/InterceptSendToEndpointReifier.java index 15897c8..0fe838d 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/InterceptSendToEndpointReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/InterceptSendToEndpointReifier.java @@ -44,8 +44,9 @@ public class InterceptSendToEndpointReifier extends ProcessorReifier<InterceptSe final Processor before = this.createChildProcessor(true); // create the after Processor afterProcessor = null; - if (definition.getAfterUri() != null) { - ToDefinition to = new ToDefinition(parseString(definition.getAfterUri())); + String afterUri = parseString(definition.getAfterUri()); + if (afterUri != null) { + ToDefinition to = new ToDefinition(afterUri); // at first use custom factory afterProcessor = camelContext.adapt(ExtendedCamelContext.class).getProcessorFactory().createProcessor(route, to); // fallback to default implementation if factory did not create the processor diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/MulticastReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/MulticastReifier.java index 2f1445b..a7ff33d 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/MulticastReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/MulticastReifier.java @@ -65,7 +65,7 @@ public class MulticastReifier extends ProcessorReifier<MulticastDefinition> { boolean shutdownThreadPool = willCreateNewThreadPool(definition, isParallelProcessing); ExecutorService threadPool = getConfiguredExecutorService("Multicast", definition, isParallelProcessing); - long timeout = definition.getTimeout() != null ? parseDuration(definition.getTimeout()) : 0; + long timeout = parseDuration(definition.getTimeout(), 0); if (timeout > 0 && !isParallelProcessing) { throw new IllegalArgumentException("Timeout is used but ParallelProcessing has not been enabled."); } @@ -82,8 +82,9 @@ public class MulticastReifier extends ProcessorReifier<MulticastDefinition> { private AggregationStrategy createAggregationStrategy() { AggregationStrategy strategy = definition.getAggregationStrategy(); - if (strategy == null && definition.getStrategyRef() != null) { - Object aggStrategy = lookup(parseString(definition.getStrategyRef()), Object.class); + String ref = parseString(definition.getStrategyRef()); + if (strategy == null && ref != null) { + Object aggStrategy = lookup(ref, Object.class); if (aggStrategy instanceof AggregationStrategy) { strategy = (AggregationStrategy) aggStrategy; } else if (aggStrategy != null) { diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/PollEnrichReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/PollEnrichReifier.java index c4de005..06b18af 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/PollEnrichReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/PollEnrichReifier.java @@ -39,7 +39,7 @@ public class PollEnrichReifier extends ProcessorReifier<PollEnrichDefinition> { public Processor createProcessor() throws Exception { // if no timeout then we should block, and there use a negative timeout - long time = definition.getTimeout() != null ? parseDuration(definition.getTimeout()) : -1; + long time = parseDuration(definition.getTimeout(), -1); boolean isIgnoreInvalidEndpoint = parseBoolean(definition.getIgnoreInvalidEndpoint(), false); PollEnricher enricher; @@ -62,8 +62,9 @@ public class PollEnrichReifier extends ProcessorReifier<PollEnrichDefinition> { if (definition.getAggregateOnException() != null) { enricher.setAggregateOnException(parseBoolean(definition.getAggregateOnException(), false)); } - if (definition.getCacheSize() != null) { - enricher.setCacheSize(parseInt(definition.getCacheSize())); + Integer num = parseInt(definition.getCacheSize()); + if (num != null) { + enricher.setCacheSize(num); } enricher.setIgnoreInvalidEndpoint(isIgnoreInvalidEndpoint); @@ -72,8 +73,9 @@ public class PollEnrichReifier extends ProcessorReifier<PollEnrichDefinition> { private AggregationStrategy createAggregationStrategy() { AggregationStrategy strategy = definition.getAggregationStrategy(); - if (strategy == null && definition.getAggregationStrategyRef() != null) { - Object aggStrategy = lookup(parseString(definition.getAggregationStrategyRef()), Object.class); + String ref = parseString(definition.getAggregationStrategyRef()); + if (strategy == null && ref != null) { + Object aggStrategy = lookup(ref, Object.class); if (aggStrategy instanceof AggregationStrategy) { strategy = (AggregationStrategy) aggStrategy; } else if (aggStrategy != null) { diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ProcessorReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ProcessorReifier.java index 5805116..0c95252 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ProcessorReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ProcessorReifier.java @@ -362,12 +362,12 @@ public abstract class ProcessorReifier<T extends ProcessorDefinition<?>> extends ObjectHelper.notNull(manager, "ExecutorServiceManager", camelContext); // prefer to use explicit configured executor on the definition + String ref = parseString(definition.getExecutorServiceRef()); if (definition.getExecutorService() != null) { return definition.getExecutorService(); - } else if (definition.getExecutorServiceRef() != null) { + } else if (ref != null) { // lookup in registry first and use existing thread pool if exists - ExecutorService answer - = lookupExecutorServiceRef(name, definition, parseString(definition.getExecutorServiceRef())); + ExecutorService answer = lookupExecutorServiceRef(name, definition, ref); if (answer == null) { throw new IllegalArgumentException( "ExecutorServiceRef " + definition.getExecutorServiceRef() diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/RecipientListReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/RecipientListReifier.java index 3d44191..7d8c1a7 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/RecipientListReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/RecipientListReifier.java @@ -52,8 +52,9 @@ public class RecipientListReifier extends ProcessorReifier<RecipientListDefiniti boolean isStopOnAggregateException = parseBoolean(definition.getStopOnAggregateException(), false); RecipientList answer; - if (definition.getDelimiter() != null) { - answer = new RecipientList(camelContext, expression, parseString(definition.getDelimiter())); + String delimiter = parseString(definition.getDelimiter()); + if (delimiter != null) { + answer = new RecipientList(camelContext, expression, delimiter); } else { answer = new RecipientList(camelContext, expression); } @@ -65,8 +66,9 @@ public class RecipientListReifier extends ProcessorReifier<RecipientListDefiniti answer.setStopOnException(isStopOnException); answer.setIgnoreInvalidEndpoints(isIgnoreInvalidEndpoints); answer.setStopOnAggregateException(isStopOnAggregateException); - if (definition.getCacheSize() != null) { - answer.setCacheSize(parseInt(definition.getCacheSize())); + Integer num = parseInt(definition.getCacheSize()); + if (num != null) { + answer.setCacheSize(num); } if (definition.getOnPrepareRef() != null) { definition.setOnPrepare(mandatoryLookup(definition.getOnPrepareRef(), Processor.class)); @@ -74,15 +76,16 @@ public class RecipientListReifier extends ProcessorReifier<RecipientListDefiniti if (definition.getOnPrepare() != null) { answer.setOnPrepare(definition.getOnPrepare()); } - if (definition.getTimeout() != null) { - answer.setTimeout(parseDuration(definition.getTimeout())); + Long dur = parseDuration(definition.getTimeout()); + if (dur != null) { + answer.setTimeout(dur); } boolean shutdownThreadPool = willCreateNewThreadPool(definition, isParallelProcessing); ExecutorService threadPool = getConfiguredExecutorService("RecipientList", definition, isParallelProcessing); answer.setExecutorService(threadPool); answer.setShutdownExecutorService(shutdownThreadPool); - long timeout = definition.getTimeout() != null ? parseDuration(definition.getTimeout()) : 0; + long timeout = parseDuration(definition.getTimeout(), 0); if (timeout > 0 && !isParallelProcessing) { throw new IllegalArgumentException("Timeout is used but ParallelProcessing has not been enabled."); } @@ -110,8 +113,9 @@ public class RecipientListReifier extends ProcessorReifier<RecipientListDefiniti private AggregationStrategy createAggregationStrategy() { AggregationStrategy strategy = definition.getAggregationStrategy(); - if (strategy == null && definition.getStrategyRef() != null) { - Object aggStrategy = lookup(parseString(definition.getStrategyRef()), Object.class); + String ref = parseString(definition.getStrategyRef()); + if (strategy == null && ref != null) { + Object aggStrategy = lookup(ref, Object.class); if (aggStrategy instanceof AggregationStrategy) { strategy = (AggregationStrategy) aggStrategy; } else if (aggStrategy != null) { diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ResequenceReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ResequenceReifier.java index 86db86a..c7b8d06 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ResequenceReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ResequenceReifier.java @@ -84,8 +84,14 @@ public class ResequenceReifier extends ProcessorReifier<ResequenceDefinition> { boolean isAllowDuplicates = parseBoolean(config.getAllowDuplicates(), false); Resequencer resequencer = new Resequencer(camelContext, target, expression, isAllowDuplicates, isReverse); - resequencer.setBatchSize(parseInt(config.getBatchSize())); - resequencer.setBatchTimeout(parseDuration(config.getBatchTimeout())); + Integer num = parseInt(config.getBatchSize()); + if (num != null) { + resequencer.setBatchSize(num); + } + Long dur = parseDuration(config.getBatchTimeout()); + if (dur != null) { + resequencer.setBatchTimeout(dur); + } resequencer.setReverse(isReverse); resequencer.setAllowDuplicates(isAllowDuplicates); if (config.getIgnoreInvalidExchanges() != null) { @@ -123,11 +129,18 @@ public class ResequenceReifier extends ProcessorReifier<ResequenceDefinition> { comparator.setExpression(expression); StreamResequencer resequencer = new StreamResequencer(camelContext, target, comparator, expression); - resequencer.setTimeout(parseDuration(config.getTimeout())); - if (config.getDeliveryAttemptInterval() != null) { - resequencer.setDeliveryAttemptInterval(parseDuration(config.getDeliveryAttemptInterval())); + Long dur = parseDuration(config.getTimeout()); + if (dur != null) { + resequencer.setTimeout(dur); + } + dur = parseDuration(config.getDeliveryAttemptInterval()); + if (dur != null) { + resequencer.setDeliveryAttemptInterval(dur); + } + Integer num = parseInt(config.getCapacity()); + if (num != null) { + resequencer.setCapacity(num); } - resequencer.setCapacity(parseInt(config.getCapacity())); resequencer.setRejectOld(parseBoolean(config.getRejectOld(), false)); if (config.getIgnoreInvalidExchanges() != null) { resequencer.setIgnoreInvalidExchanges(parseBoolean(config.getIgnoreInvalidExchanges(), false)); diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/RoutingSlipReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/RoutingSlipReifier.java index 6a871ba..0b54b7f 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/RoutingSlipReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/RoutingSlipReifier.java @@ -44,8 +44,9 @@ public class RoutingSlipReifier extends ExpressionReifier<RoutingSlipDefinition< if (definition.getIgnoreInvalidEndpoints() != null) { routingSlip.setIgnoreInvalidEndpoints(parseBoolean(definition.getIgnoreInvalidEndpoints(), false)); } - if (definition.getCacheSize() != null) { - routingSlip.setCacheSize(parseInt(definition.getCacheSize())); + Integer num = parseInt(definition.getCacheSize()); + if (num != null) { + routingSlip.setCacheSize(num); } // and wrap this in an error handler diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/SagaReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/SagaReifier.java index a60152e..447adae 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/SagaReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/SagaReifier.java @@ -93,8 +93,9 @@ public class SagaReifier extends ProcessorReifier<SagaDefinition> { return sagaService; } - if (definition.getSagaServiceRef() != null) { - return mandatoryLookup(parseString(definition.getSagaServiceRef()), CamelSagaService.class); + String ref = parseString(definition.getSagaServiceRef()); + if (ref != null) { + return mandatoryLookup(ref, CamelSagaService.class); } sagaService = camelContext.hasService(CamelSagaService.class); diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/SamplingReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/SamplingReifier.java index 547719c..a07273b 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/SamplingReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/SamplingReifier.java @@ -32,11 +32,12 @@ public class SamplingReifier extends ProcessorReifier<SamplingDefinition> { @Override public Processor createProcessor() throws Exception { - if (definition.getMessageFrequency() != null) { - return new SamplingThrottler(parseLong(definition.getMessageFrequency())); + Long freq = parseLong(definition.getMessageFrequency()); + if (freq != null) { + return new SamplingThrottler(freq); } else { // should default be 1 sample period - long time = definition.getSamplePeriod() != null ? parseDuration(definition.getSamplePeriod()) : 1L; + long time = parseDuration(definition.getSamplePeriod(), 1); // should default be in seconds TimeUnit tu = definition.getUnits() != null ? parse(TimeUnit.class, definition.getUnits()) : TimeUnit.SECONDS; return new SamplingThrottler(time, tu); diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/SortReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/SortReifier.java index 6de9bca..2a2c123 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/SortReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/SortReifier.java @@ -38,8 +38,9 @@ public class SortReifier<T, U extends SortDefinition<T>> extends ExpressionReifi @SuppressWarnings("unchecked") public Processor createProcessor() throws Exception { // lookup in registry - if (isNotEmpty(definition.getComparatorRef())) { - definition.setComparator(lookup(parseString(definition.getComparatorRef()), Comparator.class)); + String ref = parseString(definition.getComparatorRef()); + if (isNotEmpty(ref)) { + definition.setComparator(lookup(ref, Comparator.class)); } // if no comparator then default on to string representation diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/SplitReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/SplitReifier.java index 03dd7c6..b290c3d 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/SplitReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/SplitReifier.java @@ -49,23 +49,24 @@ public class SplitReifier extends ExpressionReifier<SplitDefinition> { boolean shutdownThreadPool = willCreateNewThreadPool(definition, isParallelProcessing); ExecutorService threadPool = getConfiguredExecutorService("Split", definition, isParallelProcessing); - long timeout = definition.getTimeout() != null ? parseDuration(definition.getTimeout()) : 0; + long timeout = parseDuration(definition.getTimeout(), 0); if (timeout > 0 && !isParallelProcessing) { throw new IllegalArgumentException("Timeout is used but ParallelProcessing has not been enabled."); } - if (definition.getOnPrepareRef() != null) { - definition.setOnPrepare(mandatoryLookup(parseString(definition.getOnPrepareRef()), Processor.class)); + String ref = parseString(definition.getOnPrepareRef()); + if (ref != null) { + definition.setOnPrepare(mandatoryLookup(ref, Processor.class)); } Expression exp = createExpression(definition.getExpression()); + String delimiter = parseString(definition.getDelimiter()); Splitter answer; - if (definition.getDelimiter() != null) { + if (delimiter != null) { answer = new Splitter( camelContext, route, exp, childProcessor, definition.getAggregationStrategy(), isParallelProcessing, threadPool, shutdownThreadPool, isStreaming, isStopOnException, timeout, definition.getOnPrepare(), - isShareUnitOfWork, isParallelAggregate, isStopOnAggregateException, - parseString(definition.getDelimiter())); + isShareUnitOfWork, isParallelAggregate, isStopOnAggregateException, delimiter); } else { answer = new Splitter( camelContext, route, exp, childProcessor, definition.getAggregationStrategy(), isParallelProcessing, diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ThreadsReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ThreadsReifier.java index 08f57d8..0474177 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ThreadsReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ThreadsReifier.java @@ -37,7 +37,10 @@ public class ThreadsReifier extends ProcessorReifier<ThreadsDefinition> { @Override public Processor createProcessor() throws Exception { // the threads name - String name = definition.getThreadName() != null ? parseString(definition.getThreadName()) : "Threads"; + String name = parseString(definition.getThreadName()); + if (name == null || name.isEmpty()) { + name = "Threads"; + } // prefer any explicit configured executor service boolean shutdownThreadPool = willCreateNewThreadPool(definition, true); ExecutorService threadPool = getConfiguredExecutorService(name, definition, false); @@ -101,9 +104,10 @@ public class ThreadsReifier extends ProcessorReifier<ThreadsDefinition> { } protected ThreadPoolRejectedPolicy resolveRejectedPolicy() { - if (definition.getExecutorServiceRef() != null && definition.getRejectedPolicy() == null) { + String ref = parseString(definition.getExecutorServiceRef()); + if (ref != null && definition.getRejectedPolicy() == null) { ThreadPoolProfile threadPoolProfile = camelContext.getExecutorServiceManager() - .getThreadPoolProfile(parseString(definition.getExecutorServiceRef())); + .getThreadPoolProfile(ref); if (threadPoolProfile != null) { return threadPoolProfile.getRejectedPolicy(); } diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ThrottleReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ThrottleReifier.java index e1168e4..20dc0be 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ThrottleReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ThrottleReifier.java @@ -38,7 +38,7 @@ public class ThrottleReifier extends ExpressionReifier<ThrottleDefinition> { ScheduledExecutorService threadPool = getConfiguredScheduledExecutorService("Throttle", definition, true); // should be default 1000 millis - long period = definition.getTimePeriodMillis() != null ? parseDuration(definition.getTimePeriodMillis()) : 1000L; + long period = parseDuration(definition.getTimePeriodMillis(), 1000L); // max requests per period is mandatory Expression maxRequestsExpression = createMaxRequestsPerPeriodExpression(); diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ThrowExceptionReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ThrowExceptionReifier.java index f7959da..51e0924 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ThrowExceptionReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ThrowExceptionReifier.java @@ -31,8 +31,9 @@ public class ThrowExceptionReifier extends ProcessorReifier<ThrowExceptionDefini @Override public Processor createProcessor() { Exception exception = definition.getException(); - if (exception == null && definition.getRef() != null) { - exception = lookup(parseString(definition.getRef()), Exception.class); + String ref = parseString(definition.getRef()); + if (exception == null && ref != null) { + exception = lookup(ref, Exception.class); } Class<? extends Exception> exceptionClass = definition.getExceptionClass(); diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ToDynamicReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ToDynamicReifier.java index d68fb6f..fc4ad92 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ToDynamicReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ToDynamicReifier.java @@ -24,6 +24,7 @@ import org.apache.camel.model.ProcessorDefinition; import org.apache.camel.model.ToDynamicDefinition; import org.apache.camel.processor.SendDynamicProcessor; import org.apache.camel.spi.Language; +import org.apache.camel.support.EndpointHelper; import org.apache.camel.util.StringHelper; public class ToDynamicReifier<T extends ToDynamicDefinition> extends ProcessorReifier<T> { @@ -47,8 +48,9 @@ public class ToDynamicReifier<T extends ToDynamicDefinition> extends ProcessorRe SendDynamicProcessor processor = new SendDynamicProcessor(uri, exp); processor.setCamelContext(camelContext); processor.setPattern(parse(ExchangePattern.class, definition.getPattern())); - if (definition.getCacheSize() != null) { - processor.setCacheSize(parseInt(definition.getCacheSize())); + Integer num = parseInt(definition.getCacheSize()); + if (num != null) { + processor.setCacheSize(num); } if (definition.getIgnoreInvalidEndpoint() != null) { processor.setIgnoreInvalidEndpoint(parseBoolean(definition.getIgnoreInvalidEndpoint(), false)); @@ -64,7 +66,7 @@ public class ToDynamicReifier<T extends ToDynamicDefinition> extends ProcessorRe protected Expression createExpression(String uri) { // make sure to parse property placeholders - uri = camelContext.resolvePropertyPlaceholders(uri); + uri = EndpointHelper.resolveEndpointUriPropertyPlaceholders(camelContext, uri); // we use simple language by default but you can configure a different language String language = "simple"; diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/WireTapReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/WireTapReifier.java index d8f1dfd..79c1d55 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/WireTapReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/WireTapReifier.java @@ -65,8 +65,9 @@ public class WireTapReifier extends ToDynamicReifier<WireTapDefinition<?>> { parseBoolean(definition.getDynamicUri(), true)); answer.setCopy(isCopy); Processor newExchangeProcessor = definition.getNewExchangeProcessor(); - if (definition.getNewExchangeProcessorRef() != null) { - newExchangeProcessor = mandatoryLookup(parseString(definition.getNewExchangeProcessorRef()), Processor.class); + String ref = parseString(definition.getNewExchangeProcessorRef()); + if (ref != null) { + newExchangeProcessor = mandatoryLookup(ref, Processor.class); } if (newExchangeProcessor != null) { answer.addNewExchangeProcessor(newExchangeProcessor); @@ -81,8 +82,9 @@ public class WireTapReifier extends ToDynamicReifier<WireTapDefinition<?>> { } } Processor onPrepare = definition.getOnPrepare(); - if (definition.getOnPrepareRef() != null) { - onPrepare = mandatoryLookup(parseString(definition.getOnPrepareRef()), Processor.class); + ref = parseString(definition.getOnPrepareRef()); + if (ref != null) { + onPrepare = mandatoryLookup(ref, Processor.class); } if (onPrepare != null) { answer.setOnPrepare(onPrepare); diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/dataformat/YAMLDataFormatReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/dataformat/YAMLDataFormatReifier.java index c455990..849bb18 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/dataformat/YAMLDataFormatReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/dataformat/YAMLDataFormatReifier.java @@ -64,15 +64,16 @@ public class YAMLDataFormatReifier extends DataFormatReifier<YAMLDataFormat> { List<String> typeFilterDefinitions = new ArrayList<>(definition.getTypeFilters().size()); for (YAMLTypeFilterDefinition definition : definition.getTypeFilters()) { String value = parseString(definition.getValue()); - if (!value.startsWith("type") && !value.startsWith("regexp")) { + if (value != null && !value.startsWith("type") && !value.startsWith("regexp")) { YAMLTypeFilterType type = parse(YAMLTypeFilterType.class, definition.getType()); if (type == null) { type = YAMLTypeFilterType.type; } - value = type.name() + ":" + value; } - typeFilterDefinitions.add(value); + if (value != null) { + typeFilterDefinitions.add(value); + } } return typeFilterDefinitions; } else { diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/loadbalancer/FailoverLoadBalancerReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/loadbalancer/FailoverLoadBalancerReifier.java index bf4aafa..037c668 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/loadbalancer/FailoverLoadBalancerReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/loadbalancer/FailoverLoadBalancerReifier.java @@ -57,8 +57,9 @@ public class FailoverLoadBalancerReifier extends LoadBalancerReifier<FailoverLoa answer = new FailOverLoadBalancer(classes); } - if (definition.getMaximumFailoverAttempts() != null) { - answer.setMaximumFailoverAttempts(parseInt(definition.getMaximumFailoverAttempts())); + Integer num = parseInt(definition.getMaximumFailoverAttempts()); + if (num != null) { + answer.setMaximumFailoverAttempts(num); } if (definition.getRoundRobin() != null) { answer.setRoundRobin(parseBoolean(definition.getRoundRobin(), false)); diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/CustomTransformeReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/CustomTransformeReifier.java index cf1e2ff..ae3531d 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/CustomTransformeReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/CustomTransformeReifier.java @@ -33,8 +33,9 @@ public class CustomTransformeReifier extends TransformerReifier<CustomTransforme throw new IllegalArgumentException("'ref' or 'className' must be specified for customTransformer"); } Transformer transformer; - if (definition.getRef() != null) { - transformer = lookup(parseString(definition.getRef()), Transformer.class); + String ref = parseString(definition.getRef()); + if (ref != null) { + transformer = lookup(ref, Transformer.class); if (transformer == null) { throw new IllegalArgumentException("Cannot find transformer with ref:" + definition.getRef()); } diff --git a/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelEndpointFactoryBean.java b/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelEndpointFactoryBean.java index 407d56e..32f2086 100644 --- a/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelEndpointFactoryBean.java +++ b/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelEndpointFactoryBean.java @@ -31,6 +31,7 @@ import org.apache.camel.Endpoint; import org.apache.camel.NoSuchEndpointException; import org.apache.camel.model.PropertyDefinition; import org.apache.camel.spi.Metadata; +import org.apache.camel.support.EndpointHelper; import org.apache.camel.util.URISupport; @XmlAccessorType(XmlAccessType.FIELD) @@ -48,7 +49,7 @@ public abstract class AbstractCamelEndpointFactoryBean extends AbstractCamelFact public Endpoint getObject() throws Exception { if (endpoint == null || !endpoint.isSingleton()) { // resolve placeholders (but leave the original uri unchanged) - String resolved = getCamelContext().resolvePropertyPlaceholders(uri); + String resolved = EndpointHelper.resolveEndpointUriPropertyPlaceholders(getCamelContext(), uri); String target = createUri(resolved); this.endpoint = getCamelContext().getEndpoint(target); if (endpoint == null) { diff --git a/core/camel-core/src/test/java/org/apache/camel/component/properties/OptionalPropertyPlaceholderEipTest.java b/core/camel-core/src/test/java/org/apache/camel/component/properties/OptionalPropertyPlaceholderEipTest.java new file mode 100644 index 0000000..24ad76a --- /dev/null +++ b/core/camel-core/src/test/java/org/apache/camel/component/properties/OptionalPropertyPlaceholderEipTest.java @@ -0,0 +1,84 @@ +/* + * 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.properties; + +import java.util.Properties; + +import org.apache.camel.CamelContext; +import org.apache.camel.ContextTestSupport; +import org.apache.camel.builder.RouteBuilder; +import org.junit.jupiter.api.Test; + +public class OptionalPropertyPlaceholderEipTest extends ContextTestSupport { + + @Override + public boolean isUseRouteBuilder() { + return false; + } + + @Test + public void testQueryOptionalNotPresent() throws Exception { + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .split(body()).delimiter("{{?myDelim}}") + .to("mock:line"); + } + }); + context.start(); + + getMockEndpoint("mock:line").expectedMessageCount(2); + template.sendBody("direct:start", "A,B"); + assertMockEndpointsSatisfied(); + } + + @Test + public void testQueryOptionalPresent() throws Exception { + Properties prop = new Properties(); + prop.put("myDelim", ";"); + context.getPropertiesComponent().setInitialProperties(prop); + + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .split(body()).delimiter("{{?myDelim}}") + .to("mock:line"); + } + }); + context.start(); + + getMockEndpoint("mock:line").expectedMessageCount(1); + template.sendBody("direct:start", "A,B"); + assertMockEndpointsSatisfied(); + + resetMocks(); + + getMockEndpoint("mock:line").expectedMessageCount(3); + template.sendBody("direct:start", "A;B;C"); + assertMockEndpointsSatisfied(); + } + + @Override + protected CamelContext createCamelContext() throws Exception { + CamelContext context = super.createCamelContext(); + context.getPropertiesComponent().setLocation("classpath:org/apache/camel/component/properties/myproperties.properties"); + return context; + } + +} diff --git a/core/camel-core/src/test/java/org/apache/camel/component/properties/OptionalPropertyPlaceholderTest.java b/core/camel-core/src/test/java/org/apache/camel/component/properties/OptionalPropertyPlaceholderTest.java new file mode 100644 index 0000000..63edb17 --- /dev/null +++ b/core/camel-core/src/test/java/org/apache/camel/component/properties/OptionalPropertyPlaceholderTest.java @@ -0,0 +1,228 @@ +/* + * 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.properties; + +import java.util.Properties; + +import org.apache.camel.CamelContext; +import org.apache.camel.ContextTestSupport; +import org.apache.camel.builder.RouteBuilder; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class OptionalPropertyPlaceholderTest extends ContextTestSupport { + + // TODO: eip test + // TODO: reuse code in AbstractCamelContext and endpoint-dsl + + @Override + public boolean isUseRouteBuilder() { + return false; + } + + @Test + public void testQueryOptionalNotPresent() throws Exception { + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .to("mock:result?retainFirst={{?maxKeep}}"); + } + }); + context.start(); + + getMockEndpoint("mock:result").expectedMessageCount(2); + + template.sendBody("direct:start", "Hello World"); + template.sendBody("direct:start", "Bye World"); + + assertMockEndpointsSatisfied(); + + assertEquals(2, getMockEndpoint("mock:result").getReceivedExchanges().size()); + } + + @Test + public void testQueryOptionalPresent() throws Exception { + Properties prop = new Properties(); + prop.put("maxKeep", "1"); + context.getPropertiesComponent().setInitialProperties(prop); + + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .to("mock:result?retainFirst={{?maxKeep}}"); + } + }); + context.start(); + + getMockEndpoint("mock:result?retainFirst=1").expectedMessageCount(2); + + template.sendBody("direct:start", "Hello World"); + template.sendBody("direct:start", "Bye World"); + + assertMockEndpointsSatisfied(); + + assertEquals(1, getMockEndpoint("mock:result?retainFirst=1").getReceivedExchanges().size()); + } + + @Test + public void testPathOptionalNotPresent() throws Exception { + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .to("mock:res{{?unknown}}ult"); + } + }); + context.start(); + + getMockEndpoint("mock:result").expectedMessageCount(2); + + template.sendBody("direct:start", "Hello World"); + template.sendBody("direct:start", "Bye World"); + + assertMockEndpointsSatisfied(); + } + + @Test + public void testPathOptionalPresent() throws Exception { + Properties prop = new Properties(); + prop.put("whereTo", "result"); + context.getPropertiesComponent().setInitialProperties(prop); + + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .to("mock:{{?whereTo}}"); + } + }); + context.start(); + + getMockEndpoint("mock:result").expectedMessageCount(2); + + template.sendBody("direct:start", "Hello World"); + template.sendBody("direct:start", "Bye World"); + + assertMockEndpointsSatisfied(); + } + + @Test + public void testQueryAndPathOptionalNotPresent() throws Exception { + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .to("mock:res{{?unknown}}ult?retainFirst={{?maxKeep}}"); + } + }); + context.start(); + + getMockEndpoint("mock:result").expectedMessageCount(2); + + template.sendBody("direct:start", "Hello World"); + template.sendBody("direct:start", "Bye World"); + + assertMockEndpointsSatisfied(); + + assertEquals(2, getMockEndpoint("mock:result").getReceivedExchanges().size()); + } + + @Test + public void testQueryAndPathOptionalPresent() throws Exception { + Properties prop = new Properties(); + prop.put("maxKeep", "1"); + prop.put("whereTo", "result"); + context.getPropertiesComponent().setInitialProperties(prop); + + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .to("mock:{{?whereTo}}?retainFirst={{?maxKeep}}"); + } + }); + context.start(); + + getMockEndpoint("mock:result?retainFirst=1").expectedMessageCount(2); + + template.sendBody("direct:start", "Hello World"); + template.sendBody("direct:start", "Bye World"); + + assertMockEndpointsSatisfied(); + + assertEquals(1, getMockEndpoint("mock:result?retainFirst=1").getReceivedExchanges().size()); + } + + @Test + public void testQueryAndPathOptionalMixed() throws Exception { + Properties prop = new Properties(); + prop.put("maxKeep", "1"); + context.getPropertiesComponent().setInitialProperties(prop); + + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .to("mock:res{{?unknown}}ult?retainFirst={{?maxKeep}}"); + } + }); + context.start(); + + getMockEndpoint("mock:result?retainFirst=1").expectedMessageCount(2); + + template.sendBody("direct:start", "Hello World"); + template.sendBody("direct:start", "Bye World"); + + assertMockEndpointsSatisfied(); + + assertEquals(1, getMockEndpoint("mock:result?retainFirst=1").getReceivedExchanges().size()); + } + + @Test + public void testQueryAndPathOptionalMixedTwo() throws Exception { + Properties prop = new Properties(); + prop.put("whereTo", "result"); + context.getPropertiesComponent().setInitialProperties(prop); + + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .to("mock:{{?whereTo}}?retainFirst={{?maxKeep}}"); + } + }); + context.start(); + + getMockEndpoint("mock:result").expectedMessageCount(2); + + template.sendBody("direct:start", "Hello World"); + template.sendBody("direct:start", "Bye World"); + + assertMockEndpointsSatisfied(); + } + + @Override + protected CamelContext createCamelContext() throws Exception { + CamelContext context = super.createCamelContext(); + context.getPropertiesComponent().setLocation("classpath:org/apache/camel/component/properties/myproperties.properties"); + return context; + } + +} diff --git a/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/AbstractEndpointBuilder.java b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/AbstractEndpointBuilder.java index b6f24aa..a279a09 100644 --- a/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/AbstractEndpointBuilder.java +++ b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/AbstractEndpointBuilder.java @@ -18,8 +18,10 @@ package org.apache.camel.builder.endpoint; import java.net.URISyntaxException; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Set; import java.util.TreeMap; import org.apache.camel.CamelContext; @@ -30,6 +32,8 @@ import org.apache.camel.NoSuchEndpointException; import org.apache.camel.RuntimeCamelException; import org.apache.camel.builder.SimpleBuilder; import org.apache.camel.spi.NormalizedEndpointUri; +import org.apache.camel.spi.PropertiesComponent; +import org.apache.camel.support.EndpointHelper; import org.apache.camel.support.NormalizedUri; import org.apache.camel.util.URISupport; @@ -68,16 +72,25 @@ public class AbstractEndpointBuilder { } private static void resolvePropertyPlaceholders(CamelContext context, Map<String, Object> properties) { + Set<String> toRemove = new HashSet<>(); for (Map.Entry<String, Object> entry : properties.entrySet()) { Object value = entry.getValue(); if (value instanceof String) { String text = (String) value; - String changed = context.resolvePropertyPlaceholders(text); - if (!changed.equals(text)) { + String changed = context.adapt(ExtendedCamelContext.class).resolvePropertyPlaceholders(text, true); + if (changed.startsWith(PropertiesComponent.PREFIX_OPTIONAL_TOKEN)) { + // unresolved then remove it + toRemove.add(entry.getKey()); + } else if (!changed.equals(text)) { entry.setValue(changed); } } } + if (!toRemove.isEmpty()) { + for (String key : toRemove) { + properties.remove(key); + } + } } public <T extends Endpoint> T resolve(CamelContext context, Class<T> endpointType) throws NoSuchEndpointException { @@ -109,7 +122,7 @@ public class AbstractEndpointBuilder { String targetPath = path; if (camelContext != null) { targetScheme = camelContext.resolvePropertyPlaceholders(targetScheme); - targetPath = camelContext.resolvePropertyPlaceholders(targetPath); + targetPath = EndpointHelper.resolveEndpointUriPropertyPlaceholders(camelContext, targetPath); } if (params.isEmpty()) { diff --git a/core/camel-endpointdsl/src/test/java/org/apache/camel/builder/endpoint/OptionalPropertyPlaceholderTest.java b/core/camel-endpointdsl/src/test/java/org/apache/camel/builder/endpoint/OptionalPropertyPlaceholderTest.java new file mode 100644 index 0000000..08de571 --- /dev/null +++ b/core/camel-endpointdsl/src/test/java/org/apache/camel/builder/endpoint/OptionalPropertyPlaceholderTest.java @@ -0,0 +1,121 @@ +/* + * 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.builder.endpoint; + +import java.util.Properties; + +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class OptionalPropertyPlaceholderTest extends CamelTestSupport { + + @Override + public boolean isUseRouteBuilder() { + return false; + } + + @Test + public void testQueryOptionalNotPresent() throws Exception { + context.addRoutes(new EndpointRouteBuilder() { + @Override + public void configure() throws Exception { + from(direct("start")).to(mock("result").retainFirst("{{?maxKeep}}").failFast(false)); + } + }); + context.start(); + + getMockEndpoint("mock:result").expectedMessageCount(2); + + template.sendBody("direct:start", "Hello World"); + template.sendBody("direct:start", "Bye World"); + + assertMockEndpointsSatisfied(); + + assertEquals(2, getMockEndpoint("mock:result").getReceivedExchanges().size()); + } + + @Test + public void testQueryOptionalPresent() throws Exception { + Properties prop = new Properties(); + prop.put("maxKeep", "1"); + context.getPropertiesComponent().setInitialProperties(prop); + + context.addRoutes(new EndpointRouteBuilder() { + @Override + public void configure() throws Exception { + from(direct("start")).to(mock("result").retainFirst("{{?maxKeep}}").failFast(false)); + } + }); + context.start(); + + getMockEndpoint("mock:result?retainFirst=1").expectedMessageCount(2); + + template.sendBody("direct:start", "Hello World"); + template.sendBody("direct:start", "Bye World"); + + assertMockEndpointsSatisfied(); + + assertEquals(1, getMockEndpoint("mock:result?retainFirst=1").getReceivedExchanges().size()); + } + + @Test + public void testPathOptionalNotPresent() throws Exception { + context.addRoutes(new EndpointRouteBuilder() { + @Override + public void configure() throws Exception { + from(direct("start")).to(mock("res{{?whereTo}}ult").failFast(false)); + } + }); + context.start(); + + getMockEndpoint("mock:result").expectedMessageCount(2); + + template.sendBody("direct:start", "Hello World"); + template.sendBody("direct:start", "Bye World"); + + assertMockEndpointsSatisfied(); + + assertEquals(2, getMockEndpoint("mock:result").getReceivedExchanges().size()); + } + + @Test + public void testPathOptionalPresent() throws Exception { + Properties prop = new Properties(); + prop.put("whereTo", "result"); + context.getPropertiesComponent().setInitialProperties(prop); + + context.addRoutes(new EndpointRouteBuilder() { + @Override + public void configure() throws Exception { + from(direct("start")).to(mock("{{?whereTo}}").failFast(false)); + } + }); + context.start(); + + getMockEndpoint("mock:result").expectedMessageCount(2); + + template.sendBody("direct:start", "Hello World"); + template.sendBody("direct:start", "Bye World"); + + assertMockEndpointsSatisfied(); + + assertEquals(2, getMockEndpoint("mock:result").getReceivedExchanges().size()); + } + +} diff --git a/core/camel-support/src/main/java/org/apache/camel/support/EndpointHelper.java b/core/camel-support/src/main/java/org/apache/camel/support/EndpointHelper.java index 97fdf66..285ca71 100644 --- a/core/camel-support/src/main/java/org/apache/camel/support/EndpointHelper.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/EndpointHelper.java @@ -20,6 +20,7 @@ import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -36,6 +37,7 @@ import org.apache.camel.PollingConsumer; import org.apache.camel.Processor; import org.apache.camel.ResolveEndpointFailedException; import org.apache.camel.Route; +import org.apache.camel.spi.PropertiesComponent; import org.apache.camel.support.service.ServiceHelper; import org.apache.camel.util.StringHelper; import org.apache.camel.util.URISupport; @@ -57,6 +59,90 @@ public final class EndpointHelper { } /** + * Resolves the endpoint uri that may have property placeholders (supports optional property placeholders). + * + * @param camelContext the camel context + * @param uri the endpoint uri + * @return returns endpoint uri with property placeholders resolved + */ + public static String resolveEndpointUriPropertyPlaceholders(CamelContext camelContext, String uri) { + // the uri may have optional property placeholders which is not possible to resolve + // so we keep the unresolved in the uri, which we then afterwards will remove + // which is a little complex depending on the placeholder is from context-path or query parameters + // in the uri string + try { + uri = camelContext.adapt(ExtendedCamelContext.class).resolvePropertyPlaceholders(uri, true); + if (uri == null || uri.isEmpty()) { + return uri; + } + String prefix = PropertiesComponent.PREFIX_OPTIONAL_TOKEN; + if (uri.contains(prefix)) { + String unresolved = uri; + uri = doResolveEndpointUriOptionalPropertyPlaceholders(unresolved); + LOG.trace("Unresolved optional placeholders removed from uri: {} -> {}", unresolved, uri); + } + LOG.trace("Resolved property placeholders with uri: {}", uri); + } catch (Exception e) { + throw new ResolveEndpointFailedException(uri, e); + } + return uri; + } + + private static String doResolveEndpointUriOptionalPropertyPlaceholders(String uri) throws URISyntaxException { + String prefix = PropertiesComponent.PREFIX_OPTIONAL_TOKEN; + + // find query position which is the first question mark that is not part of the optional token prefix + int pos = 0; + for (int i = 0; i < uri.length(); i++) { + char ch = uri.charAt(i); + if (ch == '?') { + // ensure that its not part of property prefix + if (i > 2) { + char ch1 = uri.charAt(i - 1); + char ch2 = uri.charAt(i - 2); + if (ch1 != '{' && ch2 != '{') { + pos = i; + break; + } + } else { + pos = i; + break; + } + } + } + String base = pos > 0 ? uri.substring(0, pos) : uri; + String query = pos > 0 ? uri.substring(pos + 1) : null; + + // the base (context path) should remove all unresolved property placeholders + // which is done by replacing all begin...end tokens with an empty string + String pattern = "\\{\\{?.*}}"; + base = base.replaceAll(pattern, ""); + + // the query parameters needs to be rebuild by removing the unresolved key=value pairs + if (query != null && query.contains(prefix)) { + Map<String, Object> params = URISupport.parseQuery(query); + Map<String, Object> keep = new LinkedHashMap<>(); + for (Map.Entry<String, Object> entry : params.entrySet()) { + String key = entry.getKey(); + if (key.startsWith(prefix)) { + continue; + } + Object value = entry.getValue(); + if (value instanceof String && ((String) value).startsWith(prefix)) { + continue; + } + keep.put(key, value); + } + // rebuild query + query = URISupport.createQueryString(keep); + } + + // assemble uri as answer + uri = query != null && !query.isEmpty() ? base + "?" + query : base; + return uri; + } + + /** * Normalize uri so we can do endpoint hits with minor mistakes and parameters is not in the same order. * * @param uri the uri @@ -112,7 +198,7 @@ public final class EndpointHelper { * Matches the endpoint with the given pattern. * <p/> * The endpoint will first resolve property placeholders using - * {@link CamelContext#resolvePropertyPlaceholders(String)}. + * {@link #resolveEndpointUriPropertyPlaceholders(CamelContext, String)} * <p/> * The match rules are applied in this order: * <ul> @@ -131,7 +217,7 @@ public final class EndpointHelper { public static boolean matchEndpoint(CamelContext context, String uri, String pattern) { if (context != null) { try { - uri = context.resolvePropertyPlaceholders(uri); + uri = resolveEndpointUriPropertyPlaceholders(context, uri); } catch (Exception e) { throw new ResolveEndpointFailedException(uri, e); } @@ -163,7 +249,7 @@ public final class EndpointHelper { /** * Toggles // separators in the given uri. If the uri does not contain ://, the slashes are added, otherwise they * are removed. - * + * * @param normalizedUri The uri to add/remove separators in * @return The uri with separators added or removed */ diff --git a/core/camel-support/src/main/java/org/apache/camel/support/component/EndpointUriFactorySupport.java b/core/camel-support/src/main/java/org/apache/camel/support/component/EndpointUriFactorySupport.java index 47b8d57..26a78df 100644 --- a/core/camel-support/src/main/java/org/apache/camel/support/component/EndpointUriFactorySupport.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/component/EndpointUriFactorySupport.java @@ -56,9 +56,9 @@ public abstract class EndpointUriFactorySupport implements CamelContextAware, En } if (ObjectHelper.isNotEmpty(obj)) { String str = camelContext.getTypeConverter().convertTo(String.class, obj); - int occurence = StringHelper.countOccurence(uri, name); - if (occurence > 1) { - uri = StringHelper.replaceFromSecondOccurence(uri, name, str); + int occurrence = StringHelper.countOccurrence(uri, name); + if (occurrence > 1) { + uri = StringHelper.replaceFromSecondOccurrence(uri, name, str); } else { uri = uri.replace(name, str); } @@ -110,37 +110,4 @@ public abstract class EndpointUriFactorySupport implements CamelContextAware, En return uri; } - private int countOccurence(String str, String findStr) { - int lastIndex = 0; - int count = 0; - - while (lastIndex != -1) { - - lastIndex = str.indexOf(findStr, lastIndex); - - if (lastIndex != -1) { - count++; - lastIndex += findStr.length(); - } - } - return count; - } - - private String replaceFromSecondOccurence(String str, String name, String repl) { - int index = str.indexOf(name); - boolean replace = false; - - while (index != -1) { - String tempString = str.substring(index); - if (replace) { - tempString = tempString.replaceFirst(name, repl); - str = str.substring(0, index) + tempString; - replace = false; - } else { - replace = true; - } - index = str.indexOf(name, index + 1); - } - return str; - } } diff --git a/core/camel-util/src/main/java/org/apache/camel/util/StringHelper.java b/core/camel-util/src/main/java/org/apache/camel/util/StringHelper.java index 684790c..ddde325 100644 --- a/core/camel-util/src/main/java/org/apache/camel/util/StringHelper.java +++ b/core/camel-util/src/main/java/org/apache/camel/util/StringHelper.java @@ -1034,13 +1034,13 @@ public final class StringHelper { } /** - * Returns the occurence of a search string in to a string + * Returns the occurrence of a search string in to a string. * * @param text the text * @param search the string to search - * @return an integer reporting the number of occurence of the searched string in to the text + * @return an integer reporting the number of occurrence of the searched string in to the text */ - public static int countOccurence(String text, String search) { + public static int countOccurrence(String text, String search) { int lastIndex = 0; int count = 0; while (lastIndex != -1) { @@ -1054,21 +1054,21 @@ public final class StringHelper { } /** - * Replaces a string in to a text starting from his second occurence + * Replaces a string in to a text starting from his second occurrence. * - * @param text the text - * @param search the string to search - * @param repl the replacement for the string - * @return the string with the replacement + * @param text the text + * @param search the string to search + * @param replacement the replacement for the string + * @return the string with the replacement */ - public static String replaceFromSecondOccurence(String text, String search, String repl) { + public static String replaceFromSecondOccurrence(String text, String search, String replacement) { int index = text.indexOf(search); boolean replace = false; while (index != -1) { String tempString = text.substring(index); if (replace) { - tempString = tempString.replaceFirst(search, repl); + tempString = tempString.replaceFirst(search, replacement); text = text.substring(0, index) + tempString; replace = false; } else { 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 6d77017..3839a86 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 @@ -134,6 +134,20 @@ public final class URISupport { } /** + * Strips the query parameters from the uri + * + * @param uri the uri + * @return the uri without the query parameter + */ + public static String stripQuery(String uri) { + int idx = uri.indexOf('?'); + if (idx > -1) { + uri = uri.substring(0, idx); + } + return uri; + } + + /** * Parses the query part of the uri (eg the parameters). * <p/> * The URI parameters will by default be URI encoded. However you can define a parameter values with the syntax: