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

126473 jkaabimofrad: Merged FILE-FOLDER-API (5.2.0) to HEAD (5.2)
      122418 gjames: RA-827 Supporting custom status codes


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.2.N/root@126817 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Ancuta Morarasu
2016-05-11 11:36:03 +00:00
parent 88b0a9159f
commit e1d542438c
19 changed files with 239 additions and 211 deletions

View File

@@ -27,6 +27,9 @@ package org.alfresco.rest.framework;
import static java.lang.annotation.ElementType.METHOD;
import org.alfresco.rest.framework.core.ResourceOperation;
import org.springframework.extensions.webscripts.Status;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@@ -41,5 +44,6 @@ import java.lang.annotation.Target;
public @interface WebApiDescription {
String title();
String description() default "";
int successStatus() default ResourceOperation.UNSET_STATUS;
}

View File

@@ -64,6 +64,7 @@ import org.alfresco.util.Pair;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.extensions.webscripts.Status;
import org.springframework.http.HttpMethod;
import org.springframework.util.ReflectionUtils;
@@ -294,14 +295,40 @@ public class ResourceInspector
Map<String, Object> annotAttribs = AnnotationUtils.getAnnotationAttributes(annot);
String title = String.valueOf(annotAttribs.get("title"));
String desc = String.valueOf(annotAttribs.get("description"));
return new ResourceOperation(httpMethod, title, desc, parameters);
Integer success = (Integer) annotAttribs.get("successStatus");
return new ResourceOperation(httpMethod, title, desc, parameters, validSuccessCode(httpMethod,success));
}
else {
return new ResourceOperation(httpMethod,
"Missing @WebApiDescription annotation", "This method should be annotated with @WebApiDescription", parameters);
"Missing @WebApiDescription annotation",
"This method should be annotated with @WebApiDescription", parameters, validSuccessCode(httpMethod, ResourceOperation.UNSET_STATUS));
}
}
public static int validSuccessCode(HttpMethod httpMethod, int success)
{
if (!(ResourceOperation.UNSET_STATUS == success))
{
//The status has been set by the api implementor so use it.
return success;
}
switch (httpMethod)
{
case GET:
return Status.STATUS_OK;
case POST:
return Status.STATUS_CREATED;
case PUT:
return Status.STATUS_OK;
case DELETE:
return Status.STATUS_NO_CONTENT;
default:
return Status.STATUS_OK;
}
}
/**
* Inspects the Method to find any @WebApiParameters and @WebApiParam
* @param resource the class

View File

@@ -72,7 +72,8 @@ public class ResourceLookupDictionary implements ResourceLocator
ResourceWithMetadata resource = apiResources.get(propertyResourceKey);
if (resource != null)
{
if (!resource.getMetaData().supports(httpMethod)) { throw new UnsupportedResourceOperationException(); }
ResourceOperation op = resource.getMetaData().getOperation(httpMethod);
if (op == null) { throw new UnsupportedResourceOperationException(); }
return resource;
}
@@ -104,7 +105,8 @@ public class ResourceLookupDictionary implements ResourceLocator
resource = apiResources.get(resourceKey);
if (resource != null)
{
if (!resource.getMetaData().supports(httpMethod)) { throw new UnsupportedResourceOperationException(); }
ResourceOperation op = resource.getMetaData().getOperation(httpMethod);
if (op == null) { throw new UnsupportedResourceOperationException(); }
return resource;
}
}
@@ -113,7 +115,8 @@ public class ResourceLookupDictionary implements ResourceLocator
}
else
{
if (!resource.getMetaData().supports(httpMethod)) { throw new UnsupportedResourceOperationException(); }
ResourceOperation op = resource.getMetaData().getOperation(httpMethod);
if (op == null) { throw new UnsupportedResourceOperationException(); }
return resource;
}
}

View File

@@ -72,17 +72,17 @@ public class ResourceMetadata
}
/**
* Indicates if this resource can support the specified HTTPMethod
* Gets the operation for the specified HTTPMethod
* @param supportedMethod HttpMethod
* @return true if can support it
* @return null if the operation is not supported
*/
public boolean supports(HttpMethod supportedMethod)
public ResourceOperation getOperation(HttpMethod supportedMethod)
{
for (ResourceOperation ops : operations)
{
if (ops.getHttpMethod().equals(supportedMethod)) return true;
if (ops.getHttpMethod().equals(supportedMethod)) return ops;
}
return false;
return null;
}
/**
@@ -91,23 +91,17 @@ public class ResourceMetadata
* @return true if can support it
*/
@SuppressWarnings("rawtypes")
public Class getObjectType(HttpMethod supportedMethod)
public Class getObjectType(ResourceOperation operation)
{
for (ResourceOperation ops : operations)
for (ResourceParameter param : operation.getParameters())
{
if (ops.getHttpMethod().equals(supportedMethod))
{
for (ResourceParameter param : ops.getParameters())
{
if (ResourceParameter.KIND.HTTP_BODY_OBJECT.equals(param.getParamType())) {
return param.getDataType();
}
}
if (ResourceParameter.KIND.HTTP_BODY_OBJECT.equals(param.getParamType())) {
return param.getDataType();
}
}
return null;
}
/**
* Indicates if this resource action is no longer supported.
* @param resourceAction Class<? extends ResourceAction>
@@ -210,20 +204,6 @@ public class ResourceMetadata
// }
// return Collections.emptyList();
// }
//
/**
* Gets the parameters for the specified http method.
* Matches the first operation.
* @param httpMethod HttpMethod
* @return If not found returns an empty list
*/
public List<ResourceParameter> getParameters(HttpMethod httpMethod)
{
for (ResourceOperation ops : operations)
{
if (ops.getHttpMethod().equals(httpMethod))return ops.getParameters();
}
return Collections.emptyList();
}
//
}

View File

@@ -36,24 +36,28 @@ import org.springframework.http.HttpMethod;
*/
public class ResourceOperation
{
public static final int UNSET_STATUS = -1;
private final HttpMethod httpMethod;
private final String title;
private final String description;
private final List<ResourceParameter> parameters;
private final int successStatus;
/**
* @param httpMethod HttpMethod
* @param title String
* @param description String
* @param parameters List<ResourceParameter>
* @param successStatus HTTP status
*/
public ResourceOperation(HttpMethod httpMethod, String title, String description, List<ResourceParameter> parameters)
public ResourceOperation(HttpMethod httpMethod, String title, String description, List<ResourceParameter> parameters, int successStatus)
{
super();
this.httpMethod = httpMethod;
this.title = title;
this.description = description;
this.parameters = parameters;
this.successStatus = successStatus;
}
public HttpMethod getHttpMethod()
@@ -76,6 +80,11 @@ public class ResourceOperation
return this.parameters;
}
public int getSuccessStatus()
{
return successStatus;
}
@Override
public String toString()
{
@@ -84,6 +93,8 @@ public class ResourceOperation
builder.append(this.httpMethod);
builder.append(", title=");
builder.append(this.title);
builder.append(", status=");
builder.append(this.successStatus);
builder.append(", description=");
builder.append(this.description);
builder.append(", parameters=");

View File

@@ -29,6 +29,7 @@ import org.alfresco.rest.framework.core.HttpMethodSupport;
import org.alfresco.rest.framework.core.ResourceWithMetadata;
import org.alfresco.rest.framework.resource.content.ContentInfo;
import org.alfresco.rest.framework.resource.parameters.Params;
import org.springframework.extensions.webscripts.Status;
/**
* Executes an action in the system
@@ -54,7 +55,7 @@ public interface ActionExecutor extends HttpMethodSupport
*/
public interface ExecutionCallback<R>
{
public void onSuccess(R result, ContentInfo contentInfo);
public void onSuccess(R result, ContentInfo contentInfo, int statusCode);
}
}

View File

@@ -117,11 +117,4 @@ public interface Parameters
* @return BasicContentInfo the content info
*/
BasicContentInfo getContentInfo();
/**
* Gets Web Script status
*
* @return {@link Status}
*/
public Status getStatus();
}

View File

@@ -55,7 +55,6 @@ public class Params implements Parameters
private final RecognizedParams recognizedParams;
private final String addressedProperty;
private final BasicContentInfo contentInfo;
private final Status status;
//Constants
private static final RecognizedParams NULL_PARAMS = new RecognizedParams(null, null, null, null, null, null, null, false);
@@ -71,7 +70,6 @@ public class Params implements Parameters
this.recognizedParams = recognizedParams;
this.addressedProperty = addressedProperty;
this.contentInfo = contentInfo==null?DEFAULT_CONTENT_INFO:contentInfo;
this.status = new Status();
}
public static Params valueOf(BeanPropertiesFilter paramFilter, String entityId)
@@ -241,12 +239,6 @@ public class Params implements Parameters
return contentInfo;
}
@Override
public Status getStatus()
{
return status;
}
/**
* A formal set of params that any rest service could potentially have passed in as request params
*/

View File

@@ -100,7 +100,7 @@ public abstract class AbstractResourceWebScript extends ApiWebScript implements
executor.execute(resource, params, new ExecutionCallback()
{
@Override
public void onSuccess(Object result, ContentInfo contentInfo)
public void onSuccess(Object result, ContentInfo contentInfo, int statusCode)
{
respons.put("toSerialize", result);
respons.put("contentInfo", contentInfo);
@@ -115,14 +115,9 @@ public abstract class AbstractResourceWebScript extends ApiWebScript implements
}
}
if (params.getStatus().getRedirect())
{
res.setStatus(params.getStatus().getCode());
}
else
{
setSuccessResponseStatus(res);
}
// 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.
res.setStatus(statusCode);
}
});
@@ -217,17 +212,6 @@ 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.
* @param res WebScriptResponse
*/
protected void setSuccessResponseStatus(final WebScriptResponse res)
{
// default for GET, HEAD, OPTIONS, PUT, TRACE
res.setStatus(Status.STATUS_OK);
}
/**
* Finds the action executor to execute actions on.
* @param httpMethod - the http method

View File

@@ -28,6 +28,7 @@ package org.alfresco.rest.framework.webscripts;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.rest.framework.core.ResourceLocator;
import org.alfresco.rest.framework.core.ResourceMetadata;
import org.alfresco.rest.framework.core.ResourceOperation;
import org.alfresco.rest.framework.core.ResourceWithMetadata;
import org.alfresco.rest.framework.core.exceptions.DeletedResourceException;
import org.alfresco.rest.framework.core.exceptions.UnsupportedResourceOperationException;
@@ -112,7 +113,7 @@ public class ResourceWebScriptDelete extends AbstractResourceWebScript implement
* @param params parameters to use
* @return anObject the result of the execute
*/
private Object executeInternal(ResourceWithMetadata resource, Params params)
private void executeInternal(ResourceWithMetadata resource, Params params)
{
switch (resource.getMetaData().getType())
{
@@ -124,7 +125,7 @@ public class ResourceWebScriptDelete extends AbstractResourceWebScript implement
EntityResourceAction.Delete entityDeleter = (EntityResourceAction.Delete) resource.getResource();
entityDeleter.delete(params.getEntityId(), params);
//Don't pass anything to the callback - its just successful
return null;
return;
case RELATIONSHIP:
if (resource.getMetaData().isDeleted(RelationshipResourceAction.Delete.class))
{
@@ -133,7 +134,7 @@ public class ResourceWebScriptDelete extends AbstractResourceWebScript implement
RelationshipResourceAction.Delete relationDeleter = (RelationshipResourceAction.Delete) resource.getResource();
relationDeleter.delete(params.getEntityId(), params.getRelationshipId(), params);
//Don't pass anything to the callback - its just successful
return null;
return;
case PROPERTY:
if (BinaryResourceAction.Delete.class.isAssignableFrom(resource.getResource().getClass()))
{
@@ -144,7 +145,7 @@ public class ResourceWebScriptDelete extends AbstractResourceWebScript implement
BinaryResourceAction.Delete binDeleter = (BinaryResourceAction.Delete) resource.getResource();
binDeleter.deleteProperty(params.getEntityId(), params);
//Don't pass anything to the callback - its just successful
return null;
return;
}
if (RelationshipResourceBinaryAction.Delete.class.isAssignableFrom(resource.getResource().getClass()))
{
@@ -155,7 +156,7 @@ public class ResourceWebScriptDelete extends AbstractResourceWebScript implement
RelationshipResourceBinaryAction.Delete binDeleter = (RelationshipResourceBinaryAction.Delete) resource.getResource();
binDeleter.deleteProperty(params.getEntityId(), params.getRelationshipId(), params);
//Don't pass anything to the callback - its just successful
return null;
return;
}
default:
throw new UnsupportedResourceOperationException("DELETE not supported for Actions");
@@ -171,17 +172,12 @@ public class ResourceWebScriptDelete extends AbstractResourceWebScript implement
@Override
public Void execute() throws Throwable
{
final ResourceOperation operation = resource.getMetaData().getOperation(HttpMethod.DELETE);
executeInternal(resource, params); //ignore return result
executionCallback.onSuccess(null, DEFAULT_JSON_CONTENT);
executionCallback.onSuccess(null, DEFAULT_JSON_CONTENT, operation.getSuccessStatus());
return null;
}
}, false, true);
}
@Override
protected void setSuccessResponseStatus(WebScriptResponse res)
{
res.setStatus(Status.STATUS_NO_CONTENT);
}
}

View File

@@ -29,6 +29,7 @@ import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransacti
import org.alfresco.rest.framework.core.ResourceInspector;
import org.alfresco.rest.framework.core.ResourceLocator;
import org.alfresco.rest.framework.core.ResourceMetadata;
import org.alfresco.rest.framework.core.ResourceOperation;
import org.alfresco.rest.framework.core.ResourceWithMetadata;
import org.alfresco.rest.framework.core.exceptions.DeletedResourceException;
import org.alfresco.rest.framework.core.exceptions.UnsupportedResourceOperationException;
@@ -47,6 +48,7 @@ import org.alfresco.rest.framework.resource.parameters.Params.RecognizedParams;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.http.HttpMethod;
@@ -234,6 +236,7 @@ public class ResourceWebScriptGet extends AbstractResourceWebScript implements P
@Override
public Void execute() throws Throwable
{
final ResourceOperation operation = resource.getMetaData().getOperation(HttpMethod.GET);
Object result = executeInternal(resource, params);
if (result instanceof BinaryResource)
{
@@ -242,11 +245,11 @@ public class ResourceWebScriptGet extends AbstractResourceWebScript implements P
{
ci = ((NodeBinaryResource)result).getContentInfo();
}
executionCallback.onSuccess(result, ci);
executionCallback.onSuccess(result, ci, operation.getSuccessStatus());
}
else
{
executionCallback.onSuccess(helper.processAdditionsToTheResponse(resource.getMetaData().getApi(), entityCollectionName, params, result), DEFAULT_JSON_CONTENT);
executionCallback.onSuccess(helper.processAdditionsToTheResponse(resource.getMetaData().getApi(), entityCollectionName, params, result), DEFAULT_JSON_CONTENT, operation.getSuccessStatus());
}
return null;
}

View File

@@ -635,7 +635,7 @@ public class ResourceWebScriptHelper
executor.execute(resource, executionParams, new ExecutionCallback()
{
@Override
public void onSuccess(Object result, ContentInfo contentInfo)
public void onSuccess(Object result, ContentInfo contentInfo, int statusCode)
{
resultOfExecution[0] = result;
}

View File

@@ -34,6 +34,7 @@ import org.alfresco.rest.framework.core.ResourceInspector;
import org.alfresco.rest.framework.core.ResourceInspectorUtil;
import org.alfresco.rest.framework.core.ResourceLocator;
import org.alfresco.rest.framework.core.ResourceMetadata;
import org.alfresco.rest.framework.core.ResourceOperation;
import org.alfresco.rest.framework.core.ResourceParameter;
import org.alfresco.rest.framework.core.ResourceWithMetadata;
import org.alfresco.rest.framework.core.exceptions.DeletedResourceException;
@@ -75,6 +76,7 @@ public class ResourceWebScriptPost extends AbstractResourceWebScript implements
final RecognizedParams params = ResourceWebScriptHelper.getRecognizedParams(req);
final String entityId = req.getServiceMatch().getTemplateVars().get(ResourceLocator.ENTITY_ID);
final String relationshipId = req.getServiceMatch().getTemplateVars().get(ResourceLocator.RELATIONSHIP_ID);
final ResourceOperation operation = resourceMeta.getOperation(HttpMethod.POST);
switch (resourceMeta.getType())
{
@@ -86,7 +88,7 @@ public class ResourceWebScriptPost extends AbstractResourceWebScript implements
}
else
{
Object postedObj = processRequest(resourceMeta, req);
Object postedObj = processRequest(resourceMeta, operation, req);
return Params.valueOf(null, params, postedObj);
}
case RELATIONSHIP:
@@ -96,7 +98,7 @@ public class ResourceWebScriptPost extends AbstractResourceWebScript implements
}
else
{
Object postedRel = processRequest(resourceMeta, req);
Object postedRel = processRequest(resourceMeta, operation, req);
return Params.valueOf(entityId, params, postedRel);
}
case OPERATION:
@@ -105,7 +107,7 @@ public class ResourceWebScriptPost extends AbstractResourceWebScript implements
if (StringUtils.isNotBlank(entityId) && StringUtils.isNotBlank(operationName))
{
Class objectType = resourceMeta.getObjectType(HttpMethod.POST);
Class objectType = resourceMeta.getObjectType(operation);
Object postedObj = null;
if (objectType!= null)
{
@@ -133,14 +135,14 @@ public class ResourceWebScriptPost extends AbstractResourceWebScript implements
* returns the {@link FormData}, otherwise it tries to extract the required
* object from the JSON payload.
*/
private Object processRequest(ResourceMetadata resourceMeta, WebScriptRequest req)
private Object processRequest(ResourceMetadata resourceMeta, ResourceOperation operation, WebScriptRequest req)
{
if (WebScriptRequestImpl.MULTIPART_FORM_DATA.equals(req.getContentType()))
{
return (FormData) req.parseContent();
}
return extractObjFromJson(resourceMeta, req);
return extractObjFromJson(resourceMeta, operation, req);
}
/**
@@ -150,10 +152,10 @@ public class ResourceWebScriptPost extends AbstractResourceWebScript implements
* @param req WebScriptRequest
* @return Either an object
*/
private Object extractObjFromJson(ResourceMetadata resourceMeta, WebScriptRequest req)
private Object extractObjFromJson(ResourceMetadata resourceMeta, ResourceOperation operation, WebScriptRequest req)
{
List<ResourceParameter> params = resourceMeta.getParameters(HttpMethod.POST);
Class<?> objType = resourceMeta.getObjectType(HttpMethod.POST);
List<ResourceParameter> params = operation.getParameters();
Class<?> objType = resourceMeta.getObjectType(operation);
if (!params.isEmpty())
{
@@ -218,6 +220,7 @@ public class ResourceWebScriptPost extends AbstractResourceWebScript implements
private Object executeInternal(ResourceWithMetadata resource, Params params) throws Throwable
{
final Object resObj = resource.getResource();
switch (resource.getMetaData().getType())
{
case ENTITY:
@@ -302,17 +305,13 @@ public class ResourceWebScriptPost extends AbstractResourceWebScript implements
@Override
public Void execute() throws Throwable
{
final ResourceOperation operation = resource.getMetaData().getOperation(HttpMethod.POST);
Object result = executeInternal(resource, params);
executionCallback.onSuccess(helper.processAdditionsToTheResponse(resource.getMetaData().getApi(), entityCollectionName, params, result), DEFAULT_JSON_CONTENT);
executionCallback.onSuccess(helper.processAdditionsToTheResponse(resource.getMetaData().getApi(), entityCollectionName, params, result),
DEFAULT_JSON_CONTENT, operation.getSuccessStatus());
return null;
}
}, false, true);
}
@Override
protected void setSuccessResponseStatus(WebScriptResponse res)
{
res.setStatus(Status.STATUS_CREATED);
}
}

View File

@@ -34,6 +34,7 @@ import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransacti
import org.alfresco.rest.framework.core.ResourceInspector;
import org.alfresco.rest.framework.core.ResourceLocator;
import org.alfresco.rest.framework.core.ResourceMetadata;
import org.alfresco.rest.framework.core.ResourceOperation;
import org.alfresco.rest.framework.core.ResourceWithMetadata;
import org.alfresco.rest.framework.core.exceptions.DeletedResourceException;
import org.alfresco.rest.framework.core.exceptions.UnsupportedResourceOperationException;
@@ -49,6 +50,7 @@ import org.alfresco.rest.framework.resource.parameters.Params.RecognizedParams;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WrappingWebScriptRequest;
import org.springframework.extensions.webscripts.servlet.WebScriptServletRequest;
@@ -78,7 +80,8 @@ public class ResourceWebScriptPut extends AbstractResourceWebScript implements P
final String relationshipId = req.getServiceMatch().getTemplateVars().get(ResourceLocator.RELATIONSHIP_ID);
final String entityId = req.getServiceMatch().getTemplateVars().get(ResourceLocator.ENTITY_ID);
final RecognizedParams params = ResourceWebScriptHelper.getRecognizedParams(req);
final ResourceOperation operation = resourceMeta.getOperation(HttpMethod.PUT);
switch (resourceMeta.getType())
{
case ENTITY:
@@ -88,7 +91,7 @@ public class ResourceWebScriptPut extends AbstractResourceWebScript implements P
} else
{
Object putEnt = ResourceWebScriptHelper.extractJsonContent(req, jsonHelper, resourceMeta.getObjectType(HttpMethod.PUT));
Object putEnt = ResourceWebScriptHelper.extractJsonContent(req, jsonHelper, resourceMeta.getObjectType(operation));
return Params.valueOf(entityId,params,putEnt);
}
case RELATIONSHIP:
@@ -97,7 +100,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(HttpMethod.PUT));
Object putRel = ResourceWebScriptHelper.extractJsonContent(req, jsonHelper, resourceMeta.getObjectType(operation));
ResourceWebScriptHelper.setUniqueId(putRel,relationshipId);
return Params.valueOf(entityId, params, putRel);
}
@@ -237,8 +240,10 @@ public class ResourceWebScriptPut extends AbstractResourceWebScript implements P
@Override
public Void execute() throws Throwable
{
final ResourceOperation operation = resource.getMetaData().getOperation(HttpMethod.PUT);
Object result = executeInternal(resource, params);
executionCallback.onSuccess(helper.processAdditionsToTheResponse(resource.getMetaData().getApi(), entityCollectionName, params, result), DEFAULT_JSON_CONTENT);
executionCallback.onSuccess(helper.processAdditionsToTheResponse(resource.getMetaData().getApi(), entityCollectionName, params, result),
DEFAULT_JSON_CONTENT, operation.getSuccessStatus());
return null;
}
}, false, true);