MARMOTTA-562: impemented basic json message for http errors
Project: http://git-wip-us.apache.org/repos/asf/marmotta/repo Commit: http://git-wip-us.apache.org/repos/asf/marmotta/commit/3ecce046 Tree: http://git-wip-us.apache.org/repos/asf/marmotta/tree/3ecce046 Diff: http://git-wip-us.apache.org/repos/asf/marmotta/diff/3ecce046 Branch: refs/heads/develop Commit: 3ecce0469f88e48ae0e0649f6e866323f33a48f1 Parents: 0965f73 Author: Sergio Fernández <[email protected]> Authored: Wed Nov 5 14:29:43 2014 +0100 Committer: Sergio Fernández <[email protected]> Committed: Wed Nov 5 15:30:50 2014 +0100 ---------------------------------------------------------------------- .../commons/http/MarmottaHttpUtils.java | 2 + .../core/exception/HttpErrorException.java | 6 +- .../platform/core/jaxrs/ErrorMessage.java | 50 ++++++++++++++ .../HttpErrorExceptionMapper.java | 69 ++++++++++++------ .../core/test/jaxrs/ExceptionHandlingTest.java | 73 ++++++++++++++++++++ 5 files changed, 176 insertions(+), 24 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/marmotta/blob/3ecce046/commons/marmotta-commons/src/main/java/org/apache/marmotta/commons/http/MarmottaHttpUtils.java ---------------------------------------------------------------------- diff --git a/commons/marmotta-commons/src/main/java/org/apache/marmotta/commons/http/MarmottaHttpUtils.java b/commons/marmotta-commons/src/main/java/org/apache/marmotta/commons/http/MarmottaHttpUtils.java index d1e070c..c0d7ce4 100644 --- a/commons/marmotta-commons/src/main/java/org/apache/marmotta/commons/http/MarmottaHttpUtils.java +++ b/commons/marmotta-commons/src/main/java/org/apache/marmotta/commons/http/MarmottaHttpUtils.java @@ -23,6 +23,8 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import com.google.common.base.Function; +import com.google.common.collect.Lists; import org.apache.commons.lang3.StringUtils; import org.openrdf.query.resultio.QueryResultFormat; http://git-wip-us.apache.org/repos/asf/marmotta/blob/3ecce046/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/exception/HttpErrorException.java ---------------------------------------------------------------------- diff --git a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/exception/HttpErrorException.java b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/exception/HttpErrorException.java index 381e9da..aba26cd 100644 --- a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/exception/HttpErrorException.java +++ b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/exception/HttpErrorException.java @@ -24,14 +24,16 @@ import java.util.HashMap; import java.util.Map; /** - * Resource Not Found Exception + * HTTP Error Exception * * @author Sergio Fernández */ public class HttpErrorException extends Exception { private final int status; + private final String reason; + private final String uri; private final Map<String, String> headers; @@ -80,7 +82,7 @@ public class HttpErrorException extends Exception { * @param msg message * @param headers custom headers */ - public HttpErrorException(int status, String reason, String uri, String msg, Map<String,String> headers) { + public HttpErrorException(int status, String reason, String uri, String msg, Map<String, String> headers) { super(msg); this.status = status; this.reason = reason; http://git-wip-us.apache.org/repos/asf/marmotta/blob/3ecce046/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/jaxrs/ErrorMessage.java ---------------------------------------------------------------------- diff --git a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/jaxrs/ErrorMessage.java b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/jaxrs/ErrorMessage.java new file mode 100644 index 0000000..b80560f --- /dev/null +++ b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/jaxrs/ErrorMessage.java @@ -0,0 +1,50 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.marmotta.platform.core.jaxrs; + +import org.apache.marmotta.platform.core.exception.HttpErrorException; + +/** + * Error Message for serialization purposes + * + * @author Sergio Fernández + */ +public class ErrorMessage { + + public String uri; + + public int status; + + public String reason; + + public String message; + + public ErrorMessage(String uri, int status, String reason, String message) { + this.status = status; + this.reason = reason; + this.message = message; + } + + public ErrorMessage(HttpErrorException exception) { + this.uri = exception.getUri(); + this.status = exception.getStatus(); + this.reason = exception.getReason(); + this.message = exception.getMessage(); + } + +} http://git-wip-us.apache.org/repos/asf/marmotta/blob/3ecce046/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/jaxrs/exceptionmappers/HttpErrorExceptionMapper.java ---------------------------------------------------------------------- diff --git a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/jaxrs/exceptionmappers/HttpErrorExceptionMapper.java b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/jaxrs/exceptionmappers/HttpErrorExceptionMapper.java index 69aabfe..d91cc43 100644 --- a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/jaxrs/exceptionmappers/HttpErrorExceptionMapper.java +++ b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/jaxrs/exceptionmappers/HttpErrorExceptionMapper.java @@ -18,9 +18,12 @@ package org.apache.marmotta.platform.core.jaxrs.exceptionmappers; import freemarker.template.TemplateException; import org.apache.commons.lang3.StringUtils; +import org.apache.marmotta.commons.http.ContentType; +import org.apache.marmotta.commons.http.MarmottaHttpUtils; import org.apache.marmotta.platform.core.api.config.ConfigurationService; import org.apache.marmotta.platform.core.api.templating.TemplatingService; import org.apache.marmotta.platform.core.exception.HttpErrorException; +import org.apache.marmotta.platform.core.jaxrs.ErrorMessage; import org.slf4j.Logger; import javax.enterprise.context.Dependent; @@ -30,6 +33,7 @@ import javax.ws.rs.ext.Provider; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -64,34 +68,55 @@ public class HttpErrorExceptionMapper implements CDIExceptionMapper<HttpErrorExc */ @Override public Response toResponse(HttpErrorException exception) { - Map<String, Object> data = new HashMap<String, Object>(); - data.put("status", exception.getStatus()); - data.put("reason", exception.getReason()); - data.put("message", exception.getMessage()); - if (StringUtils.isNotBlank(exception.getUri())) { - data.put("uri", exception.getUri()); - try { - data.put("encoded_uri", URLEncoder.encode(exception.getUri(), "UTF-8")); - } catch (UnsupportedEncodingException uee) { - data.put("encoded_uri", exception.getUri()); + final Map<String, String> exceptionHeaders = exception.getHeaders(); + + boolean htmlError = true; //HTML still by default + if (exceptionHeaders.containsKey("Accept")) { + final String acceptHeader = exceptionHeaders.get("Accept"); + final ContentType bestContentType = MarmottaHttpUtils.bestContentType(Arrays.asList(MarmottaHttpUtils.parseContentType("text/html"), MarmottaHttpUtils.parseContentType("application/json")), + Arrays.asList(MarmottaHttpUtils.parseContentType(acceptHeader))); + if (bestContentType.matches(MarmottaHttpUtils.parseContentType("application/json"))) { + htmlError = false; } - } else { - data.put("uri", ""); - data.put("encoded_uri", ""); } Response.ResponseBuilder responseBuilder; - try { - responseBuilder = Response.status(exception.getStatus()).entity(templatingService.process(TEMPLATE, data)); - } catch (IOException | TemplateException e) { - log.error("Error rendering template {}: {}", TEMPLATE, e.getMessage()); - responseBuilder = Response.status(exception.getStatus()).entity(e.getMessage()); + if (htmlError) { + //html rendering + Map<String, Object> data = new HashMap<>(); + data.put("status", exception.getStatus()); + data.put("reason", exception.getReason()); + + data.put("message", exception.getMessage()); + if (StringUtils.isNotBlank(exception.getUri())) { + data.put("uri", exception.getUri()); + try { + data.put("encoded_uri", URLEncoder.encode(exception.getUri(), "UTF-8")); + } catch (UnsupportedEncodingException uee) { + data.put("encoded_uri", exception.getUri()); + } + } else { + data.put("uri", ""); + data.put("encoded_uri", ""); + } + + try { + responseBuilder = Response.status(exception.getStatus()).entity(templatingService.process(TEMPLATE, data)); + } catch (IOException | TemplateException e) { + log.error("Error rendering html error template {}: {}", TEMPLATE, e.getMessage()); + responseBuilder = Response.status(exception.getStatus()).entity(e.getMessage()); + } + } else { + //simple json error message + responseBuilder = Response.status(exception.getStatus()).entity(new ErrorMessage(exception)); } - Response response = responseBuilder.build(); - for (Map.Entry<String, String> entry : exception.getHeaders().entrySet()) { - response.getMetadata().add(entry.getKey(), entry.getValue()); + + //forward headers + for (Map.Entry<String, String> entry : exceptionHeaders.entrySet()) { + responseBuilder.header(entry.getKey(), entry.getValue()); } - return response; + + return responseBuilder.build(); } } http://git-wip-us.apache.org/repos/asf/marmotta/blob/3ecce046/platform/marmotta-core/src/test/java/org/apache/marmotta/platform/core/test/jaxrs/ExceptionHandlingTest.java ---------------------------------------------------------------------- diff --git a/platform/marmotta-core/src/test/java/org/apache/marmotta/platform/core/test/jaxrs/ExceptionHandlingTest.java b/platform/marmotta-core/src/test/java/org/apache/marmotta/platform/core/test/jaxrs/ExceptionHandlingTest.java new file mode 100644 index 0000000..61677c0 --- /dev/null +++ b/platform/marmotta-core/src/test/java/org/apache/marmotta/platform/core/test/jaxrs/ExceptionHandlingTest.java @@ -0,0 +1,73 @@ +package org.apache.marmotta.platform.core.test.jaxrs; + +import com.jayway.restassured.RestAssured; +import com.jayway.restassured.response.ResponseBody; +import org.apache.commons.io.IOUtils; +import org.apache.marmotta.platform.core.api.config.ConfigurationService; +import org.apache.marmotta.platform.core.exception.MarmottaException; +import org.apache.marmotta.platform.core.test.base.JettyMarmotta; +import org.apache.marmotta.platform.core.webservices.resource.ResourceWebService; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.openrdf.repository.RepositoryException; +import org.openrdf.rio.RDFParseException; + +import java.io.IOException; + +import static com.jayway.restassured.RestAssured.expect; + +/** + * Test for exceptions handling + * + * @author Sergio Fernández + */ +public class ExceptionHandlingTest { + + private static JettyMarmotta marmotta; + + @BeforeClass + public static void setUp() throws RepositoryException, IOException, RDFParseException { + marmotta = new JettyMarmotta("/marmotta", ResourceWebService.class); + + RestAssured.baseURI = "http://localhost"; + RestAssured.port = marmotta.getPort(); + RestAssured.basePath = marmotta.getContext(); + } + + @AfterClass + public static void tearDown() { + marmotta.shutdown(); + } + + @Test + public void testNotFound() throws MarmottaException, IOException { + + final ResponseBody response = expect(). + log().ifError(). + statusCode(404). + contentType("text/html"). + given(). + header("Accept", "text/html"). + when(). + get(ConfigurationService.RESOURCE_PATH + "/foo"). + getBody(); + response.print(); + + final ResponseBody responseJson = expect(). + log().ifError(). + statusCode(404). + contentType("application/json"). + given(). + header("Accept", "application/json"). + when(). + get(ConfigurationService.RESOURCE_PATH + "/foo"). + getBody(); + responseJson.print(); + Assert.assertEquals(404, responseJson.jsonPath().get("status")); + Assert.assertEquals("Not Found", responseJson.jsonPath().get("reason")); + + } + +}
