From ff733f474e6580efcc096b9016ae7c6a75328985 Mon Sep 17 00:00:00 2001 From: Johannes Schneider Date: Tue, 27 Oct 2020 07:37:14 +0100 Subject: [PATCH] added feature id placeholder Signed-off-by: Johannes Schneider --- .../placeholders/FeaturePlaceholder.java | 21 ++++++ .../ImmutableFeaturePlaceholder.java | 67 +++++++++++++++++++ .../placeholders/PlaceholderFactory.java | 8 +++ .../ImmutableFeaturePlaceholderTest.java | 55 +++++++++++++++ .../connectivity/messaging/Resolvers.java | 8 +++ .../messaging/amqp/AmqpValidator.java | 3 +- .../messaging/httppush/HttpPushValidator.java | 3 +- .../messaging/mqtt/AbstractMqttValidator.java | 2 +- .../messaging/rabbitmq/RabbitMQValidator.java | 3 +- .../messaging/amqp/AmqpValidatorTest.java | 2 +- .../httppush/HttpPushValidatorTest.java | 2 + .../rabbitmq/RabbitMQValidatorTest.java | 2 + 12 files changed, 171 insertions(+), 5 deletions(-) create mode 100644 model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/FeaturePlaceholder.java create mode 100644 model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/ImmutableFeaturePlaceholder.java create mode 100644 model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/ImmutableFeaturePlaceholderTest.java diff --git a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/FeaturePlaceholder.java b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/FeaturePlaceholder.java new file mode 100644 index 0000000000..7433138be5 --- /dev/null +++ b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/FeaturePlaceholder.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2020 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; + +/** + * A {@link Placeholder} that requires a {@code String} (a valid Feature ID) to resolve it's placeholders. + * + * @since 1.5.0 + */ +public interface FeaturePlaceholder extends Placeholder { +} diff --git a/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/ImmutableFeaturePlaceholder.java b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/ImmutableFeaturePlaceholder.java new file mode 100644 index 0000000000..10849b5b47 --- /dev/null +++ b/model/placeholders/src/main/java/org/eclipse/ditto/model/placeholders/ImmutableFeaturePlaceholder.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2020 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.argumentNotEmpty; +import static org.eclipse.ditto.model.base.common.ConditionChecker.checkNotNull; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import javax.annotation.concurrent.Immutable; + +/** + * Placeholder implementation that replaces {@code feature:id}. The input value is a String and must be a valid Feature + * ID. + * + * @since 1.5.0 + */ +@Immutable +final class ImmutableFeaturePlaceholder implements FeaturePlaceholder { + + private static final String ID_PLACEHOLDER = "id"; + + private static final List SUPPORTED = Collections.singletonList(ID_PLACEHOLDER); + + /** + * Singleton instance of the {@code ImmutableFeaturePlaceholder}. + */ + static final ImmutableFeaturePlaceholder INSTANCE = new ImmutableFeaturePlaceholder(); + + @Override + public Optional resolve(final String featureId, final String placeholder) { + checkNotNull(featureId, "featureId"); + argumentNotEmpty(placeholder, "placeholder"); + if (ID_PLACEHOLDER.equals(placeholder)) { + return Optional.of(featureId); + } + return Optional.empty(); + } + + @Override + public String getPrefix() { + return "feature"; + } + + @Override + public List getSupportedNames() { + return SUPPORTED; + } + + @Override + public boolean supports(final String name) { + return SUPPORTED.contains(name); + } + +} 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 e549112380..6e25f77f41 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 @@ -47,6 +47,14 @@ public static PolicyPlaceholder newPolicyPlaceholder() { return ImmutablePolicyPlaceholder.INSTANCE; } + /** + * @return new instance of the {@link FeaturePlaceholder} + * @since 1.5.0 + */ + public static FeaturePlaceholder newFeaturePlaceholder() { + return ImmutableFeaturePlaceholder.INSTANCE; + } + /** * @return new instance of the {@link EntityPlaceholder} */ diff --git a/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/ImmutableFeaturePlaceholderTest.java b/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/ImmutableFeaturePlaceholderTest.java new file mode 100644 index 0000000000..4de84b8117 --- /dev/null +++ b/model/placeholders/src/test/java/org/eclipse/ditto/model/placeholders/ImmutableFeaturePlaceholderTest.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2020 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.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; +import org.mutabilitydetector.unittesting.MutabilityAssert; +import org.mutabilitydetector.unittesting.MutabilityMatchers; + +import nl.jqno.equalsverifier.EqualsVerifier; +import nl.jqno.equalsverifier.Warning; + +/** + * Tests {@link ImmutableFeaturePlaceholder}. + */ +public final class ImmutableFeaturePlaceholderTest { + + private static final String FEATURE_ID = "FluxCapacitor"; + private static final FeaturePlaceholder UNDER_TEST = ImmutableFeaturePlaceholder.INSTANCE; + + @Test + public void assertImmutability() { + MutabilityAssert.assertInstancesOf(ImmutableFeaturePlaceholder.class, MutabilityMatchers.areImmutable()); + } + + @Test + public void testHashCodeAndEquals() { + EqualsVerifier.forClass(ImmutableFeaturePlaceholder.class) + .suppress(Warning.INHERITED_DIRECTLY_FROM_OBJECT) + .usingGetClass() + .verify(); + } + + @Test + public void testReplaceFeatureId() { + assertThat(UNDER_TEST.resolve(FEATURE_ID, "id")).contains(FEATURE_ID); + } + + @Test + public void testUnknownPlaceholderReturnsEmpty() { + assertThat(UNDER_TEST.resolve(FEATURE_ID, "feature_id")).isEmpty(); + } + +} \ No newline at end of file diff --git a/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/Resolvers.java b/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/Resolvers.java index 67c3b3e11d..28901da458 100644 --- a/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/Resolvers.java +++ b/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/Resolvers.java @@ -31,6 +31,7 @@ import org.eclipse.ditto.services.models.connectivity.ExternalMessage; import org.eclipse.ditto.services.models.connectivity.OutboundSignal; import org.eclipse.ditto.signals.base.Signal; +import org.eclipse.ditto.signals.base.WithFeatureId; /** * Creator of expression resolvers for incoming and outgoing messages. @@ -54,6 +55,13 @@ private Resolvers() { return null; } }), + ResolverCreator.of(PlaceholderFactory.newFeaturePlaceholder(), (e, s, t, a, c) -> { + if (s instanceof WithFeatureId) { + return ((WithFeatureId) s).getFeatureId(); + } else { + return null; + } + }), ResolverCreator.of(PlaceholderFactory.newTopicPathPlaceholder(), (e, s, t, a, c) -> t), ResolverCreator.of(PlaceholderFactory.newRequestPlaceholder(), (e, s, t, a, c) -> a), ResolverCreator.of(PlaceholderFactory.newConnectionIdPlaceholder(), (e, s, t, a, c) -> c) diff --git a/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/amqp/AmqpValidator.java b/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/amqp/AmqpValidator.java index 41d69bff57..a515b41171 100644 --- a/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/amqp/AmqpValidator.java +++ b/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/amqp/AmqpValidator.java @@ -58,7 +58,8 @@ protected void validateSource(final Source source, final DittoHeaders dittoHeade enforcement.getFilters().forEach(filterTemplate -> validateTemplate(filterTemplate, dittoHeaders, PlaceholderFactory.newThingPlaceholder(), PlaceholderFactory.newPolicyPlaceholder(), - PlaceholderFactory.newEntityPlaceholder())); + PlaceholderFactory.newEntityPlaceholder(), + PlaceholderFactory.newFeaturePlaceholder())); }); source.getHeaderMapping().ifPresent(mapping -> validateHeaderMapping(mapping, dittoHeaders)); } diff --git a/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/httppush/HttpPushValidator.java b/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/httppush/HttpPushValidator.java index da29c63faf..e82fc65338 100644 --- a/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/httppush/HttpPushValidator.java +++ b/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/httppush/HttpPushValidator.java @@ -30,6 +30,7 @@ import org.eclipse.ditto.model.connectivity.ConnectionType; import org.eclipse.ditto.model.connectivity.Source; import org.eclipse.ditto.model.connectivity.Target; +import org.eclipse.ditto.model.placeholders.PlaceholderFactory; import org.eclipse.ditto.services.connectivity.messaging.validation.AbstractProtocolValidator; import akka.actor.ActorSystem; @@ -91,7 +92,7 @@ protected void validateTarget(final Target target, final DittoHeaders dittoHeade final Supplier targetDescription) { target.getHeaderMapping().ifPresent(mapping -> validateHeaderMapping(mapping, dittoHeaders)); validateTemplate(target.getAddress(), dittoHeaders, newThingPlaceholder(), newTopicPathPlaceholder(), - newHeadersPlaceholder()); + newHeadersPlaceholder(), PlaceholderFactory.newFeaturePlaceholder()); validateTargetAddress(target.getAddress(), dittoHeaders, targetDescription); } diff --git a/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/mqtt/AbstractMqttValidator.java b/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/mqtt/AbstractMqttValidator.java index fa7489e28a..670de34c12 100644 --- a/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/mqtt/AbstractMqttValidator.java +++ b/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/mqtt/AbstractMqttValidator.java @@ -103,7 +103,7 @@ protected void validateTarget(final Target target, final DittoHeaders dittoHeade validateTargetQoS(qos.get(), dittoHeaders, targetDescription); validateTemplate(target.getAddress(), dittoHeaders, newThingPlaceholder(), newTopicPathPlaceholder(), - newHeadersPlaceholder()); + newHeadersPlaceholder(), PlaceholderFactory.newFeaturePlaceholder()); } /** diff --git a/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/rabbitmq/RabbitMQValidator.java b/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/rabbitmq/RabbitMQValidator.java index c76acfd4f7..23e4d071e3 100644 --- a/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/rabbitmq/RabbitMQValidator.java +++ b/services/connectivity/messaging/src/main/java/org/eclipse/ditto/services/connectivity/messaging/rabbitmq/RabbitMQValidator.java @@ -57,7 +57,8 @@ protected void validateSource(final Source source, final DittoHeaders dittoHeade validateTemplate(enforcement.getInput(), dittoHeaders, PlaceholderFactory.newHeadersPlaceholder()); enforcement.getFilters().forEach(filterTemplate -> validateTemplate(filterTemplate, dittoHeaders, PlaceholderFactory.newThingPlaceholder(), - PlaceholderFactory.newPolicyPlaceholder(), PlaceholderFactory.newEntityPlaceholder())); + PlaceholderFactory.newPolicyPlaceholder(), PlaceholderFactory.newEntityPlaceholder(), + PlaceholderFactory.newFeaturePlaceholder())); }); source.getHeaderMapping().ifPresent(mapping -> validateHeaderMapping(mapping, dittoHeaders)); } diff --git a/services/connectivity/messaging/src/test/java/org/eclipse/ditto/services/connectivity/messaging/amqp/AmqpValidatorTest.java b/services/connectivity/messaging/src/test/java/org/eclipse/ditto/services/connectivity/messaging/amqp/AmqpValidatorTest.java index 190e598f58..dfb2f0cd7b 100644 --- a/services/connectivity/messaging/src/test/java/org/eclipse/ditto/services/connectivity/messaging/amqp/AmqpValidatorTest.java +++ b/services/connectivity/messaging/src/test/java/org/eclipse/ditto/services/connectivity/messaging/amqp/AmqpValidatorTest.java @@ -114,7 +114,7 @@ public void testValidMatchers() { @Test public void testValidPlaceholdersInTargetAddress() { final Target target = newTargetBuilder() - .address("some.address.{{ topic:action-subject }}.{{ thing:id }}.{{ header:correlation-id }}") + .address("some.address.{{ topic:action-subject }}.{{ thing:id }}.{{ feature:id }}.{{ header:correlation-id }}") .authorizationContext(AUTHORIZATION_CONTEXT) .topics(Topic.LIVE_COMMANDS) .build(); diff --git a/services/connectivity/messaging/src/test/java/org/eclipse/ditto/services/connectivity/messaging/httppush/HttpPushValidatorTest.java b/services/connectivity/messaging/src/test/java/org/eclipse/ditto/services/connectivity/messaging/httppush/HttpPushValidatorTest.java index 4dafae5678..d3ed6b0104 100644 --- a/services/connectivity/messaging/src/test/java/org/eclipse/ditto/services/connectivity/messaging/httppush/HttpPushValidatorTest.java +++ b/services/connectivity/messaging/src/test/java/org/eclipse/ditto/services/connectivity/messaging/httppush/HttpPushValidatorTest.java @@ -92,6 +92,8 @@ public void testValidTargetAddress() { underTest.validate(getConnectionWithTarget("PUT:ditto/{{thing:id}}"), emptyDittoHeaders, actorSystem); underTest.validate(getConnectionWithTarget("PATCH:/{{thing:namespace}}/{{thing:name}}"), emptyDittoHeaders, actorSystem); + underTest.validate(getConnectionWithTarget("PATCH:/{{thing:namespace}}/{{thing:name}}/{{ feature:id }}"), emptyDittoHeaders, + actorSystem); underTest.validate(getConnectionWithTarget("PUT:events#{{topic:full}}"), emptyDittoHeaders, actorSystem); underTest.validate(getConnectionWithTarget("POST:ditto?{{header:x}}"), emptyDittoHeaders, actorSystem); underTest.validate(getConnectionWithTarget("POST:"), emptyDittoHeaders, actorSystem); diff --git a/services/connectivity/messaging/src/test/java/org/eclipse/ditto/services/connectivity/messaging/rabbitmq/RabbitMQValidatorTest.java b/services/connectivity/messaging/src/test/java/org/eclipse/ditto/services/connectivity/messaging/rabbitmq/RabbitMQValidatorTest.java index f94fc2bd67..7cd898016c 100644 --- a/services/connectivity/messaging/src/test/java/org/eclipse/ditto/services/connectivity/messaging/rabbitmq/RabbitMQValidatorTest.java +++ b/services/connectivity/messaging/src/test/java/org/eclipse/ditto/services/connectivity/messaging/rabbitmq/RabbitMQValidatorTest.java @@ -106,6 +106,8 @@ public void testValidTargetAddress() { UNDER_TEST.validate(connectionWithTarget("ditto/rabbit"), DittoHeaders.empty(), actorSystem); UNDER_TEST.validate(connectionWithTarget("ditto"), DittoHeaders.empty(), actorSystem); UNDER_TEST.validate(connectionWithTarget("ditto/{{thing:id}}"), DittoHeaders.empty(), actorSystem); + UNDER_TEST.validate(connectionWithTarget("ditto/{{thing:id}}/{{feature:id}}"), DittoHeaders.empty(), + actorSystem); UNDER_TEST.validate(connectionWithTarget("ditto/{{topic:full}}"), DittoHeaders.empty(), actorSystem); UNDER_TEST.validate(connectionWithTarget("ditto/{{header:x}}"), DittoHeaders.empty(), actorSystem); }