Skip to content

Commit

Permalink
Issue #106: Adjusted thing query command responses and ThingQueryComm…
Browse files Browse the repository at this point in the history
…andResponseMappingStrategies for safe mapping from Adaptable.

Signed-off-by: Juergen Fickel <juergen.fickel@bosch.io>
  • Loading branch information
Juergen Fickel committed Dec 13, 2021
1 parent db558d9 commit e5b8610
Show file tree
Hide file tree
Showing 15 changed files with 802 additions and 154 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.eclipse.ditto.base.model.common.HttpStatus;
import org.eclipse.ditto.base.model.headers.DittoHeaders;
import org.eclipse.ditto.json.JsonKey;
import org.eclipse.ditto.json.JsonObject;
import org.eclipse.ditto.json.JsonPointer;
import org.eclipse.ditto.json.JsonValue;
import org.eclipse.ditto.policies.model.Label;
Expand Down Expand Up @@ -134,13 +135,33 @@ private Optional<JsonValue> getPayloadValue() {
}

Thing getThingOrThrow() {
return getThing().orElseThrow(() ->
new IllegalAdaptableException(
MessageFormat.format("Payload does not contain a {0} as JSON object" +
" because it has no value at all.",
Thing.class.getSimpleName()),
return getThing().orElseThrow(() -> new IllegalAdaptableException(
"Payload does not contain a Thing as JSON object because it has no value at all.",
"Please ensure that the payload contains a valid Thing JSON object as value.",
adaptable.getDittoHeaders()
));
}

JsonObject getPayloadValueAsJsonObjectOrThrow() {
final Optional<JsonValue> payloadValue = getPayloadValue();
if (payloadValue.isPresent()) {
final JsonValue jsonValue = payloadValue.get();
if (jsonValue.isObject()) {
return jsonValue.asObject();
} else {
throw new IllegalAdaptableException(
MessageFormat.format("Payload value is not a JSON object but <{0}>.", jsonValue),
"Please ensure that the payload value is a valid JSON object.",
adaptable.getDittoHeaders()
));
);
}
} else {
throw new IllegalAdaptableException(
"Payload does not contain a JSON object value because it has no value at all.",
"Please ensure that the payload value contains a valid JSON object as value.",
adaptable.getDittoHeaders()
);
}
}

JsonPointer getAttributePointerOrThrow() {
Expand Down Expand Up @@ -197,6 +218,14 @@ Optional<Attributes> getAttributes() {
return result;
}

Attributes getAttributesOrThrow() {
return getAttributes().orElseThrow(() -> new IllegalAdaptableException(
"Payload does not contain an Attributes as JSON object because it has no value at all.",
"Please ensure that the payload contains a valid Attributes JSON object as value.",
adaptable.getDittoHeaders()
));
}

Optional<Features> getFeatures() {
final Optional<Features> result;
final Optional<JsonValue> payloadValueOptional = getPayloadValue();
Expand Down Expand Up @@ -226,6 +255,14 @@ private IllegalAdaptableException newPayloadValueNotJsonObjectException(final Cl
);
}

Features getFeaturesOrThrow() {
return getFeatures().orElseThrow(() -> new IllegalAdaptableException(
"Payload does not contain a Features as JSON string object it has no value at all.",
"Please ensure that the payload contains a valid Features JSON object as value.",
adaptable.getDittoHeaders()
));
}

String getFeatureIdOrThrow() {
final MessagePath messagePath = getMessagePath();
if (!messagePath.getRoot().filter(FEATURE_PATH_PREFIX::equals).isPresent()) {
Expand Down Expand Up @@ -263,6 +300,14 @@ Optional<Feature> getFeature() {
return result;
}

Feature getFeatureOrThrow() {
return getFeature().orElseThrow(() -> new IllegalAdaptableException(
"Payload does not contain a Feature as JSON object it has no value at all.",
"Please ensure that the payload contains a valid Feature JSON object as value.",
adaptable.getDittoHeaders()
));
}

Optional<ThingDefinition> getThingDefinition() {
final Optional<ThingDefinition> result;
final Optional<JsonValue> payloadValueOptional = getPayloadValue();
Expand All @@ -284,6 +329,14 @@ Optional<ThingDefinition> getThingDefinition() {
return result;
}

ThingDefinition getThingDefinitionOrThrow() {
return getThingDefinition().orElseThrow(() -> new IllegalAdaptableException(
"Payload does not contain a ThingDefinition as JSON string because it has no value at all.",
"Please ensure that the payload contains a valid ThingDefinition JSON string as value.",
adaptable.getDittoHeaders()
));
}

Optional<FeatureDefinition> getFeatureDefinition() {
final Optional<FeatureDefinition> result;
final Optional<JsonValue> payloadValueOptional = getPayloadValue();
Expand All @@ -305,6 +358,14 @@ Optional<FeatureDefinition> getFeatureDefinition() {
return result;
}

FeatureDefinition getFeatureDefinitionOrThrow() {
return getFeatureDefinition().orElseThrow(() -> new IllegalAdaptableException(
"Payload does not contain a FeatureDefinition as JSON array because it has no value at all.",
"Please ensure that the payload contains a valid FeatureDefinition JSON array as value.",
adaptable.getDittoHeaders()
));
}

Optional<FeatureProperties> getFeatureProperties() {
final Optional<FeatureProperties> result;
final Optional<JsonValue> payloadValueOptional = getPayloadValue();
Expand All @@ -321,6 +382,14 @@ Optional<FeatureProperties> getFeatureProperties() {
return result;
}

FeatureProperties getFeaturePropertiesOrThrow() {
return getFeatureProperties().orElseThrow(() -> new IllegalAdaptableException(
"Payload does not contain a FeatureProperties as JSON object it has no value at all.",
"Please ensure that the payload contains a valid FeatureProperties JSON object as value.",
adaptable.getDittoHeaders()
));
}

JsonPointer getFeaturePropertyPointerOrThrow() {
return getFeaturePropertyPointerOrThrow(JsonKey.of("properties"));
}
Expand Down Expand Up @@ -377,6 +446,14 @@ Optional<JsonValue> getFeaturePropertyValue() {
return getPayloadValue();
}

JsonValue getFeaturePropertyValueOrThrow() {
return getFeaturePropertyValue().orElseThrow(() -> new IllegalAdaptableException(
"Payload does not contain a feature property value because it has no value at all.",
"Please ensure that the payload contains a JSON value as value.",
adaptable.getDittoHeaders()
));
}

Optional<PolicyId> getPolicyId() {
final Optional<PolicyId> result;
final Optional<JsonValue> payloadValueOptional = getPayloadValue();
Expand All @@ -398,6 +475,14 @@ Optional<PolicyId> getPolicyId() {
return result;
}

PolicyId getPolicyIdOrThrow() {
return getPolicyId().orElseThrow(() -> new IllegalAdaptableException(
"Payload does not contain a PolicyId as JSON string because it has no value at all.",
"Please ensure that the payload contains a valid PolicyId JSON string value as value.",
adaptable.getDittoHeaders()
));
}

PolicyId getPolicyIdFromTopicPath() {
final TopicPath topicPath = adaptable.getTopicPath();
final String namespace = topicPath.getNamespace();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,15 @@
*/
package org.eclipse.ditto.protocol.mappingstrategies;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Nullable;

import org.eclipse.ditto.json.JsonObject;
import org.eclipse.ditto.protocol.JsonifiableMapper;
import org.eclipse.ditto.things.model.FeatureDefinition;
import org.eclipse.ditto.things.model.signals.commands.query.RetrieveAttributeResponse;
import org.eclipse.ditto.things.model.signals.commands.query.RetrieveAttributesResponse;
import org.eclipse.ditto.things.model.signals.commands.query.RetrieveFeatureDefinitionResponse;
Expand All @@ -33,79 +38,118 @@
/**
* Defines mapping strategies (map from signal type to JsonifiableMapper) for thing query command responses.
*/
final class ThingQueryCommandResponseMappingStrategies
extends AbstractThingMappingStrategies<ThingQueryCommandResponse<?>> {
final class ThingQueryCommandResponseMappingStrategies implements MappingStrategies<ThingQueryCommandResponse<?>> {

private static final ThingQueryCommandResponseMappingStrategies INSTANCE =
new ThingQueryCommandResponseMappingStrategies();

private final Map<String, JsonifiableMapper<? extends ThingQueryCommandResponse<?>>> mappingStrategies;

private ThingQueryCommandResponseMappingStrategies() {
super(initMappingStrategies());
mappingStrategies = Collections.unmodifiableMap(initMappingStrategies());
}

static ThingQueryCommandResponseMappingStrategies getInstance() {
return INSTANCE;
}

private static Map<String, JsonifiableMapper<ThingQueryCommandResponse<?>>> initMappingStrategies() {

final Map<String, JsonifiableMapper<ThingQueryCommandResponse<?>>> mappingStrategies = new HashMap<>();
mappingStrategies.put(RetrieveThingResponse.TYPE,
adaptable -> RetrieveThingResponse.of(thingIdFrom(adaptable), payloadValueAsJsonObjectFrom(adaptable),
dittoHeadersFrom(adaptable)));


mappingStrategies.put(RetrieveAttributesResponse.TYPE,
adaptable -> RetrieveAttributesResponse.of(thingIdFrom(adaptable), attributesFrom(adaptable),
dittoHeadersFrom(adaptable)));

mappingStrategies.put(RetrieveAttributeResponse.TYPE, adaptable -> RetrieveAttributeResponse
.of(thingIdFrom(adaptable), attributePointerFrom(adaptable), attributeValueFrom(adaptable),
dittoHeadersFrom(adaptable)));

mappingStrategies.put(RetrieveThingDefinitionResponse.TYPE,
adaptable -> RetrieveThingDefinitionResponse.of(thingIdFrom(adaptable), thingDefinitionFrom(adaptable),
dittoHeadersFrom(adaptable)));

mappingStrategies.put(RetrieveFeaturesResponse.TYPE,
adaptable -> RetrieveFeaturesResponse.of(thingIdFrom(adaptable), featuresFrom(adaptable),
dittoHeadersFrom(adaptable)));

mappingStrategies.put(RetrieveFeatureResponse.TYPE, adaptable -> RetrieveFeatureResponse
.of(thingIdFrom(adaptable), featureIdFrom(adaptable), featurePropertiesFrom(adaptable),
dittoHeadersFrom(adaptable)));

mappingStrategies.put(RetrieveFeatureDefinitionResponse.TYPE, adaptable -> RetrieveFeatureDefinitionResponse
.of(thingIdFrom(adaptable), featureIdFrom(adaptable), featureDefinitionFrom(adaptable),
dittoHeadersFrom(adaptable)));

mappingStrategies.put(RetrieveFeaturePropertiesResponse.TYPE, adaptable -> RetrieveFeaturePropertiesResponse
.of(thingIdFrom(adaptable), featureIdFrom(adaptable), featurePropertiesFrom(adaptable),
dittoHeadersFrom(adaptable)));

mappingStrategies.put(RetrieveFeatureDesiredPropertiesResponse.TYPE,
adaptable -> RetrieveFeatureDesiredPropertiesResponse
.of(thingIdFrom(adaptable), featureIdFrom(adaptable), featurePropertiesFrom(adaptable),
dittoHeadersFrom(adaptable)));

mappingStrategies.put(RetrieveFeaturePropertyResponse.TYPE,
adaptable -> RetrieveFeaturePropertyResponse.of(thingIdFrom(adaptable),
featureIdFrom(adaptable),
featurePropertyPointerFrom(adaptable), featurePropertyValueFrom(adaptable),
dittoHeadersFrom(adaptable)));

mappingStrategies.put(RetrieveFeatureDesiredPropertyResponse.TYPE,
adaptable -> RetrieveFeatureDesiredPropertyResponse.of(thingIdFrom(adaptable),
featureIdFrom(adaptable),
featurePropertyPointerFrom(adaptable), featurePropertyValueFrom(adaptable),
dittoHeadersFrom(adaptable)));

mappingStrategies.put(RetrievePolicyIdResponse.TYPE,
adaptable -> RetrievePolicyIdResponse.of(thingIdFrom(adaptable),
policyIdFrom(adaptable),
dittoHeadersFrom(adaptable)));
private static Map<String, JsonifiableMapper<? extends ThingQueryCommandResponse<?>>> initMappingStrategies() {
final Map<String, JsonifiableMapper<? extends ThingQueryCommandResponse<?>>> result = new HashMap<>();
result.put(RetrieveThingResponse.TYPE,
AdaptableToSignalMapper.of(RetrieveThingResponse.class,
context -> {
final JsonObject thingJsonObject = context.getPayloadValueAsJsonObjectOrThrow();
return RetrieveThingResponse.newInstance(context.getThingId(),
thingJsonObject,
thingJsonObject.toString(),
context.getHttpStatusOrThrow(),
context.getDittoHeaders());
}));
result.put(RetrieveAttributesResponse.TYPE,
AdaptableToSignalMapper.of(RetrieveAttributesResponse.class,
context -> RetrieveAttributesResponse.newInstance(context.getThingId(),
context.getAttributesOrThrow(),
context.getHttpStatusOrThrow(),
context.getDittoHeaders())));
result.put(RetrieveAttributeResponse.TYPE,
AdaptableToSignalMapper.of(RetrieveAttributeResponse.class,
context -> RetrieveAttributeResponse.newInstance(context.getThingId(),
context.getAttributePointerOrThrow(),
context.getAttributeValueOrThrow(),
context.getHttpStatusOrThrow(),
context.getDittoHeaders())));
result.put(RetrieveThingDefinitionResponse.TYPE,
AdaptableToSignalMapper.of(RetrieveThingDefinitionResponse.class,
context -> RetrieveThingDefinitionResponse.newInstance(context.getThingId(),
context.getThingDefinitionOrThrow(),
context.getHttpStatusOrThrow(),
context.getDittoHeaders())));
result.put(RetrieveFeaturesResponse.TYPE,
AdaptableToSignalMapper.of(RetrieveFeaturesResponse.class,
context -> RetrieveFeaturesResponse.newInstance(context.getThingId(),
context.getFeaturesOrThrow(),
context.getHttpStatusOrThrow(),
context.getDittoHeaders())));
result.put(RetrieveFeatureResponse.TYPE,
AdaptableToSignalMapper.of(RetrieveFeatureResponse.class,
context -> RetrieveFeatureResponse.newInstance(context.getThingId(),
context.getFeatureOrThrow(),
context.getHttpStatusOrThrow(),
context.getDittoHeaders())));
result.put(RetrieveFeatureDefinitionResponse.TYPE,
AdaptableToSignalMapper.of(RetrieveFeatureDefinitionResponse.class,
context -> {
final FeatureDefinition featureDefinition = context.getFeatureDefinitionOrThrow();
return RetrieveFeatureDefinitionResponse.newInstance(context.getThingId(),
context.getFeatureIdOrThrow(),
featureDefinition.toJson(),
context.getHttpStatusOrThrow(),
context.getDittoHeaders());
}));
result.put(RetrieveFeaturePropertiesResponse.TYPE,
AdaptableToSignalMapper.of(RetrieveFeaturePropertiesResponse.class,
context -> RetrieveFeaturePropertiesResponse.newInstance(context.getThingId(),
context.getFeatureIdOrThrow(),
context.getFeaturePropertiesOrThrow(),
context.getHttpStatusOrThrow(),
context.getDittoHeaders())));
result.put(RetrieveFeatureDesiredPropertiesResponse.TYPE,
AdaptableToSignalMapper.of(RetrieveFeatureDesiredPropertiesResponse.class,
context -> RetrieveFeatureDesiredPropertiesResponse.newInstance(context.getThingId(),
context.getFeatureIdOrThrow(),
context.getFeaturePropertiesOrThrow(),
context.getHttpStatusOrThrow(),
context.getDittoHeaders())));
result.put(RetrieveFeaturePropertyResponse.TYPE,
AdaptableToSignalMapper.of(RetrieveFeaturePropertyResponse.class,
context -> RetrieveFeaturePropertyResponse.newInstance(context.getThingId(),
context.getFeatureIdOrThrow(),
context.getFeaturePropertyPointerOrThrow(),
context.getFeaturePropertyValueOrThrow(),
context.getHttpStatusOrThrow(),
context.getDittoHeaders())));
result.put(RetrieveFeatureDesiredPropertyResponse.TYPE,
AdaptableToSignalMapper.of(RetrieveFeatureDesiredPropertyResponse.class,
context -> RetrieveFeatureDesiredPropertyResponse.newInstance(context.getThingId(),
context.getFeatureIdOrThrow(),
context.getFeatureDesiredPropertyPointerOrThrow(),
context.getFeaturePropertyValueOrThrow(),
context.getHttpStatusOrThrow(),
context.getDittoHeaders())));
result.put(RetrievePolicyIdResponse.TYPE,
AdaptableToSignalMapper.of(RetrievePolicyIdResponse.class,
context -> RetrievePolicyIdResponse.newInstance(context.getThingId(),
context.getPolicyIdOrThrow(),
context.getHttpStatusOrThrow(),
context.getDittoHeaders())));

return result;
}

return mappingStrategies;
@Nullable
@Override
public JsonifiableMapper<ThingQueryCommandResponse<?>> find(final String type) {
return (JsonifiableMapper<ThingQueryCommandResponse<?>>) mappingStrategies.get(type);
}

}

0 comments on commit e5b8610

Please sign in to comment.