mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
MNT-24346 Fix "0" return status code when SORL unavailable (#2942)
* MNT-24346: Fix 0 status code in Search API when Solr is unavailable. * MNT-24346: Fixing PMD issues. * MNT-24346: Fixing formatting. * MNT-24346: Reverting accidental method name change. * MNT-24346: Fixing spotless issues. * MNT-24346: Fixing spotless issues. * MNT-24346: Fixing spotless issues. * MNT-24346 Fix line endings. --------- Co-authored-by: Tom Page <tom.page@alfresco.com>
This commit is contained in:
@@ -2,23 +2,23 @@
|
|||||||
* #%L
|
* #%L
|
||||||
* Alfresco Repository
|
* Alfresco Repository
|
||||||
* %%
|
* %%
|
||||||
* Copyright (C) 2005 - 2023 Alfresco Software Limited
|
* Copyright (C) 2005 - 2024 Alfresco Software Limited
|
||||||
* %%
|
* %%
|
||||||
* This file is part of the Alfresco software.
|
* This file is part of the Alfresco software.
|
||||||
* If the software was purchased under a paid Alfresco license, the terms of
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
* the paid license agreement will prevail. Otherwise, the software is
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
* provided under the following open source license terms:
|
* provided under the following open source license terms:
|
||||||
*
|
*
|
||||||
* Alfresco is free software: you can redistribute it and/or modify
|
* 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
|
* 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
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Alfresco is distributed in the hope that it will be useful,
|
* Alfresco is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU Lesser General Public License for more details.
|
* GNU Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
* #L%
|
* #L%
|
||||||
@@ -30,11 +30,8 @@ import java.io.IOException;
|
|||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.alfresco.httpclient.HttpClientException;
|
|
||||||
import org.alfresco.repo.search.QueryParserException;
|
|
||||||
import org.apache.commons.httpclient.Header;
|
import org.apache.commons.httpclient.Header;
|
||||||
import org.apache.commons.httpclient.HttpClient;
|
import org.apache.commons.httpclient.HttpClient;
|
||||||
import org.apache.commons.httpclient.HttpStatus;
|
import org.apache.commons.httpclient.HttpStatus;
|
||||||
@@ -48,13 +45,16 @@ import org.json.JSONException;
|
|||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.json.JSONTokener;
|
import org.json.JSONTokener;
|
||||||
|
|
||||||
|
import org.alfresco.httpclient.HttpClientException;
|
||||||
|
import org.alfresco.repo.search.QueryParserException;
|
||||||
|
|
||||||
public abstract class AbstractSolrQueryHTTPClient
|
public abstract class AbstractSolrQueryHTTPClient
|
||||||
{
|
{
|
||||||
/** Logger for the class. */
|
/** Logger for the class. */
|
||||||
private static final Log LOGGER = LogFactory.getLog(AbstractSolrQueryHTTPClient.class);
|
private static final Log LOGGER = LogFactory.getLog(AbstractSolrQueryHTTPClient.class);
|
||||||
|
|
||||||
public static final int DEFAULT_SAVEPOST_BUFFER = 4096;
|
public static final int DEFAULT_SAVEPOST_BUFFER = 4096;
|
||||||
|
|
||||||
// Constants copied from org.apache.solr.common.params.HighlightParams (solr-solrj:1.4.1)
|
// Constants copied from org.apache.solr.common.params.HighlightParams (solr-solrj:1.4.1)
|
||||||
// These values have been moved to this Alfresco class to avoid using solr-solrj library as dependency
|
// These values have been moved to this Alfresco class to avoid using solr-solrj library as dependency
|
||||||
public static final String HIGHLIGHT_PARAMS_HIGHLIGHT = "hl";
|
public static final String HIGHLIGHT_PARAMS_HIGHLIGHT = "hl";
|
||||||
@@ -86,7 +86,7 @@ public abstract class AbstractSolrQueryHTTPClient
|
|||||||
|
|
||||||
/** List of SOLR Exceptions that should be returning HTTP 501 status code in Remote API. */
|
/** List of SOLR Exceptions that should be returning HTTP 501 status code in Remote API. */
|
||||||
private static final List<String> STATUS_CODE_501_EXCEPTIONS = List.of("java.lang.UnsupportedOperationException");
|
private static final List<String> STATUS_CODE_501_EXCEPTIONS = List.of("java.lang.UnsupportedOperationException");
|
||||||
|
|
||||||
protected JSONObject postQuery(HttpClient httpClient, String url, JSONObject body) throws IOException, JSONException
|
protected JSONObject postQuery(HttpClient httpClient, String url, JSONObject body) throws IOException, JSONException
|
||||||
{
|
{
|
||||||
PostMethod post = createNewPostMethod(url);
|
PostMethod post = createNewPostMethod(url);
|
||||||
@@ -99,7 +99,7 @@ public abstract class AbstractSolrQueryHTTPClient
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
httpClient.executeMethod(post);
|
httpClient.executeMethod(post);
|
||||||
if(post.getStatusCode() == HttpStatus.SC_MOVED_PERMANENTLY || post.getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY)
|
if (post.getStatusCode() == HttpStatus.SC_MOVED_PERMANENTLY || post.getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY)
|
||||||
{
|
{
|
||||||
Header locationHeader = post.getResponseHeader("location");
|
Header locationHeader = post.getResponseHeader("location");
|
||||||
if (locationHeader != null)
|
if (locationHeader != null)
|
||||||
|
@@ -1,173 +1,173 @@
|
|||||||
/*
|
/*
|
||||||
* #%L
|
* #%L
|
||||||
* Alfresco Repository
|
* Alfresco Repository
|
||||||
* %%
|
* %%
|
||||||
* Copyright (C) 2005 - 2023 Alfresco Software Limited
|
* Copyright (C) 2005 - 2024 Alfresco Software Limited
|
||||||
* %%
|
* %%
|
||||||
* This file is part of the Alfresco software.
|
* This file is part of the Alfresco software.
|
||||||
* If the software was purchased under a paid Alfresco license, the terms of
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
* the paid license agreement will prevail. Otherwise, the software is
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
* provided under the following open source license terms:
|
* provided under the following open source license terms:
|
||||||
*
|
*
|
||||||
* Alfresco is free software: you can redistribute it and/or modify
|
* 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
|
* 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
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Alfresco is distributed in the hope that it will be useful,
|
* Alfresco is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU Lesser General Public License for more details.
|
* GNU Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
package org.alfresco.repo.search.impl.solr;
|
package org.alfresco.repo.search.impl.solr;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertThrows;
|
import static org.junit.Assert.assertThrows;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static org.mockito.MockitoAnnotations.openMocks;
|
import static org.mockito.MockitoAnnotations.openMocks;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.IOException;
|
||||||
import java.io.IOException;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.alfresco.httpclient.HttpClientException;
|
import org.apache.commons.httpclient.Header;
|
||||||
import org.alfresco.repo.search.QueryParserException;
|
import org.apache.commons.httpclient.HttpClient;
|
||||||
import org.apache.commons.httpclient.Header;
|
import org.apache.commons.httpclient.URI;
|
||||||
import org.apache.commons.httpclient.HttpClient;
|
import org.apache.commons.httpclient.methods.PostMethod;
|
||||||
import org.apache.commons.httpclient.URI;
|
import org.json.JSONObject;
|
||||||
import org.apache.commons.httpclient.methods.PostMethod;
|
import org.junit.Before;
|
||||||
import org.json.JSONObject;
|
import org.junit.Test;
|
||||||
import org.junit.Before;
|
import org.mockito.Mock;
|
||||||
import org.junit.Test;
|
|
||||||
import org.mockito.Mock;
|
import org.alfresco.httpclient.HttpClientException;
|
||||||
|
import org.alfresco.repo.search.QueryParserException;
|
||||||
/** Tests for the {@link AbstractSolrQueryHTTPClient}. */
|
|
||||||
public class AbstractSolrQueryHTTPClientTest
|
/** Tests for the {@link AbstractSolrQueryHTTPClient}. */
|
||||||
{
|
public class AbstractSolrQueryHTTPClientTest
|
||||||
/** A URL for use in the tests. */
|
{
|
||||||
private static final String URL = "http://this/is/a/url";
|
/** A URL for use in the tests. */
|
||||||
|
private static final String URL = "http://this/is/a/url";
|
||||||
/** The abstract class under test. */
|
|
||||||
private final AbstractSolrQueryHTTPClient abstractSolrQueryHTTPClient = spy(AbstractSolrQueryHTTPClient.class);
|
/** The abstract class under test. */
|
||||||
@Mock
|
private final AbstractSolrQueryHTTPClient abstractSolrQueryHTTPClient = spy(AbstractSolrQueryHTTPClient.class);
|
||||||
private HttpClient httpClient;
|
@Mock
|
||||||
@Mock
|
private HttpClient httpClient;
|
||||||
private JSONObject body;
|
@Mock
|
||||||
@Mock
|
private JSONObject body;
|
||||||
private PostMethod postMethod;
|
@Mock
|
||||||
@Mock
|
private PostMethod postMethod;
|
||||||
private Header header;
|
@Mock
|
||||||
|
private Header header;
|
||||||
@Before
|
|
||||||
public void setUp() throws Exception
|
@Before
|
||||||
{
|
public void setUp() throws Exception
|
||||||
openMocks(this);
|
{
|
||||||
|
openMocks(this);
|
||||||
doReturn(postMethod).when(abstractSolrQueryHTTPClient).createNewPostMethod(URL);
|
|
||||||
when(postMethod.getResponseCharSet()).thenReturn("UTF-8");
|
doReturn(postMethod).when(abstractSolrQueryHTTPClient).createNewPostMethod(URL);
|
||||||
}
|
when(postMethod.getResponseCharSet()).thenReturn("UTF-8");
|
||||||
|
}
|
||||||
/** Check postQuery works as expected for the success case. */
|
|
||||||
@Test
|
/** Check postQuery works as expected for the success case. */
|
||||||
public void testPostQuery_success() throws Exception
|
@Test
|
||||||
{
|
public void testPostQuery_success() throws Exception
|
||||||
when(body.toString()).thenReturn("Example body");
|
{
|
||||||
when(postMethod.getStatusCode()).thenReturn(HttpServletResponse.SC_OK);
|
when(body.toString()).thenReturn("Example body");
|
||||||
when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream("{}"));
|
when(postMethod.getStatusCode()).thenReturn(HttpServletResponse.SC_OK);
|
||||||
|
when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream("{}"));
|
||||||
JSONObject response = abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body);
|
|
||||||
|
JSONObject response = abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body);
|
||||||
assertEquals("Unexpected JSON response received.", "{}", response.toString());
|
|
||||||
}
|
assertEquals("Unexpected JSON response received.", "{}", response.toString());
|
||||||
|
}
|
||||||
/** Check that the status code is usually passed through from Solr. */
|
|
||||||
@Test
|
/** Check that the status code is usually passed through from Solr. */
|
||||||
public void testPostQuery_failure() throws Exception
|
@Test
|
||||||
{
|
public void testPostQuery_failure() throws Exception
|
||||||
String failureMessage = "{\"error\": {\"trace\": \"ExceptionClass: Stacktrace\"}}";
|
{
|
||||||
|
String failureMessage = "{\"error\": {\"trace\": \"ExceptionClass: Stacktrace\"}}";
|
||||||
when(body.toString()).thenReturn("Example body");
|
|
||||||
when(postMethod.getStatusCode()).thenReturn(HttpServletResponse.SC_NOT_FOUND);
|
when(body.toString()).thenReturn("Example body");
|
||||||
when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream(failureMessage));
|
when(postMethod.getStatusCode()).thenReturn(HttpServletResponse.SC_NOT_FOUND);
|
||||||
when(postMethod.getResponseBodyAsString()).thenReturn(failureMessage);
|
when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream(failureMessage));
|
||||||
|
when(postMethod.getResponseBodyAsString()).thenReturn(failureMessage);
|
||||||
try
|
|
||||||
{
|
try
|
||||||
abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body);
|
{
|
||||||
fail("Expected a QueryParserException to be thrown.");
|
abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body);
|
||||||
}
|
fail("Expected a QueryParserException to be thrown.");
|
||||||
catch (QueryParserException e)
|
}
|
||||||
{
|
catch (QueryParserException e)
|
||||||
assertEquals("Unexpected status code in exception.", e.getHttpStatusCode(), HttpServletResponse.SC_NOT_FOUND);
|
{
|
||||||
verify(postMethod).releaseConnection();
|
assertEquals("Unexpected status code in exception.", e.getHttpStatusCode(), HttpServletResponse.SC_NOT_FOUND);
|
||||||
}
|
verify(postMethod).releaseConnection();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/** Check that the status code is replaced with "Not Implemented" for an unsupported query option. */
|
|
||||||
@Test
|
/** Check that the status code is replaced with "Not Implemented" for an unsupported query option. */
|
||||||
public void testPostQuery_unsupportedOperation() throws Exception
|
@Test
|
||||||
{
|
public void testPostQuery_unsupportedOperation() throws Exception
|
||||||
String failureMessage = "{\"error\": {\"trace\": \"java.lang.UnsupportedOperationException: Stacktrace\"}}";
|
{
|
||||||
|
String failureMessage = "{\"error\": {\"trace\": \"java.lang.UnsupportedOperationException: Stacktrace\"}}";
|
||||||
when(body.toString()).thenReturn("Example body");
|
|
||||||
when(postMethod.getStatusCode()).thenReturn(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
when(body.toString()).thenReturn("Example body");
|
||||||
when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream(failureMessage));
|
when(postMethod.getStatusCode()).thenReturn(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||||
when(postMethod.getResponseBodyAsString()).thenReturn(failureMessage);
|
when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream(failureMessage));
|
||||||
|
when(postMethod.getResponseBodyAsString()).thenReturn(failureMessage);
|
||||||
try
|
|
||||||
{
|
try
|
||||||
abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body);
|
{
|
||||||
fail("Expected a QueryParserException to be thrown.");
|
abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body);
|
||||||
}
|
fail("Expected a QueryParserException to be thrown.");
|
||||||
catch (QueryParserException e)
|
}
|
||||||
{
|
catch (QueryParserException e)
|
||||||
assertEquals("Unexpected status code in exception.", e.getHttpStatusCode(), HttpServletResponse.SC_NOT_IMPLEMENTED);
|
{
|
||||||
}
|
assertEquals("Unexpected status code in exception.", e.getHttpStatusCode(), HttpServletResponse.SC_NOT_IMPLEMENTED);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/** Check that a redirect can be followed if the endpoint reports that it's moved. */
|
|
||||||
@Test
|
/** Check that a redirect can be followed if the endpoint reports that it's moved. */
|
||||||
public void testPostQuery_moved() throws Exception
|
@Test
|
||||||
{
|
public void testPostQuery_moved() throws Exception
|
||||||
when(body.toString()).thenReturn("Example body");
|
{
|
||||||
// Report "moved" for the first invocation and then OK for subsequent requests.
|
when(body.toString()).thenReturn("Example body");
|
||||||
when(postMethod.getStatusCode()).thenReturn(HttpServletResponse.SC_MOVED_PERMANENTLY).thenReturn(HttpServletResponse.SC_OK);
|
// Report "moved" for the first invocation and then OK for subsequent requests.
|
||||||
when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream("{}"));
|
when(postMethod.getStatusCode()).thenReturn(HttpServletResponse.SC_MOVED_PERMANENTLY).thenReturn(HttpServletResponse.SC_OK);
|
||||||
when(postMethod.getResponseHeader("location")).thenReturn(header);
|
when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream("{}"));
|
||||||
when(header.getValue()).thenReturn("http://new/URL");
|
when(postMethod.getResponseHeader("location")).thenReturn(header);
|
||||||
|
when(header.getValue()).thenReturn("http://new/URL");
|
||||||
JSONObject response = abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body);
|
|
||||||
|
JSONObject response = abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body);
|
||||||
verify(postMethod).setURI(new URI("http://new/URL", true));
|
|
||||||
assertEquals("Unexpected JSON response received.", "{}", response.toString());
|
verify(postMethod).setURI(new URI("http://new/URL", true));
|
||||||
}
|
assertEquals("Unexpected JSON response received.", "{}", response.toString());
|
||||||
|
}
|
||||||
@Test
|
|
||||||
public void testPostQuery_handlesIOException() throws Exception
|
@Test
|
||||||
{
|
public void testPostQuery_handlesIOException() throws Exception
|
||||||
String messageFromHttp = "Some IO Exception";
|
{
|
||||||
when(httpClient.executeMethod(any())).thenThrow(new IOException(messageFromHttp));
|
String messageFromHttp = "Some IO Exception";
|
||||||
|
when(httpClient.executeMethod(any())).thenThrow(new IOException(messageFromHttp));
|
||||||
HttpClientException expectedException =
|
|
||||||
assertThrows(HttpClientException.class, () -> abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body));
|
HttpClientException expectedException = assertThrows(HttpClientException.class, () -> abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body));
|
||||||
|
|
||||||
String exceptionMessage = expectedException.getMessage();
|
String exceptionMessage = expectedException.getMessage();
|
||||||
assertTrue(exceptionMessage.endsWith("[%s] %s".formatted(abstractSolrQueryHTTPClient.getClass().getSimpleName(), messageFromHttp)));
|
assertTrue(exceptionMessage.endsWith("[%s] %s".formatted(abstractSolrQueryHTTPClient.getClass().getSimpleName(), messageFromHttp)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Create an input stream containing the given string. */
|
/** Create an input stream containing the given string. */
|
||||||
private ByteArrayInputStream convertStringToInputStream(String message)
|
private ByteArrayInputStream convertStringToInputStream(String message)
|
||||||
{
|
{
|
||||||
return new ByteArrayInputStream(message.getBytes());
|
return new ByteArrayInputStream(message.getBytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user