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

127579 jkaabimofrad: 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/BRANCHES/DEV/5.2.N/root@127672 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Alan Davis
2016-06-03 14:14:43 +00:00
parent c49322624a
commit 50af2e5cc1
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.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.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.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}" />

View File

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

View File

@@ -24,37 +24,24 @@ package org.alfresco.rest.api.model;
public class AssocChild extends Assoc
{
private String childId;
private String prefixAssocChildQName;
private Boolean isPrimaryParent;
public AssocChild()
{
}
public AssocChild(String prefixAssocTypeQName, boolean isPrimaryParent, String prefixAssocChildQName)
public AssocChild(String prefixAssocTypeQName, boolean isPrimaryParent)
{
super(prefixAssocTypeQName);
this.prefixAssocChildQName = prefixAssocChildQName;
this.isPrimaryParent = isPrimaryParent;
}
public AssocChild(String childId, String prefixAssocTypeQName, String prefixAssocNameQName)
public AssocChild(String childId, String prefixAssocTypeQName)
{
super(prefixAssocTypeQName);
this.childId = childId;
this.prefixAssocChildQName = prefixAssocNameQName;
}
public String getChildQName()
{
return prefixAssocChildQName;
}
public void setChildQName(String prefixAssocChildQName)
{
this.prefixAssocChildQName = prefixAssocChildQName;
}
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.workflow.api.impl.MapBasedQueryWalker;
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.AssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -70,6 +71,7 @@ public class AbstractNodeRelation implements InitializingBean
protected ServiceRegistry sr;
protected NodeService nodeService;
protected NamespaceService namespaceService;
protected DictionaryService dictionaryService;
protected Nodes nodes;
public void setNodes(Nodes nodes)
@@ -90,21 +92,42 @@ public class AbstractNodeRelation implements InitializingBean
this.nodeService = sr.getNodeService();
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);
}
return QName.createQName(prefixAssocTypeStr, namespaceService);
return assocType;
}
protected QNamePattern getAssocTypeFromWhereElseAll(Parameters parameters)
{
QNamePattern assocTypeQNameParam = RegexQNamePattern.MATCH_ALL;
QNamePattern assocTypeQNamePattern = RegexQNamePattern.MATCH_ALL;
Query q = parameters.getQuery();
if (q != null)
@@ -115,10 +138,10 @@ public class AbstractNodeRelation implements InitializingBean
String assocTypeQNameStr = propertyWalker.getProperty(PARAM_ASSOC_TYPE, WhereClauseParser.EQUALS, String.class);
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
*
* List node's parent(s) - primary & also secondary, if any - based on (parent ->) child associations
*
* @author janv
*/
@RelationshipResource(name = "parents", entityResource = NodesEntityResource.class, title = "Node Parents")
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
*/
@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)
{
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);
QName assocTypeQName = assocRef.getTypeQName();
QName assocChildQName = assocRef.getQName();
String assocType = qnameMap.get(assocTypeQName);
if (assocType == null)
@@ -93,14 +91,7 @@ public class NodeParentsRelation extends AbstractNodeRelation implements Relatio
qnameMap.put(assocTypeQName, assocType);
}
String childQNameStr = qnameMap.get(assocChildQName);
if (childQNameStr == null)
{
childQNameStr = assocChildQName.toPrefixString(namespaceService);
qnameMap.put(assocChildQName, childQNameStr);
}
node.setAssociation(new AssocChild(assocType, assocRef.isPrimary(), childQNameStr));
node.setAssociation(new AssocChild(assocType, assocRef.isPrimary()));
collection.add(node);
}

View File

@@ -18,11 +18,13 @@
*/
package org.alfresco.rest.api.nodes;
import org.alfresco.model.ContentModel;
import org.alfresco.rest.api.model.AssocChild;
import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.api.model.UserInfo;
import org.alfresco.rest.framework.WebApiDescription;
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.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.DuplicateChildNodeNameException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.QNamePattern;
import org.alfresco.service.namespace.RegexQNamePattern;
@@ -106,15 +109,7 @@ public class NodeSecondaryChildrenRelation extends AbstractNodeRelation implemen
qnameMap.put(assocTypeQName, assocType);
}
QName assocChildQName = assocRef.getQName();
String childQNameStr = qnameMap.get(assocChildQName);
if (childQNameStr == null)
{
childQNameStr = assocChildQName.toPrefixString(namespaceService);
qnameMap.put(assocChildQName, childQNameStr);
}
node.setAssociation(new AssocChild(assocType, assocRef.isPrimary(), childQNameStr));
node.setAssociation(new AssocChild(assocType, assocRef.isPrimary()));
collection.add(node);
}
@@ -134,20 +129,16 @@ public class NodeSecondaryChildrenRelation extends AbstractNodeRelation implemen
for (AssocChild assoc : entity)
{
QName assocTypeQName = getAssocType(assoc.getAssocType(), true);
String childQNameStr = assoc.getChildQName();
if ((childQNameStr == null) || childQNameStr.isEmpty())
{
throw new InvalidArgumentException("Missing childQName");
}
QName childQName = QName.createQName(childQNameStr, namespaceService);
QName assocTypeQName = getAssocType(assoc.getAssocType());
try
{
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)
{
@@ -170,41 +161,53 @@ public class NodeSecondaryChildrenRelation extends AbstractNodeRelation implemen
NodeRef parentNodeRef = nodes.validateNode(parentNodeId);
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");
QName childQName = null;
if ((childQNameStr != null) && (!childQNameStr.isEmpty()))
List<ChildAssociationRef> assocRefs = nodeService.getChildAssocs(parentNodeRef);
boolean found = false;
for (ChildAssociationRef assocRef : assocRefs)
{
childQName = QName.createQName(childQNameStr, namespaceService);
if (! assocRef.getChildRef().equals(childNodeRef))
{
continue;
}
if (assocTypeQName != null)
{
if (childQName != null)
if (assocTypeQName.equals(assocRef.getTypeQName()))
{
ChildAssociationRef assocRef = new ChildAssociationRef(assocTypeQName, parentNodeRef, childQName, childNodeRef);
nodeService.removeSecondaryChildAssociation(assocRef);
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
{
throw new InvalidArgumentException("Missing childQName (in addition to assocType)");
}
}
else if (childQName != null)
if (! assocRef.isPrimary())
{
throw new InvalidArgumentException("Missing assocType (in addition to childQName)");
}
else
boolean existed = nodeService.removeSecondaryChildAssociation(assocRef);
if (existed)
{
List<ChildAssociationRef> assocRefs = nodeService.getChildAssocs(parentNodeRef);
for (ChildAssociationRef assocRef : assocRefs)
found = true;
}
}
}
}
if (! found)
{
if (assocRef.getChildRef().equals(childNodeRef) && (! assocRef.isPrimary()))
{
nodeService.removeSecondaryChildAssociation(assocRef);
}
}
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.framework.WebApiDescription;
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.actions.interfaces.RelationshipResourceAction;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
@@ -108,17 +110,25 @@ public class NodeTargetsRelation extends AbstractNodeRelation implements
for (AssocTarget assoc : entity)
{
QName assocTypeQName = getAssocType(assoc.getAssocType(), true);
String assocTypeStr = assoc.getAssocType();
QName assocTypeQName = getAssocType(assocTypeStr);
String targetNodeId = assoc.getTargetId();
try
{
NodeRef tgtNodeRef = nodes.validateNode(assoc.getTargetId());
NodeRef tgtNodeRef = nodes.validateNode(targetNodeId);
nodeService.createAssociation(srcNodeRef, tgtNodeRef, assocTypeQName);
}
catch (AssociationExistsException aee)
{
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);
}
@@ -133,21 +143,31 @@ public class NodeTargetsRelation extends AbstractNodeRelation implements
NodeRef tgtNodeRef = nodes.validateNode(targetNodeId);
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);
nodeService.removeAssociation(srcNodeRef, tgtNodeRef, assocTypeQName);
assocTypeQName = RegexQNamePattern.MATCH_ALL;
}
else
{
List<AssociationRef> assocRefs = nodeService.getTargetAssocs(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, sourceNodeId), RegexQNamePattern.MATCH_ALL);
// 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)
{
if (assocRef.getTargetRef().equals(tgtNodeRef))
{
nodeService.removeAssociation(srcNodeRef, tgtNodeRef, assocRef.getTypeQName());
}
}
found = true;
}
}
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.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
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.AssocTarget;
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.RequestContext;
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.Tag;
import org.alfresco.rest.api.tests.util.RestApiUtil;
import org.alfresco.service.cmr.security.MutableAuthenticationService;
import org.alfresco.service.cmr.security.PersonService;
@@ -44,12 +37,10 @@ import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import static org.alfresco.rest.api.tests.util.RestApiUtil.toJsonAsStringNonNull;
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 ASSOC_TYPE_CM_PREFERENCE_IMAGE = "cm:preferenceImage";
private static final String PARAM_CHILD_NAME = "childQName";
private String user1;
private String user2;
@@ -220,10 +208,6 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
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
response = getAll(getNodeTargetsUrl(o1Id), user1, paging, null, 200);
@@ -242,13 +226,9 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
nodes = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Node.class);
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)
tgt = new AssocTarget(o2Id, ASSOC_TYPE_CM_REFERENCES);
AssocTarget tgt = new AssocTarget(o2Id, ASSOC_TYPE_CM_REFERENCES);
post(getNodeTargetsUrl(o1Id), user1, toJsonAsStringNonNull(tgt), 201);
tgt = new AssocTarget(o2Id, ASSOC_TYPE_CM_PARTS);
@@ -311,7 +291,7 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
assertEquals(o2Id, nodes.get(0).getId());
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+"')");
response = getAll(getNodeTargetsUrl(o2Id), user1, paging, params, 200);
@@ -326,10 +306,6 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
assertEquals(o1Id, nodes.get(0).getId());
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
params = new HashMap<>(2);
params.put(PARAM_ASSOC_TYPE, ASSOC_TYPE_CM_REFERENCES);
@@ -393,6 +369,15 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
assertEquals(0, nodes.size());
//
// -ve tests - add assoc
//
{
// -ve test - unauthenticated - belts-and-braces ;-)
tgt = new AssocTarget(o2Id, ASSOC_TYPE_CM_REFERENCES);
post(getNodeTargetsUrl(o1Id), null, toJsonAsStringNonNull(tgt), 401);
// -ve test - model integrity
tgt = new AssocTarget(f2Id, ASSOC_TYPE_CM_REFERENCES);
post(getNodeTargetsUrl(o1Id), user1, toJsonAsStringNonNull(tgt), 422);
@@ -402,9 +387,56 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
post(getNodeTargetsUrl(o2Id), user1, toJsonAsStringNonNull(tgt), 201);
post(getNodeTargetsUrl(o2Id), user1, toJsonAsStringNonNull(tgt), 409);
// TODO some more negative tests
// 400s - eg. invalid qname
// 404s - eg. unknown src, tgt, assoc of given type
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
{
@@ -469,10 +501,6 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
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
response = getAll(getNodeSecondaryChildrenUrl(f1Id), user1, paging, null, 200);
@@ -485,22 +513,14 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
assertEquals(1, nodes.size());
assertEquals(f2Id, nodes.get(0).getId());
assertEquals(ASSOC_TYPE_CM_CONTAINS, nodes.get(0).getAssociation().getAssocType());
assertEquals("cm:"+o2Name, nodes.get(0).getAssociation().getChildQName());
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
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);
// 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);
@@ -520,7 +540,6 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
i++;
}
assertEquals(o2Id, node.getId());
assertEquals(o2SecChildName, nodeAssoc.getChildQName());
assertFalse(nodeAssoc.getIsPrimaryParent());
}
assertEquals(2, i);
@@ -536,7 +555,6 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
if (nodeId.equals(f2Id))
{
assertEquals(ASSOC_TYPE_CM_CONTAINS, nodeAssoc.getAssocType());
assertEquals("cm:"+o2Name, nodeAssoc.getChildQName());
assertTrue(nodeAssoc.getIsPrimaryParent());
i++;
}
@@ -550,7 +568,6 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
{
i++;
}
assertEquals(o2SecChildName, nodeAssoc.getChildQName());
assertFalse(nodeAssoc.getIsPrimaryParent());
}
}
@@ -577,14 +594,12 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
if (nodeId.equals(f2Id))
{
assertEquals(ASSOC_TYPE_CM_CONTAINS, nodeAssoc.getAssocType());
assertEquals("cm:"+o2Name, nodeAssoc.getChildQName());
assertTrue(nodeAssoc.getIsPrimaryParent());
i++;
}
else if (nodeId.equals(f1Id))
{
assertEquals(ASSOC_TYPE_CM_CONTAINS, nodeAssoc.getAssocType());
assertEquals(o2SecChildName, nodeAssoc.getChildQName());
assertFalse(nodeAssoc.getIsPrimaryParent());
i++;
}
@@ -611,10 +626,6 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
params = new HashMap<>(2);
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
delete(getNodeSecondaryChildrenUrl(f1Id), user1, o2Id, params, 204);
@@ -629,7 +640,6 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
params = new HashMap<>(2);
params.put(PARAM_ASSOC_TYPE, ASSOC_TYPE_CM_PREFERENCE_IMAGE);
params.put(PARAM_CHILD_NAME, o2SecChildName);
// remove other secondary child assoc
delete(getNodeSecondaryChildrenUrl(f1Id), user1, o2Id, params, 204);
@@ -642,26 +652,83 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest
nodes = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Node.class);
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 - unauthenticated - belts-and-braces ;-)
secChild = new AssocChild(o2Id, ASSOC_TYPE_CM_CONTAINS);
post(getNodeSecondaryChildrenUrl(f1Id), null, toJsonAsStringNonNull(secChild), 401);
// -ve test - model integrity
secChild = new AssocChild(o2Id, ASSOC_TYPE_CM_CONTAINS, o2SecChildName);
secChild = new AssocChild(o2Id, ASSOC_TYPE_CM_CONTAINS);
post(getNodeSecondaryChildrenUrl(o1Id), user1, toJsonAsStringNonNull(secChild), 422);
// -ve test - duplicate assoc
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(f1Id), user1, toJsonAsStringNonNull(secChild), 409);
delete(getNodeSecondaryChildrenUrl(f1Id), user1, o2Id, null, 204); // cleanup
// TODO some more negative tests
// 400s - eg. invalid qname
// 404s - eg. unknown src, tgt, assoc of given type
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
{
// 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, f2Id, params, 204);
}

View File

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