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/HEAD/root@127571 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Jamal Kaabi-Mofrad
2016-06-02 21:40:03 +00:00
parent 00c3315166
commit f17a4d19cf
24 changed files with 382 additions and 236 deletions

View File

@@ -45,6 +45,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;
@@ -145,11 +146,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);
}
}
@@ -157,7 +158,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>()
{
@@ -191,7 +192,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());
@@ -226,7 +227,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())
@@ -262,7 +263,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

@@ -32,6 +32,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;
@@ -57,10 +58,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
@@ -73,9 +71,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)
@@ -102,41 +99,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);
@@ -161,24 +135,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
@@ -195,97 +151,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

@@ -12,6 +12,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;
@@ -189,7 +190,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

@@ -58,6 +58,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;
@@ -668,7 +669,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

@@ -102,7 +102,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))
@@ -156,7 +156,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)
@@ -173,7 +173,7 @@ public class ResourceWebScriptPost extends AbstractResourceWebScript implements
}
}
}
return ResourceWebScriptHelper.extractJsonContentAsList(req, jsonHelper, objType);
return ResourceWebScriptHelper.extractJsonContentAsList(req, assistant.getJsonHelper(), objType);
}

View File

@@ -81,7 +81,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:
@@ -90,7 +90,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

@@ -52,8 +52,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

@@ -130,8 +130,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)