Skip to content

Commit

Permalink
Issue #106: Reworked deserialization of CommandResponses from JSON.
Browse files Browse the repository at this point in the history
* HTTP status is now validated; therefore a predicate has to be given to the deserializer.
* Initialization of the deserializer is now clearly separated from actual deserialization. Thus, it is possible to reuse the same deserializer.
* Exceptions within deserialization are now all wrapped by a JsonParseException with an appropriate message and cause.
* Adjusted CommandResponses accordingly.

Signed-off-by: Juergen Fickel <juergen.fickel@bosch.io>
  • Loading branch information
Juergen Fickel committed Dec 1, 2021
1 parent 8ae818b commit 6360834
Show file tree
Hide file tree
Showing 140 changed files with 4,550 additions and 3,042 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,25 @@

import static org.eclipse.ditto.base.model.common.ConditionChecker.checkNotNull;

import java.util.Arrays;
import java.util.Objects;
import java.util.function.Predicate;

import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;

import org.eclipse.ditto.json.JsonFactory;
import org.eclipse.ditto.json.JsonField;
import org.eclipse.ditto.json.JsonFieldDefinition;
import org.eclipse.ditto.json.JsonObject;
import org.eclipse.ditto.json.JsonObjectBuilder;
import org.eclipse.ditto.base.api.common.CommonCommandResponse;
import org.eclipse.ditto.base.model.common.HttpStatus;
import org.eclipse.ditto.base.model.entity.type.EntityType;
import org.eclipse.ditto.base.model.headers.DittoHeaders;
import org.eclipse.ditto.base.model.json.FieldType;
import org.eclipse.ditto.base.model.json.JsonParsableCommandResponse;
import org.eclipse.ditto.base.model.json.JsonSchemaVersion;
import org.eclipse.ditto.base.model.signals.commands.CommandResponseJsonDeserializer;
import org.eclipse.ditto.base.api.common.CommonCommandResponse;
import org.eclipse.ditto.json.JsonField;
import org.eclipse.ditto.json.JsonFieldDefinition;
import org.eclipse.ditto.json.JsonObject;
import org.eclipse.ditto.json.JsonObjectBuilder;

/**
* Response to {@link PurgeEntities}.
Expand All @@ -46,13 +46,28 @@ public final class PurgeEntitiesResponse extends CommonCommandResponse<PurgeEnti
*/
public static final String TYPE = TYPE_PREFIX + PurgeEntities.NAME;

private static final CommandResponseJsonDeserializer<PurgeEntitiesResponse> JSON_DESERIALIZER =
CommandResponseJsonDeserializer.newInstance(TYPE,
Arrays.asList(HttpStatus.OK, HttpStatus.INTERNAL_SERVER_ERROR)::contains,
context -> {
final var jsonObject = context.getJsonObject();
return new PurgeEntitiesResponse(
EntityType.of(jsonObject.getValueOrThrow(JsonFields.ENTITY_TYPE)),
jsonObject.getValueOrThrow(JsonFields.SUCCESSFUL),
context.getDeserializedHttpStatus(),
context.getDittoHeaders()
);
});

private final EntityType entityType;
private final boolean successful;

private PurgeEntitiesResponse(final EntityType entityType, final boolean successful,
private PurgeEntitiesResponse(final EntityType entityType,
final boolean successful,
final HttpStatus httpStatus,
final DittoHeaders dittoHeaders) {

super(TYPE, HttpStatus.OK, dittoHeaders);
super(TYPE, httpStatus, dittoHeaders);
this.entityType = checkNotNull(entityType);
this.successful = successful;
}
Expand All @@ -65,7 +80,7 @@ private PurgeEntitiesResponse(final EntityType entityType, final boolean success
* @return a response for a successful purge.
*/
public static PurgeEntitiesResponse successful(final EntityType entityType, final DittoHeaders dittoHeaders) {
return new PurgeEntitiesResponse(entityType, true, dittoHeaders);
return new PurgeEntitiesResponse(entityType, true, HttpStatus.OK, dittoHeaders);
}

/**
Expand All @@ -76,7 +91,7 @@ public static PurgeEntitiesResponse successful(final EntityType entityType, fina
* @return a response for a failed purge.
*/
public static PurgeEntitiesResponse failed(final EntityType entityType, final DittoHeaders dittoHeaders) {
return new PurgeEntitiesResponse(entityType, false, dittoHeaders);
return new PurgeEntitiesResponse(entityType, false, HttpStatus.INTERNAL_SERVER_ERROR, dittoHeaders);
}

/**
Expand All @@ -87,12 +102,7 @@ public static PurgeEntitiesResponse failed(final EntityType entityType, final Di
* @return the deserialized response.
*/
public static PurgeEntitiesResponse fromJson(final JsonObject jsonObject, final DittoHeaders headers) {
return new CommandResponseJsonDeserializer<PurgeEntitiesResponse>(TYPE, jsonObject).deserialize(httpStatus -> {
final EntityType parsedEntityType = EntityType.of(jsonObject.getValueOrThrow(JsonFields.ENTITY_TYPE));
final boolean parsedSuccessful = jsonObject.getValueOrThrow(JsonFields.SUCCESSFUL);

return new PurgeEntitiesResponse(parsedEntityType, parsedSuccessful, headers);
});
return JSON_DESERIALIZER.deserialize(jsonObject, headers);
}

/**
Expand All @@ -115,7 +125,7 @@ public boolean isSuccessful() {

@Override
public PurgeEntitiesResponse setDittoHeaders(final DittoHeaders dittoHeaders) {
return new PurgeEntitiesResponse(entityType, successful, dittoHeaders);
return new PurgeEntitiesResponse(entityType, successful, getHttpStatus(), dittoHeaders);
}

@Override
Expand All @@ -129,7 +139,7 @@ public boolean equals(final Object o) {
if (!super.equals(o)) {
return false;
}
final PurgeEntitiesResponse that = (PurgeEntitiesResponse) o;
final var that = (PurgeEntitiesResponse) o;
return Objects.equals(entityType, that.entityType) && successful == that.successful;
}

Expand All @@ -144,11 +154,11 @@ public int hashCode() {
}

@Override
protected void appendPayload(final JsonObjectBuilder jsonObjectBuilder, final JsonSchemaVersion schemaVersion,
protected void appendPayload(final JsonObjectBuilder jsonObjectBuilder,
final JsonSchemaVersion schemaVersion,
final Predicate<JsonField> aPredicate) {

final Predicate<JsonField> predicate = schemaVersion.and(aPredicate);

final var predicate = schemaVersion.and(aPredicate);
jsonObjectBuilder.set(JsonFields.ENTITY_TYPE, entityType.toString(), predicate);
jsonObjectBuilder.set(JsonFields.SUCCESSFUL, successful, predicate);
}
Expand All @@ -171,14 +181,12 @@ public static final class JsonFields {
* The type of the entities affected by this response.
*/
public static final JsonFieldDefinition<String> ENTITY_TYPE =
JsonFactory.newStringFieldDefinition("entityType", FieldType.REGULAR,
JsonSchemaVersion.V_2);
JsonFieldDefinition.ofString("entityType", FieldType.REGULAR, JsonSchemaVersion.V_2);
/**
* This JSON field indicates whether the entities were purged successfully.
*/
public static final JsonFieldDefinition<Boolean> SUCCESSFUL =
JsonFactory.newBooleanFieldDefinition("successful", FieldType.REGULAR,
JsonSchemaVersion.V_2);
JsonFieldDefinition.ofBoolean("successful", FieldType.REGULAR, JsonSchemaVersion.V_2);

private JsonFields() {
throw new AssertionError();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,20 @@ public final class AggregatedDevOpsCommandResponse
public static final String TYPE = TYPE_PREFIX + "aggregatedResponse";

private static final JsonFieldDefinition<String> JSON_RESPONSES_TYPE =
JsonFactory.newStringFieldDefinition("responsesType", FieldType.REGULAR,
JsonSchemaVersion.V_2);
JsonFieldDefinition.ofString("responsesType", FieldType.REGULAR, JsonSchemaVersion.V_2);
private static final JsonFieldDefinition<JsonObject> JSON_AGGREGATED_RESPONSES =
JsonFactory.newJsonObjectFieldDefinition("responses", FieldType.REGULAR,
JsonSchemaVersion.V_2);
JsonFieldDefinition.ofJsonObject("responses", FieldType.REGULAR, JsonSchemaVersion.V_2);

private static final CommandResponseJsonDeserializer<AggregatedDevOpsCommandResponse> JSON_DESERIALIZER =
CommandResponseJsonDeserializer.newInstance(TYPE,
Objects::nonNull,
context -> {
final var jsonObject = context.getJsonObject();
return new AggregatedDevOpsCommandResponse(jsonObject.getValueOrThrow(JSON_AGGREGATED_RESPONSES),
jsonObject.getValueOrThrow(JSON_RESPONSES_TYPE),
context.getDeserializedHttpStatus(),
context.getDittoHeaders());
});

private final JsonObject aggregatedResponses;
private final String responsesType;
Expand Down Expand Up @@ -83,7 +92,7 @@ public static AggregatedDevOpsCommandResponse of(final List<CommandResponse<?>>
final HttpStatus httpStatus,
final DittoHeaders dittoHeaders) {

final JsonObject jsonRepresentation = buildJsonRepresentation(commandResponses, dittoHeaders);
final var jsonRepresentation = buildJsonRepresentation(commandResponses, dittoHeaders);
return new AggregatedDevOpsCommandResponse(jsonRepresentation, responsesType, httpStatus, dittoHeaders);
}

Expand Down Expand Up @@ -133,12 +142,7 @@ public static AggregatedDevOpsCommandResponse fromJson(final String jsonString,
public static AggregatedDevOpsCommandResponse fromJson(final JsonObject jsonObject,
final DittoHeaders dittoHeaders) {

return new CommandResponseJsonDeserializer<AggregatedDevOpsCommandResponse>(TYPE, jsonObject)
.deserialize(httpStatus -> {
final JsonObject aggregatedResponsesJsonObj = jsonObject.getValueOrThrow(JSON_AGGREGATED_RESPONSES);
final String theResponsesType = jsonObject.getValueOrThrow(JSON_RESPONSES_TYPE);
return of(aggregatedResponsesJsonObj, theResponsesType, httpStatus, dittoHeaders);
});
return JSON_DESERIALIZER.deserialize(jsonObject, dittoHeaders);
}

@Override
Expand All @@ -164,25 +168,26 @@ public JsonValue getEntity(final JsonSchemaVersion schemaVersion) {
}

@Override
protected void appendPayload(final JsonObjectBuilder jsonObjectBuilder, final JsonSchemaVersion schemaVersion,
protected void appendPayload(final JsonObjectBuilder jsonObjectBuilder,
final JsonSchemaVersion schemaVersion,
final Predicate<JsonField> thePredicate) {

super.appendPayload(jsonObjectBuilder, schemaVersion, thePredicate);

final Predicate<JsonField> predicate = schemaVersion.and(thePredicate);
final var predicate = schemaVersion.and(thePredicate);
jsonObjectBuilder.set(JSON_RESPONSES_TYPE, responsesType, predicate);
jsonObjectBuilder.set(JSON_AGGREGATED_RESPONSES, aggregatedResponses, predicate);
}

private static JsonObject buildJsonRepresentation(final List<CommandResponse<?>> commandResponses,
final DittoHeaders dittoHeaders) {

final JsonSchemaVersion schemaVersion = dittoHeaders.getSchemaVersion().orElse(JsonSchemaVersion.LATEST);
final JsonObjectBuilder builder = JsonObject.newBuilder();
final var schemaVersion = dittoHeaders.getSchemaVersion().orElse(JsonSchemaVersion.LATEST);
final var builder = JsonObject.newBuilder();

int i = 0;
for (final CommandResponse<?> cmdR : commandResponses) {
final String key = String.format("/%s/%s", calculateServiceName(cmdR), calculateInstance(cmdR, i++));
var i = 0;
for (final var cmdR : commandResponses) {
final var key = String.format("/%s/%s", calculateServiceName(cmdR), calculateInstance(cmdR, i++));
// include both regular and special fields for devops command responses
final JsonValue responseJson;
if (cmdR instanceof ExecutePiggybackCommandResponse) {
Expand All @@ -201,20 +206,25 @@ private static JsonObject buildJsonRepresentation(final List<CommandResponse<?>>
}

private static String calculateServiceName(final CommandResponse<?> commandResponse) {
final String result;
if (commandResponse instanceof DevOpsCommandResponse) {
return ((DevOpsCommandResponse<?>) commandResponse).getServiceName().orElse("?");
result = ((DevOpsCommandResponse<?>) commandResponse).getServiceName().orElse("?");
} else {
return "?";
result = "?";
}
return result;
}

private static String calculateInstance(final CommandResponse<?> commandResponse, final int i) {
final String result;
final var fallBackValue = "?" + (i == 0 ? "" : String.valueOf(i));
if (commandResponse instanceof DevOpsCommandResponse) {
return ((DevOpsCommandResponse<?>) commandResponse).getInstance()
.orElse("?" + (i == 0 ? "" : String.valueOf(i)));
result = ((DevOpsCommandResponse<?>) commandResponse).getInstance()
.orElse(fallBackValue);
} else {
return "?" + (i == 0 ? "" : String.valueOf(i));
result = fallBackValue;
}
return result;
}

@SuppressWarnings("squid:MethodCyclomaticComplexity")
Expand All @@ -229,7 +239,7 @@ public boolean equals(@Nullable final Object o) {
if (!super.equals(o)) {
return false;
}
final AggregatedDevOpsCommandResponse that = (AggregatedDevOpsCommandResponse) o;
final var that = (AggregatedDevOpsCommandResponse) o;
return that.canEqual(this) &&
Objects.equals(responsesType, that.responsesType) &&
Objects.equals(aggregatedResponses, that.aggregatedResponses) &&
Expand Down

0 comments on commit 6360834

Please sign in to comment.