diff --git a/config/alfresco/public-rest-context.xml b/config/alfresco/public-rest-context.xml
index 12de17f01d..789323b30c 100644
--- a/config/alfresco/public-rest-context.xml
+++ b/config/alfresco/public-rest-context.xml
@@ -433,6 +433,10 @@
+
+
+
+
@@ -659,6 +663,10 @@
+
+
+
+
diff --git a/source/java/org/alfresco/rest/api/Nodes.java b/source/java/org/alfresco/rest/api/Nodes.java
index e402f53b58..42853ca643 100644
--- a/source/java/org/alfresco/rest/api/Nodes.java
+++ b/source/java/org/alfresco/rest/api/Nodes.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2012 Alfresco Software Limited.
+ * Copyright (C) 2005-2015 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -23,10 +23,16 @@ import java.util.Set;
import org.alfresco.rest.api.model.Document;
import org.alfresco.rest.api.model.Folder;
import org.alfresco.rest.api.model.Node;
+import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
+import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.QName;
+/**
+ * @author steveglover
+ * @author janv
+ */
public interface Nodes
{
NodeRef validateNode(StoreRef storeRef, String nodeId);
@@ -54,4 +60,49 @@ public interface Nodes
* @return Folder
*/
Folder getFolder(NodeRef nodeRef);
+
+ /**
+ * Get the folder or document representation (as appropriate) for the given node.
+ * @param nodeId String nodeId or well-known alias, eg. "-root-" or "-my-"
+ * @param parameters the {@link Parameters} object to get the parameters passed into the request
+ * including:
+ * - incPrimaryParent
+ * @return
+ */
+ Node getFolderOrDocument(String nodeId, Parameters parameters);
+
+ /**
+ * Get list of children of a parent folder.
+ * @param parentFolderNodeId String id of parent folder node or well-known alias, eg. "-root-" or "-my-"
+ * @param parameters the {@link Parameters} object to get the parameters passed into the request
+ * including:
+ * - filter, sort & paging params (where, orderBy, skipCount, maxItems)
+ * - incFiles, incFolders (both true by default)
+ * @return a paged list of {@code org.alfresco.rest.api.model.Node} objects
+ */
+ CollectionWithPagingInfo getChildren(String parentFolderNodeId, Parameters parameters);
+
+ /**
+ * Delete the given node. Note: will cascade delete for a folder.
+ * @param nodeId String id of node (folder or document)
+ */
+ void deleteNode(String nodeId);
+
+ /**
+ *
+ * @param parentFolderNodeId
+ * @param folderInfo
+ * @param parameters
+ * @return
+ */
+ Folder createFolder(String parentFolderNodeId, Folder folderInfo, Parameters parameters);
+
+ /**
+ *
+ * @param nodeId
+ * @param entity
+ * @param parameters
+ * @return
+ */
+ Node updateNode(String nodeId, Node entity, Parameters parameters);
}
diff --git a/source/java/org/alfresco/rest/api/impl/NodesImpl.java b/source/java/org/alfresco/rest/api/impl/NodesImpl.java
index 203b153181..0b1d74ea8d 100644
--- a/source/java/org/alfresco/rest/api/impl/NodesImpl.java
+++ b/source/java/org/alfresco/rest/api/impl/NodesImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2012 Alfresco Software Limited.
+ * Copyright (C) 2005-2015 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -36,7 +36,9 @@
*/
package org.alfresco.rest.api.impl;
-import java.util.ArrayList;
+import java.io.Serializable;
+import java.util.AbstractList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -45,27 +47,35 @@ import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.opencmis.CMISConnector;
-import org.alfresco.opencmis.CMISNodeInfoImpl;
+import org.alfresco.query.PagingRequest;
+import org.alfresco.query.PagingResults;
+import org.alfresco.repo.model.Repository;
import org.alfresco.rest.api.Nodes;
import org.alfresco.rest.api.model.Document;
import org.alfresco.rest.api.model.Folder;
import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
+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.dictionary.DictionaryService;
+import org.alfresco.service.cmr.model.FileFolderService;
+import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.repository.Path.Element;
import org.alfresco.service.cmr.repository.StoreRef;
+import org.alfresco.service.cmr.security.PermissionService;
+import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
-import org.apache.chemistry.opencmis.commons.data.CmisExtensionElement;
-import org.apache.chemistry.opencmis.commons.data.Properties;
-import org.apache.chemistry.opencmis.commons.data.PropertyData;
-import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyStringImpl;
/**
- * Centralises access to node services and maps between representations.
+ * Centralises access to file/folder/node services and maps between representations.
*
* @author steveglover
+ * @author janv
+ *
* @since publicapi1.0
*/
public class NodesImpl implements Nodes
@@ -76,9 +86,16 @@ public class NodesImpl implements Nodes
DOCUMENT, FOLDER;
};
+ private final static String PATH_ROOT = "-root-";
+ private final static String PATH_MY = "-my-";
+
private NodeService nodeService;
private DictionaryService dictionaryService;
private CMISConnector cmisConnector;
+ private FileFolderService fileFolderService;
+ private Repository repositoryHelper;
+ private NamespaceService namespaceService;
+ private PermissionService permissionService;
public void setDictionaryService(DictionaryService dictionaryService)
{
@@ -94,6 +111,26 @@ public class NodesImpl implements Nodes
{
this.cmisConnector = cmisConnector;
}
+
+ public void setFileFolderService(FileFolderService fileFolderService)
+ {
+ this.fileFolderService = fileFolderService;
+ }
+
+ public void setRepositoryHelper(Repository repositoryHelper)
+ {
+ this.repositoryHelper = repositoryHelper;
+ }
+
+ public void setNamespaceService(NamespaceService namespaceService)
+ {
+ this.namespaceService = namespaceService;
+ }
+
+ public void setPermissionService(PermissionService permissionService)
+ {
+ this.permissionService = permissionService;
+ }
/*
*
@@ -170,23 +207,29 @@ public class NodesImpl implements Nodes
{
NodeRef nodeRef = validateNode(nodeId);
- return new Node(nodeRef, nodeService.getProperties(nodeRef));
+ return new Node(nodeRef, nodeService.getProperties(nodeRef), namespaceService);
}
public Node getNode(NodeRef nodeRef)
{
- return new Node(nodeRef, nodeService.getProperties(nodeRef));
+ return new Node(nodeRef, nodeService.getProperties(nodeRef), namespaceService);
}
private Type getType(NodeRef nodeRef)
{
- QName type = nodeService.getType(nodeRef);
+ return getType(nodeService.getType(nodeRef));
+ }
+
+ private Type getType(QName type)
+ {
boolean isContainer = Boolean.valueOf((dictionaryService.isSubClass(type, ContentModel.TYPE_FOLDER) == true &&
!dictionaryService.isSubClass(type, ContentModel.TYPE_SYSTEM_FOLDER)));
return isContainer ? Type.FOLDER : Type.DOCUMENT;
}
+ /*
// TODO filter CMIS properties
+ // TODO review & optimise - do we really need to go via CMIS properties !?
private Properties getCMISProperties(NodeRef nodeRef)
{
CMISNodeInfoImpl nodeInfo = cmisConnector.createNodeInfo(nodeRef);
@@ -228,6 +271,7 @@ public class NodesImpl implements Nodes
return wrapProperties;
}
+ */
/**
* Returns the public api representation of a document.
@@ -237,10 +281,11 @@ public class NodesImpl implements Nodes
public Document getDocument(NodeRef nodeRef)
{
Type type = getType(nodeRef);
- if(type.equals(Type.DOCUMENT))
+ if (type.equals(Type.DOCUMENT))
{
- Properties properties = getCMISProperties(nodeRef);
- Document doc = new Document(nodeRef, properties);
+ //Properties properties = getCMISProperties(nodeRef);
+ Map properties = nodeService.getProperties(nodeRef);
+ Document doc = new Document(nodeRef, properties, namespaceService);
return doc;
}
else
@@ -257,10 +302,11 @@ public class NodesImpl implements Nodes
public Folder getFolder(NodeRef nodeRef)
{
Type type = getType(nodeRef);
- if(type.equals(Type.FOLDER))
+ if (type.equals(Type.FOLDER))
{
- Properties properties = getCMISProperties(nodeRef);
- Folder folder = new Folder(nodeRef, properties);
+ //Properties properties = getCMISProperties(nodeRef);
+ Map properties = nodeService.getProperties(nodeRef);
+ Folder folder = new Folder(nodeRef, properties, namespaceService);
return folder;
}
else
@@ -268,4 +314,223 @@ public class NodesImpl implements Nodes
throw new InvalidArgumentException("Node is not a folder");
}
}
+
+ private NodeRef validateOrLookupNode(String nodeId, String path) {
+ final NodeRef parentNodeRef;
+ if (nodeId.equals(PATH_ROOT))
+ {
+ parentNodeRef = repositoryHelper.getCompanyHome();
+ }
+ else if (nodeId.equals(PATH_MY))
+ {
+ NodeRef person = repositoryHelper.getPerson();
+ if (person == null)
+ {
+ throw new IllegalArgumentException("Unexpected: cannot use "+PATH_MY);
+ }
+ parentNodeRef = repositoryHelper.getUserHome(person);
+ }
+ else
+ {
+ parentNodeRef = validateNode(nodeId);
+ }
+ return parentNodeRef;
+ }
+
+ public Node getFolderOrDocument(String nodeId, Parameters parameters)
+ {
+ String path = parameters.getParameter("path");
+
+ boolean incPrimaryPath = false;
+ String str = parameters.getParameter("incPrimaryPath");
+ if (str != null) {
+ incPrimaryPath = new Boolean(str);
+ }
+
+ NodeRef nodeRef = validateOrLookupNode(nodeId, path);
+ QName typeQName = nodeService.getType(nodeRef);
+ return getFolderOrDocument(nodeRef, typeQName, incPrimaryPath);
+ }
+
+ private Node getFolderOrDocument(NodeRef nodeRef, QName typeQName,boolean incPrimaryPath)
+ {
+ String primaryPath = null;
+ if (incPrimaryPath)
+ {
+ org.alfresco.service.cmr.repository.Path pp = nodeService.getPath(nodeRef);
+
+ // Remove "app:company_home" (2nd element)
+ int ppSize = pp.size();
+ if (ppSize > 1) {
+ if (ppSize == 2) {
+ pp = pp.subPath(0, 0);
+ }
+ else {
+ Element rootElement = pp.get(0);
+ pp = pp.subPath(2, ppSize-1).prepend(rootElement);
+ }
+ }
+
+ primaryPath = pp.toDisplayPath(nodeService, permissionService); // note: slower (hence optional when getting node info)
+ }
+
+ Node node = null;
+ Type type = getType(typeQName);
+
+ Map properties = nodeService.getProperties(nodeRef);
+
+ if (type.equals(Type.DOCUMENT))
+ {
+ //Properties properties = getCMISProperties(nodeRef);
+ node = new Document(nodeRef, properties, namespaceService);
+ }
+ else if (type.equals(Type.FOLDER))
+ {
+ // container/folder
+ //Properties properties = getCMISProperties(nodeRef);
+ node = new Folder(nodeRef, properties, namespaceService);
+ }
+ else
+ {
+ throw new InvalidArgumentException("Node is not a folder or file");
+ }
+
+ node.setType(typeQName.toPrefixString(namespaceService));
+ node.setPrimaryPath(primaryPath); // optional - can be null
+ return node;
+ }
+
+ public CollectionWithPagingInfo getChildren(String parentFolderNodeId, Parameters parameters)
+ {
+ // TODO consider using: where=(exists(target/file)) / where=(exists(target/file))
+ // instead of: includeFiles=true / includeFolders=true
+
+ boolean includeFolders = true;
+ String str = parameters.getParameter("includeFolders");
+ if (str != null) {
+ includeFolders = new Boolean(str);
+ }
+
+ boolean includeFiles = true;
+ str = parameters.getParameter("includeFiles");
+ if (str != null) {
+ includeFiles = new Boolean(str);
+ }
+
+ String path = parameters.getParameter("path");
+
+ Paging paging = parameters.getPaging();
+ final NodeRef parentNodeRef = validateOrLookupNode(parentFolderNodeId, path);
+
+ final Set folders = new HashSet<>(Arrays.asList(ContentModel.TYPE_FOLDER));
+ if (! nodeMatches(parentNodeRef, folders, null))
+ {
+ throw new InvalidArgumentException("NodeId of folder is expected");
+ }
+
+ PagingRequest pagingRequest = Util.getPagingRequest(paging);
+
+ final PagingResults pagingResults = fileFolderService.list(parentNodeRef, includeFiles, includeFolders, null, null, pagingRequest);
+
+ final List page = pagingResults.getPage();
+ List nodes = new AbstractList()
+ {
+ @Override
+ public Node get(int index)
+ {
+ FileInfo fInfo = page.get(index);
+ return getFolderOrDocument(fInfo.getNodeRef(), fInfo.getType(), false);
+ }
+
+ @Override
+ public int size()
+ {
+ return page.size();
+ }
+ };
+
+ return CollectionWithPagingInfo.asPaged(paging, nodes, pagingResults.hasMoreItems(), pagingResults.getTotalResultCount().getFirst());
+ }
+
+ public void deleteNode(String nodeId)
+ {
+ NodeRef nodeRef = validateNode(nodeId);
+ fileFolderService.delete(nodeRef);
+ }
+
+ public Folder createFolder(String parentFolderNodeId, Folder folderInfo, Parameters parameters)
+ {
+ final NodeRef parentNodeRef = validateNode(parentFolderNodeId);
+
+ final Set folders = new HashSet<>(Arrays.asList(ContentModel.TYPE_FOLDER));
+ if (! nodeMatches(parentNodeRef, folders, null))
+ {
+ throw new InvalidArgumentException("NodeId of folder is expected");
+ }
+
+ String folderName = folderInfo.getName();
+ String folderType = folderInfo.getType();
+ if (folderType == null) {
+ folderType = "cm:folder";
+ }
+
+ QName folderTypeQName = QName.resolveToQName(namespaceService, folderType);
+
+ Map props = new HashMap(10);
+
+ props.put(ContentModel.PROP_NAME, folderName);
+
+ String title = folderInfo.getTitle();
+ if ((title != null) && (! title.isEmpty())) {
+ props.put(ContentModel.PROP_TITLE, title);
+ }
+
+ String description = folderInfo.getDescription();
+ if ((description != null) && (! description.isEmpty())) {
+ props.put(ContentModel.PROP_DESCRIPTION, description);
+ }
+
+ // TODO other custom properties !!
+
+ QName assocQName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, QName.createValidLocalName(folderName));
+
+ NodeRef nodeRef = nodeService.createNode(parentNodeRef, ContentModel.ASSOC_CONTAINS, assocQName, folderTypeQName, props).getChildRef();
+
+ return (Folder) getFolderOrDocument(nodeRef.getId(), parameters);
+ }
+
+ public Node updateNode(String nodeId, Node nodeInfo, Parameters parameters) {
+
+ final NodeRef nodeRef = validateNode(nodeId);
+
+ final Set fileOrFolder = new HashSet<>(Arrays.asList(ContentModel.TYPE_FOLDER, ContentModel.TYPE_CONTENT));
+ if (! nodeMatches(nodeRef, fileOrFolder, null))
+ {
+ throw new InvalidArgumentException("NodeId of file or folder is expected");
+ }
+
+ Map props = new HashMap<>(10);
+
+ String name = nodeInfo.getName();
+ if ((name != null) && (! name.isEmpty())) {
+ // note: this is equivalent of a rename within target folder
+ props.put(ContentModel.PROP_NAME, name);
+ }
+
+ String title = nodeInfo.getTitle();
+ if ((title != null) && (! title.isEmpty())) {
+ props.put(ContentModel.PROP_TITLE, title);
+ }
+
+ String description = nodeInfo.getDescription();
+ if ((description != null) && (! description.isEmpty())) {
+ props.put(ContentModel.PROP_DESCRIPTION, description);
+ }
+
+ if (props.size() > 0) {
+ nodeService.addProperties(nodeRef, props);
+ }
+
+ return getFolderOrDocument(nodeRef.getId(), parameters);
+ }
}
diff --git a/source/java/org/alfresco/rest/api/model/Document.java b/source/java/org/alfresco/rest/api/model/Document.java
index fef05c6982..0d5210c1d6 100644
--- a/source/java/org/alfresco/rest/api/model/Document.java
+++ b/source/java/org/alfresco/rest/api/model/Document.java
@@ -5,6 +5,7 @@ import java.math.BigInteger;
import java.util.Map;
import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.apache.chemistry.opencmis.commons.PropertyIds;
import org.apache.chemistry.opencmis.commons.data.Properties;
@@ -14,6 +15,7 @@ import org.apache.chemistry.opencmis.commons.data.PropertyData;
* Representation of a document node.
*
* @author steveglover
+ * @author janv
*
*/
public class Document extends Node
@@ -26,7 +28,8 @@ public class Document extends Node
{
super();
}
-
+
+ /*
public Document(NodeRef nodeRef, Properties properties)
{
super(nodeRef, properties);
@@ -36,10 +39,11 @@ public class Document extends Node
this.sizeInBytes = (BigInteger)getValue(props, PropertyIds.CONTENT_STREAM_LENGTH);
this.versionLabel = (String)getValue(props, PropertyIds.VERSION_LABEL);
}
+ */
- public Document(NodeRef nodeRef, Map nodeProps)
+ public Document(NodeRef nodeRef, Map nodeProps, NamespaceService namespaceService)
{
- super(nodeRef, nodeProps);
+ super(nodeRef, nodeProps, namespaceService);
}
public String getMimeType()
@@ -57,6 +61,11 @@ public class Document extends Node
return versionLabel;
}
+ public Boolean getIsFolder()
+ {
+ return false;
+ }
+
@Override
public String toString()
{
diff --git a/source/java/org/alfresco/rest/api/model/Folder.java b/source/java/org/alfresco/rest/api/model/Folder.java
index 69ad18a4a2..20f1395893 100644
--- a/source/java/org/alfresco/rest/api/model/Folder.java
+++ b/source/java/org/alfresco/rest/api/model/Folder.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import java.util.Map;
import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.apache.chemistry.opencmis.commons.data.Properties;
@@ -11,6 +12,7 @@ import org.apache.chemistry.opencmis.commons.data.Properties;
* Representation of a folder node.
*
* @author steveglover
+ * @author janv
*
*/
public class Folder extends Node
@@ -20,14 +22,21 @@ public class Folder extends Node
super();
}
+ /*
public Folder(NodeRef nodeRef, Properties properties)
{
super(nodeRef, properties);
}
+ */
- public Folder(NodeRef nodeRef, Map nodeProps)
+ public Folder(NodeRef nodeRef, Map nodeProps, NamespaceService namespaceService)
{
- super(nodeRef, nodeProps);
+ super(nodeRef, nodeProps, namespaceService);
+ }
+
+ public Boolean getIsFolder()
+ {
+ return true;
}
@Override
diff --git a/source/java/org/alfresco/rest/api/model/Node.java b/source/java/org/alfresco/rest/api/model/Node.java
index 0404dc0706..6a53801899 100644
--- a/source/java/org/alfresco/rest/api/model/Node.java
+++ b/source/java/org/alfresco/rest/api/model/Node.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2012 Alfresco Software Limited.
+ * Copyright (C) 2005-2015 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -19,13 +19,19 @@
package org.alfresco.rest.api.model;
import java.io.Serializable;
+import java.util.Arrays;
import java.util.Date;
import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import java.util.Set;
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
import org.alfresco.model.ContentModel;
import org.alfresco.rest.framework.resource.UniqueId;
import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.EqualsHelper;
import org.apache.chemistry.opencmis.commons.PropertyIds;
@@ -37,20 +43,45 @@ import org.apache.chemistry.opencmis.commons.data.PropertyData;
*
* @author steveglover
* @author Gethin James
+ * @author janv
*/
public class Node implements Comparable
{
protected NodeRef nodeRef;
protected String name;
protected String title;
- protected NodeRef guid;
+ protected NodeRef guid; // TODO review - do we need for favorites (backwards compat') ?
protected String description;
protected Date createdAt;
protected Date modifiedAt;
protected String createdBy;
protected String modifiedBy;
- public Node(NodeRef nodeRef, Map nodeProps)
+ protected String primaryPath;
+ protected String prefixTypeQName;
+
+ protected Map props;
+
+ private static final List EXCLUDED_PROPS = Arrays.asList(
+ ContentModel.PROP_NAME,
+ ContentModel.PROP_TITLE,
+ ContentModel.PROP_DESCRIPTION,
+ ContentModel.PROP_MODIFIER,
+ ContentModel.PROP_MODIFIED,
+ ContentModel.PROP_CREATOR,
+ ContentModel.PROP_CREATED,
+ ContentModel.PROP_CONTENT,
+ ContentModel.PROP_LOCALE,
+ ContentModel.PROP_NODE_UUID,
+ ContentModel.PROP_STORE_IDENTIFIER,
+ ContentModel.PROP_STORE_PROTOCOL,
+ ContentModel.PROP_NODE_DBID,
+ ContentModel.PROP_INITIAL_VERSION,
+ ContentModel.PROP_AUTO_VERSION_PROPS,
+ ContentModel.PROP_AUTO_VERSION);
+
+ // TODO fixme !
+ public Node(NodeRef nodeRef, Map nodeProps, NamespaceService namespaceService)
{
if(nodeRef == null)
{
@@ -58,7 +89,7 @@ public class Node implements Comparable
}
this.nodeRef = nodeRef;
- mapProperties(nodeProps);
+ mapProperties(nodeProps, namespaceService);
}
protected Object getValue(Map> props, String name)
@@ -68,14 +99,19 @@ public class Node implements Comparable
return value;
}
+ /*
public Node(NodeRef nodeRef, Properties properties)
{
this.nodeRef = nodeRef;
Map> props = properties.getProperties();
+
+ this.guid = nodeRef;
+
this.name = (String)getValue(props, PropertyIds.NAME);
this.title = (String)getValue(props, ContentModel.PROP_TITLE.toString());
- this.guid = nodeRef;
+ this.description = (String)getValue(props, PropertyIds.DESCRIPTION);
+
GregorianCalendar cal = (GregorianCalendar)getValue(props, PropertyIds.CREATION_DATE);
this.createdAt = cal.getTime();
cal = (GregorianCalendar)getValue(props, PropertyIds.LAST_MODIFICATION_DATE);
@@ -83,21 +119,34 @@ public class Node implements Comparable
this.createdBy = (String)getValue(props, PropertyIds.CREATED_BY);
this.modifiedBy = (String)getValue(props, PropertyIds.LAST_MODIFIED_BY);
}
+ */
public Node()
{
}
- protected void mapProperties(Map nodeProps)
+ protected void mapProperties(Map nodeProps, NamespaceService namespaceService)
{
+ // TODO review backwards compat' for favorites & others (eg. set guid explicitly where still needed)
+ //this.guid = nodeRef;
+
this.name = (String)nodeProps.get(ContentModel.PROP_NAME);
- this.guid = nodeRef;
this.title = (String)nodeProps.get(ContentModel.PROP_TITLE);
+ this.description = (String)nodeProps.get(ContentModel.PROP_DESCRIPTION);
+
this.createdAt = (Date)nodeProps.get(ContentModel.PROP_CREATED);
this.createdBy = (String)nodeProps.get(ContentModel.PROP_CREATOR);
this.modifiedAt = (Date)nodeProps.get(ContentModel.PROP_MODIFIED);
this.modifiedBy = (String)nodeProps.get(ContentModel.PROP_MODIFIER);
- this.description = (String)nodeProps.get(ContentModel.PROP_DESCRIPTION);
+
+ this.props = new HashMap<>(nodeProps.size());
+
+ for (Map.Entry entry : nodeProps.entrySet()) {
+ QName propQName = entry.getKey();
+ if (! EXCLUDED_PROPS.contains(propQName)) {
+ props.put(entry.getKey().toPrefixString(namespaceService), entry.getValue());
+ }
+ }
}
public void setGuid(NodeRef guid)
@@ -175,6 +224,30 @@ public class Node implements Comparable
this.createdBy = createdBy;
}
+ public String getPrimaryPath()
+ {
+ return primaryPath;
+ }
+
+ public void setPrimaryPath(String primaryPath)
+ {
+ this.primaryPath = primaryPath;
+ }
+
+ public String getType()
+ {
+ return prefixTypeQName;
+ }
+
+ public void setType(String prefixType)
+ {
+ this.prefixTypeQName = prefixType;
+ }
+
+ public Map getProperties() {
+ return this.props;
+ }
+
public boolean equals(Object other)
{
if(this == other)
@@ -200,9 +273,9 @@ public class Node implements Comparable
@Override
public String toString()
{
- return "Node [nodeRef=" + nodeRef + ", name=" + name + ", title="
+ return "Node [nodeRef=" + nodeRef + ", type=" + prefixTypeQName + ", name=" + name + ", title="
+ title + ", description=" + description + ", createdAt="
+ createdAt + ", modifiedAt=" + modifiedAt + ", createdBy=" + createdBy + ", modifiedBy="
- + modifiedBy + "]";
+ + modifiedBy + ", primaryPath =" + primaryPath +"]";
}
}
diff --git a/source/java/org/alfresco/rest/api/nodes/NodeChildrenRelation.java b/source/java/org/alfresco/rest/api/nodes/NodeChildrenRelation.java
new file mode 100644
index 0000000000..e982948641
--- /dev/null
+++ b/source/java/org/alfresco/rest/api/nodes/NodeChildrenRelation.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2005-2015 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.Nodes;
+import org.alfresco.rest.api.model.Folder;
+import org.alfresco.rest.api.model.Node;
+import org.alfresco.rest.framework.WebApiDescription;
+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.Parameters;
+import org.alfresco.util.ParameterCheck;
+import org.springframework.beans.factory.InitializingBean;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * TODO ... work-in-progress
+ *
+ * @author janv
+ */
+@RelationshipResource(name = "children", entityResource = NodesEntityResource.class, title = "Folder children")
+public class NodeChildrenRelation implements RelationshipResourceAction.Read, RelationshipResourceAction.Create, InitializingBean
+{
+ private Nodes nodes;
+
+ public void setNodes(Nodes nodes)
+ {
+ this.nodes = nodes;
+ }
+
+ @Override
+ public void afterPropertiesSet()
+ {
+ ParameterCheck.mandatory("nodes", this.nodes);
+ }
+
+ /**
+ * List folder children - returns a filtered/sorted/paged list of nodes that are immediate children of the parent folder
+ *
+ * TODO filtering, sorting, ...
+ * 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:
+ *
+ * - incFiles
+ * - incFolders
+ *
+ * - properties
+ * - where
+ * - orderBy
+ *
+ * - skipCount
+ * - maxItems
+ *
+ * If parentFolderNodeId does not exist, EntityNotFoundException (status 404).
+ * If parentFolderNodeId does not represent a folder, InvalidArgumentException (status 400).
+ */
+ @Override
+ @WebApiDescription(title = "Return a paged list of nodes for the document/folder identified by parentFolderNodeId")
+ public CollectionWithPagingInfo readAll(String parentFolderNodeId, Parameters parameters)
+ {
+ return nodes.getChildren(parentFolderNodeId, parameters);
+ }
+
+ /**
+ * Create one or more sub-folders below parent folder. Note: can also use well-known alias, eg. -root- or -my-
+ *
+ * TODO also consider option to create path - eg. by passing name path in name (see Sparta API as an example) ... or should this be a separate API ?
+ *
+ * If parentFolderNodeId does not exist, EntityNotFoundException (status 404).
+ * If parentFolderNodeId does not represent a folder, InvalidArgumentException (status 400).
+ */
+ @Override
+ @WebApiDescription(title="Create one (or more) folder(s) as a child of folder identified by parentFolderNodeId")
+ public List create(String parentFolderNodeId, List folderInfos, Parameters parameters)
+ {
+ List result = new ArrayList<>(folderInfos.size());
+
+ for (Folder folderInfo : folderInfos)
+ {
+ result.add(nodes.createFolder(parentFolderNodeId, folderInfo, parameters));
+ }
+
+ return result;
+ }
+}
diff --git a/source/java/org/alfresco/rest/api/nodes/NodesEntityResource.java b/source/java/org/alfresco/rest/api/nodes/NodesEntityResource.java
index fefb730ff6..d9c03517c2 100644
--- a/source/java/org/alfresco/rest/api/nodes/NodesEntityResource.java
+++ b/source/java/org/alfresco/rest/api/nodes/NodesEntityResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2012 Alfresco Software Limited.
+ * Copyright (C) 2005-2015 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -19,7 +19,12 @@
package org.alfresco.rest.api.nodes;
import org.alfresco.rest.api.Nodes;
+import org.alfresco.rest.api.model.Node;
+import org.alfresco.rest.framework.WebApiDescription;
+import org.alfresco.rest.framework.WebApiParam;
import org.alfresco.rest.framework.resource.EntityResource;
+import org.alfresco.rest.framework.resource.actions.interfaces.EntityResourceAction;
+import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.util.ParameterCheck;
import org.springframework.beans.factory.InitializingBean;
@@ -28,9 +33,10 @@ import org.springframework.beans.factory.InitializingBean;
*
* @author sglover
* @author Gethin James
+ * @author janv
*/
@EntityResource(name="nodes", title = "Nodes")
-public class NodesEntityResource implements InitializingBean
+public class NodesEntityResource implements EntityResourceAction.ReadById, EntityResourceAction.Delete, EntityResourceAction.Update, InitializingBean
{
private Nodes nodes;
@@ -44,4 +50,53 @@ public class NodesEntityResource implements InitializingBean
{
ParameterCheck.mandatory("nodes", this.nodes);
}
+
+ /**
+ * Returns information regarding the node 'nodeId' - folder or document
+ *
+ * TODO other metadata/properties & permissions etc ...
+ *
+ * @param nodeId String id of node (folder or document) - will also accept well-known aliases, eg. "-root-" or "-my-"
+ *
+ * Optional parameters:
+ * - path
+ * - incPrimaryPath
+ */
+ @WebApiDescription(title = "Get Node Information", description = "Get information for the node with id 'nodeId'")
+ @WebApiParam(name = "nodeId", title = "The node id")
+ public Node readById(String nodeId, Parameters parameters)
+ {
+ return nodes.getFolderOrDocument(nodeId, parameters);
+ }
+
+ /**
+ * Update info on the node 'nodeId' - folder or document
+ *
+ * Initially, name, title &/or description. Note: changing name is a "rename" (and must be unique within the current parent folder).
+ *
+ * TODO other metadata/properties & permissions etc ...
+ *
+ * @param nodeId String nodeId of node (folder or document)
+ * @param nodeInfo node entity with info to update (eg. name, title, description ...)
+ * @param parameters
+ * @return
+ */
+ @Override
+ @WebApiDescription(title="Updates a node (file or folder) with id 'nodeId'")
+ public Node update(String nodeId, Node nodeInfo, Parameters parameters)
+ {
+ return nodes.updateNode(nodeId, nodeInfo, parameters);
+ }
+
+ /**
+ * Delete the given node. Note: will cascade delete for a folder.
+ *
+ * @param nodeId String id of node (folder or document)
+ */
+ @Override
+ @WebApiDescription(title = "Delete Node", description="Delete the file or folder with id 'nodeId'. Folder will cascade delete")
+ public void delete(String nodeId, Parameters parameters)
+ {
+ nodes.deleteNode(nodeId);
+ }
}
diff --git a/source/java/org/alfresco/rest/framework/core/ResourceDictionaryBuilder.java b/source/java/org/alfresco/rest/framework/core/ResourceDictionaryBuilder.java
index 337c569827..47d88fc2e4 100644
--- a/source/java/org/alfresco/rest/framework/core/ResourceDictionaryBuilder.java
+++ b/source/java/org/alfresco/rest/framework/core/ResourceDictionaryBuilder.java
@@ -138,7 +138,11 @@ public class ResourceDictionaryBuilder
ResourceDictionary rd = new ResourceDictionary();
processResources(rd,apiMap,null);
processTopLevelApis(rd);
- logger.debug(rd.prettyPrint());
+
+ if (logger.isDebugEnabled()) {
+ logger.debug(rd.prettyPrint());
+ }
+
return rd;
}