Skip to content

Commit

Permalink
Merge pull request #3475 from IQSS/3423-api-server-error-handler
Browse files Browse the repository at this point in the history
Added API-wide exception handlers for common exceptions
  • Loading branch information
kcondon authored Nov 29, 2016
2 parents 9a485f2 + ebffecf commit 0cefe11
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 5 deletions.
25 changes: 21 additions & 4 deletions src/main/java/edu/harvard/iq/dataverse/api/AbstractApiBean.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import edu.harvard.iq.dataverse.validation.BeanValidationServiceBean;
import java.io.StringReader;
import java.net.URI;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
Expand Down Expand Up @@ -424,8 +425,16 @@ protected Response response( Callable<Response> hdl ) {
} catch ( WrappedResponse rr ) {
return rr.getResponse();
} catch ( Exception ex ) {
logger.log( Level.WARNING, "Error executing callable: " + ex.getMessage(), ex );
return error(Status.INTERNAL_SERVER_ERROR, ex.getMessage());
String incidentId = UUID.randomUUID().toString();
logger.log(Level.SEVERE, "API internal error " + incidentId +": " + ex.getMessage(), ex);
return Response.status(500)
.entity( Json.createObjectBuilder()
.add("status", "ERROR")
.add("code", 500)
.add("message", "Internal server error. More details available at the server logs.")
.add("incidentId", incidentId)
.build())
.type("application/json").build();
}
}

Expand All @@ -448,8 +457,16 @@ protected Response response( DataverseRequestHandler hdl ) {
} catch ( WrappedResponse rr ) {
return rr.getResponse();
} catch ( Exception ex ) {
logger.log( Level.WARNING, "Error executing callable: " + ex.getMessage(), ex );
return error(Status.INTERNAL_SERVER_ERROR, ex.getMessage());
String incidentId = UUID.randomUUID().toString();
logger.log(Level.SEVERE, "API internal error " + incidentId +": " + ex.getMessage(), ex);
return Response.status(500)
.entity( Json.createObjectBuilder()
.add("status", "ERROR")
.add("code", 500)
.add("message", "Internal server error. More details available at the server logs.")
.add("incidentId", incidentId)
.build())
.type("application/json").build();
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package edu.harvard.iq.dataverse.api;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;

/**
* An API endpoint that crashes. Used for testing the error handlers. Should
* be removed once #3423 is closed.
*
* @author michael
*/
@Path("boom")
public class CrashBoomBangEndpoint extends AbstractApiBean {

@GET
@Path("aoob")
public Response arrayError() {
String boom = "abc".split("3")[9];
return ok("Not gonna happen");
}

@GET
@Path("npe")
public Response nullPointer() {
String boom = null;
boom.length();
return ok("Not gonna happen");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package edu.harvard.iq.dataverse.api.errorhandlers;

import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.json.Json;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

/**
* Produces custom 500 messages for the API.
* @author michael
*/
@Provider
public class ArrayOutOfBoundsExceptionHandler implements ExceptionMapper<java.lang.ArrayIndexOutOfBoundsException>{

private static final Logger logger = Logger.getLogger(ServeletExceptionHandler.class.getName());

@Context
HttpServletRequest request;

@Override
public Response toResponse(java.lang.ArrayIndexOutOfBoundsException ex){
String incidentId = UUID.randomUUID().toString();
logger.log(Level.SEVERE, "API internal error " + incidentId +": ArrayOutOfBounds:" + ex.getMessage(), ex);
return Response.status(500)
.entity( Json.createObjectBuilder()
.add("status", "ERROR")
.add("code", 500)
.add("message", "Internal server error. More details available at the server logs.")
.add("incidentId", incidentId)
.build())
.type("application/json").build();
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
package edu.harvard.iq.dataverse.api.errorhandlers;

import javax.json.Json;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.NotAllowedException;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package edu.harvard.iq.dataverse.api;
package edu.harvard.iq.dataverse.api.errorhandlers;

import javax.json.Json;
import javax.servlet.http.HttpServletRequest;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package edu.harvard.iq.dataverse.api.errorhandlers;

import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.json.Json;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

/**
* Produces custom 500 messages for the API.
* @author michael
*/
@Provider
public class NullPointerExceptionHandler implements ExceptionMapper<java.lang.NullPointerException>{

private static final Logger logger = Logger.getLogger(ServeletExceptionHandler.class.getName());

@Context
HttpServletRequest request;

@Override
public Response toResponse(java.lang.NullPointerException ex){
String incidentId = UUID.randomUUID().toString();
logger.log(Level.SEVERE, "API internal error " + incidentId +": Null Pointer", ex);
return Response.status(500)
.entity( Json.createObjectBuilder()
.add("status", "ERROR")
.add("code", 500)
.add("message", "Internal server error. More details available at the server logs.")
.add("incidentId", incidentId)
.build())
.type("application/json").build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package edu.harvard.iq.dataverse.api.errorhandlers;

import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.json.Json;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

/**
* Produces custom 500 messages for the API.
* @author michael
*/
@Provider
public class ServeletExceptionHandler implements ExceptionMapper<javax.servlet.ServletException>{

private static final Logger logger = Logger.getLogger(ServeletExceptionHandler.class.getName());

@Context
HttpServletRequest request;

@Override
public Response toResponse(javax.servlet.ServletException ex){
String incidentId = UUID.randomUUID().toString();
logger.log(Level.SEVERE, "API internal error " + incidentId +": " + ex.getMessage(), ex);
return Response.status(500)
.entity( Json.createObjectBuilder()
.add("status", "ERROR")
.add("code", 500)
.add("message", "Internal server error. More details available at the server logs.")
.add("incidentId", incidentId)
.build())
.type("application/json").build();
}
}

0 comments on commit 0cefe11

Please sign in to comment.