Skip to content

Commit

Permalink
eclipse-ditto#760 updated @SInCE for mapping context conditions and i…
Browse files Browse the repository at this point in the history
…mplicit thing creation mapper, added logging to mapper

Signed-off-by: Johannes Schneider <johannes.schneider@bosch.io>
  • Loading branch information
jokraehe committed Aug 27, 2020
1 parent da8bddf commit 4df498b
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 24 deletions.
Expand Up @@ -390,7 +390,7 @@ public static MappingContext newMappingContext(final String mappingEngine, final
* @param conditions the conditions to be checked before mapping.
* @return the created MappingContext.
* @throws NullPointerException if any argument is {@code null}.
* @since 1.2.0
* @since 1.3.0
*/
public static MappingContext newMappingContext(final String mappingEngine, final Map<String, String> options,
final Map<String, String> conditions) {
Expand Down
Expand Up @@ -76,7 +76,7 @@ public static ImmutableMappingContext of(final String mappingEngine, final Map<S
* @param conditions the conditions to be checked before mapping.
* @return a new instance of ImmutableMappingContext.
*
* @since 1.2.0
* @since 1.3.0
*/
public static ImmutableMappingContext of(final String mappingEngine, final Map<String, String> options,
final Map<String, String> conditions) {
Expand Down
Expand Up @@ -55,7 +55,7 @@ public interface MappingContext extends Jsonifiable.WithFieldSelectorAndPredicat
* All conditions to be validated before mapping.
*
* @return the conditions
* @since 1.2.0
* @since 1.3.0
*/
Map<String, String> getConditions();

Expand Down
Expand Up @@ -39,25 +39,30 @@
import org.eclipse.ditto.protocoladapter.Adaptable;
import org.eclipse.ditto.protocoladapter.DittoProtocolAdapter;
import org.eclipse.ditto.services.models.connectivity.ExternalMessage;
import org.eclipse.ditto.services.utils.akka.logging.DittoLogger;
import org.eclipse.ditto.services.utils.akka.logging.DittoLoggerFactory;
import org.eclipse.ditto.signals.base.Signal;
import org.eclipse.ditto.signals.commands.things.modify.CreateThing;

/**
* This mapper creates a {@link org.eclipse.ditto.signals.commands.things.modify.CreateThing} command from
* a given thing template and may substitutes placeholders by given headers which can be {@code device_id},
* {@code entity_id} or {@code gateway_id}.
* The policyId must not be set in the mapping configuration. If not set, the policyId will be the same as the thingId.
* The thingId must be set in the mapping configuration. It can either be a fixed Thing ID
* or it can be resolved from the message headers by using a placeholder e.g. {@code {{ header:device_id }}}.
* The policyId is not required to be set in the mapping configuration. If not set, the policyId will be the same as
* the thingId.
*
* @since 1.2.0
* @since 1.3.0
*/
@PayloadMapper(
alias = "ImplicitThingCreation",
requiresMandatoryConfiguration = true // "thing" is mandatory configuration
)
public class ImplicitThingCreationMessageMapper extends AbstractMessageMapper {

private static final DittoLogger LOGGER = DittoLoggerFactory.getLogger(ImplicitThingCreationMessageMapper.class);

private static final DittoProtocolAdapter DITTO_PROTOCOL_ADAPTER = DittoProtocolAdapter.newInstance();
private static final HeadersPlaceholder HEADERS_PLACEHOLDER = PlaceholderFactory.newHeadersPlaceholder();
private static final String THING_TEMPLATE = "thing";
Expand Down Expand Up @@ -87,6 +92,7 @@ protected void doConfigure(final MappingConfig mappingConfig, final MessageMappe
.map(JsonValue::asString)
.ifPresent(ImplicitThingCreationMessageMapper::validatePolicyEntityId);

LOGGER.debug("Configured with Thing template: {}", thingTemplate);
}

private static void validateThingEntityId(final String thingId) {
Expand Down Expand Up @@ -117,6 +123,8 @@ private static void validatePolicyEntityId(final String policyId) {

@Override
public List<Adaptable> map(final ExternalMessage message) {
LOGGER.withCorrelationId(message.getInternalHeaders()).debug("Received ExternalMessage: {}", message);

final Map<String, String> externalHeaders = message.getHeaders();
final ExpressionResolver expressionResolver = getExpressionResolver(externalHeaders);

Expand All @@ -127,6 +135,9 @@ public List<Adaptable> map(final ExternalMessage message) {
final Signal<CreateThing> createThing = getCreateThingSignal(message);
final Adaptable adaptable = DITTO_PROTOCOL_ADAPTER.toAdaptable(createThing);

LOGGER.withCorrelationId(message.getInternalHeaders())
.debug("Mapped ExternalMessage to Adaptable: {}", adaptable);

return Collections.singletonList(adaptable);
}

Expand Down
Expand Up @@ -19,6 +19,7 @@
import static org.eclipse.ditto.services.models.things.Permission.READ;
import static org.eclipse.ditto.services.models.things.Permission.WRITE;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -42,17 +43,18 @@

import com.typesafe.config.ConfigFactory;

/**
* Unit test for {@link org.eclipse.ditto.services.connectivity.mapping.ImplicitThingCreationMessageMapper}.
*/
public class ImplicitThingCreationMessageMapperTest {

private static final DittoProtocolAdapter DITTO_PROTOCOL_ADAPTER = DittoProtocolAdapter.newInstance();

private static final String HEADER_HONO_DEVICE_ID = "device_id";
private static final String HEADER_HONO_GATEWAY_ID = "gateway_id";
private static final String HEADER_POLICY_ID = "policy_id";

private static final String THING_TEMPLATE_WITH_POLICY_ID = "{" +
private static final String THING_TEMPLATE = "{" +
"\"thingId\": \"{{ header:device_id }}\"," +
"\"policyId\": \"{{ header:policy_id }}\"," +
"\"attributes\": {" +
"\"info\": {" +
"\"gatewayId\": \"{{ header:gateway_id }}\"" +
Expand All @@ -71,7 +73,7 @@ public class ImplicitThingCreationMessageMapperTest {

private static final String THING_TEMPLATE_WITH_POLICY = JsonObject.newBuilder()
.set("thingId", "{{ header:device_id }}")
.set("policyId", "{{ header:policy_id }}")
.set("policyId", "{{ header:device_id }}")
.set("_policy", INITIAL_POLICY)
.set("attributes", JsonObject.newBuilder()
.set("info", JsonObject.newBuilder()
Expand Down Expand Up @@ -101,9 +103,9 @@ public void setUp() {
}

@Test
public void doForwardMappingContextWithPolicyIdPlaceholder() {
public void doForwardMappingContextWithDeviceIdPlaceholder() {
final Map<String, String> headers = createValidHeaders();
underTest.configure(mappingConfig, createMapperConfig(THING_TEMPLATE_WITH_POLICY_ID));
underTest.configure(mappingConfig, createMapperConfig(THING_TEMPLATE));

final ExternalMessage externalMessage = ExternalMessageFactory.newExternalMessageBuilder(headers).build();
final List<Adaptable> mappingResult = underTest.map(externalMessage);
Expand All @@ -113,10 +115,10 @@ public void doForwardMappingContextWithPolicyIdPlaceholder() {
final CreateThing createThing = (CreateThing) firstMappedSignal;

final Thing expectedThing =
createExpectedThing("headerNamespace:headerDeviceId", "headerNamespace:headerPolicyId",
createExpectedThing("headerNamespace:headerDeviceId", "headerNamespace:headerDeviceId",
"headerNamespace:headerGatewayId");
assertThat(createThing.getThing().getEntityId()).isEqualTo(expectedThing.getEntityId());
assertThat(createThing.getThing().getPolicyEntityId()).isEqualTo(expectedThing.getPolicyEntityId());
assertThat(createThing.getThing().getPolicyEntityId()).isEmpty();
assertThat(createThing.getThing().getAttributes()).isEqualTo(expectedThing.getAttributes());
}

Expand All @@ -133,7 +135,7 @@ public void doForwardMappingContextWithPolicyPlaceholder() {
final CreateThing createThing = (CreateThing) firstMappedSignal;

final Thing expectedThing =
createExpectedThing("headerNamespace:headerDeviceId", "headerNamespace:headerPolicyId",
createExpectedThing("headerNamespace:headerDeviceId", "headerNamespace:headerDeviceId",
"headerNamespace:headerGatewayId");
assertThat(createThing.getThing().getEntityId()).isEqualTo(expectedThing.getEntityId());
assertThat(createThing.getThing().getPolicyEntityId()).isEqualTo(expectedThing.getPolicyEntityId());
Expand Down Expand Up @@ -181,7 +183,7 @@ public void throwErrorIfThingIdIsMissingInConfig() {

@Test
public void throwErrorIfHeaderForPlaceholderIsMissing() {
underTest.configure(mappingConfig, createMapperConfig(THING_TEMPLATE_WITH_POLICY_ID));
underTest.configure(mappingConfig, createMapperConfig(THING_TEMPLATE));

final Map<String, String> missingEntityHeader = new HashMap<>();
missingEntityHeader.put(HEADER_HONO_DEVICE_ID, "headerNamespace:headerDeviceId");
Expand All @@ -203,7 +205,6 @@ private Map<String, String> createValidHeaders() {
final Map<String, String> validHeader = new HashMap<>();
validHeader.put(HEADER_HONO_DEVICE_ID, "headerNamespace:headerDeviceId");
validHeader.put(HEADER_HONO_GATEWAY_ID, "headerNamespace:headerGatewayId");
validHeader.put(HEADER_POLICY_ID, "headerNamespace:headerPolicyId");
return validHeader;
}

Expand All @@ -220,9 +221,10 @@ private Thing createExpectedThing(final String thingId, final String policyId, f
}

private DefaultMessageMapperConfiguration createMapperConfig(final String thingTemplate) {
final Map<String, String> configPropsWithoutPolicyId = new HashMap<>();
configPropsWithoutPolicyId.put("thing", thingTemplate);
return DefaultMessageMapperConfiguration.of("valid", configPropsWithoutPolicyId);
final Map<String, String> options = Collections.singletonMap("thing", thingTemplate);
final Map<String, String> conditions = Collections.singletonMap("implicitThingCreation",
"{{ header:hono_registration_status | fn:filter(header:hono_registration_status,'eq','NEW') }}");
return DefaultMessageMapperConfiguration.of("valid", options, conditions);
}

}
Expand Up @@ -21,11 +21,9 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand Down Expand Up @@ -73,8 +71,8 @@ public final class MessageMappingProcessorTest {
private MessageMappingProcessor underTest;

private static final String DITTO_MAPPER = "ditto";
private static final Map<String, String> DITTO_MAPPER_CONDITIONS = Map.of("testCondition",
"fn:filter(header:correlation-id,'ne','testCor')",
private static final Map<String, String> DITTO_MAPPER_CONDITIONS = Map.of(
"testCondition", "fn:filter(header:correlation-id,'ne','testCor')",
"testCondition2", "fn:filter(header:correlation-id,'ne','testCor2')");
private static final String DITTO_MAPPER_BY_ALIAS = "ditto-by-alias";
private static final String DITTO_MAPPER_CUSTOM_HEADER_BLOCKLIST = "ditto-cust-header";
Expand Down Expand Up @@ -313,7 +311,8 @@ private void testOutbound(final int mapped, final int dropped, final int failed,
}

private void testOutboundWithCor(final int mapped, final int dropped, final int failed, final Target... targets) {
testOutbound(TestConstants.thingModifiedWithCor(Collections.emptyList()), mapped, dropped, failed, true, targets);
testOutbound(TestConstants.thingModifiedWithCor(Collections.emptyList()), mapped, dropped, failed, true,
targets);
}

private void testOutbound(final ThingModifiedEvent<?> signal, final int mapped, final int dropped, final int failed,
Expand Down

0 comments on commit 4df498b

Please sign in to comment.