001 package de.deepamehta.plugins.webservice.provider; 002 003 import de.deepamehta.core.JSONEnabled; 004 import de.deepamehta.core.service.accesscontrol.AccessControlException; 005 import de.deepamehta.core.util.JavaUtils; 006 007 import org.codehaus.jettison.json.JSONArray; 008 import org.codehaus.jettison.json.JSONException; 009 import org.codehaus.jettison.json.JSONObject; 010 011 import javax.servlet.http.HttpServletRequest; 012 013 import javax.ws.rs.WebApplicationException; 014 import javax.ws.rs.core.Context; 015 import javax.ws.rs.core.MediaType; 016 import javax.ws.rs.core.Response; 017 import javax.ws.rs.core.Response.Status; 018 import javax.ws.rs.ext.ExceptionMapper; 019 import javax.ws.rs.ext.Provider; 020 021 // ### import java.io.PrintWriter; 022 // ### import java.io.StringWriter; 023 import java.util.logging.Level; 024 import java.util.logging.Logger; 025 026 027 028 /** 029 * Maps all Throwables but WebApplicationExceptions to a 500 (Internal Server Error) response. 030 * A WebApplicationException's response is returned directly. 031 * <p> 032 * We don't want Jersey to re-throw anything to the HTTP container as this would result in logging 033 * the exception twice and possibly to interspersed illegible stack traces (see #484). 034 */ 035 @Provider 036 public class CatchAllExceptionMapper implements ExceptionMapper<Throwable> { 037 038 // ---------------------------------------------------------------------------------------------- Instance Variables 039 040 @Context 041 HttpServletRequest request; 042 043 private Logger logger = Logger.getLogger(getClass().getName()); 044 045 // -------------------------------------------------------------------------------------------------- Public Methods 046 047 @Override 048 public Response toResponse(Throwable e) { 049 if (e instanceof WebApplicationException) { 050 return ((WebApplicationException) e).getResponse(); 051 } 052 // 053 Status status = hasNestedAccessControlException(e) ? Status.UNAUTHORIZED : Status.INTERNAL_SERVER_ERROR; 054 // 055 logger.log(Level.SEVERE, errorMessage(status), e); 056 return Response.status(status).type(MediaType.APPLICATION_JSON).entity(new ExceptionInfo(e)).build(); 057 } 058 059 // ------------------------------------------------------------------------------------------------- Private Methods 060 061 private boolean hasNestedAccessControlException(Throwable e) { 062 while (e != null) { 063 if (e instanceof AccessControlException) { 064 return true; 065 } 066 e = e.getCause(); 067 } 068 return false; 069 } 070 071 private String errorMessage(Status status) { 072 return "Request \"" + JavaUtils.requestInfo(request) + "\" failed. Responding with " + 073 JavaUtils.responseInfo(status) + ". The original exception/error is:"; 074 } 075 076 /* ### private String toJSON(Throwable e) { 077 try { 078 StringWriter out = new StringWriter(); 079 e.printStackTrace(new PrintWriter(out)); 080 return new JSONObject().put("exception", out).toString(); 081 } catch (JSONException je) { 082 throw new RuntimeException("Generating exception info failed", je); 083 } 084 } */ 085 086 // --------------------------------------------------------------------------------------------------- Private Class 087 088 private static class ExceptionInfo implements JSONEnabled { 089 090 private JSONObject json; 091 092 private ExceptionInfo(Throwable e) { 093 try { 094 json = createJSONObject(e); 095 } catch (JSONException je) { 096 throw new RuntimeException("Generating exception info failed", je); 097 } 098 } 099 100 private JSONObject createJSONObject(Throwable e) throws JSONException { 101 JSONObject json = new JSONObject() 102 .put("exception", e.getClass().getName()) 103 .put("message", e.getMessage()); 104 // 105 Throwable cause = e.getCause(); 106 if (cause != null) { 107 json.put("cause", createJSONObject(cause)); 108 } 109 // 110 return json; 111 } 112 113 @Override 114 public JSONObject toJSON() { 115 return json; 116 } 117 } 118 }