diff --git a/source/java/org/alfresco/rest/api/nodes/NodeSecondaryChildrenRelation.java b/source/java/org/alfresco/rest/api/nodes/NodeSecondaryChildrenRelation.java new file mode 100644 index 0000000000..6317a64e8a --- /dev/null +++ b/source/java/org/alfresco/rest/api/nodes/NodeSecondaryChildrenRelation.java @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2005-2016 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.rest.api.nodes; + +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.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; +import org.alfresco.rest.framework.resource.parameters.Paging; +import org.alfresco.rest.framework.resource.parameters.Parameters; +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.QName; +import org.alfresco.service.namespace.QNamePattern; +import org.alfresco.service.namespace.RegexQNamePattern; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Node Secondary Children + * + * Manage secondary child associations (sometimes also known as multi-filing) + * + * Please note, if you wish to manage primary child associations then please refer to other endpoints, for example: + * + * - to create primary child, use POST /nodes/{parentId}/children + * - to delete node (ie. primary child), use DELETE /nodes/{nodeId} + * - to move a node from one primary parent to another, use POST /nodes/{nodeId}/copy + * + * @author janv + */ +@RelationshipResource(name = "secondary-children", entityResource = NodesEntityResource.class, title = "Node Secondary Children") +public class NodeSecondaryChildrenRelation extends AbstractNodeRelation implements + RelationshipResourceAction.Read, + RelationshipResourceAction.Create, + RelationshipResourceAction.Delete +{ + /** + * List secondary children only + * + * @param parentNodeId String id of parent node + */ + @Override + @WebApiDescription(title = "Return a paged list of secondary child nodes based on child assocs") + public CollectionWithPagingInfo readAll(String parentNodeId, Parameters parameters) + { + NodeRef parentNodeRef = nodes.validateOrLookupNode(parentNodeId, null); + + QNamePattern assocTypeQNameParam = getAssocTypeFromWhereElseAll(parameters); + + List assocRefs = null; + if (assocTypeQNameParam.equals(RegexQNamePattern.MATCH_ALL)) + { + assocRefs = nodeService.getChildAssocs(parentNodeRef); + } + else + { + assocRefs = nodeService.getChildAssocs(parentNodeRef, assocTypeQNameParam, RegexQNamePattern.MATCH_ALL); + } + + Map qnameMap = new HashMap<>(3); + + Map mapUserInfo = new HashMap<>(10); + + List includeParam = parameters.getInclude(); + + List collection = new ArrayList<>(assocRefs.size()); + for (ChildAssociationRef assocRef : assocRefs) + { + if (! assocRef.isPrimary()) + { + // minimal info by default (unless "include"d otherwise) + Node node = nodes.getFolderOrDocument(assocRef.getChildRef(), null, null, includeParam, mapUserInfo); + + QName assocTypeQName = assocRef.getTypeQName(); + String assocType = qnameMap.get(assocTypeQName); + if (assocType == null) + { + assocType = assocTypeQName.toPrefixString(namespaceService); + 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)); + + collection.add(node); + } + } + + Paging paging = parameters.getPaging(); + return CollectionWithPagingInfo.asPaged(paging, collection, false, collection.size()); + } + + @Override + @WebApiDescription(title="Add secondary child assoc") + public List create(String parentNodeId, List entity, Parameters parameters) + { + List result = new ArrayList<>(entity.size()); + + NodeRef parentNodeRef = nodes.validateNode(parentNodeId); + + 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); + + try + { + NodeRef childNodeRef = nodes.validateNode(assoc.getChildId()); + nodeService.addChild(parentNodeRef, childNodeRef, assocTypeQName, childQName); + } + catch (AssociationExistsException aee) + { + throw new ConstraintViolatedException(aee.getMessage()); + } + catch (DuplicateChildNodeNameException dcne) + { + throw new ConstraintViolatedException(dcne.getMessage()); + } + + result.add(assoc); + } + return result; + } + + @Override + @WebApiDescription(title = "Remove secondary child assoc(s)") + public void delete(String parentNodeId, String childNodeId, Parameters parameters) + { + NodeRef parentNodeRef = nodes.validateNode(parentNodeId); + NodeRef childNodeRef = nodes.validateNode(childNodeId); + + QName assocTypeQName = getAssocType(parameters.getParameter("assocType"), false); + + String childQNameStr = parameters.getParameter("childQName"); + QName childQName = null; + if ((childQNameStr != null) && (!childQNameStr.isEmpty())) + { + childQName = QName.createQName(childQNameStr, namespaceService); + } + + if (assocTypeQName != null) + { + if (childQName != null) + { + ChildAssociationRef assocRef = new ChildAssociationRef(assocTypeQName, parentNodeRef, childQName, childNodeRef); + nodeService.removeSecondaryChildAssociation(assocRef); + } + else + { + throw new InvalidArgumentException("Missing childQName (in addition to assocType)"); + } + } + else if (childQName != null) + { + throw new InvalidArgumentException("Missing assocType (in addition to childQName)"); + } + else + { + List assocRefs = nodeService.getChildAssocs(parentNodeRef); + for (ChildAssociationRef assocRef : assocRefs) + { + if (assocRef.getChildRef().equals(childNodeRef) && (! assocRef.isPrimary())) + { + nodeService.removeSecondaryChildAssociation(assocRef); + } + } + } + } +}