SEARCH-2909 Return Http Status Code 501 (Not Implemented) in REST API… (#519)

* SEARCH-2909 Return Http Status Code 501 (Not Implemented) in REST API for invocations to Search Services that are not supported.

* SEARCH-2909 Refactor exception mapping to simplify QueryParserException.

* SEARCH-2909 Add unit tests for postQuery.

This includes a test for the status code replacement with unsupported operations.

* SEARCH-2909 Add new unit test file to test suite.

Also add copyright header to test class.

Co-authored-by: Tom Page <thomas.page@alfresco.com>
This commit is contained in:
Angel Borroy
2021-06-11 17:03:55 +02:00
committed by GitHub
parent 29d5093c93
commit f1a5425f62
10 changed files with 371 additions and 87 deletions

View File

@@ -41,7 +41,11 @@ public class DefaultExceptionResolver implements ExceptionResolver<Exception>
@Override
public ErrorResponse resolveException(Exception ex)
{
return new ErrorResponse(DEFAULT_MESSAGE_ID, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex.getLocalizedMessage(), ex.getStackTrace(), null);
return new ErrorResponse(DEFAULT_MESSAGE_ID,
HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
ex.getLocalizedMessage(),
ex.getStackTrace(),
null);
}
}

View File

@@ -0,0 +1,48 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.framework.core.exceptions;
import org.alfresco.repo.search.QueryParserException;
/**
* QueryParserException is related with search requests to Search Services.
*/
public class QueryParserExceptionResolver implements ExceptionResolver<QueryParserException>
{
@Override
public ErrorResponse resolveException(QueryParserException ex)
{
return new ErrorResponse(
DefaultExceptionResolver.DEFAULT_MESSAGE_ID,
// Mapping the original HTTP Status code returned by Search Services
ex.getHttpStatusCode(),
ex.getLocalizedMessage(),
ex.getStackTrace(),
null);
}
}

View File

@@ -26,10 +26,12 @@
package org.alfresco.rest.framework.tools;
import org.alfresco.metrics.rest.RestMetricsReporter;
import org.alfresco.repo.search.QueryParserException;
import org.alfresco.rest.framework.Api;
import org.alfresco.rest.framework.core.exceptions.DefaultExceptionResolver;
import org.alfresco.rest.framework.core.exceptions.ErrorResponse;
import org.alfresco.rest.framework.core.exceptions.ExceptionResolver;
import org.alfresco.rest.framework.core.exceptions.QueryParserExceptionResolver;
import org.alfresco.rest.framework.jacksonextensions.JacksonHelper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -48,6 +50,7 @@ public class ApiAssistant {
private ExceptionResolver<Exception> defaultResolver = new DefaultExceptionResolver();
private ExceptionResolver<WebScriptException> webScriptExceptionResolver;
private ExceptionResolver<QueryParserException> queryParserExceptionResolver;
private ExceptionResolver<Exception> resolver;
private JacksonHelper jsonHelper;
private RestMetricsReporter restMetricsReporter;
@@ -77,6 +80,10 @@ public class ApiAssistant {
{
error = webScriptExceptionResolver.resolveException((WebScriptException) ex);
}
else if (ex instanceof QueryParserException)
{
error = queryParserExceptionResolver.resolveException((QueryParserException) ex);
}
else
{
error = resolver.resolveException(ex);
@@ -100,6 +107,11 @@ public class ApiAssistant {
this.webScriptExceptionResolver = webScriptExceptionResolver;
}
public void setQueryParserExceptionResolver(ExceptionResolver<QueryParserException> queryParserExceptionResolver)
{
this.queryParserExceptionResolver = queryParserExceptionResolver;
}
public void setResolver(ExceptionResolver<Exception> resolver) {
this.resolver = resolver;
}

View File

@@ -134,6 +134,8 @@
</bean>
<bean id="webScriptExceptionResolver" class="org.alfresco.rest.framework.core.exceptions.WebScriptExceptionResolver">
</bean>
<bean id="queryParserExceptionResolver" class="org.alfresco.rest.framework.core.exceptions.QueryParserExceptionResolver">
</bean>
<bean id="simpleMappingExceptionResolverParent" abstract="true" class="org.alfresco.rest.framework.core.exceptions.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<map>
@@ -182,6 +184,7 @@
<property name="resolver" ref="simpleMappingExceptionResolver" />
<property name="webScriptExceptionResolver" ref="webScriptExceptionResolver" />
<property name="restMetricsReporter" ref="restMetricsReporter"/>
<property name="queryParserExceptionResolver" ref="queryParserExceptionResolver" />
</bean>
<!-- Using annotation-config=false means AutowiredAnnotationBeanPostProcessor

View File

@@ -23,45 +23,46 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.framework.tests.core;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import org.alfresco.repo.forms.FormNotFoundException;
package org.alfresco.rest.framework.tests.core;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import org.alfresco.repo.forms.FormNotFoundException;
import org.alfresco.repo.node.integrity.IntegrityException;
import org.alfresco.rest.framework.core.exceptions.ApiException;
import org.alfresco.rest.framework.core.exceptions.ConstraintViolatedException;
import org.alfresco.rest.framework.core.exceptions.DeletedResourceException;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.core.exceptions.ErrorResponse;
import org.alfresco.repo.search.QueryParserException;
import org.alfresco.rest.framework.core.exceptions.ApiException;
import org.alfresco.rest.framework.core.exceptions.ConstraintViolatedException;
import org.alfresco.rest.framework.core.exceptions.DeletedResourceException;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.core.exceptions.ErrorResponse;
import org.alfresco.rest.framework.core.exceptions.InsufficientStorageException;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.core.exceptions.NotFoundException;
import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
import org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException;
import org.alfresco.rest.framework.core.exceptions.StaleEntityException;
import org.alfresco.rest.framework.core.exceptions.UnsupportedResourceOperationException;
import org.alfresco.rest.framework.resource.parameters.where.InvalidQueryException;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.core.exceptions.NotFoundException;
import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
import org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException;
import org.alfresco.rest.framework.core.exceptions.StaleEntityException;
import org.alfresco.rest.framework.core.exceptions.UnsupportedResourceOperationException;
import org.alfresco.rest.framework.resource.parameters.where.InvalidQueryException;
import org.alfresco.rest.framework.tools.ApiAssistant;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.servlet.http.HttpServletResponse;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:test-rest-context.xml" })
public class ExceptionResolverTests
{
@Autowired
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:test-rest-context.xml" })
public class ExceptionResolverTests
{
@Autowired
ApiAssistant assistant;
@Test
@Test
public void testWebscriptException()
{
ErrorResponse response = assistant.resolveException(new WebScriptException(null));
@@ -75,43 +76,43 @@ public class ExceptionResolverTests
//04180006 Authentication failed for Web Script org/alfresco/api/ResourceWebScript.get
@Test
public void testMatchException()
{
public void testMatchException()
{
ErrorResponse response = assistant.resolveException(new ApiException(null));
assertNotNull(response);
assertEquals(500, response.getStatusCode()); //default to INTERNAL_SERVER_ERROR
assertNotNull(response);
assertEquals(500, response.getStatusCode()); //default to INTERNAL_SERVER_ERROR
response = assistant.resolveException(new InvalidArgumentException(null));
assertEquals(400, response.getStatusCode()); //default to STATUS_BAD_REQUEST
response = assistant.resolveException(new InvalidQueryException(null));
assertEquals(400, response.getStatusCode()); //default to STATUS_BAD_REQUEST
response = assistant.resolveException(new NotFoundException(null));
assertEquals(404, response.getStatusCode()); //default to STATUS_NOT_FOUND
response = assistant.resolveException(new EntityNotFoundException(null));
assertEquals(404, response.getStatusCode()); //default to STATUS_NOT_FOUND
response = assistant.resolveException(new RelationshipResourceNotFoundException(null, null));
assertEquals(404, response.getStatusCode()); //default to STATUS_NOT_FOUND
response = assistant.resolveException(new PermissionDeniedException(null));
assertEquals(403, response.getStatusCode()); //default to STATUS_FORBIDDEN
response = assistant.resolveException(new UnsupportedResourceOperationException(null));
assertEquals(405, response.getStatusCode()); //default to STATUS_METHOD_NOT_ALLOWED
response = assistant.resolveException(new DeletedResourceException(null));
assertEquals(405, response.getStatusCode()); //default to STATUS_METHOD_NOT_ALLOWED
response = assistant.resolveException(new ConstraintViolatedException(null));
assertEquals(409, response.getStatusCode()); //default to STATUS_CONFLICT
response = assistant.resolveException(new StaleEntityException(null));
assertEquals(409, response.getStatusCode()); //default to STATUS_CONFLICT
assertEquals(400, response.getStatusCode()); //default to STATUS_BAD_REQUEST
//Try a random exception
response = assistant.resolveException(new InvalidQueryException(null));
assertEquals(400, response.getStatusCode()); //default to STATUS_BAD_REQUEST
response = assistant.resolveException(new NotFoundException(null));
assertEquals(404, response.getStatusCode()); //default to STATUS_NOT_FOUND
response = assistant.resolveException(new EntityNotFoundException(null));
assertEquals(404, response.getStatusCode()); //default to STATUS_NOT_FOUND
response = assistant.resolveException(new RelationshipResourceNotFoundException(null, null));
assertEquals(404, response.getStatusCode()); //default to STATUS_NOT_FOUND
response = assistant.resolveException(new PermissionDeniedException(null));
assertEquals(403, response.getStatusCode()); //default to STATUS_FORBIDDEN
response = assistant.resolveException(new UnsupportedResourceOperationException(null));
assertEquals(405, response.getStatusCode()); //default to STATUS_METHOD_NOT_ALLOWED
response = assistant.resolveException(new DeletedResourceException(null));
assertEquals(405, response.getStatusCode()); //default to STATUS_METHOD_NOT_ALLOWED
response = assistant.resolveException(new ConstraintViolatedException(null));
assertEquals(409, response.getStatusCode()); //default to STATUS_CONFLICT
response = assistant.resolveException(new StaleEntityException(null));
assertEquals(409, response.getStatusCode()); //default to STATUS_CONFLICT
//Try a random exception
response = assistant.resolveException(new FormNotFoundException(null));
assertEquals(500, response.getStatusCode()); //default to INTERNAL_SERVER_ERROR
@@ -120,6 +121,15 @@ public class ExceptionResolverTests
response = assistant.resolveException(new IntegrityException(null));
assertEquals(422, response.getStatusCode());
}
}
}
/** Check that the status code from SS is passed back to the caller. */
@Test
public void testQueryParserException()
{
ErrorResponse response = assistant.resolveException(new QueryParserException("Endpoint not found", 404));
assertNotNull(response);
assertEquals("Expected status code to be passed through from query parser.", 404, response.getStatusCode());
}
}

View File

@@ -33,10 +33,12 @@
</bean>
<bean id="webScriptExceptionResolver" class="org.alfresco.rest.framework.core.exceptions.WebScriptExceptionResolver">
</bean>
<bean id="queryParserExceptionResolver" class="org.alfresco.rest.framework.core.exceptions.QueryParserExceptionResolver" />
<bean id="apiAssistant" class="org.alfresco.rest.framework.tools.ApiAssistant">
<property name="jsonHelper" ref="jsonHelper" />
<property name="resolver" ref="simpleMappingExceptionResolver" />
<property name="webScriptExceptionResolver" ref="webScriptExceptionResolver" />
<property name="queryParserExceptionResolver" ref="queryParserExceptionResolver" />
</bean>
<bean id="simpleMappingExceptionResolver" class="org.alfresco.rest.framework.core.exceptions.SimpleMappingExceptionResolver">
<property name="exceptionMappings">