mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-14 17:58:59 +00:00
Merged HEAD (5.2) to 5.2.N (5.2.1)
126420 jkaabimofrad: Merged FILE-FOLDER-API (5.2.0) to HEAD (5.2) 121807 gjames: RA-774 Added basic action support git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.2.N/root@126766 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
19
source/java/org/alfresco/rest/framework/Action.java
Executable file
19
source/java/org/alfresco/rest/framework/Action.java
Executable file
@@ -0,0 +1,19 @@
|
||||
package org.alfresco.rest.framework;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* An action as on an entity in the Rest API
|
||||
*
|
||||
* @author Gethin James
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Action
|
||||
{
|
||||
String value();
|
||||
}
|
||||
|
@@ -37,6 +37,7 @@ import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.rest.framework.Action;
|
||||
import org.alfresco.rest.framework.Api;
|
||||
import org.alfresco.rest.framework.BinaryProperties;
|
||||
import org.alfresco.rest.framework.WebApi;
|
||||
@@ -134,12 +135,12 @@ public class ResourceInspector
|
||||
helper.operations, api, helper.apiDeleted, null));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inspectAddressedProperties(api, resource, urlPath, metainfo);
|
||||
inspectActions(api, resource, urlPath, metainfo);
|
||||
return metainfo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inspects the entity resource and returns meta data about any addresssed/binary properties
|
||||
* @param api Api
|
||||
@@ -323,8 +324,7 @@ public class ResourceInspector
|
||||
}
|
||||
if (paramsCount(params,ResourceParameter.KIND.HTTP_BODY_OBJECT) == 0)
|
||||
{
|
||||
Class<?> dType = ResourceInspectorUtil.determineType(resource,aMethod);
|
||||
params.add(ResourceParameter.valueOf(dType.getSimpleName().toUpperCase(), "The entity", "Unique entity properties", true, ResourceParameter.KIND.HTTP_BODY_OBJECT, true, dType));
|
||||
inspectBodyParamAndReturnType(resource, aMethod, params);
|
||||
}
|
||||
break;
|
||||
case PUT:
|
||||
@@ -339,8 +339,7 @@ public class ResourceInspector
|
||||
}
|
||||
if (paramsCount(params,ResourceParameter.KIND.HTTP_BODY_OBJECT)== 0)
|
||||
{
|
||||
Class<?> dType = ResourceInspectorUtil.determineType(resource,aMethod);
|
||||
params.add(ResourceParameter.valueOf(dType.getSimpleName().toUpperCase(), "The entity", "Unique entity properties", true, ResourceParameter.KIND.HTTP_BODY_OBJECT, true, dType));
|
||||
inspectBodyParamAndReturnType(resource, aMethod, params);
|
||||
}
|
||||
break;
|
||||
case GET:
|
||||
@@ -385,6 +384,12 @@ public class ResourceInspector
|
||||
return params;
|
||||
}
|
||||
|
||||
private static void inspectBodyParamAndReturnType(Class<?> resource, Method aMethod, List<ResourceParameter> params)
|
||||
{
|
||||
Class<?> dType = ResourceInspectorUtil.determineType(resource,aMethod);
|
||||
params.add(ResourceParameter.valueOf(dType.getSimpleName().toUpperCase(), "The entity", "Unique entity properties", true, KIND.HTTP_BODY_OBJECT, true, dType));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Indicates the number of params of the Kind specified
|
||||
@@ -536,6 +541,61 @@ public class ResourceInspector
|
||||
return embeds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inspect a resource to find actions on it.
|
||||
* @param api Api
|
||||
* @param resource Class<?>
|
||||
* @param entityPath String
|
||||
* @param metainfo List<ResourceMetadata>
|
||||
*/
|
||||
public static void inspectActions(Api api, Class<?> resource, final String entityPath, List<ResourceMetadata> metainfo)
|
||||
{
|
||||
Map<String,Pair<ResourceOperation,Method>> operations = findActions(entityPath, resource);
|
||||
if (operations != null && !operations.isEmpty())
|
||||
{
|
||||
for (Entry<String, Pair<ResourceOperation, Method>> opera : operations.entrySet())
|
||||
{
|
||||
if (isDeleted(opera.getValue().getSecond()))
|
||||
{
|
||||
metainfo.add(new ResourceMetadata(opera.getKey(), RESOURCE_TYPE.ACTION, null, api, new HashSet(Arrays.asList(opera.getValue().getFirst())), null));
|
||||
}
|
||||
else
|
||||
{
|
||||
metainfo.add(new ResourceMetadata(opera.getKey(), RESOURCE_TYPE.ACTION, Arrays.asList(opera.getValue().getFirst()), api, null, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds actions on an entity
|
||||
* @param entityPath path to the entity
|
||||
* @param anyClass resource clause
|
||||
* @return The operations
|
||||
*/
|
||||
private static Map<String,Pair<ResourceOperation,Method>> findActions(String entityPath, Class<?> anyClass)
|
||||
{
|
||||
Map<String, Pair<ResourceOperation,Method>> embeds = new HashMap<String, Pair<ResourceOperation,Method>>();
|
||||
List<Method> annotatedMethods = ResourceInspectorUtil.findMethodsByAnnotation(anyClass, Action.class);
|
||||
if (annotatedMethods != null && !annotatedMethods.isEmpty())
|
||||
{
|
||||
for (Method annotatedMethod : annotatedMethods)
|
||||
{
|
||||
Annotation annot = AnnotationUtils.findAnnotation(annotatedMethod, Action.class);
|
||||
if (annot != null)
|
||||
{
|
||||
Map<String, Object> annotAttribs = AnnotationUtils.getAnnotationAttributes(annot);
|
||||
String actionName = String.valueOf(annotAttribs.get("value"));
|
||||
String actionPath = ResourceDictionary.resourceKey(entityPath,actionName);
|
||||
ResourceOperation ro = inspectOperation(anyClass, annotatedMethod, HttpMethod.POST);
|
||||
embeds.put(actionPath, new Pair<ResourceOperation,Method>(ro,annotatedMethod));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return embeds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inspects the resource to determine what api it belongs to.
|
||||
* It does this by looking for the WebApi package annotation.
|
||||
|
@@ -78,7 +78,7 @@ public class ResourceInspectorUtil
|
||||
* @return - the List of Method or an empty List
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
protected static List<Method> findMethodsByAnnotation(Class objClass, Class<? extends Annotation> annotationType)
|
||||
public static List<Method> findMethodsByAnnotation(Class objClass, Class<? extends Annotation> annotationType)
|
||||
{
|
||||
|
||||
List<Method> annotatedMethods = new ArrayList<Method>();
|
||||
|
@@ -42,7 +42,7 @@ import org.springframework.http.HttpMethod;
|
||||
*/
|
||||
public class ResourceMetadata
|
||||
{
|
||||
public enum RESOURCE_TYPE {ENTITY,RELATIONSHIP, PROPERTY};
|
||||
public enum RESOURCE_TYPE {ENTITY, RELATIONSHIP, PROPERTY, ACTION};
|
||||
private final String uniqueId;
|
||||
private final RESOURCE_TYPE type;
|
||||
private final List<ResourceOperation> operations;
|
||||
|
@@ -25,6 +25,7 @@
|
||||
*/
|
||||
package org.alfresco.rest.framework.tests.api.mocks;
|
||||
|
||||
import org.alfresco.rest.framework.Action;
|
||||
import org.alfresco.rest.framework.WebApiDescription;
|
||||
import org.alfresco.rest.framework.WebApiParam;
|
||||
import org.alfresco.rest.framework.resource.EntityResource;
|
||||
@@ -42,4 +43,16 @@ public class GrassEntityResource implements EntityResourceAction.ReadById<Grass>
|
||||
return new Grass(id);
|
||||
}
|
||||
|
||||
@Action("cut")
|
||||
@WebApiDescription(title = "Cuts the grass")
|
||||
public String cutLawn(String id, Parameters parameters) {
|
||||
return "All done";
|
||||
}
|
||||
|
||||
@Action("grow")
|
||||
@WebApiDescription(title = "Grow the grass")
|
||||
public String growTheLawn(String id, Grass grass, Parameters parameters) {
|
||||
return "Growing well";
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -40,13 +40,17 @@ import java.util.Map;
|
||||
|
||||
import org.alfresco.rest.api.model.Comment;
|
||||
import org.alfresco.rest.api.nodes.NodeCommentsRelation;
|
||||
import org.alfresco.rest.framework.Action;
|
||||
import org.alfresco.rest.framework.Api;
|
||||
import org.alfresco.rest.framework.BinaryProperties;
|
||||
import org.alfresco.rest.framework.core.ResourceInspector;
|
||||
import org.alfresco.rest.framework.core.ResourceInspectorUtil;
|
||||
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.resource.actions.interfaces.BinaryResourceAction;
|
||||
import org.alfresco.rest.framework.resource.actions.interfaces.EntityResourceAction;
|
||||
import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction;
|
||||
import org.alfresco.rest.framework.tests.api.mocks.Farmer;
|
||||
import org.alfresco.rest.framework.tests.api.mocks.GoatEntityResource;
|
||||
import org.alfresco.rest.framework.tests.api.mocks.Grass;
|
||||
@@ -61,6 +65,7 @@ import org.alfresco.rest.framework.tests.api.mocks.SheepNoActionEntityResource;
|
||||
import org.alfresco.rest.framework.tests.api.mocks2.FarmersDaughter;
|
||||
import org.alfresco.rest.framework.tests.api.mocks2.FarmersGrandson;
|
||||
import org.alfresco.rest.framework.tests.api.mocks2.FarmersSon;
|
||||
import org.alfresco.rest.framework.tests.api.mocks3.Flock;
|
||||
import org.alfresco.rest.framework.tests.api.mocks3.FlockEntityResource;
|
||||
import org.alfresco.rest.framework.tests.api.mocks3.FlocketEntityResource;
|
||||
import org.alfresco.rest.framework.tests.api.mocks3.GrassEntityResourceNowDeleted;
|
||||
@@ -358,13 +363,83 @@ public class InspectorTests
|
||||
op = ResourceInspector.inspectOperation(FlockEntityResource.class, aMethod, HttpMethod.GET);
|
||||
assertNotNull(op);
|
||||
assertTrue(op.getTitle().startsWith("Deletes a photo"));
|
||||
|
||||
|
||||
aMethod = ResourceInspector.findMethod(BinaryResourceAction.Update.class, FlockEntityResource.class);
|
||||
op = ResourceInspector.inspectOperation(FlockEntityResource.class, aMethod, HttpMethod.GET);
|
||||
assertNotNull(op);
|
||||
assertTrue(op.getTitle().startsWith("Updates a photo"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testInspectBodyParam()
|
||||
{
|
||||
Method aMethod = ResourceInspector.findMethod(BinaryResourceAction.Update.class, FlockEntityResource.class);
|
||||
ResourceOperation op = ResourceInspector.inspectOperation(FlockEntityResource.class, aMethod, HttpMethod.PUT);
|
||||
assertNotNull(op);
|
||||
List<ResourceParameter> params = op.getParameters();
|
||||
assertNotNull(params);
|
||||
for (ResourceParameter param:params)
|
||||
{
|
||||
if (ResourceParameter.KIND.HTTP_BODY_OBJECT.equals(param.getParamType()))
|
||||
{
|
||||
assertEquals(Flock.class, param.getDataType());
|
||||
}
|
||||
}
|
||||
|
||||
aMethod = ResourceInspector.findMethod(RelationshipResourceAction.Create.class, SheepBlackSheepResource.class);
|
||||
op = ResourceInspector.inspectOperation(SheepBlackSheepResource.class, aMethod, HttpMethod.POST);
|
||||
assertNotNull(op);
|
||||
params = op.getParameters();
|
||||
assertNotNull(params);
|
||||
for (ResourceParameter param:params)
|
||||
{
|
||||
if (ResourceParameter.KIND.HTTP_BODY_OBJECT.equals(param.getParamType()))
|
||||
{
|
||||
assertEquals(Sheep.class, param.getDataType());
|
||||
}
|
||||
}
|
||||
|
||||
aMethod = ResourceInspector.findMethod(EntityResourceAction.Update.class, SheepEntityResourceWithDeletedMethods.class);
|
||||
op = ResourceInspector.inspectOperation(SheepEntityResourceWithDeletedMethods.class, aMethod, HttpMethod.POST);
|
||||
assertNotNull(op);
|
||||
params = op.getParameters();
|
||||
assertNotNull(params);
|
||||
for (ResourceParameter param:params)
|
||||
{
|
||||
if (ResourceParameter.KIND.HTTP_BODY_OBJECT.equals(param.getParamType()))
|
||||
{
|
||||
assertEquals(Sheep.class, param.getDataType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInspectActions()
|
||||
{
|
||||
Api api = Api.valueOf("alfrescomock", "private", "1");
|
||||
List<ResourceMetadata> metainfo = new ArrayList<ResourceMetadata>();
|
||||
|
||||
ResourceInspector.inspectActions(api, GrassEntityResource.class,"-root-", metainfo);
|
||||
assertTrue(metainfo.size()==2);
|
||||
for (ResourceMetadata resourceMetadata : metainfo)
|
||||
{
|
||||
assertEquals(ResourceMetadata.RESOURCE_TYPE.ACTION, resourceMetadata.getType());
|
||||
switch (resourceMetadata.getUniqueId())
|
||||
{
|
||||
case "/-root-/{entityId}/grow":
|
||||
assertTrue("GrassEntityResource supports POST", resourceMetadata.supports(HttpMethod.POST));
|
||||
assertFalse("GrassEntityResource does not support DELETE", resourceMetadata.supports(HttpMethod.DELETE));
|
||||
break;
|
||||
case "/-root-/{entityId}/cut":
|
||||
assertTrue("GrassEntityResource supports POST", resourceMetadata.supports(HttpMethod.POST));
|
||||
assertFalse("GrassEntityResource does not support GET", resourceMetadata.supports(HttpMethod.GET));
|
||||
break;
|
||||
default:
|
||||
fail("Invalid action information.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInspectAddressedProperties()
|
||||
{
|
||||
|
@@ -455,6 +455,18 @@ public class ParamsExtractorTests
|
||||
//when(resourceMock.getObjectType(HttpMethod.POST)).thenReturn(Farmer.class);
|
||||
return resourceMock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mocks an action
|
||||
* @return ResourceMetadata a Entity
|
||||
*/
|
||||
private static ResourceMetadata mockAction()
|
||||
{
|
||||
ResourceMetadata resourceMock = mock(ResourceMetadata.class);
|
||||
when(resourceMock.getType()).thenReturn(ResourceMetadata.RESOURCE_TYPE.ACTION);
|
||||
return resourceMock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mocks a Relationship Resource
|
||||
* @return ResourceMetadata a Relationship
|
||||
|
@@ -32,9 +32,11 @@ import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
@@ -51,6 +53,7 @@ import org.alfresco.rest.framework.resource.EntityResource;
|
||||
import org.alfresco.rest.framework.resource.RelationshipResource;
|
||||
import org.alfresco.rest.framework.tests.api.mocks.Farmer;
|
||||
import org.alfresco.rest.framework.tests.api.mocks.GoatEntityResource;
|
||||
import org.alfresco.rest.framework.tests.api.mocks.GrassEntityResource;
|
||||
import org.alfresco.rest.framework.tests.api.mocks.SheepBaaaahResource;
|
||||
import org.alfresco.rest.framework.tests.api.mocks.SheepBlackSheepResource;
|
||||
import org.alfresco.rest.framework.tests.api.mocks.SheepEntityResource;
|
||||
@@ -148,7 +151,30 @@ public class ResourceLocatorTests
|
||||
collResource = locator.locateResource(api,templateVars, HttpMethod.GET);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLocateActions()
|
||||
{
|
||||
Map<String, String> templateVars = new HashMap<String, String>();
|
||||
ResourceWithMetadata collResource = null;
|
||||
templateVars.put(ResourceLocator.COLLECTION_RESOURCE, "grass");
|
||||
templateVars.put(ResourceLocator.ENTITY_ID, "grassId");
|
||||
templateVars.put(ResourceLocator.RELATIONSHIP_RESOURCE, "cut");
|
||||
try
|
||||
{
|
||||
collResource = locator.locateResource(api, templateVars, HttpMethod.GET);
|
||||
fail("Should throw an UnsupportedResourceOperationException");
|
||||
}
|
||||
catch (UnsupportedResourceOperationException error)
|
||||
{
|
||||
//this is correct
|
||||
}
|
||||
|
||||
collResource = locator.locateResource(api, templateVars, HttpMethod.POST);
|
||||
assertEquals(GrassEntityResource.class, collResource.getResource().getClass());
|
||||
assertEquals(ResourceMetadata.RESOURCE_TYPE.ACTION, collResource.getMetaData().getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocateProperties()
|
||||
{
|
||||
|
Reference in New Issue
Block a user