diff --git a/source/java/org/alfresco/rest/framework/webscripts/AbstractResourceWebScript.java b/source/java/org/alfresco/rest/framework/webscripts/AbstractResourceWebScript.java index 1945c6d639..b8bfb2b04a 100644 --- a/source/java/org/alfresco/rest/framework/webscripts/AbstractResourceWebScript.java +++ b/source/java/org/alfresco/rest/framework/webscripts/AbstractResourceWebScript.java @@ -27,8 +27,12 @@ package org.alfresco.rest.framework.webscripts; import java.io.IOException; import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; import java.util.Map; +import org.alfresco.repo.node.integrity.IntegrityException; import org.alfresco.repo.tenant.TenantUtil; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.web.scripts.content.ContentStreamer; @@ -134,6 +138,10 @@ public abstract class AbstractResourceWebScript extends ApiWebScript implements } } + catch (IntegrityException intException) + { + renderErrorResponse(resolveException(intException), res); + } catch (ApiException apiException) { renderErrorResponse(resolveException(apiException), res); @@ -204,17 +212,39 @@ public abstract class AbstractResourceWebScript extends ApiWebScript implements /** * The response status must be set before the response is written by Jackson (which will by default close and commit the response). * In a r/w txn, web script buffered responses ensure that it doesn't really matter but for r/o txns this is important. + * + * If you set content information via the contentInfo object and ALSO the headers then "headers" will win because they are + * set last. + * * @param res * @param status * @param cache * @param contentInfo * @param headers */ - protected void setResponse(final WebScriptResponse res, int status, Cache cache, ContentInfo contentInfo, Map headers) + public void setResponse(final WebScriptResponse res, int status, Cache cache, ContentInfo contentInfo, Map> headers) { res.setStatus(status); - res.setCache(cache); + if (cache != null) res.setCache(cache); setContentInfoOnResponse(res,contentInfo); + if (headers != null && !headers.isEmpty()) + { + for (Map.Entry> header:headers.entrySet()) + { + for (int i=0; i < header.getValue().size(); i++) { + if (i==0) + { + //If its the first one then set the header overwriting. + res.setHeader(header.getKey(), header.getValue().get(i)); + } + else + { + //If its not the first one than update the header + res.addHeader(header.getKey(), header.getValue().get(i)); + } + } + } + } } protected void setResponse(final WebScriptResponse res, WithResponse withResponse) diff --git a/source/java/org/alfresco/rest/framework/webscripts/WithResponse.java b/source/java/org/alfresco/rest/framework/webscripts/WithResponse.java index 44c17b4732..9309a7244f 100644 --- a/source/java/org/alfresco/rest/framework/webscripts/WithResponse.java +++ b/source/java/org/alfresco/rest/framework/webscripts/WithResponse.java @@ -3,7 +3,10 @@ package org.alfresco.rest.framework.webscripts; import org.alfresco.rest.framework.resource.content.ContentInfo; import org.springframework.extensions.webscripts.Cache; +import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -17,7 +20,7 @@ public class WithResponse { private ContentInfo contentInfo; private int status; - private Map headers; + private Map> headers; private Cache cache; public WithResponse(int status, ContentInfo contentInfo, Cache cache) @@ -57,7 +60,27 @@ public class WithResponse */ public void setHeader(String name, String value) { - headers.put(name, value); + headers.put(name, new ArrayList(Arrays.asList(value))); + } + + /** + * Adds a response header with the given name and value. This method + * allows a response header to have multiple values. + * + * @param name header name + * @param value header value + */ + public void addHeader(String name, String value) + { + List existing = headers.get(name); + if (existing != null) + { + existing.add(value); + } + else + { + setHeader(name, value); + } } /** @@ -85,10 +108,9 @@ public class WithResponse return cache; } - public Map getHeaders() + public Map> getHeaders() { return headers; } - } diff --git a/source/test-java/org/alfresco/rest/framework/tests/core/AllRestFrameworkTest.java b/source/test-java/org/alfresco/rest/framework/tests/core/AllRestFrameworkTest.java index 107f3a997b..0efa9069a9 100644 --- a/source/test-java/org/alfresco/rest/framework/tests/core/AllRestFrameworkTest.java +++ b/source/test-java/org/alfresco/rest/framework/tests/core/AllRestFrameworkTest.java @@ -35,7 +35,8 @@ import org.junit.runners.Suite.SuiteClasses; */ @RunWith(Suite.class) @SuiteClasses({ InspectorTests.class, JsonJacksonTests.class, ParamsExtractorTests.class, - ResourceLocatorTests.class, ResourceWebScriptHelperTests.class, SerializeTests.class, WhereTests.class, ExecutionTests.class }) + ResourceLocatorTests.class, ResourceWebScriptHelperTests.class, SerializeTests.class, + WhereTests.class, ExecutionTests.class, WithResponseTest.class }) public class AllRestFrameworkTest { diff --git a/source/test-java/org/alfresco/rest/framework/tests/core/WithResponseTest.java b/source/test-java/org/alfresco/rest/framework/tests/core/WithResponseTest.java new file mode 100644 index 0000000000..197877f536 --- /dev/null +++ b/source/test-java/org/alfresco/rest/framework/tests/core/WithResponseTest.java @@ -0,0 +1,159 @@ +package org.alfresco.rest.framework.tests.core; + +import static org.junit.Assert.*; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.alfresco.rest.framework.resource.content.ContentInfo; +import org.alfresco.rest.framework.resource.content.ContentInfoImpl; +import org.alfresco.rest.framework.webscripts.AbstractResourceWebScript; +import org.alfresco.rest.framework.webscripts.ApiWebScript; +import org.alfresco.rest.framework.webscripts.ResourceWebScriptDelete; +import org.alfresco.rest.framework.webscripts.WithResponse; +import org.junit.Before; +import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.springframework.extensions.webscripts.Cache; +import org.springframework.extensions.webscripts.Description; +import org.springframework.extensions.webscripts.Format; +import org.springframework.extensions.webscripts.Status; +import org.springframework.extensions.webscripts.WebScriptRequest; +import org.springframework.extensions.webscripts.WebScriptResponse; + +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +/** + * Created by gethin on 24/02/16. + */ +public class WithResponseTest +{ + + @Test + public void testDefaults() throws Exception + { + WithResponse callBack = new WithResponse(Status.STATUS_OK,ApiWebScript.DEFAULT_JSON_CONTENT, ApiWebScript.CACHE_NEVER); + assertEquals(Status.STATUS_OK, callBack.getStatus()); + assertEquals(ApiWebScript.DEFAULT_JSON_CONTENT, callBack.getContentInfo()); + assertEquals(ApiWebScript.CACHE_NEVER, callBack.getCache()); + assertTrue(callBack.getHeaders().isEmpty()); + } + + @Test + public void testSetHeader() throws Exception + { + WithResponse callBack = new WithResponse(Status.STATUS_OK,ApiWebScript.DEFAULT_JSON_CONTENT, ApiWebScript.CACHE_NEVER); + callBack.setHeader("king", "can"); + callBack.setHeader("king", "kong"); + assertTrue(callBack.getHeaders().size() == 1); + List vals = callBack.getHeaders().get("king"); + assertTrue(vals.size() == 1); + assertEquals("kong", vals.get(0)); + } + + @Test + public void testAddHeader() throws Exception + { + WithResponse callBack = new WithResponse(Status.STATUS_OK,ApiWebScript.DEFAULT_JSON_CONTENT, ApiWebScript.CACHE_NEVER); + callBack.addHeader("king", "can"); + callBack.addHeader("king", "kong"); + assertTrue(callBack.getHeaders().size() == 1); + List vals = callBack.getHeaders().get("king"); + assertTrue(vals.size() == 2); + assertEquals(vals, Arrays.asList("can", "kong")); + } + + + @Test + public void testSetters() throws Exception + { + WithResponse callBack = new WithResponse(Status.STATUS_OK, ApiWebScript.DEFAULT_JSON_CONTENT, ApiWebScript.CACHE_NEVER); + callBack.setStatus(Status.STATUS_GONE); + Cache myCache = new Cache(new Description.RequiredCache() + { + @Override + public boolean getNeverCache() + { + return false; + } + + @Override + public boolean getIsPublic() + { + return true; + } + + @Override + public boolean getMustRevalidate() + { + return true; + } + }); + callBack.setCache(myCache); + ContentInfo myContent = new ContentInfoImpl(Format.HTML.mimetype(),"UTF-16", 12, Locale.FRENCH); + callBack.setContentInfo(myContent); + + assertEquals(Status.STATUS_GONE, callBack.getStatus()); + assertEquals(myCache, callBack.getCache()); + assertEquals(myContent, callBack.getContentInfo()); + } + + + @Test + public void testSetResponse() throws Exception + { + AbstractResourceWebScript responseWriter = new ResourceWebScriptDelete(); + WithResponse wr = new WithResponse(Status.STATUS_OK, ApiWebScript.DEFAULT_JSON_CONTENT, ApiWebScript.CACHE_NEVER); + + WebScriptResponse response = mock(WebScriptResponse.class); + + responseWriter.setResponse(response,wr.getStatus(), wr.getCache(), wr.getContentInfo(), wr.getHeaders()); + verify(response, times(1)).setStatus(anyInt()); + verify(response, times(1)).setCache((Cache) any()); + verify(response, times(1)).setContentType(anyString()); + verify(response, times(0)).setHeader(anyString(), anyString()); + + response = mock(WebScriptResponse.class); + + responseWriter.setResponse(response,wr.getStatus(), null, null, null); + verify(response, times(1)).setStatus(anyInt()); + verify(response, times(0)).setCache((Cache) any()); + verify(response, times(0)).setContentType(anyString()); + verify(response, times(0)).setHeader(anyString(), anyString()); + + response = mock(WebScriptResponse.class); + + wr.addHeader("king", "can"); + wr.addHeader("king", "kong"); + responseWriter.setResponse(response,wr.getStatus(), null, null, wr.getHeaders()); + verify(response, times(1)).setStatus(anyInt()); + verify(response, times(0)).setCache((Cache) any()); + verify(response, times(0)).setContentType(anyString()); + verify(response, times(1)).setHeader(eq("king"), anyString()); + verify(response, times(1)).addHeader(eq("king"), anyString()); + + response = mock(WebScriptResponse.class); + + wr.addHeader("king", "kin"); + wr.setHeader("ping", "ping"); + responseWriter.setResponse(response,wr.getStatus(), null, null, wr.getHeaders()); + verify(response, times(1)).setStatus(anyInt()); + verify(response, times(0)).setCache((Cache) any()); + verify(response, times(0)).setContentType(anyString()); + verify(response, times(1)).setHeader(eq("king"), anyString()); + verify(response, times(1)).setHeader(eq("ping"), anyString()); + verify(response, times(2)).addHeader(eq("king"), anyString()); + + + } + +} \ No newline at end of file