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_FORBIDDEN; 022import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR; 023import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; 024 025import javax.ws.rs.WebApplicationException; 026import javax.ws.rs.core.Context; 027import javax.ws.rs.core.HttpHeaders; 028import javax.ws.rs.core.Response; 029import javax.ws.rs.core.Response.Status; 030import javax.ws.rs.ext.ExceptionMapper; 031import javax.ws.rs.ext.Provider; 032 033import org.apache.commons.logging.Log; 034import org.apache.commons.logging.LogFactory; 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.transaction.TransactionHelper; 042 043/** 044 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 045 */ 046@Provider 047public class WebEngineExceptionMapper implements ExceptionMapper<Throwable> { 048 049 @Context 050 HttpHeaders headers; 051 052 protected static final Log log = LogFactory.getLog(WebEngineExceptionMapper.class); 053 054 @Override 055 public Response toResponse(Throwable cause) { 056 TransactionHelper.setTransactionRollbackOnly(); 057 if (headers.getAcceptableMediaTypes().contains(APPLICATION_JSON_TYPE)) { 058 if (cause instanceof DocumentValidationException) { 059 DocumentValidationException dve = (DocumentValidationException) cause; 060 return Response.status(Status.BAD_REQUEST).entity(dve.getReport()).build(); 061 } 062 } 063 064 // backward compatibility 065 if (cause instanceof WebException) { 066 return ((WebException) cause).toResponse(); 067 } 068 069 // webengine custom error handling, if any 070 Object result = handleErrorOnWebModule(cause); 071 if (result instanceof Throwable) { 072 cause = (Throwable) result; 073 } else if (result instanceof Response) { 074 return (Response) result; 075 } else if (result != null) { 076 return Response.status(SC_INTERNAL_SERVER_ERROR).entity(result).build(); 077 } 078 079 int statusCode = getStatusCode(cause); 080 if (statusCode >= SC_INTERNAL_SERVER_ERROR) { 081 log.error(cause, cause); 082 } else { 083 log.debug(cause, cause); 084 } 085 // make sure we have a NuxeoException 086 return Response.status(statusCode) 087 .entity(cause instanceof NuxeoException ? cause : new NuxeoException(cause, statusCode)) 088 .build(); 089 } 090 091 protected static int getStatusCode(Throwable t) { 092 if (t instanceof WebException) { 093 WebException webException = (WebException) t; 094 return webException.getStatusCode(); 095 } else if (t instanceof WebApplicationException) { 096 WebApplicationException e = (WebApplicationException) t; 097 return e.getResponse().getStatus(); 098 } else if (t instanceof NuxeoException) { 099 NuxeoException e = (NuxeoException) t; 100 return e.getStatusCode(); 101 } else if (t instanceof SecurityException) { 102 return SC_FORBIDDEN; 103 } 104 105 Throwable cause = t.getCause(); 106 if (cause == null || t == cause) { 107 return SC_INTERNAL_SERVER_ERROR; 108 } 109 return getStatusCode(cause); 110 } 111 112 protected static Object handleErrorOnWebModule(Throwable t) { 113 WebContext ctx = WebEngine.getActiveContext(); 114 if (ctx != null && ctx.head() instanceof ModuleResource) { 115 ModuleResource mr = (ModuleResource) ctx.head(); 116 return mr.handleError(t); 117 } 118 return null; 119 } 120 121}