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

127571 jkaabimofrad: Merged API-STRIKES-BACK (5.2.0) to HEAD (5.2)
      126242 gjames: RA-878:All api errors should return the standard error object


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.2.N/root@127665 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Alan Davis
2016-06-03 14:14:04 +00:00
parent 4521ecaed9
commit b2fe847b6c
24 changed files with 364 additions and 236 deletions

View File

@@ -52,6 +52,7 @@ import org.alfresco.rest.framework.resource.content.ContentInfo;
import org.alfresco.rest.framework.resource.content.FileBinaryResource;
import org.alfresco.rest.framework.resource.content.NodeBinaryResource;
import org.alfresco.rest.framework.resource.parameters.Params;
import org.alfresco.rest.framework.tools.ApiAssistant;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -152,11 +153,11 @@ public abstract class AbstractResourceWebScript extends ApiWebScript implements
}
catch (AlfrescoRuntimeException | ApiException | WebScriptException xception )
{
renderErrorResponse(resolveException(xception), res);
assistant.renderException(xception, res);
}
catch (RuntimeException runtimeException)
{
renderErrorResponse(resolveException(runtimeException), res);
assistant.renderException(runtimeException, res);
}
}
@@ -164,7 +165,7 @@ public abstract class AbstractResourceWebScript extends ApiWebScript implements
{
final String entityCollectionName = ResourceInspector.findEntityCollectionNameName(resource.getMetaData());
final ResourceOperation operation = resource.getMetaData().getOperation(getHttpMethod());
final WithResponse callBack = new WithResponse(operation.getSuccessStatus(),DEFAULT_JSON_CONTENT,ApiWebScript.CACHE_NEVER);
final WithResponse callBack = new WithResponse(operation.getSuccessStatus(), ApiAssistant.DEFAULT_JSON_CONTENT,ApiAssistant.CACHE_NEVER);
Object toReturn = transactionService.getRetryingTransactionHelper().doInTransaction(
new RetryingTransactionHelper.RetryingTransactionCallback<Object>()
{
@@ -198,7 +199,7 @@ public abstract class AbstractResourceWebScript extends ApiWebScript implements
{
NodeBinaryResource nodeResource = (NodeBinaryResource) resource;
ContentInfo contentInfo = nodeResource.getContentInfo();
setContentInfoOnResponse(res, contentInfo);
assistant.setContentInfoOnResponse(res, contentInfo);
// if requested, set attachment
boolean attach = StringUtils.isNotEmpty(nodeResource.getAttachFileName());
Map<String, Object> model = getModelForCacheDirective(nodeResource.getCacheDirective());
@@ -233,7 +234,7 @@ public abstract class AbstractResourceWebScript extends ApiWebScript implements
{
res.setStatus(status);
if (cache != null) res.setCache(cache);
setContentInfoOnResponse(res,contentInfo);
assistant.setContentInfoOnResponse(res,contentInfo);
if (headers != null && !headers.isEmpty())
{
for (Map.Entry<String, List<String>> header:headers.entrySet())
@@ -269,7 +270,7 @@ public abstract class AbstractResourceWebScript extends ApiWebScript implements
protected void renderJsonResponse(final WebScriptResponse res, final Object toSerialize)
throws IOException
{
jsonHelper.withWriter(res.getOutputStream(), new JacksonHelper.Writer()
assistant.getJsonHelper().withWriter(res.getOutputStream(), new JacksonHelper.Writer()
{
@Override
public void writeContents(JsonGenerator generator, ObjectMapper objectMapper)

View File

@@ -39,6 +39,7 @@ import org.alfresco.rest.framework.jacksonextensions.JacksonHelper;
import org.alfresco.rest.framework.jacksonextensions.JacksonHelper.Writer;
import org.alfresco.rest.framework.resource.content.ContentInfo;
import org.alfresco.rest.framework.resource.content.ContentInfoImpl;
import org.alfresco.rest.framework.tools.ApiAssistant;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.GUID;
import org.alfresco.util.TempFileProvider;
@@ -64,10 +65,7 @@ import org.springframework.extensions.webscripts.servlet.WebScriptServletRespons
public abstract class ApiWebScript extends AbstractWebScript
{
private static Log logger = LogFactory.getLog(ApiWebScript.class);
protected JacksonHelper jsonHelper;
ExceptionResolver<Exception> defaultResolver = new DefaultExceptionResolver();
ExceptionResolver<Exception> resolver;
protected ApiAssistant assistant;
protected boolean encryptTempFiles = false;
protected String tempDirectoryName = null;
protected int memoryThreshold = 4 * 1024 * 1024; // 4mb
@@ -80,9 +78,8 @@ public abstract class ApiWebScript extends AbstractWebScript
this.transactionService = transactionService;
}
public void setDefaultResolver(ExceptionResolver<Exception> defaultResolver)
{
this.defaultResolver = defaultResolver;
public void setAssistant(ApiAssistant assistant) {
this.assistant = assistant;
}
public void setTempDirectoryName(String tempDirectoryName)
@@ -109,41 +106,18 @@ public abstract class ApiWebScript extends AbstractWebScript
{
this.streamFactory = streamFactory;
}
public void init()
{
File tempDirectory = TempFileProvider.getTempDir(tempDirectoryName);
this.streamFactory = ThresholdOutputStreamFactory.newInstance(tempDirectory, memoryThreshold, maxContentSize, encryptTempFiles);
}
public final static String UTF8 = "UTF-8";
public final static Cache CACHE_NEVER = new Cache(new RequiredCache()
{
@Override
public boolean getNeverCache()
{
return true;
}
@Override
public boolean getIsPublic()
{
return false;
}
@Override
public boolean getMustRevalidate()
{
return true;
}
});
public final static ContentInfo DEFAULT_JSON_CONTENT = new ContentInfoImpl(Format.JSON.mimetype(),UTF8, 0, null);
@Override
public void execute(final WebScriptRequest req, final WebScriptResponse res) throws IOException
{
Map<String, String> templateVars = req.getServiceMatch().getTemplateVars();
Api api = determineApi(templateVars);
Api api = assistant.determineApi(templateVars);
final BufferedRequest bufferedReq = getRequest(req);
final BufferedResponse bufferedRes = getResponse(res);
@@ -168,24 +142,6 @@ public abstract class ApiWebScript extends AbstractWebScript
}
}
public Api determineApi(Map<String, String> templateVars)
{
String apiScope = templateVars.get("apiScope");
String apiVersion = templateVars.get("apiVersion");
String apiName = templateVars.get("apiName");
return Api.valueOf(apiName,apiScope,apiVersion);
}
protected ErrorResponse resolveException(Exception ex)
{
ErrorResponse error = resolver.resolveException(ex);
if (error == null)
{
error = defaultResolver.resolveException(ex);
}
return error;
}
protected BufferedRequest getRequest(final WebScriptRequest req)
{
// create buffered request and response that allow transaction retrying
@@ -202,97 +158,4 @@ public abstract class ApiWebScript extends AbstractWebScript
public abstract void execute(final Api api, WebScriptRequest req, WebScriptResponse res) throws IOException;
/**
* Renders a JSON error response
* @param errorResponse The error
* @param res web script response
* @throws IOException
*/
public void renderErrorResponse(ErrorResponse errorResponse, final WebScriptResponse res) throws IOException {
String logId = "";
if (Status.STATUS_INTERNAL_SERVER_ERROR == errorResponse.getStatusCode() || logger.isDebugEnabled())
{
logId = GUID.generate();
logger.error(logId+" : "+errorResponse.getStackTrace());
}
String stackMessage = I18NUtil.getMessage(DefaultExceptionResolver.STACK_MESSAGE_ID);
final ErrorResponse errorToWrite = new ErrorResponse(errorResponse.getErrorKey(),
errorResponse.getStatusCode(),
errorResponse.getBriefSummary(),
stackMessage,
logId,
errorResponse.getAdditionalState(),
DefaultExceptionResolver.ERROR_URL);
setContentInfoOnResponse(res, DEFAULT_JSON_CONTENT);
// 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.
res.setStatus(errorToWrite.getStatusCode());
jsonHelper.withWriter(res.getOutputStream(), new Writer()
{
@SuppressWarnings("unchecked")
@Override
public void writeContents(JsonGenerator generator, ObjectMapper objectMapper)
throws JsonGenerationException, JsonMappingException, IOException
{
JSONObject obj = new JSONObject();
obj.put("error", errorToWrite);
objectMapper.writeValue(generator, obj);
}
});
}
/**
* Sets the response headers with any information we know about the content
* @param res WebScriptResponse
* @param contentInfo Content Information
*/
protected void setContentInfoOnResponse(WebScriptResponse res, ContentInfo contentInfo)
{
if (contentInfo != null)
{
//Set content info on the response
res.setContentType(contentInfo.getMimeType());
res.setContentEncoding(contentInfo.getEncoding());
if (res instanceof WrappingWebScriptResponse)
{
WrappingWebScriptResponse wrappedRes = ((WrappingWebScriptResponse) res);
res = wrappedRes.getNext();
}
if (res instanceof WebScriptServletResponse)
{
WebScriptServletResponse servletResponse = (WebScriptServletResponse) res;
if (contentInfo.getLength() > 0)
{
if (contentInfo.getLength() > 0 && contentInfo.getLength() < Integer.MAX_VALUE)
{
servletResponse.getHttpServletResponse().setContentLength((int) contentInfo.getLength());
}
}
if (contentInfo.getLocale() != null)
{
servletResponse.getHttpServletResponse().setLocale(contentInfo.getLocale());
}
}
}
}
public void setResolver(ExceptionResolver<Exception> resolver)
{
this.resolver = resolver;
}
public void setJsonHelper(JacksonHelper jsonHelper)
{
this.jsonHelper = jsonHelper;
}
}

View File

@@ -37,6 +37,7 @@ import org.alfresco.rest.framework.resource.actions.interfaces.EntityResourceAct
import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction;
import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceBinaryAction;
import org.alfresco.rest.framework.resource.parameters.Params;
import org.alfresco.rest.framework.tools.ApiAssistant;
import org.apache.commons.lang.StringUtils;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WebScriptResponse;
@@ -214,7 +215,7 @@ public class ResourceWebScriptDelete extends AbstractResourceWebScript implement
public Void execute(final ResourceWithMetadata resource, final Params params, final WebScriptResponse res, boolean isReadOnly)
{
final ResourceOperation operation = resource.getMetaData().getOperation(HttpMethod.DELETE);
final WithResponse callBack = new WithResponse(operation.getSuccessStatus(),DEFAULT_JSON_CONTENT,ApiWebScript.CACHE_NEVER);
final WithResponse callBack = new WithResponse(operation.getSuccessStatus(), ApiAssistant.DEFAULT_JSON_CONTENT,ApiAssistant.CACHE_NEVER);
transactionService.getRetryingTransactionHelper().doInTransaction(
new RetryingTransactionCallback<Void>()
{

View File

@@ -66,6 +66,7 @@ import org.alfresco.rest.framework.resource.parameters.where.InvalidQueryExcepti
import org.alfresco.rest.framework.resource.parameters.where.Query;
import org.alfresco.rest.framework.resource.parameters.where.QueryImpl;
import org.alfresco.rest.framework.resource.parameters.where.WhereCompiler;
import org.alfresco.rest.framework.tools.ApiAssistant;
import org.alfresco.util.Pair;
import org.alfresco.util.PropertyCheck;
import org.antlr.runtime.RecognitionException;
@@ -676,7 +677,7 @@ public class ResourceWebScriptHelper
paramFilter = filters.get(resourceKey);
}
final Params executionParams = Params.valueOf(paramFilter, uniqueEntityId, params.getRequest());
final WithResponse callBack = new WithResponse(Status.STATUS_OK,ApiWebScript.DEFAULT_JSON_CONTENT,ApiWebScript.CACHE_NEVER);
final WithResponse callBack = new WithResponse(Status.STATUS_OK, ApiAssistant.DEFAULT_JSON_CONTENT,ApiAssistant.CACHE_NEVER);
//Read only because this only occurs for GET requests
Object result = executor.executeAction(resource, executionParams, callBack);
return processAdditionsToTheResponse(null, api, null, executionParams, result);

View File

@@ -108,7 +108,7 @@ public class ResourceWebScriptPost extends AbstractResourceWebScript implements
if (objectType!= null)
{
//Operations don't support a List as json body
postedObj = ResourceWebScriptHelper.extractJsonContent(req, jsonHelper, objectType);
postedObj = ResourceWebScriptHelper.extractJsonContent(req, assistant.getJsonHelper(), objectType);
}
if (StringUtils.isNotBlank(propertyName))
@@ -162,7 +162,7 @@ public class ResourceWebScriptPost extends AbstractResourceWebScript implements
// Only allow 1 value.
try
{
Object content = ResourceWebScriptHelper.extractJsonContent(req,jsonHelper, objType);
Object content = ResourceWebScriptHelper.extractJsonContent(req,assistant.getJsonHelper(), objType);
return Arrays.asList(content);
}
catch (InvalidArgumentException iae)
@@ -179,7 +179,7 @@ public class ResourceWebScriptPost extends AbstractResourceWebScript implements
}
}
}
return ResourceWebScriptHelper.extractJsonContentAsList(req, jsonHelper, objType);
return ResourceWebScriptHelper.extractJsonContentAsList(req, assistant.getJsonHelper(), objType);
}

View File

@@ -87,7 +87,7 @@ public class ResourceWebScriptPut extends AbstractResourceWebScript implements P
} else
{
Object putEnt = ResourceWebScriptHelper.extractJsonContent(req, jsonHelper, resourceMeta.getObjectType(operation));
Object putEnt = ResourceWebScriptHelper.extractJsonContent(req, assistant.getJsonHelper(), resourceMeta.getObjectType(operation));
return Params.valueOf(entityId,params,putEnt, req);
}
case RELATIONSHIP:
@@ -96,7 +96,7 @@ public class ResourceWebScriptPut extends AbstractResourceWebScript implements P
throw new UnsupportedResourceOperationException("PUT is executed against the instance URL");
} else
{
Object putRel = ResourceWebScriptHelper.extractJsonContent(req, jsonHelper, resourceMeta.getObjectType(operation));
Object putRel = ResourceWebScriptHelper.extractJsonContent(req, assistant.getJsonHelper(), resourceMeta.getObjectType(operation));
ResourceWebScriptHelper.setUniqueId(putRel,relationshipId);
return Params.valueOf(entityId, params, putRel, req);
}

View File

@@ -77,8 +77,8 @@ public class InfoWebScriptGet extends ApiWebScript
{
throw new InvalidArgumentException(InvalidArgumentException.DEFAULT_INVALID_API);
}
jsonHelper.withWriter(res.getOutputStream(), new Writer()
assistant.getJsonHelper().withWriter(res.getOutputStream(), new Writer()
{
@Override
public void writeContents(JsonGenerator generator, ObjectMapper objectMapper)

View File

@@ -155,8 +155,8 @@ public class WebScriptOptionsMetaData extends ApiWebScript implements ResourceMe
{
final Object result = processResult(resource,allApiResources);
jsonHelper.withWriter(out, new Writer()
assistant.getJsonHelper().withWriter(out, new Writer()
{
@Override
public void writeContents(JsonGenerator generator, ObjectMapper objectMapper)