001/*
002 * Copyright 2015-2024 Ping Identity Corporation
003 *
004 * This program is free software; you can redistribute it and/or modify
005 * it under the terms of the GNU General Public License (GPLv2 only)
006 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
007 * as published by the Free Software Foundation.
008 *
009 * This program is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012 * GNU General Public License for more details.
013 *
014 * You should have received a copy of the GNU General Public License
015 * along with this program; if not, see <http://www.gnu.org/licenses>.
016 */
017
018package com.unboundid.scim2.server.providers;
019
020import com.fasterxml.jackson.core.JsonParseException;
021import com.fasterxml.jackson.core.JsonProcessingException;
022import com.fasterxml.jackson.databind.JsonMappingException;
023import com.unboundid.scim2.common.annotations.NotNull;
024import com.unboundid.scim2.common.exceptions.BadRequestException;
025import com.unboundid.scim2.common.exceptions.ScimException;
026import com.unboundid.scim2.common.exceptions.ServerErrorException;
027import com.unboundid.scim2.common.messages.ErrorResponse;
028import com.unboundid.scim2.server.utils.ServerUtils;
029
030import jakarta.ws.rs.core.Context;
031import jakarta.ws.rs.core.HttpHeaders;
032import jakarta.ws.rs.core.Request;
033import jakarta.ws.rs.core.Response;
034import jakarta.ws.rs.ext.ExceptionMapper;
035import jakarta.ws.rs.ext.Provider;
036
037/**
038 * A JAX-RS ExceptionMapper for to convert Jackson JsonProcessingException to
039 * SCIM ErrorResponses.
040 */
041@Provider
042public class JsonProcessingExceptionMapper implements
043    ExceptionMapper<JsonProcessingException>
044{
045  @NotNull
046  @Context
047  private Request request;
048
049  @NotNull
050  @Context
051  private HttpHeaders headers;
052
053  /**
054   * {@inheritDoc}
055   */
056  @NotNull
057  public Response toResponse(@NotNull final JsonProcessingException exception)
058  {
059    ErrorResponse errorResponse;
060    if((exception instanceof JsonParseException) ||
061        (exception instanceof JsonMappingException))
062    {
063      StringBuilder builder = new StringBuilder();
064      builder.append("Unable to parse request: ");
065      builder.append(exception.getOriginalMessage());
066      if(exception.getLocation() != null)
067      {
068        builder.append(" at line: ");
069        builder.append(exception.getLocation().getLineNr());
070        builder.append(", column: ");
071        builder.append(exception.getLocation().getColumnNr());
072      }
073      errorResponse =
074          BadRequestException.invalidSyntax(builder.toString()).getScimError();
075    }
076    else
077    {
078      if(exception.getCause() != null &&
079          exception.getCause() instanceof ScimException)
080      {
081        errorResponse = ((ScimException) exception.getCause()).getScimError();
082      }
083      else
084      {
085        errorResponse =
086            new ServerErrorException(exception.getMessage()).getScimError();
087      }
088    }
089
090    return ServerUtils.setAcceptableType(
091        Response.status(errorResponse.getStatus()).entity(errorResponse),
092        headers.getAcceptableMediaTypes()).build();
093  }
094}