001/* 002 * (C) Copyright 2006-2010 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * bstefanescu 018 */ 019package org.nuxeo.ecm.webengine.app; 020 021import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST; 022import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN; 023import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR; 024import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; 025 026import javax.ws.rs.WebApplicationException; 027import javax.ws.rs.core.Context; 028import javax.ws.rs.core.HttpHeaders; 029import javax.ws.rs.core.Response; 030import javax.ws.rs.ext.ExceptionMapper; 031import javax.ws.rs.ext.Provider; 032 033import org.apache.logging.log4j.LogManager; 034import org.apache.logging.log4j.Logger; 035import org.nuxeo.ecm.core.api.NuxeoException; 036import org.nuxeo.ecm.core.api.validation.DocumentValidationException; 037import org.nuxeo.ecm.webengine.WebEngine; 038import org.nuxeo.ecm.webengine.WebException; 039import org.nuxeo.ecm.webengine.model.ModuleResource; 040import org.nuxeo.ecm.webengine.model.WebContext; 041import org.nuxeo.runtime.api.Framework; 042import org.nuxeo.runtime.transaction.TransactionHelper; 043 044/** 045 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 046 */ 047@Provider 048public class WebEngineExceptionMapper implements ExceptionMapper<Throwable> { 049 050 @Context 051 HttpHeaders headers; 052 053 private static final Logger log = LogManager.getLogger(WebEngineExceptionMapper.class); 054 055 @Override 056 public Response toResponse(Throwable cause) { 057 TransactionHelper.setTransactionRollbackOnly(); 058 if (headers.getAcceptableMediaTypes().contains(APPLICATION_JSON_TYPE)) { 059 if (cause instanceof DocumentValidationException) { 060 DocumentValidationException dve = (DocumentValidationException) cause; 061 return Response.status(dve.getStatusCode()).entity(dve.getReport()).build(); 062 } 063 } 064 065 // backward compatibility 066 if (cause instanceof WebException) { 067 return ((WebException) cause).toResponse(); 068 } 069 070 // webengine custom error handling, if any 071 Object result = handleErrorOnWebModule(cause); 072 if (result instanceof Throwable) { 073 cause = (Throwable) result; 074 } else if (result instanceof Response) { 075 return (Response) result; 076 } else if (result != null) { 077 return Response.status(SC_INTERNAL_SERVER_ERROR).entity(result).build(); 078 } 079 080 int statusCode = getStatusCode(cause); 081 if (statusCode >= SC_INTERNAL_SERVER_ERROR) { 082 log.error(cause, cause); 083 } else if (Framework.isDevModeSet()) { 084 log.warn(cause, cause); 085 } else { 086 log.debug(cause, cause); 087 } 088 // make sure we have a NuxeoException 089 return Response.status(statusCode) 090 .entity(cause instanceof NuxeoException ? cause : new NuxeoException(cause, statusCode)) 091 .build(); 092 } 093 094 protected static int getStatusCode(Throwable t) { 095 if (t instanceof WebException) { 096 WebException webException = (WebException) t; 097 return webException.getStatusCode(); 098 } else if (t instanceof WebApplicationException) { 099 WebApplicationException e = (WebApplicationException) t; 100 return e.getResponse().getStatus(); 101 } else if (t instanceof NuxeoException) { 102 NuxeoException e = (NuxeoException) t; 103 return e.getStatusCode(); 104 } else if (t instanceof SecurityException) { 105 return SC_FORBIDDEN; 106 } else if (t instanceof IllegalArgumentException) { 107 return SC_BAD_REQUEST; 108 } 109 110 Throwable cause = t.getCause(); 111 if (cause == null || t == cause) { 112 return SC_INTERNAL_SERVER_ERROR; 113 } 114 return getStatusCode(cause); 115 } 116 117 protected static Object handleErrorOnWebModule(Throwable t) { 118 WebContext ctx = WebEngine.getActiveContext(); 119 if (ctx != null && ctx.head() instanceof ModuleResource) { 120 ModuleResource mr = (ModuleResource) ctx.head(); 121 return mr.handleError(t); 122 } 123 return null; 124 } 125 126}