All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.naharoo.commons.mstoolkit.rest.exceptionhandler.client.MsExceptionFactory Maven / Gradle / Ivy

There is a newer version: 0.7.12
Show newest version
package com.naharoo.commons.mstoolkit.rest.exceptionhandler.client;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.naharoo.commons.mstoolkit.exceptions.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import static java.util.Collections.singletonList;

@Component
public class MsExceptionFactory {

  private final ObjectMapper objectMapper;

  @Autowired
  public MsExceptionFactory(final ObjectMapper objectMapper) {
    this.objectMapper = objectMapper;
  }

  public MsException createInstance(
          final int status,
          final InputStreamSupplier inputStreamSupplier
  ) {
    if (inputStreamSupplier == null) {
      final HttpStatus httpStatus = HttpStatus.valueOf(status);
      if (httpStatus.is4xxClientError()) {
        return CustomMsException.createInstance(singletonList(new LocalIssueType(
                "UNKNOWN_ERROR",
                status
        )));
      }
      throw new IllegalStateException(
              "Failed to process HTTP request's response. Unable to extract response body.");
    }

    try (final InputStream inputStream = inputStreamSupplier.supply()) {
      final ApiErrorResponse apiErrorResponse =
              objectMapper.readValue(inputStream, ApiErrorResponse.class);

      final Set types = apiErrorResponse.getTypes();
      if (types.isEmpty()) {
        throw new IllegalStateException(
                "Failed to process HTTP request's response. Unable to create MsException instance.");
      }

      if (types.size() > 1) {
        return CustomMsException.createInstance(
                convertToIssuesList(types, status), extractErrorMessage(apiErrorResponse));
      }

      final String type = types.iterator().next();
      if (!isCommonIssue(type)) {
        return CustomMsException.createInstance(
                convertToIssuesList(types, status), extractErrorMessage(apiErrorResponse));
      }

      final CommonIssueType commonIssue = CommonIssueType.valueOf(type);
      switch (commonIssue) {
        case RESOURCE_NOT_FOUND:
          return new ResourceNotFoundException(extractErrorMessage(apiErrorResponse), null);
        case RESOURCE_ALREADY_EXISTS:
          return new ResourceAlreadyExistsException(extractErrorMessage(apiErrorResponse), null);
        case RESOURCE_NOT_VIABLE:
          return new ResourceNotViableException(extractErrorMessage(apiErrorResponse), null);
        case PRECONDITION_VIOLATED:
          return new PreconditionViolationException(extractErrorMessage(apiErrorResponse), null);
        default:
          return CustomMsException.createInstance(
                  convertToIssuesList(types, status), extractErrorMessage(apiErrorResponse));
      }

    } catch (final Exception exception) {
      throw new IllegalStateException(exception);
    }
  }

  private boolean isCommonIssue(String type) {
    return Arrays.stream(CommonIssueType.values())
                 .anyMatch(commonType -> commonType.name().equals(type));
  }

  private List convertToIssuesList(Set types, int statusCode) {
    return types.stream()
                .map(value -> new LocalIssueType(value, statusCode))
                .collect(Collectors.toList());
  }

  private String extractErrorMessage(final ApiErrorResponse apiErrorResponse) {
    return apiErrorResponse.getMessages().isEmpty()
           ? null
           : apiErrorResponse.getMessages().iterator().next();
  }

  @FunctionalInterface
  public interface InputStreamSupplier {
    InputStream supply() throws IOException;
  }

  private static class ApiErrorResponse {
    private final int statusCode;
    private final Set types;
    private final Set messages;
    private final LocalDateTime timestamp;

    @JsonCreator
    private ApiErrorResponse(
            @JsonProperty("statusCode") final int statusCode,
            @JsonProperty("types") final Set types,
            @JsonProperty("messages") final Set messages,
            @JsonProperty("timestamp") final LocalDateTime timestamp
    ) {
      this.statusCode = statusCode;
      this.types = types;
      this.messages = messages;
      this.timestamp = timestamp;
    }

    public int getStatusCode() {
      return statusCode;
    }

    public Set getTypes() {
      return types;
    }

    public Set getMessages() {
      return messages;
    }

    public LocalDateTime getTimestamp() {
      return timestamp;
    }
  }

  @JsonSerialize(using = LocalIssueType.Serializer.class)
  private static class LocalIssueType implements IssueType {

    private final String value;
    private final int statusCode;

    public LocalIssueType(final String value, final int statusCode) {
      this.value = value;
      this.statusCode = statusCode;
    }

    @Override
    public String asString() {
      return value;
    }

    @Override
    public int statusCode() {
      return statusCode;
    }

    private static class Serializer extends StdSerializer {

      public Serializer() {
        this(null);
      }

      public Serializer(final Class clazz) {
        super(clazz);
      }

      @Override
      public void serialize(
              final LocalIssueType value,
              final JsonGenerator jsonGenerator,
              final SerializerProvider provider
      ) throws IOException {
        jsonGenerator.writeString(Optional
                                          .ofNullable(value)
                                          .map(LocalIssueType::asString)
                                          .orElse(null));
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy