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

org.openmetadata.service.exception.CatalogGenericExceptionMapper Maven / Gradle / Ivy

There is a newer version: 1.5.11
Show newest version
/*
 *  Copyright 2021 Collate
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *  http://www.apache.org/licenses/LICENSE-2.0
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package org.openmetadata.service.exception;

import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
import static javax.ws.rs.core.Response.Status.CONFLICT;
import static javax.ws.rs.core.Response.Status.FORBIDDEN;
import static javax.ws.rs.core.Response.Status.Family;
import static javax.ws.rs.core.Response.Status.NOT_FOUND;
import static javax.ws.rs.core.Response.Status.UNAUTHORIZED;

import io.dropwizard.jersey.errors.ErrorMessage;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.concurrent.ThreadLocalRandom;
import javax.ws.rs.Path;
import javax.ws.rs.ProcessingException;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import lombok.extern.slf4j.Slf4j;
import org.jdbi.v3.core.statement.UnableToExecuteStatementException;
import org.openmetadata.sdk.exception.WebServiceException;
import org.openmetadata.service.security.AuthenticationException;
import org.openmetadata.service.security.AuthorizationException;
import org.postgresql.util.PSQLException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Slf4j
public class CatalogGenericExceptionMapper implements ExceptionMapper {
  @Override
  public Response toResponse(Throwable ex) {
    LOG.debug(ex.getMessage());
    if (ex instanceof ProcessingException
        || ex instanceof IllegalArgumentException
        || ex instanceof javax.ws.rs.BadRequestException) {
      return getResponse(BadRequestException.of().getResponse(), ex);
    } else if (ex instanceof UnableToExecuteStatementException) {
      if (ex.getCause() instanceof SQLIntegrityConstraintViolationException
          || ex.getCause() instanceof PSQLException
              && ex.getCause().getMessage().contains("duplicate")) {
        return getResponse(CONFLICT, CatalogExceptionMessage.ENTITY_ALREADY_EXISTS);
      }
    } else if (ex instanceof EntityNotFoundException) {
      return getResponse(NOT_FOUND, ex.getLocalizedMessage());
    } else if (ex instanceof IngestionPipelineDeploymentException) {
      return getResponse(BAD_REQUEST, ex.getLocalizedMessage());
    } else if (ex instanceof AuthenticationException) {
      return getResponse(UNAUTHORIZED, ex.getLocalizedMessage());
    } else if (ex instanceof AuthorizationException) {
      return getResponse(FORBIDDEN, ex.getLocalizedMessage());
    } else if (ex instanceof WebServiceException webServiceException) {
      final Response response = webServiceException.getResponse();
      Family family = response.getStatusInfo().getFamily();
      if (family.equals(Response.Status.Family.REDIRECTION)) {
        return response;
      }
      if (family.equals(Family.SERVER_ERROR)) {
        throwException(ex);
      }

      return getResponse(response, ex);
    }

    LOG.info("exception ", ex);
    logUnhandledException(ex);
    return new UnhandledServerException(ex.getMessage()).getResponse();
  }

  public Response getResponse(Response response, Throwable ex) {
    return Response.fromResponse(response)
        .type(APPLICATION_JSON_TYPE)
        .entity(new ErrorMessage(response.getStatus(), ex.getLocalizedMessage()))
        .build();
  }

  public static Response getResponse(Response.Status status, String message) {
    return Response.status(status)
        .type(APPLICATION_JSON_TYPE)
        .entity(new ErrorMessage(status.getStatusCode(), message))
        .header("WWW-Authenticate", "om-auth")
        .build();
  }

  private void logUnhandledException(Throwable ex) {
    String errMessage =
        String.format(
            "Got exception: [%s] / message [%s]", ex.getClass().getSimpleName(), ex.getMessage());
    StackTraceElement elem = findFirstResourceCallFromCallStack(ex.getStackTrace());
    String resourceClassName = null;
    if (elem != null) {
      errMessage +=
          String.format(
              " / related resource location: [%s.%s](%s:%d)",
              elem.getClassName(), elem.getMethodName(), elem.getFileName(), elem.getLineNumber());
      resourceClassName = elem.getClassName();
    }

    Logger log = getEffectiveLogger(resourceClassName);
    log.error(errMessage, ex);
  }

  protected void throwException(Throwable exception) {
    final long id = ThreadLocalRandom.current().nextLong();
    throwException(id, exception);
  }

  protected void throwException(long id, Throwable exception) {
    LOG.error(formatLogMessage(id), exception);
  }

  protected String formatLogMessage(long id) {
    return String.format("Error handling a request: %016x", id);
  }

  private StackTraceElement findFirstResourceCallFromCallStack(StackTraceElement[] stackTrace) {
    for (StackTraceElement stackTraceElement : stackTrace) {
      try {
        Class aClass = Class.forName(stackTraceElement.getClassName());
        Path pathAnnotation = aClass.getAnnotation(Path.class);

        if (pathAnnotation != null) {
          return stackTraceElement;
        }
      } catch (ClassNotFoundException e) {
        // skip
      }
    }

    return null;
  }

  private Logger getEffectiveLogger(String resourceClassName) {
    Logger log = LOG;
    if (resourceClassName != null) {
      log = LoggerFactory.getLogger(resourceClassName);
    }
    return log;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy