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

126360 jkaabimofrad: Merged FILE-FOLDER-API (5.2.0) to HEAD (5.2)
      119711 jvonka: FileFolder API - consistently handle node aspects &/or properties  (on create or update)
      - also allow specialise node type (when updating a node)
      - minor tweaks to javadoc/comments
      - RA-635, RA-636, RA-639


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.2.N/root@126706 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Ancuta Morarasu
2016-05-11 10:47:59 +00:00
parent 2997aa5bfe
commit 8d24f35395
2 changed files with 72 additions and 31 deletions

View File

@@ -549,8 +549,8 @@ public class NodesImpl implements Nodes
if (! minimalInfo) if (! minimalInfo)
{ {
node.setProperties(mapProperties(properties, selectParam, mapUserInfo)); node.setProperties(mapFromNodeProperties(properties, selectParam, mapUserInfo));
node.setAspectNames(mapAspects(nodeService.getAspects(nodeRef))); node.setAspectNames(mapFromNodeAspects(nodeService.getAspects(nodeRef)));
} }
node.setNodeType(typeQName.toPrefixString(namespaceService)); node.setNodeType(typeQName.toPrefixString(namespaceService));
@@ -661,7 +661,20 @@ public class NodesImpl implements Nodes
return new PathInfo(pathStr, isComplete, pathElements); return new PathInfo(pathStr, isComplete, pathElements);
} }
protected Map<String, Object> mapProperties(Map<QName, Serializable> nodeProps, List<String> selectParam, Map<String,UserInfo> mapUserInfo) protected Map<QName, Serializable> mapToNodeProperties(Map<String, Object> props)
{
Map<QName, Serializable> nodeProps = new HashMap<>(props.size());
for (Entry<String, Object> entry : props.entrySet())
{
QName propQName = QName.createQName(entry.getKey(), namespaceService);
nodeProps.put(propQName, (Serializable)entry.getValue());
}
return nodeProps;
}
protected Map<String, Object> mapFromNodeProperties(Map<QName, Serializable> nodeProps, List<String> selectParam, Map<String,UserInfo> mapUserInfo)
{ {
List<QName> selectedProperties; List<QName> selectedProperties;
@@ -708,7 +721,7 @@ public class NodesImpl implements Nodes
return props; return props;
} }
protected List<String> mapAspects(Set<QName> nodeAspects) protected List<String> mapFromNodeAspects(Set<QName> nodeAspects)
{ {
List<String> aspectNames = new ArrayList<>(nodeAspects.size()); List<String> aspectNames = new ArrayList<>(nodeAspects.size());
@@ -833,19 +846,20 @@ public class NodesImpl implements Nodes
throw new InvalidArgumentException("NodeId of folder is expected: "+parentNodeRef); throw new InvalidArgumentException("NodeId of folder is expected: "+parentNodeRef);
} }
// node name - mandatory
String nodeName = nodeInfo.getName(); String nodeName = nodeInfo.getName();
if ((nodeName == null) || nodeName.isEmpty()) if ((nodeName == null) || nodeName.isEmpty())
{ {
throw new InvalidArgumentException("Node name is expected: "+parentNodeRef); throw new InvalidArgumentException("Node name is expected: "+parentNodeRef);
} }
// node type - check that requested type is a (sub-) type of folder or content
String nodeType = nodeInfo.getNodeType(); String nodeType = nodeInfo.getNodeType();
if ((nodeType == null) || nodeType.isEmpty()) if ((nodeType == null) || nodeType.isEmpty())
{ {
throw new InvalidArgumentException("Node type is expected: "+parentNodeRef+","+nodeName); throw new InvalidArgumentException("Node type is expected: "+parentNodeRef+","+nodeName);
} }
// check that requested type is a (sub-) type of folder or content
QName nodeTypeQName = createQName(nodeType); QName nodeTypeQName = createQName(nodeType);
Set<QName> contentAndFolders = new HashSet<>(Arrays.asList(ContentModel.TYPE_FOLDER, ContentModel.TYPE_CONTENT)); Set<QName> contentAndFolders = new HashSet<>(Arrays.asList(ContentModel.TYPE_FOLDER, ContentModel.TYPE_CONTENT));
@@ -855,15 +869,12 @@ public class NodesImpl implements Nodes
boolean isContent = typeMatches(nodeTypeQName, Collections.singleton(ContentModel.TYPE_CONTENT), null); boolean isContent = typeMatches(nodeTypeQName, Collections.singleton(ContentModel.TYPE_CONTENT), null);
Map<QName, Serializable> props = new HashMap<>(10); Map<QName, Serializable> props = new HashMap<>(1);
if (nodeInfo.getProperties() != null) if (nodeInfo.getProperties() != null)
{ {
for (Entry<String, Object> entry : nodeInfo.getProperties().entrySet()) // node properties - set any additional properties
{ props = mapToNodeProperties(nodeInfo.getProperties());
QName propQName = QName.createQName(entry.getKey(), namespaceService);
props.put(propQName, (Serializable)entry.getValue());
}
} }
props.put(ContentModel.PROP_NAME, nodeName); props.put(ContentModel.PROP_NAME, nodeName);
@@ -871,6 +882,22 @@ public class NodesImpl implements Nodes
QName assocQName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, QName.createValidLocalName(nodeName)); QName assocQName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, QName.createValidLocalName(nodeName));
NodeRef nodeRef = nodeService.createNode(parentNodeRef, ContentModel.ASSOC_CONTAINS, assocQName, nodeTypeQName, props).getChildRef(); NodeRef nodeRef = nodeService.createNode(parentNodeRef, ContentModel.ASSOC_CONTAINS, assocQName, nodeTypeQName, props).getChildRef();
List<String> aspectNames = nodeInfo.getAspectNames();
if (aspectNames != null)
{
// node aspects - set any additional aspects
for (String aspectName : aspectNames)
{
QName aspectQName = QName.createQName(aspectName, namespaceService);
if (EXCLUDED_ASPECTS.contains(aspectQName) || aspectQName.equals(ContentModel.ASPECT_AUDITABLE))
{
continue; // ignore
}
nodeService.addAspect(nodeRef, aspectQName, null);
}
}
if (isContent) { if (isContent) {
// add empty file // add empty file
ContentWriter writer = sr.getContentService().getWriter(nodeRef, ContentModel.PROP_CONTENT, true); ContentWriter writer = sr.getContentService().getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
@@ -886,34 +913,48 @@ public class NodesImpl implements Nodes
{ {
final NodeRef nodeRef = validateNode(nodeId); final NodeRef nodeRef = validateNode(nodeId);
QName nodeTypeQName = nodeService.getType(nodeRef);
final Set<QName> fileOrFolder = new HashSet<>(Arrays.asList(ContentModel.TYPE_FOLDER, ContentModel.TYPE_CONTENT)); final Set<QName> fileOrFolder = new HashSet<>(Arrays.asList(ContentModel.TYPE_FOLDER, ContentModel.TYPE_CONTENT));
if (! nodeMatches(nodeRef, fileOrFolder, null)) if (! typeMatches(nodeTypeQName, fileOrFolder, null))
{ {
throw new InvalidArgumentException("NodeId of file or folder is expected"); throw new InvalidArgumentException("NodeId of file or folder is expected");
} }
Map<QName, Serializable> props = new HashMap<>(10); Map<QName, Serializable> props = new HashMap<>(0);
if (nodeInfo.getProperties() != null) if (nodeInfo.getProperties() != null)
{ {
for (Entry<String, Object> entry : nodeInfo.getProperties().entrySet()) props = mapToNodeProperties(nodeInfo.getProperties());
{
QName propQName = QName.createQName(entry.getKey(), namespaceService);
props.put(propQName, (Serializable)entry.getValue());
}
} }
String name = nodeInfo.getName(); String name = nodeInfo.getName();
if ((name != null) && (! name.isEmpty())) if ((name != null) && (! name.isEmpty()))
{ {
// note: this is equivalent of a rename within target folder // update node name if needed - note: if the name is different than existing then this is equivalent of a rename (within parent folder)
props.put(ContentModel.PROP_NAME, name); props.put(ContentModel.PROP_NAME, name);
} }
String nodeType = nodeInfo.getNodeType();
if ((nodeType != null) && (! nodeType.isEmpty()))
{
// update node type - ensure that we are performing a specialise (we do not support generalise)
QName destNodeTypeQName = QName.createQName(nodeType, namespaceService);
if ((! destNodeTypeQName.equals(nodeTypeQName)) && dictionaryService.isSubClass(destNodeTypeQName, nodeTypeQName))
{
nodeService.setType(nodeRef, destNodeTypeQName);
}
else
{
throw new IllegalArgumentException("Cannot generalise the node type (from "+nodeTypeQName+" to "+destNodeTypeQName+")");
}
}
List<String> aspectNames = nodeInfo.getAspectNames(); List<String> aspectNames = nodeInfo.getAspectNames();
if (aspectNames != null) if (aspectNames != null)
{ {
// note: can be empty (eg. to remove existing aspects (+ aspect properties) ... apart from cm:auditable, sys:referencable, sys:localized) // update aspects - note: can be empty (eg. to remove existing aspects+properties) but not cm:auditable, sys:referencable, sys:localized
Set<QName> aspectQNames = new HashSet<>(aspectNames.size()); Set<QName> aspectQNames = new HashSet<>(aspectNames.size());
for (String aspectName : aspectNames) for (String aspectName : aspectNames)
{ {
@@ -967,6 +1008,7 @@ public class NodesImpl implements Nodes
if (props.size() > 0) if (props.size() > 0)
{ {
// update node properties - note: null will unset the specified property
nodeService.addProperties(nodeRef, props); nodeService.addProperties(nodeRef, props);
} }

View File

@@ -35,7 +35,11 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* TODO ... work-in-progress * Node Children
*
* - list folder children
* - create folder &/or empty file
* - create (ie. upload) file with content
* *
* @author janv * @author janv
* @author Jamal Kaabi-Mofrad * @author Jamal Kaabi-Mofrad
@@ -60,16 +64,11 @@ public class NodeChildrenRelation implements RelationshipResourceAction.Read<Nod
/** /**
* List folder children - returns a filtered/sorted/paged list of nodes that are immediate children of the parent folder * List folder children - returns a filtered/sorted/paged list of nodes that are immediate children of the parent folder
* *
* TODO filtering, sorting, ... * @param parentFolderNodeId String id of parent folder - will also accept well-known alias, eg. -root- or -my- or -shared-
* TODO metadata/properties & permissions etc ...
*
* @param parentFolderNodeId String id of parent folder - will also accept aliases "-root-" (Company Home) or "-my-" (current user's home folder)
* *
* Optional query parameters: * Optional query parameters:
* *
* - incFiles * - select
* - incFolders
*
* - properties * - properties
* - where * - where
* - orderBy * - orderBy
@@ -90,7 +89,7 @@ public class NodeChildrenRelation implements RelationshipResourceAction.Read<Nod
/** /**
* Create one or more nodes (folder or empty file) below parent folder. * Create one or more nodes (folder or empty file) below parent folder.
* *
* Note: for parent folder nodeId, can also use well-known alias, eg. -root- or -my- * Note: for parent folder nodeId, can also use well-known alias, eg. -root- or -my- or -shared-
* *
* If parentFolderNodeId does not exist, EntityNotFoundException (status 404). * If parentFolderNodeId does not exist, EntityNotFoundException (status 404).
* If parentFolderNodeId does not represent a folder, InvalidArgumentException (status 400). * If parentFolderNodeId does not represent a folder, InvalidArgumentException (status 400).