Merged HEAD (5.2) to 5.2.N (5.2.1)

126496 jkaabimofrad: Merged FILE-FOLDER-API (5.2.0) to HEAD (5.2)
      122700 gjames: RA-211: Response header handling


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.2.N/root@126840 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Ancuta Morarasu
2016-05-11 11:45:04 +00:00
parent b6eec668c7
commit 551eb0b4d7
4 changed files with 219 additions and 7 deletions

View File

@@ -27,8 +27,12 @@ package org.alfresco.rest.framework.webscripts;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map; import java.util.Map;
import org.alfresco.repo.node.integrity.IntegrityException;
import org.alfresco.repo.tenant.TenantUtil; import org.alfresco.repo.tenant.TenantUtil;
import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.web.scripts.content.ContentStreamer; 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) catch (ApiException apiException)
{ {
renderErrorResponse(resolveException(apiException), res); 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). * 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. * 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 res
* @param status * @param status
* @param cache * @param cache
* @param contentInfo * @param contentInfo
* @param headers * @param headers
*/ */
protected void setResponse(final WebScriptResponse res, int status, Cache cache, ContentInfo contentInfo, Map<String, String> headers) public void setResponse(final WebScriptResponse res, int status, Cache cache, ContentInfo contentInfo, Map<String, List<String>> headers)
{ {
res.setStatus(status); res.setStatus(status);
res.setCache(cache); if (cache != null) res.setCache(cache);
setContentInfoOnResponse(res,contentInfo); setContentInfoOnResponse(res,contentInfo);
if (headers != null && !headers.isEmpty())
{
for (Map.Entry<String, List<String>> 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) protected void setResponse(final WebScriptResponse res, WithResponse withResponse)

View File

@@ -3,7 +3,10 @@ package org.alfresco.rest.framework.webscripts;
import org.alfresco.rest.framework.resource.content.ContentInfo; import org.alfresco.rest.framework.resource.content.ContentInfo;
import org.springframework.extensions.webscripts.Cache; import org.springframework.extensions.webscripts.Cache;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
@@ -17,7 +20,7 @@ public class WithResponse
{ {
private ContentInfo contentInfo; private ContentInfo contentInfo;
private int status; private int status;
private Map<String, String> headers; private Map<String, List<String>> headers;
private Cache cache; private Cache cache;
public WithResponse(int status, ContentInfo contentInfo, Cache cache) public WithResponse(int status, ContentInfo contentInfo, Cache cache)
@@ -57,7 +60,27 @@ public class WithResponse
*/ */
public void setHeader(String name, String value) public void setHeader(String name, String value)
{ {
headers.put(name, value); headers.put(name, new ArrayList<String>(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<String> existing = headers.get(name);
if (existing != null)
{
existing.add(value);
}
else
{
setHeader(name, value);
}
} }
/** /**
@@ -85,10 +108,9 @@ public class WithResponse
return cache; return cache;
} }
public Map<String, String> getHeaders() public Map<String, List<String>> getHeaders()
{ {
return headers; return headers;
} }
} }

View File

@@ -35,7 +35,8 @@ import org.junit.runners.Suite.SuiteClasses;
*/ */
@RunWith(Suite.class) @RunWith(Suite.class)
@SuiteClasses({ InspectorTests.class, JsonJacksonTests.class, ParamsExtractorTests.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 public class AllRestFrameworkTest
{ {

View File

@@ -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<String> 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<String> 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());
}
}