View Javadoc
1   /*
2    * This file is part of ***  M y C o R e  ***
3    * See http://www.mycore.de/ for details.
4    *
5    * MyCoRe is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    *
10   * MyCoRe is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with MyCoRe.  If not, see <http://www.gnu.org/licenses/>.
17   */
18  
19  package org.mycore.restapi.v2;
20  
21  import java.util.List;
22  import java.util.Optional;
23  
24  import org.apache.logging.log4j.LogManager;
25  import org.apache.logging.log4j.Logger;
26  
27  import jakarta.ws.rs.WebApplicationException;
28  import jakarta.ws.rs.core.Context;
29  import jakarta.ws.rs.core.MediaType;
30  import jakarta.ws.rs.core.Request;
31  import jakarta.ws.rs.core.Response;
32  import jakarta.ws.rs.core.Variant;
33  import jakarta.ws.rs.ext.ExceptionMapper;
34  
35  public class MCRExceptionMapper implements ExceptionMapper<Exception> {
36  
37      private final static List<Variant> SUPPORTED_VARIANTS = Variant
38          .mediaTypes(MediaType.APPLICATION_JSON_TYPE, MediaType.APPLICATION_XML_TYPE).build();
39  
40      private final static Logger LOGGER = LogManager.getLogger();
41  
42      @Context
43      Request request;
44  
45      @Override
46      public Response toResponse(Exception exception) {
47          return Optional.ofNullable(request.selectVariant(SUPPORTED_VARIANTS))
48              .map(v -> fromException(exception))
49              .orElseGet(() -> (exception instanceof WebApplicationException)
50                  ? ((WebApplicationException) exception).getResponse()
51                  : null);
52      }
53  
54      public static Response fromWebApplicationException(WebApplicationException wae) {
55          if (wae.getResponse().hasEntity()) {
56              //usually WAEs with entity do not arrive here
57              LOGGER.warn("WebApplicationException already has an entity attached, forwarding response");
58              return wae.getResponse();
59          }
60          final Response response = getResponse(wae, wae.getResponse().getStatus());
61          response.getHeaders().putAll(wae.getResponse().getHeaders());
62          return response;
63      }
64  
65      public static Response fromException(Exception e) {
66          if (e instanceof WebApplicationException) {
67              return fromWebApplicationException((WebApplicationException) e);
68          }
69          return getResponse(e, Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
70      }
71  
72      private static Response getResponse(Exception e, int statusCode) {
73          MCRErrorResponse response = MCRErrorResponse.fromStatus(statusCode)
74              .withCause(e)
75              .withMessage(e.getMessage())
76              .withDetail(Optional.of(e)
77                  .map(ex -> (ex instanceof WebApplicationException) ? ex.getCause() : ex)
78                  .map(Object::getClass)
79                  .map(Class::getName)
80                  .orElse(null));
81          LogManager.getLogger().error(response::getLogMessage, e);
82          return Response.status(response.getStatus())
83              .entity(response)
84              .build();
85      }
86  }