From f174579544de632600ebadb9afaceb1928af200d Mon Sep 17 00:00:00 2001 From: Yufei Cai Date: Wed, 30 Oct 2019 15:17:31 +0100 Subject: [PATCH] Placeholder pipeline: Replace Option by dedicated PipelineElement. Reason: To add another pipeline function fn:delete that should delete the entire string containing the pipeline, which is not evaluated yet. Signed-off-by: Yufei Cai --- .../placeholders/ExpressionResolver.java | 1 + .../placeholders/FunctionExpression.java | 6 +- .../ImmutableExpressionResolver.java | 14 ++- .../ImmutableFunctionExpression.java | 14 +-- .../model/placeholders/ImmutablePipeline.java | 27 +++-- .../ImmutablePipelineElementVisitor.java | 94 +++++++++++++++ .../ditto/model/placeholders/Pipeline.java | 6 +- .../model/placeholders/PipelineElement.java | 103 +++++++++++++++++ .../placeholders/PipelineElementDeleted.java | 56 +++++++++ .../placeholders/PipelineElementResolved.java | 62 ++++++++++ .../PipelineElementUnresolved.java | 56 +++++++++ .../placeholders/PipelineElementVisitor.java | 56 +++++++++ .../model/placeholders/PipelineFunction.java | 12 +- .../placeholders/PipelineFunctionDefault.java | 31 ++--- .../placeholders/PipelineFunctionDelete.java | 78 +++++++++++++ .../placeholders/PipelineFunctionLower.java | 10 +- .../PipelineFunctionSubstringAfter.java | 16 +-- .../PipelineFunctionSubstringBefore.java | 17 +-- .../placeholders/PipelineFunctionUpper.java | 8 +- .../placeholders/PlaceholderFactory.java | 25 ++-- .../model/placeholders/PlaceholderFilter.java | 67 +++-------- .../ImmutableFunctionExpressionTest.java | 32 ++--- .../placeholders/ImmutablePipelineTest.java | 15 ++- .../PipelineFunctionDefaultTest.java | 9 +- .../PipelineFunctionLowerTest.java | 2 +- .../PipelineFunctionSubstringAfterTest.java | 6 +- .../PipelineFunctionSubstringBeforeTest.java | 6 +- .../PipelineFunctionUpperTest.java | 2 +- .../placeholders/PlaceholderFilterTest.java | 109 +++++++++--------- .../ConnectionStatusMessageMapper.java | 2 +- .../messaging/BasePublisherActor.java | 2 +- .../MessageMappingProcessorActor.java | 5 +- 32 files changed, 703 insertions(+), 246 deletions(-) create mode 100644 model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/ImmutablePipelineElementVisitor.java create mode 100644 model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineElement.java create mode 100644 model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineElementDeleted.java create mode 100644 model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineElementResolved.java create mode 100644 model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineElementUnresolved.java create mode 100644 model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineElementVisitor.java create mode 100644 model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunctionDelete.java diff --git a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/ExpressionResolver.java b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/ExpressionResolver.java index c4a0a9398f..70bc8139c0 100644 --- a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/ExpressionResolver.java +++ b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/ExpressionResolver.java @@ -47,6 +47,7 @@ public interface ExpressionResolver { * @throws PlaceholderFunctionTooComplexException thrown if the {@code expressionTemplate} contains a placeholder * function chain which is too complex (e.g. too much chained function calls) */ + // TODO change signature String resolve(String expressionTemplate, boolean allowUnresolved); /** diff --git a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/FunctionExpression.java b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/FunctionExpression.java index cd4d8661dc..50ce8634cb 100644 --- a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/FunctionExpression.java +++ b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/FunctionExpression.java @@ -12,8 +12,6 @@ */ package org.eclipse.ditto.model.placeholders; -import java.util.Optional; - /** * Defines a function expression used in a Pipeline after the "input" stage of a resolved {@link Placeholder}, e.g. * function expressions are expressions like {@code fn:starts-with(':')} or {@code fn:default('fallback')}. Used in a @@ -30,11 +28,11 @@ interface FunctionExpression extends Expression { * Executes the Stage by passing in a value and returning a resolved result. * * @param expression the expression string of this stage including prefix, e.g.: {@code fn:substring-before(':')}. - * @param resolvedInputValue the resolved input value (e.g. via {@link Placeholder} to process. + * @param resolvedInputValue the resolved input value (e.g. via {@link org.eclipse.ditto.model.placeholders.Placeholder} to process. * @param expressionResolver the expressionResolver to use in order to resolve placeholders occurring in the * pipeline expression. * @return processed output value, or an empty optional if this stage resolved to an empty Optional. */ - Optional resolve(String expression, Optional resolvedInputValue, + PipelineElement resolve(String expression, PipelineElement resolvedInputValue, ExpressionResolver expressionResolver); } diff --git a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/ImmutableExpressionResolver.java b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/ImmutableExpressionResolver.java index 33713881d8..476e725b37 100644 --- a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/ImmutableExpressionResolver.java +++ b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/ImmutableExpressionResolver.java @@ -122,15 +122,21 @@ private Function> makePlaceholderReplacerFunction( final Optional placeholderWithoutPrefix = resolvePlaceholderWithoutPrefixIfSupported(placeholderResolver, placeholderTemplate); - return placeholderWithoutPrefix - .map(p -> resolvePlaceholder(placeholderResolver, p)) + return placeholderWithoutPrefix.map(p -> resolvePlaceholder(placeholderResolver, p)) .flatMap(pipelineInput -> { - if (Optional.of(placeholderReplacementInValidation).equals(pipelineInput)) { + if (pipelineInput.filter(placeholderReplacementInValidation::equals).isPresent()) { pipeline.validate(); // let the input pass if validation succeeded: return pipelineInput; } - return pipeline.execute(pipelineInput, this); + final PipelineElement element = pipelineInput.map(PipelineElement::resolved) + .orElse(PipelineElement.unresolved()); + return pipeline.execute(element, this) + .accept(PipelineElement.>newVisitorBuilder() + .deleted(Optional.empty()) // TODO: distinguish + .unresolved(Optional.empty()) + .resolved(Optional::of) + .build()); }); }; diff --git a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/ImmutableFunctionExpression.java b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/ImmutableFunctionExpression.java index 2506e9e4df..48716462a5 100644 --- a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/ImmutableFunctionExpression.java +++ b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/ImmutableFunctionExpression.java @@ -15,7 +15,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Optional; import java.util.stream.Collectors; import javax.annotation.concurrent.Immutable; @@ -32,11 +31,12 @@ final class ImmutableFunctionExpression implements FunctionExpression { static final ImmutableFunctionExpression INSTANCE = new ImmutableFunctionExpression(); private static final List SUPPORTED = Collections.unmodifiableList(Arrays.asList( - new PipelineFunctionDefault(), // fn:default('fallback value') + new PipelineFunctionDefault(), // fn:default('fallback value') new PipelineFunctionSubstringBefore(), // fn:substring-before(':') - new PipelineFunctionSubstringAfter(), // fn:substring-after(':') - new PipelineFunctionLower(), // fn:lower() - new PipelineFunctionUpper() // fn:upper() + new PipelineFunctionSubstringAfter(), // fn:substring-after(':') + new PipelineFunctionLower(), // fn:lower() + new PipelineFunctionUpper(), // fn:upper() + new PipelineFunctionDelete() // fn:delete() )); @Override @@ -63,7 +63,7 @@ public boolean supports(final String expressionName) { } @Override - public Optional resolve(final String expression, final Optional resolvedInputValue, + public PipelineElement resolve(final String expression, final PipelineElement resolvedInputValue, final ExpressionResolver expressionResolver) { if (!supports(expression.replaceFirst(getPrefix() + ":", ""))) { @@ -77,7 +77,7 @@ public Optional resolve(final String expression, final Optional expressionResolver) ) .findFirst() - .flatMap(o -> o); + .orElse(PipelineElement.unresolved()); } } diff --git a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/ImmutablePipeline.java b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/ImmutablePipeline.java index f4668a25ee..d6cf420e40 100644 --- a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/ImmutablePipeline.java +++ b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/ImmutablePipeline.java @@ -16,7 +16,6 @@ import java.util.Collections; import java.util.List; import java.util.Objects; -import java.util.Optional; import javax.annotation.concurrent.Immutable; @@ -35,13 +34,13 @@ final class ImmutablePipeline implements Pipeline { } @Override - public Optional execute(final Optional pipelineInput, final ExpressionResolver expressionResolver) { + public PipelineElement execute(final PipelineElement pipelineInput, final ExpressionResolver expressionResolver) { - Optional stageValue = pipelineInput; - for (final String expression : stageExpressions) { - stageValue = functionExpression.resolve(expression, stageValue, expressionResolver); - } - return stageValue; + return stageExpressions.stream().reduce( + pipelineInput, + (element, expression) -> functionExpression.resolve(expression, element, expressionResolver), + ImmutablePipeline::combineElements + ); } @Override @@ -82,4 +81,18 @@ public String toString() { ", stageExpressions=" + stageExpressions + "]"; } + + private static PipelineElement combineElements(final PipelineElement self, final PipelineElement other) { + return self.onDeleted(() -> self) + .onUnresolved(() -> other) + .onResolved(s -> other.onDeleted(() -> other) + .onUnresolved(() -> self) + .onResolved(t -> { + // should not happen - stream of stage expressions is not parallel + throw new IllegalArgumentException( + String.format("Conflict: combining 2 resolved elements <%s> and <%s>", s, t) + ); + }) + ); + } } diff --git a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/ImmutablePipelineElementVisitor.java b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/ImmutablePipelineElementVisitor.java new file mode 100644 index 0000000000..5fbf37a1d8 --- /dev/null +++ b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/ImmutablePipelineElementVisitor.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2019 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.ditto.model.placeholders; + +import static org.eclipse.ditto.model.base.common.ConditionChecker.checkNotNull; + +import java.util.function.Function; + +import javax.annotation.Nullable; + +/** + * Package-private implementation of {@code PipelineElementVisitor}. + * + * @param type of visitor result. + */ +final class ImmutablePipelineElementVisitor implements PipelineElementVisitor { + + private final Function onResolution; + private final T onIrresolution; + private final T onDeletion; + + private ImmutablePipelineElementVisitor( + final Function onResolution, + final T onIrresolution, + final T onDeletion) { + this.onResolution = onResolution; + this.onIrresolution = onIrresolution; + this.onDeletion = onDeletion; + } + + static PipelineElementVisitor.Builder newBuilder() { + return new Builder<>(); + } + + @Override + public T resolved(final String resolved) { + return onResolution.apply(resolved); + } + + @Override + public T unresolved() { + return onIrresolution; + } + + @Override + public T deleted() { + return onDeletion; + } + + private static final class Builder implements PipelineElementVisitor.Builder { + + @Nullable private Function onResolution; + @Nullable private T onIrresolution; + @Nullable private T onDeletion; + + private Builder() {} + + @Override + public PipelineElementVisitor build() { + return new ImmutablePipelineElementVisitor<>( + checkNotNull(onResolution, "onResolution"), + checkNotNull(onIrresolution, "onIrresolution"), + checkNotNull(onDeletion, "onDeletion")); + } + + @Override + public PipelineElementVisitor.Builder resolved(final Function onResolution) { + this.onResolution = onResolution; + return this; + } + + @Override + public PipelineElementVisitor.Builder unresolved(final T onIrresolution) { + this.onIrresolution = onIrresolution; + return this; + } + + @Override + public PipelineElementVisitor.Builder deleted(final T onDeletion) { + this.onDeletion = onDeletion; + return this; + } + } +} diff --git a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/Pipeline.java b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/Pipeline.java index 187da11c0b..e22f83f3a9 100644 --- a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/Pipeline.java +++ b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/Pipeline.java @@ -12,8 +12,6 @@ */ package org.eclipse.ditto.model.placeholders; -import java.util.Optional; - /** * A Pipeline is able to execute its {@code stageExpressions} starting with a {@code pipelineInput} derived from a * {@link Placeholder}. @@ -23,12 +21,12 @@ interface Pipeline { /** * Executes the Pipeline function expressions by first evaluating the placeholder variable by name. * - * @param pipelineInput the input into the pipe, usually an already resolved {@link Placeholder} - may also be an + * @param pipelineInput the input into the pipe, usually an already resolved {@link org.eclipse.ditto.model.placeholders.Placeholder} - may also be an * empty optional as there are pipeline stages which can make use of a default fallback value. * @param expressionResolver the resolver from which placeholders are resolved. * @return the result of the Pipeline execution after all stages were handled. */ - Optional execute(Optional pipelineInput, ExpressionResolver expressionResolver); + PipelineElement execute(PipelineElement pipelineInput, ExpressionResolver expressionResolver); /** * Validates the instantiated Pipeline and checks whether all configured {@code stageExpressions} are supported. diff --git a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineElement.java b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineElement.java new file mode 100644 index 0000000000..99e3d9ba1c --- /dev/null +++ b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineElement.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2019 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.ditto.model.placeholders; + +import java.util.function.Function; +import java.util.function.Supplier; + +/** + * An element going through some pipeline of functions. + */ +public interface PipelineElement extends Iterable { + + /** + * Advance a resolved value to the next stage. Other elements are unchanged. + * + * @param stringProcessor What to do for resolved values. + * @return the pipeline element at the next pipeline stage. + */ + PipelineElement onResolved(Function stringProcessor); + + /** + * Advance an unresolved value to the next stage. Other elements are unchanged. + * + * @param nextPipelineElement supplier of the next pipeline element. + * @return the pipeline element at the next pipeline stage. + */ + PipelineElement onUnresolved(Supplier nextPipelineElement); + + /** + * Advance a deleted value to the next stage. Other elements are unchanged. + * + * @param nextPipelineElement supplier of the next pipeline element. + * @return the pipeline element at the next pipeline stage. + */ + PipelineElement onDeleted(Supplier nextPipelineElement); + + /** + * Evaluate this pipeline element by a visitor. + * + * @param visitor the visitor. + * @param the type of results. + * @return the evaluation result. + */ + T accept(PipelineElementVisitor visitor); + + /** + * Convert a resolved value into another resolved value and leave other elements untouched. + * + * @param mapper what to do about the resolved value. + * @return the mapped resolved value. + */ + default PipelineElement map(Function mapper) { + return onResolved(mapper.andThen(PipelineElement::resolved)); + } + + /** + * Create a builder of a visitor to evaluate pipeline elements. + * + * @param the type of results. + * @return the visitor builder. + */ + static PipelineElementVisitor.Builder newVisitorBuilder() { + return ImmutablePipelineElementVisitor.newBuilder(); + } + + /** + * Creat a pipeline element containing a resolved value. + * + * @param value the resolved value. + * @return the pipeline element. + */ + static PipelineElement resolved(final String value) { + return PipelineElementResolved.of(value); + } + + /** + * Get the unique pipeline element signifying deletion of the whole string containing the pipeline. + * + * @return the deleted element. + */ + static PipelineElement deleted() { + return PipelineElementDeleted.INSTANCE; + } + + /** + * Get the unique pipeline element signifying failed resolution. + * + * @return the unresolved element. + */ + static PipelineElement unresolved() { + return PipelineElementUnresolved.INSTANCE; + } +} diff --git a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineElementDeleted.java b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineElementDeleted.java new file mode 100644 index 0000000000..a15371d89f --- /dev/null +++ b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineElementDeleted.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2019 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.ditto.model.placeholders; + +import java.util.Collections; +import java.util.Iterator; +import java.util.function.Function; +import java.util.function.Supplier; + +import javax.annotation.concurrent.Immutable; + +/** + * A unique pipeline element signifying deletion of the entire string containing the pipeline. + */ +@Immutable +final class PipelineElementDeleted implements PipelineElement { + + static final PipelineElement INSTANCE = new PipelineElementDeleted(); + + private PipelineElementDeleted() {} + + @Override + public PipelineElement onResolved(final Function stringProcessor) { + return this; + } + + @Override + public PipelineElement onUnresolved(final Supplier nextPipelineElement) { + return this; + } + + @Override + public PipelineElement onDeleted(final Supplier nextPipelineElement) { + return nextPipelineElement.get(); + } + + @Override + public T accept(final PipelineElementVisitor visitor) { + return visitor.deleted(); + } + + @Override + public Iterator iterator() { + return Collections.emptyIterator(); + } +} diff --git a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineElementResolved.java b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineElementResolved.java new file mode 100644 index 0000000000..ba3cce47a9 --- /dev/null +++ b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineElementResolved.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.ditto.model.placeholders; + +import java.util.Collections; +import java.util.Iterator; +import java.util.function.Function; +import java.util.function.Supplier; + +import javax.annotation.concurrent.Immutable; + +/** + * Pipeline elements containing a resolved value. + */ +@Immutable +final class PipelineElementResolved implements PipelineElement { + + private final String value; + + private PipelineElementResolved(final String value) { + this.value = value; + } + + static PipelineElement of(final String value) { + return new PipelineElementResolved(value); + } + + @Override + public PipelineElement onResolved(final Function stringProcessor) { + return stringProcessor.apply(value); + } + + @Override + public PipelineElement onUnresolved(final Supplier nextPipelineElement) { + return this; + } + + @Override + public PipelineElement onDeleted(final Supplier nextPipelineElement) { + return this; + } + + @Override + public T accept(final PipelineElementVisitor visitor) { + return visitor.resolved(value); + } + + @Override + public Iterator iterator() { + return Collections.singletonList(value).iterator(); + } +} diff --git a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineElementUnresolved.java b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineElementUnresolved.java new file mode 100644 index 0000000000..7e1671ae82 --- /dev/null +++ b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineElementUnresolved.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2019 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.ditto.model.placeholders; + +import java.util.Collections; +import java.util.Iterator; +import java.util.function.Function; +import java.util.function.Supplier; + +import javax.annotation.concurrent.Immutable; + +/** + * The unique pipeline element signifying failed resolution. + */ +@Immutable +final class PipelineElementUnresolved implements PipelineElement { + + static final PipelineElement INSTANCE = new PipelineElementUnresolved(); + + private PipelineElementUnresolved() {} + + @Override + public PipelineElement onResolved(final Function stringProcessor) { + return this; + } + + @Override + public PipelineElement onUnresolved(final Supplier nextPipelineElement) { + return nextPipelineElement.get(); + } + + @Override + public PipelineElement onDeleted(final Supplier nextPipelineElement) { + return this; + } + + @Override + public T accept(final PipelineElementVisitor visitor) { + return visitor.unresolved(); + } + + @Override + public Iterator iterator() { + return Collections.emptyIterator(); + } +} diff --git a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineElementVisitor.java b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineElementVisitor.java new file mode 100644 index 0000000000..170022a764 --- /dev/null +++ b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineElementVisitor.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2019 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.ditto.model.placeholders; + +import java.util.function.Function; + +/** + * Visitor to evaluate pipeline elements. + * + * @param type of results. + */ +public interface PipelineElementVisitor { + + /** + * Evaluate a resolved value. + * + * @param value the resolved value. + * @return the result. + */ + T resolved(String value); + + /** + * Evaluate the unique pipeline element signifying failed resolution. + * + * @return the result. + */ + T unresolved(); + + /** + * Evaluate the unique pipeline element signifying deletion of the whole string containing the pipeline. + * + * @return the result. + */ + T deleted(); + + interface Builder { + + PipelineElementVisitor build(); + + Builder resolved(Function onResolution); + + Builder unresolved(T onIrresolution); + + Builder deleted(T onDeletion); + } +} diff --git a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunction.java b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunction.java index 79d2b4fe0c..bee463fd24 100644 --- a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunction.java +++ b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunction.java @@ -13,7 +13,6 @@ package org.eclipse.ditto.model.placeholders; import java.util.List; -import java.util.Optional; /** * Describes a pipeline function with {@code name}, {@code signature}, signature validation capability and @@ -51,7 +50,7 @@ interface PipelineFunction { * function. * @return processed output value, or an empty optional otherwise. */ - Optional apply(Optional value, String paramsIncludingParentheses, + PipelineElement apply(PipelineElement value, String paramsIncludingParentheses, ExpressionResolver expressionResolver); /** @@ -64,15 +63,6 @@ interface Signature { */ List getParameterDefinitions(); - /** - * Determines the parameter definition at the passed {@code index} providing the requeste type {@code }. - * - * @param index the index of the parameter whose definition to return. - * @param the type of the parameter. - * @return the requested typed parameter definition - */ - PipelineFunction.ParameterDefinition getParameterDefinition(int index); - /** * @return renders a nice String description of the complete signature */ diff --git a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunctionDefault.java b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunctionDefault.java index 3e266a5b47..dccb586bcc 100644 --- a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunctionDefault.java +++ b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunctionDefault.java @@ -40,25 +40,24 @@ public DefaultFunctionSignature getSignature() { } @Override - public Optional apply(final Optional value, final String paramsIncludingParentheses, + public PipelineElement apply(final PipelineElement value, final String paramsIncludingParentheses, final ExpressionResolver expressionResolver) { - if (value.isPresent()) { - // if previous stage was non-empty: proceed with that - return value; - } else { - // parse + resolve the specified default value: - return parseAndResolveThrow(paramsIncludingParentheses, expressionResolver); - } + // parse + resolve the specified default value for unresolved placeholders + // if previous stage does not resolve to a value. deleted pipeline elements remain deleted. + return value.onUnresolved(() -> + PipelineElement.resolved(parseAndResolveThrow(paramsIncludingParentheses, expressionResolver))); } - private Optional parseAndResolveThrow(final String paramsIncludingParentheses, final ExpressionResolver expressionResolver) { - final Optional resolved = this.parameterResolver.apply(paramsIncludingParentheses, expressionResolver); - if(!resolved.isPresent()) { + private String parseAndResolveThrow(final String paramsIncludingParentheses, final ExpressionResolver resolver) { + final Optional parameterOptional = + this.parameterResolver.apply(paramsIncludingParentheses, resolver); + if (!parameterOptional.isPresent()) { throw PlaceholderFunctionSignatureInvalidException.newBuilder(paramsIncludingParentheses, this) .build(); + } else { + return parameterOptional.get(); } - return resolved; } /** @@ -79,14 +78,6 @@ public List getParameterDefinitions() { return Collections.singletonList(defaultValueDescription); } - @Override - public ParameterDefinition getParameterDefinition(final int index) { - if (index == 0) { - return (ParameterDefinition) defaultValueDescription; - } - throw new IllegalArgumentException("Signature does not define a parameter at index '" + index + "'"); - } - @Override public String toString() { return renderSignature(); diff --git a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunctionDelete.java b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunctionDelete.java new file mode 100644 index 0000000000..376cf1d269 --- /dev/null +++ b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunctionDelete.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2017 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.ditto.model.placeholders; + +import java.util.Collections; +import java.util.List; + +import javax.annotation.concurrent.Immutable; + +/** + * Provides the {@code fn:delete()} function implementation. + */ +@Immutable +final class PipelineFunctionDelete implements PipelineFunction { + + private static final String FUNCTION_NAME = "delete"; + + private final PipelineFunctionParameterResolverFactory.EmptyParameterResolver parameterResolver = + PipelineFunctionParameterResolverFactory.forEmptyParameters(); + + @Override + public String getName() { + return FUNCTION_NAME; + } + + @Override + public DeleteFunctionSignature getSignature() { + return DeleteFunctionSignature.INSTANCE; + } + + @Override + public PipelineElement apply(final PipelineElement value, final String paramsIncludingParentheses, + final ExpressionResolver expressionResolver) { + + // check if signature matches (empty params!) + validateOrThrow(paramsIncludingParentheses); + return PipelineElement.deleted(); + } + + private void validateOrThrow(final String paramsIncludingParentheses) { + if (!parameterResolver.test(paramsIncludingParentheses)) { + throw PlaceholderFunctionSignatureInvalidException.newBuilder(paramsIncludingParentheses, this) + .build(); + } + } + + /** + * Describes the signature of the {@code upper()} function. + */ + private static final class DeleteFunctionSignature implements Signature { + + private static final DeleteFunctionSignature INSTANCE = new DeleteFunctionSignature(); + + private DeleteFunctionSignature() { + } + + @Override + public List getParameterDefinitions() { + return Collections.emptyList(); + } + + @Override + public String toString() { + return renderSignature(); + } + } + +} diff --git a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunctionLower.java b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunctionLower.java index a195b13ba2..913d7bbeba 100644 --- a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunctionLower.java +++ b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunctionLower.java @@ -14,7 +14,6 @@ import java.util.Collections; import java.util.List; -import java.util.Optional; import javax.annotation.concurrent.Immutable; @@ -40,12 +39,12 @@ public LowerFunctionSignature getSignature() { } @Override - public Optional apply(final Optional value, final String paramsIncludingParentheses, + public PipelineElement apply(final PipelineElement element, final String paramsIncludingParentheses, final ExpressionResolver expressionResolver) { // check if signature matches (empty params!) validateOrThrow(paramsIncludingParentheses); - return value.map(String::toLowerCase); + return element.map(String::toLowerCase); } private void validateOrThrow(final String paramsIncludingParentheses) { @@ -70,11 +69,6 @@ public List getParameterDefinitions() { return Collections.emptyList(); } - @Override - public ParameterDefinition getParameterDefinition(final int index) { - throw new IllegalArgumentException("Signature does not define a parameter at index '" + index + "'"); - } - @Override public String toString() { return renderSignature(); diff --git a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunctionSubstringAfter.java b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunctionSubstringAfter.java index bc10872822..e3718df46f 100644 --- a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunctionSubstringAfter.java +++ b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunctionSubstringAfter.java @@ -40,16 +40,16 @@ public Signature getSignature() { } @Override - public Optional apply(final Optional value, final String paramsIncludingParentheses, + public PipelineElement apply(final PipelineElement value, final String paramsIncludingParentheses, final ExpressionResolver expressionResolver) { final String splitValue = parseAndResolve(paramsIncludingParentheses, expressionResolver); - return value.map(previousStage -> { + return value.onResolved(previousStage -> { if (previousStage.contains(splitValue)) { - return previousStage.substring(previousStage.indexOf(splitValue) + 1); + return PipelineElement.resolved(previousStage.substring(previousStage.indexOf(splitValue) + 1)); } else { - return null; + return PipelineElement.unresolved(); } }); } @@ -80,14 +80,6 @@ public List getParameterDefinitions() { return Collections.singletonList(givenStringDescription); } - @Override - public ParameterDefinition getParameterDefinition(final int index) { - if (index == 0) { - return (ParameterDefinition) givenStringDescription; - } - throw new IllegalArgumentException("Signature does not define a parameter at index '" + index + "'"); - } - @Override public String toString() { return renderSignature(); diff --git a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunctionSubstringBefore.java b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunctionSubstringBefore.java index 86f222e4a6..3814aa4354 100644 --- a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunctionSubstringBefore.java +++ b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunctionSubstringBefore.java @@ -14,7 +14,6 @@ import java.util.Collections; import java.util.List; -import java.util.Optional; import javax.annotation.concurrent.Immutable; @@ -40,16 +39,16 @@ public Signature getSignature() { } @Override - public Optional apply(final Optional value, final String paramsIncludingParentheses, + public PipelineElement apply(final PipelineElement value, final String paramsIncludingParentheses, final ExpressionResolver expressionResolver) { final String splitValue = parseAndResolve(paramsIncludingParentheses, expressionResolver); - return value.map(previousStage -> { + return value.onResolved(previousStage -> { if (previousStage.contains(splitValue)) { - return previousStage.substring(0, previousStage.indexOf(splitValue)); + return PipelineElement.resolved(previousStage.substring(0, previousStage.indexOf(splitValue))); } else { - return null; + return PipelineElement.unresolved(); } }); } @@ -81,14 +80,6 @@ public List getParameterDefinitions() { return Collections.singletonList(givenStringDescription); } - @Override - public ParameterDefinition getParameterDefinition(final int index) { - if (index == 0) { - return (ParameterDefinition) givenStringDescription; - } - throw new IllegalArgumentException("Signature does not define a parameter at index '" + index + "'"); - } - @Override public String toString() { return renderSignature(); diff --git a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunctionUpper.java b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunctionUpper.java index aa10a7602c..3d312e2e59 100644 --- a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunctionUpper.java +++ b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PipelineFunctionUpper.java @@ -14,7 +14,6 @@ import java.util.Collections; import java.util.List; -import java.util.Optional; import javax.annotation.concurrent.Immutable; @@ -40,7 +39,7 @@ public UpperFunctionSignature getSignature() { } @Override - public Optional apply(final Optional value, final String paramsIncludingParentheses, + public PipelineElement apply(final PipelineElement value, final String paramsIncludingParentheses, final ExpressionResolver expressionResolver) { // check if signature matches (empty params!) @@ -70,11 +69,6 @@ public List getParameterDefinitions() { return Collections.emptyList(); } - @Override - public ParameterDefinition getParameterDefinition(final int index) { - throw new IllegalArgumentException("Signature does not define a parameter at index '" + index + "'"); - } - @Override public String toString() { return renderSignature(); diff --git a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PlaceholderFactory.java b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PlaceholderFactory.java index e457dd1e3b..6304b9222c 100644 --- a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PlaceholderFactory.java +++ b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PlaceholderFactory.java @@ -15,6 +15,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; import javax.annotation.Nullable; @@ -114,27 +115,33 @@ public static ExpressionResolver newExpressionResolver(final Placeholder } /** - * Creates a new ExpressionResolver instance for validation initialized with a single {@code placeholder}. + * Creates a new ExpressionResolver instance for validation initialized with 0 or more placeholders. * - * @param placeholder the placeholder. + * @param placeholders the placeholders. * @return the created ExpressionResolver instance */ - public static ExpressionResolver newExpressionResolverForValidation(final Placeholder placeholder) { - return newExpressionResolver(Collections.singletonList(newPlaceholderResolverForValidation(placeholder))); + public static ExpressionResolver newExpressionResolverForValidation(final Placeholder... placeholders) { + return newExpressionResolverForValidation("", placeholders); } /** - * Creates a new ExpressionResolver instance for validation initialized with a single {@code placeholder}. + * Creates a new ExpressionResolver instance for validation initialized with 0 or more placeholders. * - * @param placeholder the placeholder. * @param stringUsedInPlaceholderReplacement the dummy value used as a replacement for the found placeholders. + * @param placeholders the placeholders. * @return the created ExpressionResolver instance */ - public static ExpressionResolver newExpressionResolverForValidation(final Placeholder placeholder, final String stringUsedInPlaceholderReplacement) { - return newExpressionResolver(Collections.singletonList(newPlaceholderResolverForValidation(placeholder)), stringUsedInPlaceholderReplacement); + public static ExpressionResolver newExpressionResolverForValidation(final String stringUsedInPlaceholderReplacement, + final Placeholder... placeholders) { + return newExpressionResolver( + Arrays.stream(placeholders) + .map(PlaceholderFactory::newPlaceholderResolverForValidation) + .collect(Collectors.toList()), + stringUsedInPlaceholderReplacement); } - private static ExpressionResolver newExpressionResolver(final List> placeholderResolvers, final String stringUsedInPlaceholderValidation) { + private static ExpressionResolver newExpressionResolver(final List> placeholderResolvers, + final String stringUsedInPlaceholderValidation) { return new ImmutableExpressionResolver(placeholderResolvers, stringUsedInPlaceholderValidation); } diff --git a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PlaceholderFilter.java b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PlaceholderFilter.java index af7be4e3a1..c610450217 100644 --- a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PlaceholderFilter.java +++ b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/PlaceholderFilter.java @@ -43,7 +43,8 @@ public final class PlaceholderFilter { * @return AuthorizationContext as result of placeholder substitution. * @throws UnresolvedPlaceholderException if not all placeholders could be resolved */ - public static AuthorizationContext applyHeadersPlaceholderToAuthContext(final AuthorizationContext authorizationContext, + public static AuthorizationContext applyHeadersPlaceholderToAuthContext( + final AuthorizationContext authorizationContext, final Map headers) { // check if we have to replace anything at all @@ -112,24 +113,6 @@ static String apply(final String template, final T placeholderSource, final return apply(template, PlaceholderFactory.newExpressionResolver(placeholder, placeholderSource)); } - /** - * Finds all placeholders ({@code {{ ... }}}) defined in the given {@code template} and tries to replace them - * by applying the given {@code placeholder}. - * - * @param template the template to replace placeholders and optionally apply pipeline stages (functions) in. - * @param placeholderSource the source to resolve {@code placeholder} names from. - * @param placeholder the placeholder used to resolve placeholders. - * @param allowUnresolved if {@code false} this method throws an exception if there are any - * unresolved placeholders after applying the given placeholders. - * @param the type of the placeholderSource - * @throws UnresolvedPlaceholderException if {@code allowUnresolved} was @{code false} and not all placeholders - * could be resolved - */ - static String apply(final String template, final T placeholderSource, final Placeholder placeholder, - boolean allowUnresolved) { - return apply(template, PlaceholderFactory.newExpressionResolver(placeholder, placeholderSource), allowUnresolved); - } - /** * Finds all placeholders ({@code {{ ... }}}) defined in the given {@code template} and tries to replace them * by applying the given {@code expressionResolver}. @@ -141,28 +124,28 @@ static String apply(final String template, final T placeholderSource, final * @throws UnresolvedPlaceholderException if not all placeholders could be resolved */ public static String apply(final String template, final ExpressionResolver expressionResolver) { - return apply(template, expressionResolver, false); + return doApply(template, expressionResolver, false); } /** * Finds all placeholders ({@code {{ ... }}}) defined in the given {@code template} and tries to replace them - * by applying the given {@code expressionResolver}. + * by applying the given {@code expressionResolver}. If a pipeline function deletes the element, then return + * an empty optional. * * @param template the template string. - * @param expressionResolver the expressionResolver used to resolve placeholders and optionally pipeline stages + * @param resolver the expression-resolver used to resolve placeholders and optionally pipeline stages * (functions). - * @param allowUnresolved if {@code false} this method throws an exception if there are any - * unresolved placeholders after applying the given placeholders. - * @return the template string with the resolved values + * @return a template string if resolution succeeds with a result, + * or an empty optional if the template string is deleted. * @throws UnresolvedPlaceholderException if {@code allowUnresolved} is true and not all * placeholders were resolved * @throws PlaceholderFunctionTooComplexException thrown if the {@code template} contains a placeholder * function chain which is too complex (e.g. too much chained function calls) */ - public static String apply(final String template, final ExpressionResolver expressionResolver, - final boolean allowUnresolved) { + // TODO: change signature to actuially apply deletion + public static String applyWithDeletion(final String template, final ExpressionResolver resolver) { - return doApply(template, expressionResolver, allowUnresolved); + return resolver.resolve(template, true); } /** @@ -176,15 +159,7 @@ public static String apply(final String template, final ExpressionResolver expre * function chain which is too complex (e.g. too much chained function calls) */ public static void validate(final String template, final Placeholder... placeholders) { - String replaced = template; - for (int i = 0; i < placeholders.length; i++) { - boolean isNotLastPlaceholder = i < placeholders.length - 1; - final Placeholder thePlaceholder = placeholders[i]; - final ExpressionResolver expressionResolver = PlaceholderFactory - .newExpressionResolverForValidation(thePlaceholder); - - replaced = doApply(replaced, expressionResolver, isNotLastPlaceholder); - } + doApply(template, PlaceholderFactory.newExpressionResolverForValidation(placeholders), false); } /** @@ -195,22 +170,16 @@ public static void validate(final String template, final Placeholder... place * @param template a string potentially containing placeholders to replace * @param stringUsedInPlaceholderReplacement the dummy value used as a replacement for the found placeholders. * @param placeholders the {@link Placeholder}s to use for replacement + * @return the {@code template} with every placeholder replaced by {@code stringUsedInPlaceholderReplacement}. * @throws UnresolvedPlaceholderException in case the template's placeholders could not completely be resolved * @throws PlaceholderFunctionTooComplexException thrown if the {@code template} contains a placeholder * function chain which is too complex (e.g. too much chained function calls) - * @return the {@code template} with every placeholder replaced by {@code stringUsedInPlaceholderReplacement}. */ - public static String validateAndReplace(final String template, final String stringUsedInPlaceholderReplacement, final Placeholder... placeholders) { - String replaced = template; - for (int i = 0; i < placeholders.length; i++) { - boolean isNotLastPlaceholder = i < placeholders.length - 1; - final Placeholder thePlaceholder = placeholders[i]; - final ExpressionResolver expressionResolver = PlaceholderFactory - .newExpressionResolverForValidation(thePlaceholder, stringUsedInPlaceholderReplacement); - - replaced = doApply(replaced, expressionResolver, isNotLastPlaceholder); - } - return replaced; + public static String validateAndReplace(final String template, final String stringUsedInPlaceholderReplacement, + final Placeholder... placeholders) { + return doApply(template, + PlaceholderFactory.newExpressionResolverForValidation(stringUsedInPlaceholderReplacement, placeholders), + false); } private static String doApply(final String template, diff --git a/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/ImmutableFunctionExpressionTest.java b/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/ImmutableFunctionExpressionTest.java index beeba98af3..51cd2131b6 100644 --- a/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/ImmutableFunctionExpressionTest.java +++ b/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/ImmutableFunctionExpressionTest.java @@ -19,7 +19,6 @@ import java.util.Collections; import java.util.HashSet; import java.util.Map; -import java.util.Optional; import java.util.Set; import org.eclipse.ditto.model.things.ThingId; @@ -40,7 +39,8 @@ public class ImmutableFunctionExpressionTest { "substring-before", "substring-after", "lower", - "upper" + "upper", + "delete" ))); private static final HeadersPlaceholder HEADERS_PLACEHOLDER = PlaceholderFactory.newHeadersPlaceholder(); private static final ThingPlaceholder THING_PLACEHOLDER = PlaceholderFactory.newThingPlaceholder(); @@ -88,72 +88,76 @@ public void testCompletenessOfRegisteredFunctions() { @Test public void testUnknownFunction() { assertThatExceptionOfType(PlaceholderFunctionUnknownException.class).isThrownBy(() -> - UNDER_TEST.resolve("fn:unknown", Optional.of(THING_ID.toString()), EXPRESSION_RESOLVER)); + UNDER_TEST.resolve("fn:unknown", PipelineElement.resolved(THING_ID.toString()), EXPRESSION_RESOLVER)); } @Test public void testFunctionUpper() { - assertThat(UNDER_TEST.resolve("fn:upper()", Optional.of(THING_ID.toString()), EXPRESSION_RESOLVER)) + assertThat(UNDER_TEST.resolve("fn:upper()", PipelineElement.resolved(THING_ID.toString()), EXPRESSION_RESOLVER)) .contains(THING_ID.toString().toUpperCase()); } @Test public void testFunctionUpperWrongSignature() { assertThatExceptionOfType(PlaceholderFunctionSignatureInvalidException.class).isThrownBy(() -> - UNDER_TEST.resolve("fn:upper('foo')", Optional.of(THING_ID.toString()), EXPRESSION_RESOLVER)); + UNDER_TEST.resolve("fn:upper('foo')", PipelineElement.resolved(THING_ID.toString()), + EXPRESSION_RESOLVER)); } @Test public void testFunctionLower() { - assertThat(UNDER_TEST.resolve("fn:lower()", Optional.of(HEADER_VAL), EXPRESSION_RESOLVER)) + assertThat(UNDER_TEST.resolve("fn:lower()", PipelineElement.resolved(HEADER_VAL), EXPRESSION_RESOLVER)) .contains(HEADER_VAL.toLowerCase()); } @Test public void testFunctionLowerWrongSignature() { assertThatExceptionOfType(PlaceholderFunctionUnknownException.class).isThrownBy(() -> - UNDER_TEST.resolve("fn:lower", Optional.of(THING_ID.toString()), EXPRESSION_RESOLVER)); + UNDER_TEST.resolve("fn:lower", PipelineElement.resolved(THING_ID.toString()), EXPRESSION_RESOLVER)); } @Test public void testFunctionDefaultWhenInputPresent() { - assertThat(UNDER_TEST.resolve("fn:default('constant')", Optional.of(HEADER_VAL), EXPRESSION_RESOLVER)) + assertThat( + UNDER_TEST.resolve("fn:default('constant')", PipelineElement.resolved(HEADER_VAL), EXPRESSION_RESOLVER)) .contains(HEADER_VAL); } @Test public void testFunctionDefaultWhenInputEmptyWithConstant() { - assertThat(UNDER_TEST.resolve("fn:default('constant')", Optional.empty(), EXPRESSION_RESOLVER)) + assertThat(UNDER_TEST.resolve("fn:default('constant')", PipelineElement.unresolved(), EXPRESSION_RESOLVER)) .contains("constant"); } @Test public void testFunctionDefaultWhenInputEmptyWithConstantDoubleQuotes() { - assertThat(UNDER_TEST.resolve("fn:default(\"constant\")", Optional.empty(), EXPRESSION_RESOLVER)) + assertThat(UNDER_TEST.resolve("fn:default(\"constant\")", PipelineElement.unresolved(), EXPRESSION_RESOLVER)) .contains("constant"); } @Test public void testFunctionDefaultWhenInputEmptyWithPlaceholder() { - assertThat(UNDER_TEST.resolve("fn:default(thing:id)", Optional.empty(), EXPRESSION_RESOLVER)) + assertThat(UNDER_TEST.resolve("fn:default(thing:id)", PipelineElement.unresolved(), EXPRESSION_RESOLVER)) .contains(THING_ID.toString()); } @Test public void testFunctionDefaultWithWrongSignature() { assertThatExceptionOfType(PlaceholderFunctionSignatureInvalidException.class).isThrownBy(() -> - UNDER_TEST.resolve("fn:default('constant',2)", Optional.empty(), EXPRESSION_RESOLVER)); + UNDER_TEST.resolve("fn:default('constant',2)", PipelineElement.unresolved(), EXPRESSION_RESOLVER)); } @Test public void testFunctionSubstringBefore() { - assertThat(UNDER_TEST.resolve("fn:substring-before(\"-\")", Optional.of(THING_NAME), EXPRESSION_RESOLVER)) + assertThat(UNDER_TEST.resolve("fn:substring-before(\"-\")", PipelineElement.resolved(THING_NAME), + EXPRESSION_RESOLVER)) .contains("test"); } @Test public void testFunctionSubstringAfter() { - assertThat(UNDER_TEST.resolve("fn:substring-after(\"-\")", Optional.of(THING_NAME), EXPRESSION_RESOLVER)) + assertThat(UNDER_TEST.resolve("fn:substring-after(\"-\")", PipelineElement.resolved(THING_NAME), + EXPRESSION_RESOLVER)) .contains("id"); } diff --git a/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/ImmutablePipelineTest.java b/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/ImmutablePipelineTest.java index 0fb5875e6f..bbedad38c5 100644 --- a/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/ImmutablePipelineTest.java +++ b/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/ImmutablePipelineTest.java @@ -18,7 +18,6 @@ import java.util.Arrays; import java.util.List; -import java.util.Optional; import org.junit.Test; import org.junit.runner.RunWith; @@ -47,10 +46,10 @@ public class ImmutablePipelineTest { "fn:substring-before(':')", "fn:unknown('foo')" ); - private static final Optional PIPELINE_INPUT = Optional.of("my-gateway:my-thing"); - private static final List> RESPONSES = Arrays.asList( - Optional.of("my-gateway"), - Optional.of("my-gateway") + private static final PipelineElement PIPELINE_INPUT = PipelineElement.resolved("my-gateway:my-thing"); + private static final List RESPONSES = Arrays.asList( + PipelineElement.resolved("my-gateway"), + PipelineElement.resolved("my-gateway") ); @Mock @@ -76,7 +75,7 @@ public void execute() { prepareFunctionExpressionResponses(); final ImmutablePipeline pipeline = new ImmutablePipeline(functionExpression, STAGES); - final Optional result = pipeline.execute(PIPELINE_INPUT, expressionResolver); + final PipelineElement result = pipeline.execute(PIPELINE_INPUT, expressionResolver); verifyResultEqualsLastResponse(result); verifyFunctionExpressionWasCalledWithIntermediateValues(); @@ -91,11 +90,11 @@ public void validate() { } private void prepareFunctionExpressionResponses() { - Mockito.when(functionExpression.resolve(anyString(), any(Optional.class), any(ExpressionResolver.class))) + Mockito.when(functionExpression.resolve(anyString(), any(PipelineElement.class), any(ExpressionResolver.class))) .thenReturn(RESPONSES.get(0), RESPONSES.get(1)); } - private void verifyResultEqualsLastResponse(final Optional result) { + private void verifyResultEqualsLastResponse(final PipelineElement result) { assertThat(result).isEqualTo(RESPONSES.get(1)); } diff --git a/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/PipelineFunctionDefaultTest.java b/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/PipelineFunctionDefaultTest.java index a2fe9cd5e6..a0d70e0847 100644 --- a/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/PipelineFunctionDefaultTest.java +++ b/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/PipelineFunctionDefaultTest.java @@ -43,23 +43,24 @@ public void getName() { @Test public void applyReturnsExistingValue() { - final Optional input = Optional.of(KNOWN_VALUE); + final PipelineElement input = PipelineElement.resolved(KNOWN_VALUE); final String params = "(\"" + KNOWN_FALLBACK + "\")"; assertThat(function.apply(input, params, expressionResolver)).contains(KNOWN_VALUE); } @Test public void applyReturnsDefault() { - final Optional input = Optional.empty(); + final PipelineElement input = PipelineElement.unresolved(); final String params = "(\'" + KNOWN_FALLBACK + "\')"; assertThat(function.apply(input, params, expressionResolver)).contains(KNOWN_FALLBACK); } @Test public void applyReturnsDefaultPlaceholder() { - final Optional input = Optional.empty(); + final PipelineElement input = PipelineElement.unresolved(); final String params = "(" + KNOWN_PLACEHOLDER + ")"; - when(expressionResolver.resolveSinglePlaceholder(anyString())).thenReturn(Optional.of(KNOWN_VALUE)); + when(expressionResolver.resolveSinglePlaceholder(anyString())) + .thenReturn(Optional.of(KNOWN_VALUE)); assertThat(function.apply(input, params, expressionResolver)).contains(KNOWN_VALUE); diff --git a/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/PipelineFunctionLowerTest.java b/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/PipelineFunctionLowerTest.java index 10bf394db1..2cd7eddb25 100644 --- a/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/PipelineFunctionLowerTest.java +++ b/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/PipelineFunctionLowerTest.java @@ -27,7 +27,7 @@ @RunWith(MockitoJUnitRunner.class) public class PipelineFunctionLowerTest { - private static final Optional KNOWN_INPUT = Optional.of("CamElCase"); + private static final PipelineElement KNOWN_INPUT = PipelineElement.resolved("CamElCase"); private static final String LOWER_CASE = "camelcase"; private final PipelineFunctionLower function = new PipelineFunctionLower(); diff --git a/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/PipelineFunctionSubstringAfterTest.java b/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/PipelineFunctionSubstringAfterTest.java index eeafc5bef4..cddeeb4de6 100644 --- a/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/PipelineFunctionSubstringAfterTest.java +++ b/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/PipelineFunctionSubstringAfterTest.java @@ -27,9 +27,9 @@ @RunWith(MockitoJUnitRunner.class) public class PipelineFunctionSubstringAfterTest { - private static final Optional KNOWN_INPUT = Optional.of("org.eclipse.ditto:any.thing.or.else"); - private static final Optional EMPTY_INPUT = Optional.empty(); - private static final Optional UNMATCHING_INPUT = Optional.of("any.thing.without.colon"); + private static final PipelineElement KNOWN_INPUT = PipelineElement.resolved("org.eclipse.ditto:any.thing.or.else"); + private static final PipelineElement EMPTY_INPUT = PipelineElement.unresolved(); + private static final PipelineElement UNMATCHING_INPUT = PipelineElement.resolved("any.thing.without.colon"); private static final String SUBSTRING_AT = ":"; private static final String EXPECTED_RESULT = "any.thing.or.else"; diff --git a/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/PipelineFunctionSubstringBeforeTest.java b/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/PipelineFunctionSubstringBeforeTest.java index 2934a381e6..3736c5e9c4 100644 --- a/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/PipelineFunctionSubstringBeforeTest.java +++ b/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/PipelineFunctionSubstringBeforeTest.java @@ -27,9 +27,9 @@ @RunWith(MockitoJUnitRunner.class) public class PipelineFunctionSubstringBeforeTest { - private static final Optional KNOWN_INPUT = Optional.of("org.eclipse.ditto:any.thing.or.else"); - private static final Optional EMPTY_INPUT = Optional.empty(); - private static final Optional UNMATCHING_INPUT = Optional.of("any.thing.without.colon"); + private static final PipelineElement KNOWN_INPUT = PipelineElement.resolved("org.eclipse.ditto:any.thing.or.else"); + private static final PipelineElement EMPTY_INPUT = PipelineElement.unresolved(); + private static final PipelineElement UNMATCHING_INPUT = PipelineElement.resolved("any.thing.without.colon"); private static final String SUBSTRING_AT = ":"; private static final String EXPECTED_RESULT = "org.eclipse.ditto"; diff --git a/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/PipelineFunctionUpperTest.java b/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/PipelineFunctionUpperTest.java index fc92927d6f..73fd82611b 100644 --- a/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/PipelineFunctionUpperTest.java +++ b/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/PipelineFunctionUpperTest.java @@ -27,7 +27,7 @@ @RunWith(MockitoJUnitRunner.class) public class PipelineFunctionUpperTest { - private static final Optional KNOWN_INPUT = Optional.of("CamElCase"); + private static final PipelineElement KNOWN_INPUT = PipelineElement.resolved("CamElCase"); private static final String UPPER_CASE = "CAMELCASE"; private final PipelineFunctionUpper function = new PipelineFunctionUpper(); diff --git a/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/PlaceholderFilterTest.java b/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/PlaceholderFilterTest.java index f2127c8958..495c7b59f7 100644 --- a/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/PlaceholderFilterTest.java +++ b/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/PlaceholderFilterTest.java @@ -43,18 +43,18 @@ public class PlaceholderFilterTest { .twin().things().commands().modify().build(); private static final TopicPath KNOWN_TOPIC_PATH_SUBJECT1 = TopicPath.newBuilder(ThingId.of(KNOWN_NAMESPACE, KNOWN_ID)) - .live().things().messages().subject(KNOWN_SUBJECT).build(); + .live().things().messages().subject(KNOWN_SUBJECT).build(); private static final TopicPath KNOWN_TOPIC_PATH_SUBJECT2 = TopicPath.newBuilder(ThingId.of(KNOWN_NAMESPACE, KNOWN_ID)) - .live().things().messages().subject(KNOWN_SUBJECT2).build(); + .live().things().messages().subject(KNOWN_SUBJECT2).build(); private static final HeadersPlaceholder headersPlaceholder = PlaceholderFactory.newHeadersPlaceholder(); private static final ThingPlaceholder thingPlaceholder = PlaceholderFactory.newThingPlaceholder(); private static final TopicPathPlaceholder topicPlaceholder = PlaceholderFactory.newTopicPathPlaceholder(); - private static final FilterTuple[] filterChain = new FilterTuple[]{ - FilterTuple.of(HEADERS, headersPlaceholder), - FilterTuple.of(THING_ID, thingPlaceholder) + private static final PlaceholderResolver[] filterChain = new PlaceholderResolver[]{ + PlaceholderFactory.newPlaceholderResolver(headersPlaceholder, HEADERS), + PlaceholderFactory.newPlaceholderResolver(thingPlaceholder, THING_ID) }; private static final Placeholder[] placeholders = new Placeholder[]{ headersPlaceholder, @@ -69,7 +69,8 @@ public class PlaceholderFilterTest { @Test public void testHeadersPlaceholder() { - assertThatExceptionOfType(NullPointerException.class).isThrownBy(() -> headersPlaceholder.resolve(HEADERS, null)); + assertThatExceptionOfType(NullPointerException.class).isThrownBy( + () -> headersPlaceholder.resolve(HEADERS, null)); assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy( () -> headersPlaceholder.resolve(HEADERS, "")); assertThatExceptionOfType(UnresolvedPlaceholderException.class).isThrownBy( @@ -85,7 +86,8 @@ public void testHeadersPlaceholder() { @Test public void testThingPlaceholder() { - assertThatExceptionOfType(NullPointerException.class).isThrownBy(() -> thingPlaceholder.resolve(THING_ID, null)); + assertThatExceptionOfType(NullPointerException.class).isThrownBy( + () -> thingPlaceholder.resolve(THING_ID, null)); assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy( () -> thingPlaceholder.resolve(THING_ID, "")); assertThatExceptionOfType(UnresolvedPlaceholderException.class).isThrownBy( @@ -106,14 +108,16 @@ public void testThingPlaceholder() { @Test public void testTopicPlaceholder() { - assertThatExceptionOfType(NullPointerException.class).isThrownBy(() -> topicPlaceholder.resolve(KNOWN_TOPIC_PATH, null)); + assertThatExceptionOfType(NullPointerException.class).isThrownBy( + () -> topicPlaceholder.resolve(KNOWN_TOPIC_PATH, null)); assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy( () -> topicPlaceholder.resolve(KNOWN_TOPIC_PATH, "")); assertThatExceptionOfType(UnresolvedPlaceholderException.class).isThrownBy( () -> PlaceholderFilter.apply("{{ topic:unknown }}", KNOWN_TOPIC_PATH, topicPlaceholder)); assertThatExceptionOfType(UnresolvedPlaceholderException.class).isThrownBy( () -> PlaceholderFilter.apply("{{ {{ topic:name }} }}", KNOWN_TOPIC_PATH, topicPlaceholder)); - assertThat(PlaceholderFilter.apply("eclipse:ditto", KNOWN_TOPIC_PATH, topicPlaceholder)).isEqualTo("eclipse:ditto"); + assertThat(PlaceholderFilter.apply("eclipse:ditto", KNOWN_TOPIC_PATH, topicPlaceholder)).isEqualTo( + "eclipse:ditto"); assertThat(PlaceholderFilter.apply("prefix:{{ topic:channel }}:{{ topic:group }}:suffix", KNOWN_TOPIC_PATH, topicPlaceholder)).isEqualTo("prefix:twin:things:suffix"); @@ -208,87 +212,88 @@ public void testValidate() { PlaceholderFilter.validate(" {{thing:namespace }}{{ thing:name }}{{header:device-id }} ", placeholders); // pre/postfix - PlaceholderFilter.validate("-----{{thing:namespace }}{{ thing:name }}{{header:device-id }}-----", placeholders); + PlaceholderFilter.validate("-----{{thing:namespace }}{{ thing:name }}{{header:device-id }}-----", + placeholders); // pre/postfix and separators - PlaceholderFilter.validate("-----{{thing:namespace }}///{{ thing:name }}///{{header:device-id }}-----", placeholders); + PlaceholderFilter.validate("-----{{thing:namespace }}///{{ thing:name }}///{{header:device-id }}-----", + placeholders); } @Test public void testValidateFails() { // illegal braces combinations assertThatExceptionOfType(UnresolvedPlaceholderException.class).isThrownBy( - () -> PlaceholderFilter.validate("{{th{{ing:namespace }}{{ thing:name }}{{header:device-id }}", placeholders)); + () -> PlaceholderFilter.validate("{{th{{ing:namespace }}{{ thing:name }}{{header:device-id }}", + placeholders)); assertThatExceptionOfType(UnresolvedPlaceholderException.class).isThrownBy( - () -> PlaceholderFilter.validate("{{th}}ing:namespace }}{{ thing:name }}{{header:device-id }}", placeholders)); + () -> PlaceholderFilter.validate("{{th}}ing:namespace }}{{ thing:name }}{{header:device-id }}", + placeholders)); assertThatExceptionOfType(UnresolvedPlaceholderException.class).isThrownBy( - () -> PlaceholderFilter.validate("{{thing:nam{{espace }}{{ thing:name }}{{header:device-id }}", placeholders)); + () -> PlaceholderFilter.validate("{{thing:nam{{espace }}{{ thing:name }}{{header:device-id }}", + placeholders)); assertThatExceptionOfType(UnresolvedPlaceholderException.class).isThrownBy( - () -> PlaceholderFilter.validate("{{thing:nam}}espace }}{{ thing:name }}{{header:device-id }}", placeholders)); + () -> PlaceholderFilter.validate("{{thing:nam}}espace }}{{ thing:name }}{{header:device-id }}", + placeholders)); assertThatExceptionOfType(PlaceholderFunctionTooComplexException.class).isThrownBy( - () -> PlaceholderFilter.validate("{{ header:unknown | fn:default('fallback') | fn:upper() | fn:lower() | fn:upper() | fn:lower() | fn:upper() | fn:lower() | fn:upper() | fn:lower() | fn:upper() | fn:lower() }}", placeholders)); + () -> PlaceholderFilter.validate( + "{{ header:unknown | fn:default('fallback') | fn:upper() | fn:lower() | fn:upper() | fn:lower() | fn:upper() | fn:lower() | fn:upper() | fn:lower() | fn:upper() | fn:lower() }}", + placeholders)); } @Test public void testValidateAndReplace() { final String replacement = UUID.randomUUID().toString(); // no whitespace - assertThat(PlaceholderFilter.validateAndReplace("{{thing:namespace}}/{{thing:name}}:{{header:device-id}}", replacement, placeholders)) - .isEqualTo(String.format("%s/%s:%s", replacement, replacement, replacement)); + assertThat(PlaceholderFilter.validateAndReplace("{{thing:namespace}}/{{thing:name}}:{{header:device-id}}", + replacement, placeholders)) + .isEqualTo(String.format("%s/%s:%s", replacement, replacement, replacement)); // multi whitespace - assertThat(PlaceholderFilter.validateAndReplace("{{ thing:namespace }}/{{ thing:name }}:{{ header:device-id }}", replacement, placeholders)) - .isEqualTo(String.format("%s/%s:%s", replacement, replacement, replacement)); + assertThat(PlaceholderFilter.validateAndReplace( + "{{ thing:namespace }}/{{ thing:name }}:{{ header:device-id }}", replacement, placeholders)) + .isEqualTo(String.format("%s/%s:%s", replacement, replacement, replacement)); // mixed whitespace - assertThat(PlaceholderFilter.validateAndReplace("{{thing:namespace }}/{{ thing:name }}:{{header:device-id }}", replacement, placeholders)) - .isEqualTo(String.format("%s/%s:%s", replacement, replacement, replacement)); + assertThat(PlaceholderFilter.validateAndReplace("{{thing:namespace }}/{{ thing:name }}:{{header:device-id }}", + replacement, placeholders)) + .isEqualTo(String.format("%s/%s:%s", replacement, replacement, replacement)); // no separators - assertThat(PlaceholderFilter.validateAndReplace("{{thing:namespace }}{{ thing:name }}{{header:device-id }}", replacement, placeholders)) - .isEqualTo(String.format("%s%s%s", replacement, replacement, replacement)); + assertThat(PlaceholderFilter.validateAndReplace("{{thing:namespace }}{{ thing:name }}{{header:device-id }}", + replacement, placeholders)) + .isEqualTo(String.format("%s%s%s", replacement, replacement, replacement)); // whitespace separators - assertThat(PlaceholderFilter.validateAndReplace("{{thing:namespace }} {{ thing:name }} {{header:device-id }}", replacement, placeholders)) - .isEqualTo(String.format("%s %s %s", replacement, replacement, replacement)); + assertThat( + PlaceholderFilter.validateAndReplace("{{thing:namespace }} {{ thing:name }} {{header:device-id }}", + replacement, placeholders)) + .isEqualTo(String.format("%s %s %s", replacement, replacement, replacement)); // pre/postfix whitespace - assertThat(PlaceholderFilter.validateAndReplace(" {{thing:namespace }}{{ thing:name }}{{header:device-id }} ", replacement, placeholders)) - .isEqualTo(String.format(" %s%s%s ", replacement, replacement, replacement)); + assertThat( + PlaceholderFilter.validateAndReplace(" {{thing:namespace }}{{ thing:name }}{{header:device-id }} ", + replacement, placeholders)) + .isEqualTo(String.format(" %s%s%s ", replacement, replacement, replacement)); // pre/postfix - assertThat(PlaceholderFilter.validateAndReplace("-----{{thing:namespace }}{{ thing:name }}{{header:device-id }}-----", replacement, placeholders)) - .isEqualTo(String.format("-----%s%s%s-----", replacement, replacement, replacement)); + assertThat(PlaceholderFilter.validateAndReplace( + "-----{{thing:namespace }}{{ thing:name }}{{header:device-id }}-----", replacement, placeholders)) + .isEqualTo(String.format("-----%s%s%s-----", replacement, replacement, replacement)); // pre/postfix and separators - assertThat(PlaceholderFilter.validateAndReplace("-----{{thing:namespace }}///{{ thing:name }}///{{header:device-id }}-----", replacement, placeholders)) - .isEqualTo(String.format("-----%s///%s///%s-----", replacement, replacement, replacement)); + assertThat(PlaceholderFilter.validateAndReplace( + "-----{{thing:namespace }}///{{ thing:name }}///{{header:device-id }}-----", replacement, + placeholders)) + .isEqualTo(String.format("-----%s///%s///%s-----", replacement, replacement, replacement)); } - private static String filterChain(final String template, final FilterTuple... tuples) { - String result = template; - for (final FilterTuple tuple : tuples) { - result = PlaceholderFilter.apply(result, tuple.value, tuple.placeholder, true); - } - return PlaceholderFilter.checkAllPlaceholdersResolved(result); + private static String filterChain(final String template, final PlaceholderResolver... tuples) { + return PlaceholderFilter.apply(template, PlaceholderFactory.newExpressionResolver(tuples)); } - static class FilterTuple { - - final Object value; - final Placeholder placeholder; - - private FilterTuple(final Object value, final Placeholder placeholder) { - this.value = value; - this.placeholder = placeholder; - } - - static FilterTuple of(final Object value, final Placeholder placeholder) { - return new FilterTuple(value, placeholder); - } - } } diff --git a/services/connectivity/mapping/src/main/java/org/eclipse/ditto/services/connectivity/mapping/ConnectionStatusMessageMapper.java b/services/connectivity/mapping/src/main/java/org/eclipse/ditto/services/connectivity/mapping/ConnectionStatusMessageMapper.java index 1974383c42..d1e8e6795c 100644 --- a/services/connectivity/mapping/src/main/java/org/eclipse/ditto/services/connectivity/mapping/ConnectionStatusMessageMapper.java +++ b/services/connectivity/mapping/src/main/java/org/eclipse/ditto/services/connectivity/mapping/ConnectionStatusMessageMapper.java @@ -188,7 +188,7 @@ private Adaptable getModifyFeatureAdaptable(final ThingId thingId, final String private ThingId extractThingId(final String mappingOptionThingId, final Map headers) { final ExpressionResolver expressionResolver = PlaceholderFactory.newExpressionResolver( PlaceholderFactory.newPlaceholderResolver(HEADERS_PLACEHOLDER, headers)); - return ThingId.of(PlaceholderFilter.apply(mappingOptionThingId, expressionResolver, false)); + return ThingId.of(PlaceholderFilter.apply(mappingOptionThingId, expressionResolver)); } private MessageMappingFailedException getMappingFailedException(final String message, final String theContentType) { diff --git a/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/BasePublisherActor.java b/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/BasePublisherActor.java index 34042bbf9f..b1fd7faf74 100644 --- a/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/BasePublisherActor.java +++ b/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/BasePublisherActor.java @@ -340,7 +340,7 @@ private static ExternalMessage applyHeaderMapping(final ExpressionResolver expre } private static String applyExpressionResolver(final ExpressionResolver expressionResolver, final String value) { - return PlaceholderFilter.apply(value, expressionResolver, true); + return PlaceholderFilter.applyWithDeletion(value, expressionResolver); } private static ExpressionResolver getExpressionResolver(final ExternalMessage originalMessage, diff --git a/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/MessageMappingProcessorActor.java b/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/MessageMappingProcessorActor.java index 09d125639a..557a3e0dc2 100644 --- a/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/MessageMappingProcessorActor.java +++ b/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/MessageMappingProcessorActor.java @@ -441,8 +441,7 @@ public OutboundSignal.WithExternalMessage apply(final OutboundSignal outboundSig ); final List targets = outboundSignal.getTargets().stream().map(t -> { - final String address = - PlaceholderFilter.apply(t.getAddress(), expressionResolver, true); + final String address = PlaceholderFilter.apply(t.getAddress(), expressionResolver); return ConnectivityModelFactory.newTarget(t, address, t.getQos().orElse(null)); }).collect(Collectors.toList()); final OutboundSignal modifiedOutboundSignal = @@ -588,7 +587,7 @@ public DittoHeaders apply(final InboundExternalMessage inboundExternalMessage) { final DittoHeadersBuilder dittoHeadersBuilder = dittoHeaders.toBuilder(); mapping.getMapping().entrySet().stream() .map(e -> newEntry(e.getKey(), - PlaceholderFilter.apply(e.getValue(), expressionResolver, true)) + PlaceholderFilter.applyWithDeletion(e.getValue(), expressionResolver)) ) .forEach(e -> dittoHeadersBuilder.putHeader(e.getKey(), e.getValue()));