Merged API-STRIKES-BACK (5.2.0) to HEAD (5.2)

126567 jvonka: Node Associations - further updates
   - for child assocs, do not expose assoc child qname (nominally like file/folder for primary child assoc)
   - additional api tests (+ve & -ve) for peer assocs & secondary child assocs
   - RA-745, RA-920, RA-921, RA-930, RA-742, RA-918, RA-919


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@127579 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Jamal Kaabi-Mofrad
2016-06-02 21:42:19 +00:00
parent db6dec979f
commit 4bb6852a79
9 changed files with 257 additions and 176 deletions

View File

@@ -137,6 +137,7 @@
<entry key="org.alfresco.rest.framework.core.exceptions.InvalidArgumentException" value="#{T(org.springframework.extensions.webscripts.Status).STATUS_BAD_REQUEST}" /> <entry key="org.alfresco.rest.framework.core.exceptions.InvalidArgumentException" value="#{T(org.springframework.extensions.webscripts.Status).STATUS_BAD_REQUEST}" />
<entry key="org.alfresco.rest.framework.core.exceptions.NotFoundException" value="#{T(org.springframework.extensions.webscripts.Status).STATUS_NOT_FOUND}" /> <entry key="org.alfresco.rest.framework.core.exceptions.NotFoundException" value="#{T(org.springframework.extensions.webscripts.Status).STATUS_NOT_FOUND}" />
<entry key="org.alfresco.rest.framework.core.exceptions.EntityNotFoundException" value="#{T(org.springframework.extensions.webscripts.Status).STATUS_NOT_FOUND}" /> <entry key="org.alfresco.rest.framework.core.exceptions.EntityNotFoundException" value="#{T(org.springframework.extensions.webscripts.Status).STATUS_NOT_FOUND}" />
<entry key="org.alfresco.service.cmr.repository.InvalidNodeRefException" value="#{T(org.springframework.extensions.webscripts.Status).STATUS_NOT_FOUND}" />
<entry key="org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException" value="#{T(org.springframework.extensions.webscripts.Status).STATUS_NOT_FOUND}" /> <entry key="org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException" value="#{T(org.springframework.extensions.webscripts.Status).STATUS_NOT_FOUND}" />
<entry key="org.alfresco.rest.framework.core.exceptions.PermissionDeniedException" value="#{T(org.springframework.extensions.webscripts.Status).STATUS_FORBIDDEN}" /> <entry key="org.alfresco.rest.framework.core.exceptions.PermissionDeniedException" value="#{T(org.springframework.extensions.webscripts.Status).STATUS_FORBIDDEN}" />
<entry key="org.alfresco.rest.framework.core.exceptions.UnsupportedResourceOperationException" value="#{T(org.springframework.extensions.webscripts.Status).STATUS_METHOD_NOT_ALLOWED}" /> <entry key="org.alfresco.rest.framework.core.exceptions.UnsupportedResourceOperationException" value="#{T(org.springframework.extensions.webscripts.Status).STATUS_METHOD_NOT_ALLOWED}" />

View File

@@ -915,8 +915,8 @@ public class NodesImpl implements Nodes
AssocChild childAssoc = new AssocChild( AssocChild childAssoc = new AssocChild(
parentAssocRef.getTypeQName().toPrefixString(namespaceService), parentAssocRef.getTypeQName().toPrefixString(namespaceService),
parentAssocRef.isPrimary(), parentAssocRef.isPrimary());
parentAssocRef.getQName().toPrefixString(namespaceService));
node.setAssociation(childAssoc); node.setAssociation(childAssoc);
} }

View File

@@ -24,37 +24,24 @@ package org.alfresco.rest.api.model;
public class AssocChild extends Assoc public class AssocChild extends Assoc
{ {
private String childId; private String childId;
private String prefixAssocChildQName;
private Boolean isPrimaryParent; private Boolean isPrimaryParent;
public AssocChild() public AssocChild()
{ {
} }
public AssocChild(String prefixAssocTypeQName, boolean isPrimaryParent, String prefixAssocChildQName) public AssocChild(String prefixAssocTypeQName, boolean isPrimaryParent)
{ {
super(prefixAssocTypeQName); super(prefixAssocTypeQName);
this.prefixAssocChildQName = prefixAssocChildQName;
this.isPrimaryParent = isPrimaryParent; this.isPrimaryParent = isPrimaryParent;
} }
public AssocChild(String childId, String prefixAssocTypeQName, String prefixAssocNameQName) public AssocChild(String childId, String prefixAssocTypeQName)
{ {
super(prefixAssocTypeQName); super(prefixAssocTypeQName);
this.childId = childId; this.childId = childId;
this.prefixAssocChildQName = prefixAssocNameQName;
}
public String getChildQName()
{
return prefixAssocChildQName;
}
public void setChildQName(String prefixAssocChildQName)
{
this.prefixAssocChildQName = prefixAssocChildQName;
} }
public Boolean getIsPrimaryParent() public Boolean getIsPrimaryParent()

View File

@@ -36,6 +36,7 @@ import org.alfresco.rest.framework.resource.parameters.where.Query;
import org.alfresco.rest.framework.resource.parameters.where.QueryHelper; import org.alfresco.rest.framework.resource.parameters.where.QueryHelper;
import org.alfresco.rest.workflow.api.impl.MapBasedQueryWalker; import org.alfresco.rest.workflow.api.impl.MapBasedQueryWalker;
import org.alfresco.service.ServiceRegistry; import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.AssociationExistsException; import org.alfresco.service.cmr.repository.AssociationExistsException;
import org.alfresco.service.cmr.repository.AssociationRef; import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
@@ -70,6 +71,7 @@ public class AbstractNodeRelation implements InitializingBean
protected ServiceRegistry sr; protected ServiceRegistry sr;
protected NodeService nodeService; protected NodeService nodeService;
protected NamespaceService namespaceService; protected NamespaceService namespaceService;
protected DictionaryService dictionaryService;
protected Nodes nodes; protected Nodes nodes;
public void setNodes(Nodes nodes) public void setNodes(Nodes nodes)
@@ -90,21 +92,42 @@ public class AbstractNodeRelation implements InitializingBean
this.nodeService = sr.getNodeService(); this.nodeService = sr.getNodeService();
this.namespaceService = sr.getNamespaceService(); this.namespaceService = sr.getNamespaceService();
this.dictionaryService = sr.getDictionaryService();
} }
protected QName getAssocType(String prefixAssocTypeStr, boolean mandatory) protected QName getAssocType(String prefixAssocTypeStr)
{ {
if (mandatory && ((prefixAssocTypeStr == null) || prefixAssocTypeStr.isEmpty())) return getAssocType(prefixAssocTypeStr, true, true);
}
protected QName getAssocType(String prefixAssocTypeStr, boolean mandatory, boolean validate)
{
QName assocType = null;
if ((prefixAssocTypeStr != null) && (! prefixAssocTypeStr.isEmpty()))
{
assocType = QName.createQName(prefixAssocTypeStr, namespaceService);
if (validate)
{
if (dictionaryService.getAssociation(assocType) == null)
{
throw new InvalidArgumentException("Unknown filter assocType: "+prefixAssocTypeStr);
}
}
}
else if (mandatory)
{ {
throw new InvalidArgumentException("Missing "+PARAM_ASSOC_TYPE); throw new InvalidArgumentException("Missing "+PARAM_ASSOC_TYPE);
} }
return QName.createQName(prefixAssocTypeStr, namespaceService); return assocType;
} }
protected QNamePattern getAssocTypeFromWhereElseAll(Parameters parameters) protected QNamePattern getAssocTypeFromWhereElseAll(Parameters parameters)
{ {
QNamePattern assocTypeQNameParam = RegexQNamePattern.MATCH_ALL; QNamePattern assocTypeQNamePattern = RegexQNamePattern.MATCH_ALL;
Query q = parameters.getQuery(); Query q = parameters.getQuery();
if (q != null) if (q != null)
@@ -115,10 +138,10 @@ public class AbstractNodeRelation implements InitializingBean
String assocTypeQNameStr = propertyWalker.getProperty(PARAM_ASSOC_TYPE, WhereClauseParser.EQUALS, String.class); String assocTypeQNameStr = propertyWalker.getProperty(PARAM_ASSOC_TYPE, WhereClauseParser.EQUALS, String.class);
if (assocTypeQNameStr != null) if (assocTypeQNameStr != null)
{ {
assocTypeQNameParam = getAssocType(assocTypeQNameStr, true); assocTypeQNamePattern = getAssocType(assocTypeQNameStr);
} }
} }
return assocTypeQNameParam; return assocTypeQNamePattern;
} }
} }

View File

@@ -41,20 +41,19 @@ import java.util.Map;
/** /**
* Node Parents * Node Parents
* *
* List node's parent(s) - primary & also secondary, if any - based on (parent ->) child associations
*
* @author janv * @author janv
*/ */
@RelationshipResource(name = "parents", entityResource = NodesEntityResource.class, title = "Node Parents") @RelationshipResource(name = "parents", entityResource = NodesEntityResource.class, title = "Node Parents")
public class NodeParentsRelation extends AbstractNodeRelation implements RelationshipResourceAction.Read<Node> public class NodeParentsRelation extends AbstractNodeRelation implements RelationshipResourceAction.Read<Node>
{ {
/** /**
* List parents * List child node's parent(s) based on (parent ->) child associations.
* Returns primary parent & also secondary parents, if any.
* *
* @param childNodeId String id of child node * @param childNodeId String id of child node
*/ */
@Override @Override
@WebApiDescription(title = "Return a paged list of parent nodes based on child assocs") @WebApiDescription(title = "Return a list of parent nodes based on child assocs")
public CollectionWithPagingInfo<Node> readAll(String childNodeId, Parameters parameters) public CollectionWithPagingInfo<Node> readAll(String childNodeId, Parameters parameters)
{ {
NodeRef childNodeRef = nodes.validateOrLookupNode(childNodeId, null); NodeRef childNodeRef = nodes.validateOrLookupNode(childNodeId, null);
@@ -84,7 +83,6 @@ public class NodeParentsRelation extends AbstractNodeRelation implements Relatio
Node node = nodes.getFolderOrDocument(assocRef.getParentRef(), null, null, includeParam, mapUserInfo); Node node = nodes.getFolderOrDocument(assocRef.getParentRef(), null, null, includeParam, mapUserInfo);
QName assocTypeQName = assocRef.getTypeQName(); QName assocTypeQName = assocRef.getTypeQName();
QName assocChildQName = assocRef.getQName();
String assocType = qnameMap.get(assocTypeQName); String assocType = qnameMap.get(assocTypeQName);
if (assocType == null) if (assocType == null)
@@ -93,14 +91,7 @@ public class NodeParentsRelation extends AbstractNodeRelation implements Relatio
qnameMap.put(assocTypeQName, assocType); qnameMap.put(assocTypeQName, assocType);
} }
String childQNameStr = qnameMap.get(assocChildQName); node.setAssociation(new AssocChild(assocType, assocRef.isPrimary()));
if (childQNameStr == null)
{
childQNameStr = assocChildQName.toPrefixString(namespaceService);
qnameMap.put(assocChildQName, childQNameStr);
}
node.setAssociation(new AssocChild(assocType, assocRef.isPrimary(), childQNameStr));
collection.add(node); collection.add(node);
} }

View File

@@ -18,11 +18,13 @@
*/ */
package org.alfresco.rest.api.nodes; package org.alfresco.rest.api.nodes;
import org.alfresco.model.ContentModel;
import org.alfresco.rest.api.model.AssocChild; import org.alfresco.rest.api.model.AssocChild;
import org.alfresco.rest.api.model.Node; import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.api.model.UserInfo; import org.alfresco.rest.api.model.UserInfo;
import org.alfresco.rest.framework.WebApiDescription; import org.alfresco.rest.framework.WebApiDescription;
import org.alfresco.rest.framework.core.exceptions.ConstraintViolatedException; import org.alfresco.rest.framework.core.exceptions.ConstraintViolatedException;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException; import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.resource.RelationshipResource; import org.alfresco.rest.framework.resource.RelationshipResource;
import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction; import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction;
@@ -33,6 +35,7 @@ import org.alfresco.service.cmr.repository.AssociationExistsException;
import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException; import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.QNamePattern; import org.alfresco.service.namespace.QNamePattern;
import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.service.namespace.RegexQNamePattern;
@@ -106,15 +109,7 @@ public class NodeSecondaryChildrenRelation extends AbstractNodeRelation implemen
qnameMap.put(assocTypeQName, assocType); qnameMap.put(assocTypeQName, assocType);
} }
QName assocChildQName = assocRef.getQName(); node.setAssociation(new AssocChild(assocType, assocRef.isPrimary()));
String childQNameStr = qnameMap.get(assocChildQName);
if (childQNameStr == null)
{
childQNameStr = assocChildQName.toPrefixString(namespaceService);
qnameMap.put(assocChildQName, childQNameStr);
}
node.setAssociation(new AssocChild(assocType, assocRef.isPrimary(), childQNameStr));
collection.add(node); collection.add(node);
} }
@@ -134,20 +129,16 @@ public class NodeSecondaryChildrenRelation extends AbstractNodeRelation implemen
for (AssocChild assoc : entity) for (AssocChild assoc : entity)
{ {
QName assocTypeQName = getAssocType(assoc.getAssocType(), true); QName assocTypeQName = getAssocType(assoc.getAssocType());
String childQNameStr = assoc.getChildQName();
if ((childQNameStr == null) || childQNameStr.isEmpty())
{
throw new InvalidArgumentException("Missing childQName");
}
QName childQName = QName.createQName(childQNameStr, namespaceService);
try try
{ {
NodeRef childNodeRef = nodes.validateNode(assoc.getChildId()); NodeRef childNodeRef = nodes.validateNode(assoc.getChildId());
nodeService.addChild(parentNodeRef, childNodeRef, assocTypeQName, childQName);
String nodeName = (String)nodeService.getProperty(childNodeRef, ContentModel.PROP_NAME);
QName assocChildQName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, QName.createValidLocalName(nodeName));
nodeService.addChild(parentNodeRef, childNodeRef, assocTypeQName, assocChildQName);
} }
catch (AssociationExistsException aee) catch (AssociationExistsException aee)
{ {
@@ -170,41 +161,53 @@ public class NodeSecondaryChildrenRelation extends AbstractNodeRelation implemen
NodeRef parentNodeRef = nodes.validateNode(parentNodeId); NodeRef parentNodeRef = nodes.validateNode(parentNodeId);
NodeRef childNodeRef = nodes.validateNode(childNodeId); NodeRef childNodeRef = nodes.validateNode(childNodeId);
QName assocTypeQName = getAssocType(parameters.getParameter("assocType"), false); String assocTypeStr = parameters.getParameter(PARAM_ASSOC_TYPE);
QName assocTypeQName = getAssocType(assocTypeStr, false, true);
String childQNameStr = parameters.getParameter("childQName"); List<ChildAssociationRef> assocRefs = nodeService.getChildAssocs(parentNodeRef);
QName childQName = null;
if ((childQNameStr != null) && (!childQNameStr.isEmpty()))
{
childQName = QName.createQName(childQNameStr, namespaceService);
}
if (assocTypeQName != null) boolean found = false;
for (ChildAssociationRef assocRef : assocRefs)
{ {
if (childQName != null) if (! assocRef.getChildRef().equals(childNodeRef))
{ {
ChildAssociationRef assocRef = new ChildAssociationRef(assocTypeQName, parentNodeRef, childQName, childNodeRef); continue;
nodeService.removeSecondaryChildAssociation(assocRef); }
if (assocTypeQName != null)
{
if (assocTypeQName.equals(assocRef.getTypeQName()))
{
if (assocRef.isPrimary())
{
throw new InvalidArgumentException("Cannot use secondary-children to delete primary assoc: "
+parentNodeId+","+assocTypeStr+","+childNodeId);
}
boolean existed = nodeService.removeSecondaryChildAssociation(assocRef);
if (existed)
{
found = true;
}
}
} }
else else
{ {
throw new InvalidArgumentException("Missing childQName (in addition to assocType)"); if (! assocRef.isPrimary())
}
}
else if (childQName != null)
{
throw new InvalidArgumentException("Missing assocType (in addition to childQName)");
}
else
{
List<ChildAssociationRef> assocRefs = nodeService.getChildAssocs(parentNodeRef);
for (ChildAssociationRef assocRef : assocRefs)
{
if (assocRef.getChildRef().equals(childNodeRef) && (! assocRef.isPrimary()))
{ {
nodeService.removeSecondaryChildAssociation(assocRef); boolean existed = nodeService.removeSecondaryChildAssociation(assocRef);
if (existed)
{
found = true;
}
} }
} }
} }
if (! found)
{
throw new EntityNotFoundException(parentNodeId+","+assocTypeStr+","+childNodeId);
}
} }
} }

View File

@@ -24,6 +24,8 @@ import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.api.model.UserInfo; import org.alfresco.rest.api.model.UserInfo;
import org.alfresco.rest.framework.WebApiDescription; import org.alfresco.rest.framework.WebApiDescription;
import org.alfresco.rest.framework.core.exceptions.ConstraintViolatedException; import org.alfresco.rest.framework.core.exceptions.ConstraintViolatedException;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.resource.RelationshipResource; import org.alfresco.rest.framework.resource.RelationshipResource;
import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction; import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
@@ -108,17 +110,25 @@ public class NodeTargetsRelation extends AbstractNodeRelation implements
for (AssocTarget assoc : entity) for (AssocTarget assoc : entity)
{ {
QName assocTypeQName = getAssocType(assoc.getAssocType(), true); String assocTypeStr = assoc.getAssocType();
QName assocTypeQName = getAssocType(assocTypeStr);
String targetNodeId = assoc.getTargetId();
try try
{ {
NodeRef tgtNodeRef = nodes.validateNode(assoc.getTargetId()); NodeRef tgtNodeRef = nodes.validateNode(targetNodeId);
nodeService.createAssociation(srcNodeRef, tgtNodeRef, assocTypeQName); nodeService.createAssociation(srcNodeRef, tgtNodeRef, assocTypeQName);
} }
catch (AssociationExistsException aee) catch (AssociationExistsException aee)
{ {
throw new ConstraintViolatedException(aee.getMessage()); throw new ConstraintViolatedException(aee.getMessage());
} }
catch (IllegalArgumentException iae)
{
// note: for now, we assume it is invalid assocType - alternatively, we could attempt to pre-validate via dictionary.getAssociation
throw new InvalidArgumentException(sourceNodeId+","+assocTypeStr+","+targetNodeId);
}
result.add(assoc); result.add(assoc);
} }
@@ -133,21 +143,31 @@ public class NodeTargetsRelation extends AbstractNodeRelation implements
NodeRef tgtNodeRef = nodes.validateNode(targetNodeId); NodeRef tgtNodeRef = nodes.validateNode(targetNodeId);
String assocTypeStr = parameters.getParameter(PARAM_ASSOC_TYPE); String assocTypeStr = parameters.getParameter(PARAM_ASSOC_TYPE);
if ((assocTypeStr != null) && (! assocTypeStr.isEmpty())) QNamePattern assocTypeQName = getAssocType(assocTypeStr, false, true);
if (assocTypeQName == null)
{ {
QName assocTypeQName = QName.createQName(assocTypeStr, namespaceService); assocTypeQName = RegexQNamePattern.MATCH_ALL;
nodeService.removeAssociation(srcNodeRef, tgtNodeRef, assocTypeQName);
} }
else
// note: even if assocType is provided, we currently don't use nodeService.removeAssociation(srcNodeRef, tgtNodeRef, assocTypeQName);
// since silent it returns void even if nothing deleted, where as we return 404
boolean found = false;
List<AssociationRef> assocRefs = nodeService.getTargetAssocs(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, sourceNodeId), assocTypeQName);
for (AssociationRef assocRef : assocRefs)
{ {
List<AssociationRef> assocRefs = nodeService.getTargetAssocs(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, sourceNodeId), RegexQNamePattern.MATCH_ALL); if (assocRef.getTargetRef().equals(tgtNodeRef))
for (AssociationRef assocRef : assocRefs)
{ {
if (assocRef.getTargetRef().equals(tgtNodeRef)) nodeService.removeAssociation(srcNodeRef, tgtNodeRef, assocRef.getTypeQName());
{ found = true;
nodeService.removeAssociation(srcNodeRef, tgtNodeRef, assocRef.getTypeQName());
}
} }
} }
if (! found)
{
throw new EntityNotFoundException(sourceNodeId+","+assocTypeStr+","+targetNodeId);
}
} }
} }

View File

@@ -21,19 +21,12 @@ package org.alfresco.rest.api.tests;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.rest.api.Nodes; import org.alfresco.rest.api.Nodes;
import org.alfresco.rest.api.Queries;
import org.alfresco.rest.api.model.AssocChild; import org.alfresco.rest.api.model.AssocChild;
import org.alfresco.rest.api.model.AssocTarget; import org.alfresco.rest.api.model.AssocTarget;
import org.alfresco.rest.api.tests.client.HttpResponse; import org.alfresco.rest.api.tests.client.HttpResponse;
import org.alfresco.rest.api.tests.client.PublicApiClient;
import org.alfresco.rest.api.tests.client.PublicApiClient.Paging; import org.alfresco.rest.api.tests.client.PublicApiClient.Paging;
import org.alfresco.rest.api.tests.client.RequestContext;
import org.alfresco.rest.api.tests.client.data.Association; import org.alfresco.rest.api.tests.client.data.Association;
import org.alfresco.rest.api.tests.client.data.ContentInfo;
import org.alfresco.rest.api.tests.client.data.Document;
import org.alfresco.rest.api.tests.client.data.Folder;
import org.alfresco.rest.api.tests.client.data.Node; import org.alfresco.rest.api.tests.client.data.Node;
import org.alfresco.rest.api.tests.client.data.Tag;
import org.alfresco.rest.api.tests.util.RestApiUtil; import org.alfresco.rest.api.tests.util.RestApiUtil;
import org.alfresco.service.cmr.security.MutableAuthenticationService; import org.alfresco.service.cmr.security.MutableAuthenticationService;
import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.cmr.security.PersonService;
@@ -44,12 +37,10 @@ import org.junit.Test;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID;
import static org.alfresco.rest.api.tests.util.RestApiUtil.toJsonAsStringNonNull; import static org.alfresco.rest.api.tests.util.RestApiUtil.toJsonAsStringNonNull;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@@ -100,9 +91,6 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
private static final String ASPECT_CM_PREFERENCES = "cm:preferences"; private static final String ASPECT_CM_PREFERENCES = "cm:preferences";
private static final String ASSOC_TYPE_CM_PREFERENCE_IMAGE = "cm:preferenceImage"; private static final String ASSOC_TYPE_CM_PREFERENCE_IMAGE = "cm:preferenceImage";
private static final String PARAM_CHILD_NAME = "childQName";
private String user1; private String user1;
private String user2; private String user2;
@@ -220,10 +208,6 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
Paging paging = getPaging(0, 100); Paging paging = getPaging(0, 100);
// -ve test - unauthenticated - belts-and-braces ;-)
getAll(getNodeTargetsUrl(f1Id), null, paging, null, 401);
getAll(getNodeSourcesUrl(f1Id), null, paging, null, 401);
// empty lists - before // empty lists - before
response = getAll(getNodeTargetsUrl(o1Id), user1, paging, null, 200); response = getAll(getNodeTargetsUrl(o1Id), user1, paging, null, 200);
@@ -242,13 +226,9 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
nodes = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Node.class); nodes = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Node.class);
assertEquals(0, nodes.size()); assertEquals(0, nodes.size());
// -ve test - unauthenticated - belts-and-braces ;-)
AssocTarget tgt = new AssocTarget(o2Id, ASSOC_TYPE_CM_REFERENCES);
post(getNodeTargetsUrl(o1Id), null, toJsonAsStringNonNull(tgt), 401);
// create two assocs in one direction (from src to tgt) // create two assocs in one direction (from src to tgt)
tgt = new AssocTarget(o2Id, ASSOC_TYPE_CM_REFERENCES); AssocTarget tgt = new AssocTarget(o2Id, ASSOC_TYPE_CM_REFERENCES);
post(getNodeTargetsUrl(o1Id), user1, toJsonAsStringNonNull(tgt), 201); post(getNodeTargetsUrl(o1Id), user1, toJsonAsStringNonNull(tgt), 201);
tgt = new AssocTarget(o2Id, ASSOC_TYPE_CM_PARTS); tgt = new AssocTarget(o2Id, ASSOC_TYPE_CM_PARTS);
@@ -311,7 +291,7 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
assertEquals(o2Id, nodes.get(0).getId()); assertEquals(o2Id, nodes.get(0).getId());
assertEquals(ASSOC_TYPE_CM_REFERENCES, nodes.get(0).getAssociation().getAssocType()); assertEquals(ASSOC_TYPE_CM_REFERENCES, nodes.get(0).getAssociation().getAssocType());
params = new HashMap<>(); params = new HashMap<>(1);
params.put("where", "(assocType='"+ASSOC_TYPE_CM_PARTS+"')"); params.put("where", "(assocType='"+ASSOC_TYPE_CM_PARTS+"')");
response = getAll(getNodeTargetsUrl(o2Id), user1, paging, params, 200); response = getAll(getNodeTargetsUrl(o2Id), user1, paging, params, 200);
@@ -326,10 +306,6 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
assertEquals(o1Id, nodes.get(0).getId()); assertEquals(o1Id, nodes.get(0).getId());
assertEquals(ASSOC_TYPE_CM_PARTS, nodes.get(0).getAssociation().getAssocType()); assertEquals(ASSOC_TYPE_CM_PARTS, nodes.get(0).getAssociation().getAssocType());
// -ve test - unauthenticated - belts-and-braces ;-)
delete(getNodeTargetsUrl(o1Id), null, o2Id, 401);
// remove assocs - specific type - in one direction // remove assocs - specific type - in one direction
params = new HashMap<>(2); params = new HashMap<>(2);
params.put(PARAM_ASSOC_TYPE, ASSOC_TYPE_CM_REFERENCES); params.put(PARAM_ASSOC_TYPE, ASSOC_TYPE_CM_REFERENCES);
@@ -393,18 +369,74 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
assertEquals(0, nodes.size()); assertEquals(0, nodes.size());
// -ve test - model integrity //
tgt = new AssocTarget(f2Id, ASSOC_TYPE_CM_REFERENCES); // -ve tests - add assoc
post(getNodeTargetsUrl(o1Id), user1, toJsonAsStringNonNull(tgt), 422); //
// -ve test - duplicate assoc {
tgt = new AssocTarget(o1Id, ASSOC_TYPE_CM_REFERENCES); // -ve test - unauthenticated - belts-and-braces ;-)
post(getNodeTargetsUrl(o2Id), user1, toJsonAsStringNonNull(tgt), 201); tgt = new AssocTarget(o2Id, ASSOC_TYPE_CM_REFERENCES);
post(getNodeTargetsUrl(o2Id), user1, toJsonAsStringNonNull(tgt), 409); post(getNodeTargetsUrl(o1Id), null, toJsonAsStringNonNull(tgt), 401);
// TODO some more negative tests // -ve test - model integrity
// 400s - eg. invalid qname tgt = new AssocTarget(f2Id, ASSOC_TYPE_CM_REFERENCES);
// 404s - eg. unknown src, tgt, assoc of given type post(getNodeTargetsUrl(o1Id), user1, toJsonAsStringNonNull(tgt), 422);
// -ve test - duplicate assoc
tgt = new AssocTarget(o1Id, ASSOC_TYPE_CM_REFERENCES);
post(getNodeTargetsUrl(o2Id), user1, toJsonAsStringNonNull(tgt), 201);
post(getNodeTargetsUrl(o2Id), user1, toJsonAsStringNonNull(tgt), 409);
tgt = new AssocTarget(o1Id, "cm:unknowntype");
post(getNodeTargetsUrl(o2Id), user1, toJsonAsStringNonNull(tgt), 400);
}
//
// -ve test - list assocs
//
{
// -ve test - unauthenticated - belts-and-braces ;-)
getAll(getNodeTargetsUrl(f1Id), null, paging, null, 401);
getAll(getNodeSourcesUrl(f1Id), null, paging, null, 401);
getAll(getNodeTargetsUrl(UUID.randomUUID().toString()), user1, paging, null, 404);
getAll(getNodeSourcesUrl(UUID.randomUUID().toString()), user1, paging, null, 404);
params = new HashMap<>(1);
params.put("where", "(assocType='cm:unknownassoctype')");
getAll(getNodeTargetsUrl(o1Id), user1, paging, params, 400);
getAll(getNodeSourcesUrl(o1Id), user1, paging, params, 400);
// TODO paging - in-built sort order ?
}
//
// -ve test - remove assoc(s)
//
{
// -ve test - unauthenticated - belts-and-braces ;-)
delete(getNodeTargetsUrl(o1Id), null, o2Id, 401);
delete(getNodeTargetsUrl(UUID.randomUUID().toString()), user1, o2Id, null, 404);
delete(getNodeTargetsUrl(o1Id), user1, UUID.randomUUID().toString(), null, 404);
// -ve test -nothing to delete - for any assoc type
delete(getNodeTargetsUrl(o1Id), user1, o2Id, null, 404);
// -ve test - nothing to delete - for given assoc type
params = new HashMap<>(2);
params.put(PARAM_ASSOC_TYPE, ASSOC_TYPE_CM_REFERENCES);
delete(getNodeTargetsUrl(o1Id), user1, o2Id, params, 404);
// -ve test - unknown assoc type
params = new HashMap<>(2);
params.put(PARAM_ASSOC_TYPE, "cm:unknowntype");
delete(getNodeTargetsUrl(o1Id), user1, o2Id, params, 400);
}
} }
finally finally
{ {
@@ -469,10 +501,6 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
Paging paging = getPaging(0, 100); Paging paging = getPaging(0, 100);
// -ve test - unauthenticated - belts-and-braces ;-)
getAll(getNodeSecondaryChildrenUrl(f1Id), null, paging, null, 401);
getAll(getNodeParentsUrl(o2Id), null, paging, null, 401);
// lists - before // lists - before
response = getAll(getNodeSecondaryChildrenUrl(f1Id), user1, paging, null, 200); response = getAll(getNodeSecondaryChildrenUrl(f1Id), user1, paging, null, 200);
@@ -485,22 +513,14 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
assertEquals(1, nodes.size()); assertEquals(1, nodes.size());
assertEquals(f2Id, nodes.get(0).getId()); assertEquals(f2Id, nodes.get(0).getId());
assertEquals(ASSOC_TYPE_CM_CONTAINS, nodes.get(0).getAssociation().getAssocType()); assertEquals(ASSOC_TYPE_CM_CONTAINS, nodes.get(0).getAssociation().getAssocType());
assertEquals("cm:"+o2Name, nodes.get(0).getAssociation().getChildQName());
assertTrue(nodes.get(0).getAssociation().getIsPrimaryParent()); assertTrue(nodes.get(0).getAssociation().getIsPrimaryParent());
String o2SecChildName = "cm:o2SecChildName";
// -ve test - unauthenticated - belts-and-braces ;-)
AssocChild secChild = new AssocChild(o2Id, ASSOC_TYPE_CM_CONTAINS, o2SecChildName);
post(getNodeSecondaryChildrenUrl(f1Id), null, toJsonAsStringNonNull(secChild), 401);
// create secondary child assoc // create secondary child assoc
secChild = new AssocChild(o2Id, ASSOC_TYPE_CM_CONTAINS, o2SecChildName); AssocChild secChild = new AssocChild(o2Id, ASSOC_TYPE_CM_CONTAINS);
post(getNodeSecondaryChildrenUrl(f1Id), user1, toJsonAsStringNonNull(secChild), 201); post(getNodeSecondaryChildrenUrl(f1Id), user1, toJsonAsStringNonNull(secChild), 201);
// create ano' secondary child assoc (different type) between the same two nodes // create ano' secondary child assoc (different type) between the same two nodes
secChild = new AssocChild(o2Id, ASSOC_TYPE_CM_PREFERENCE_IMAGE, o2SecChildName); secChild = new AssocChild(o2Id, ASSOC_TYPE_CM_PREFERENCE_IMAGE);
post(getNodeSecondaryChildrenUrl(f1Id), user1, toJsonAsStringNonNull(secChild), 201); post(getNodeSecondaryChildrenUrl(f1Id), user1, toJsonAsStringNonNull(secChild), 201);
@@ -520,7 +540,6 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
i++; i++;
} }
assertEquals(o2Id, node.getId()); assertEquals(o2Id, node.getId());
assertEquals(o2SecChildName, nodeAssoc.getChildQName());
assertFalse(nodeAssoc.getIsPrimaryParent()); assertFalse(nodeAssoc.getIsPrimaryParent());
} }
assertEquals(2, i); assertEquals(2, i);
@@ -536,7 +555,6 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
if (nodeId.equals(f2Id)) if (nodeId.equals(f2Id))
{ {
assertEquals(ASSOC_TYPE_CM_CONTAINS, nodeAssoc.getAssocType()); assertEquals(ASSOC_TYPE_CM_CONTAINS, nodeAssoc.getAssocType());
assertEquals("cm:"+o2Name, nodeAssoc.getChildQName());
assertTrue(nodeAssoc.getIsPrimaryParent()); assertTrue(nodeAssoc.getIsPrimaryParent());
i++; i++;
} }
@@ -550,7 +568,6 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
{ {
i++; i++;
} }
assertEquals(o2SecChildName, nodeAssoc.getChildQName());
assertFalse(nodeAssoc.getIsPrimaryParent()); assertFalse(nodeAssoc.getIsPrimaryParent());
} }
} }
@@ -577,14 +594,12 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
if (nodeId.equals(f2Id)) if (nodeId.equals(f2Id))
{ {
assertEquals(ASSOC_TYPE_CM_CONTAINS, nodeAssoc.getAssocType()); assertEquals(ASSOC_TYPE_CM_CONTAINS, nodeAssoc.getAssocType());
assertEquals("cm:"+o2Name, nodeAssoc.getChildQName());
assertTrue(nodeAssoc.getIsPrimaryParent()); assertTrue(nodeAssoc.getIsPrimaryParent());
i++; i++;
} }
else if (nodeId.equals(f1Id)) else if (nodeId.equals(f1Id))
{ {
assertEquals(ASSOC_TYPE_CM_CONTAINS, nodeAssoc.getAssocType()); assertEquals(ASSOC_TYPE_CM_CONTAINS, nodeAssoc.getAssocType());
assertEquals(o2SecChildName, nodeAssoc.getChildQName());
assertFalse(nodeAssoc.getIsPrimaryParent()); assertFalse(nodeAssoc.getIsPrimaryParent());
i++; i++;
} }
@@ -611,10 +626,6 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
params = new HashMap<>(2); params = new HashMap<>(2);
params.put(PARAM_ASSOC_TYPE, ASSOC_TYPE_CM_CONTAINS); params.put(PARAM_ASSOC_TYPE, ASSOC_TYPE_CM_CONTAINS);
params.put(PARAM_CHILD_NAME, o2SecChildName);
// -ve test - unauthenticated - belts-and-braces ;-)
delete(getNodeSecondaryChildrenUrl(f1Id), null, o2Id, params, 401);
// remove one secondary child assoc // remove one secondary child assoc
delete(getNodeSecondaryChildrenUrl(f1Id), user1, o2Id, params, 204); delete(getNodeSecondaryChildrenUrl(f1Id), user1, o2Id, params, 204);
@@ -629,7 +640,6 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
params = new HashMap<>(2); params = new HashMap<>(2);
params.put(PARAM_ASSOC_TYPE, ASSOC_TYPE_CM_PREFERENCE_IMAGE); params.put(PARAM_ASSOC_TYPE, ASSOC_TYPE_CM_PREFERENCE_IMAGE);
params.put(PARAM_CHILD_NAME, o2SecChildName);
// remove other secondary child assoc // remove other secondary child assoc
delete(getNodeSecondaryChildrenUrl(f1Id), user1, o2Id, params, 204); delete(getNodeSecondaryChildrenUrl(f1Id), user1, o2Id, params, 204);
@@ -642,26 +652,83 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
nodes = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Node.class); nodes = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Node.class);
assertEquals(1, nodes.size()); assertEquals(1, nodes.size());
// TODO test delete of multiple secondary child assocs (if assoc type is not specified) // TODO +ve test delete of multiple secondary child assocs (if assoc type is not specified)
//
// -ve tests - add assoc
//
// -ve test - model integrity {
secChild = new AssocChild(o2Id, ASSOC_TYPE_CM_CONTAINS, o2SecChildName); // -ve test - unauthenticated - belts-and-braces ;-)
post(getNodeSecondaryChildrenUrl(o1Id), user1, toJsonAsStringNonNull(secChild), 422); secChild = new AssocChild(o2Id, ASSOC_TYPE_CM_CONTAINS);
post(getNodeSecondaryChildrenUrl(f1Id), null, toJsonAsStringNonNull(secChild), 401);
// -ve test - duplicate assoc // -ve test - model integrity
secChild = new AssocChild(o2Id, ASSOC_TYPE_CM_CONTAINS, o2SecChildName); secChild = new AssocChild(o2Id, ASSOC_TYPE_CM_CONTAINS);
post(getNodeSecondaryChildrenUrl(f1Id), user1, toJsonAsStringNonNull(secChild), 201); post(getNodeSecondaryChildrenUrl(o1Id), user1, toJsonAsStringNonNull(secChild), 422);
post(getNodeSecondaryChildrenUrl(f1Id), user1, toJsonAsStringNonNull(secChild), 409);
// TODO some more negative tests // -ve test - duplicate assoc
// 400s - eg. invalid qname secChild = new AssocChild(o2Id, ASSOC_TYPE_CM_CONTAINS);
// 404s - eg. unknown src, tgt, assoc of given type post(getNodeSecondaryChildrenUrl(f1Id), user1, toJsonAsStringNonNull(secChild), 201);
post(getNodeSecondaryChildrenUrl(f1Id), user1, toJsonAsStringNonNull(secChild), 409);
delete(getNodeSecondaryChildrenUrl(f1Id), user1, o2Id, null, 204); // cleanup
secChild = new AssocChild(o2Id, "cm:unknowntype");
post(getNodeSecondaryChildrenUrl(f1Id), user1, toJsonAsStringNonNull(secChild), 400);
}
//
// -ve test - list assocs
//
{
// -ve test - unauthenticated - belts-and-braces ;-)
getAll(getNodeSecondaryChildrenUrl(f1Id), null, paging, null, 401);
getAll(getNodeParentsUrl(o2Id), null, paging, null, 401);
getAll(getNodeSecondaryChildrenUrl(UUID.randomUUID().toString()), user1, paging, null, 404);
getAll(getNodeParentsUrl(UUID.randomUUID().toString()), user1, paging, null, 404);
params = new HashMap<>(1);
params.put("where", "(assocType='cm:unknownassoctype')");
getAll(getNodeSecondaryChildrenUrl(o1Id), user1, paging, params, 400);
getAll(getNodeParentsUrl(o1Id), user1, paging, params, 400);
// TODO paging - in-built sort order ?
}
//
// -ve test - remove assoc(s)
//
{
// unauthenticated - belts-and-braces ;-)
delete(getNodeSecondaryChildrenUrl(f1Id), null, o2Id, null, 401);
delete(getNodeSecondaryChildrenUrl(UUID.randomUUID().toString()), user1, o2Id, null, 404);
delete(getNodeSecondaryChildrenUrl(f1Id), user1, UUID.randomUUID().toString(), null, 404);
// nothing to delete - for any assoc type
delete(getNodeSecondaryChildrenUrl(f1Id), user1, o2Id, null, 404);
// nothing to delete - for given assoc type
params = new HashMap<>(2);
params.put(PARAM_ASSOC_TYPE, ASSOC_TYPE_CM_PREFERENCE_IMAGE);
delete(getNodeSecondaryChildrenUrl(f1Id), user1, o2Id, params, 404);
// unknown assoc type
params = new HashMap<>(2);
params.put(PARAM_ASSOC_TYPE, "cm:unknowntype");
delete(getNodeSecondaryChildrenUrl(o1Id), user1, o2Id, params, 400);
// TODO 400 - try to delete primary assoc using /secondary-children
}
} }
finally finally
{ {
// some cleanup // some cleanup
Map<String, String> params = Collections.singletonMap("permanent", "true"); Map<String, String> params = Collections.singletonMap(Nodes.PARAM_PERMANENT, "true");
delete(URL_NODES, user1, f1Id, params, 204); delete(URL_NODES, user1, f1Id, params, 204);
delete(URL_NODES, user1, f2Id, params, 204); delete(URL_NODES, user1, f2Id, params, 204);
} }

View File

@@ -34,19 +34,8 @@ public class Association
} }
// child assoc // child assoc
private String prefixAssocChildQName;
private Boolean isPrimaryParent; private Boolean isPrimaryParent;
public String getChildQName()
{
return prefixAssocChildQName;
}
public void setChildQName(String prefixAssocChildQName)
{
this.prefixAssocChildQName = prefixAssocChildQName;
}
public Boolean getIsPrimaryParent() public Boolean getIsPrimaryParent()
{ {
return isPrimaryParent; return isPrimaryParent;