Merged FILE-FOLDER-API (5.2.0) to HEAD (5.2)

118825 jkaabimofrad: RA-655: manual merge of SFS module to FILE-FOLDER-API.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@126351 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Jamal Kaabi-Mofrad
2016-05-10 10:27:38 +00:00
parent 09eac586f6
commit d8eb979be3
11 changed files with 1803 additions and 931 deletions

View File

@@ -429,9 +429,22 @@
</property> </property>
</bean> </bean>
<bean id="nodes" class="org.alfresco.rest.api.impl.NodesImpl"> <bean id="nodes.ignoreTypes" class="org.springframework.beans.factory.config.SetFactoryBean">
<property name="sourceSet">
<set>
<value>cm:systemfolder</value>
<value>fm:forums</value>
<value>fm:forum</value>
<value>fm:topic</value>
<value>fm:post</value>
</set>
</property>
</bean>
<bean id="nodes" class="org.alfresco.rest.api.impl.NodesImpl" init-method="init">
<property name="serviceRegistry" ref="ServiceRegistry"/> <property name="serviceRegistry" ref="ServiceRegistry"/>
<property name="repositoryHelper" ref="repositoryHelper"/> <property name="repositoryHelper" ref="repositoryHelper"/>
<property name="ignoreTypes" ref="nodes.ignoreTypes"/>
</bean> </bean>
<bean id="Nodes" class="org.springframework.aop.framework.ProxyFactoryBean"> <bean id="Nodes" class="org.springframework.aop.framework.ProxyFactoryBean">

View File

@@ -29,6 +29,7 @@ import org.alfresco.rest.api.model.Document;
import org.alfresco.rest.api.model.Folder; import org.alfresco.rest.api.model.Folder;
import org.alfresco.rest.api.model.Node; import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.api.model.PathInfo; import org.alfresco.rest.api.model.PathInfo;
import org.alfresco.rest.api.model.PathInfo.ElementInfo;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException; 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.content.BasicContentInfo; import org.alfresco.rest.framework.resource.content.BasicContentInfo;
@@ -46,11 +47,14 @@ import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.model.FileNotFoundException; import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.InvalidNodeRefException; import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.Path.Element;
import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.AccessStatus; import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PermissionService;
@@ -69,6 +73,7 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
/** /**
@@ -76,6 +81,7 @@ import java.util.Set;
* *
* @author steveglover * @author steveglover
* @author janv * @author janv
* @author Jamal Kaabi-Mofrad
* *
* @since publicapi1.0 * @since publicapi1.0
*/ */
@@ -98,6 +104,20 @@ public class NodesImpl implements Nodes
private PermissionService permissionService; private PermissionService permissionService;
private Repository repositoryHelper; private Repository repositoryHelper;
private ServiceRegistry sr; private ServiceRegistry sr;
private Set<String> defaultIgnoreTypes;
private Set<QName> ignoreTypeQNames;
public void init()
{
if (defaultIgnoreTypes != null)
{
ignoreTypeQNames = new HashSet<>(defaultIgnoreTypes.size());
for (String type : defaultIgnoreTypes)
{
ignoreTypeQNames.add(createQName(type));
}
}
}
public void setServiceRegistry(ServiceRegistry sr) { public void setServiceRegistry(ServiceRegistry sr) {
this.sr = sr; this.sr = sr;
@@ -114,6 +134,11 @@ public class NodesImpl implements Nodes
this.repositoryHelper = repositoryHelper; this.repositoryHelper = repositoryHelper;
} }
public void setIgnoreTypes(Set<String> ignoreTypes)
{
this.defaultIgnoreTypes = ignoreTypes;
}
private static final List<QName> EXCLUDED_ASPECTS = Arrays.asList( private static final List<QName> EXCLUDED_ASPECTS = Arrays.asList(
ContentModel.ASPECT_REFERENCEABLE, ContentModel.ASPECT_REFERENCEABLE,
ContentModel.ASPECT_LOCALIZED); ContentModel.ASPECT_LOCALIZED);
@@ -169,7 +194,6 @@ public class NodesImpl implements Nodes
new HashSet<>(Arrays.asList(new String[] {PARAM_ISFOLDER})); new HashSet<>(Arrays.asList(new String[] {PARAM_ISFOLDER}));
/* /*
*
* Note: assumes workspace://SpacesStore * Note: assumes workspace://SpacesStore
*/ */
public NodeRef validateNode(String nodeId) public NodeRef validateNode(String nodeId)
@@ -182,11 +206,11 @@ public class NodesImpl implements Nodes
String versionLabel = null; String versionLabel = null;
int idx = nodeId.indexOf(";"); int idx = nodeId.indexOf(";");
if(idx != -1) if (idx != -1)
{ {
versionLabel = nodeId.substring(idx + 1); versionLabel = nodeId.substring(idx + 1);
nodeId = nodeId.substring(0, idx); nodeId = nodeId.substring(0, idx);
if(versionLabel.equals("pwc")) if (versionLabel.equals("pwc"))
{ {
// TODO correct exception? // TODO correct exception?
throw new EntityNotFoundException(nodeId); throw new EntityNotFoundException(nodeId);
@@ -199,7 +223,7 @@ public class NodesImpl implements Nodes
public NodeRef validateNode(NodeRef nodeRef) public NodeRef validateNode(NodeRef nodeRef)
{ {
if (! nodeService.exists(nodeRef)) if (!nodeService.exists(nodeRef))
{ {
throw new EntityNotFoundException(nodeRef.getId()); throw new EntityNotFoundException(nodeRef.getId());
} }
@@ -209,7 +233,7 @@ public class NodesImpl implements Nodes
public boolean nodeMatches(NodeRef nodeRef, Set<QName> expectedTypes, Set<QName> excludedTypes) public boolean nodeMatches(NodeRef nodeRef, Set<QName> expectedTypes, Set<QName> excludedTypes)
{ {
if (! nodeService.exists(nodeRef)) if (!nodeService.exists(nodeRef))
{ {
throw new EntityNotFoundException(nodeRef.getId()); throw new EntityNotFoundException(nodeRef.getId());
} }
@@ -239,7 +263,7 @@ public class NodesImpl implements Nodes
boolean inExpected = allExpectedTypes.contains(type); boolean inExpected = allExpectedTypes.contains(type);
boolean excluded = allExcludedTypes.contains(type); boolean excluded = allExcludedTypes.contains(type);
return(inExpected && !excluded); return (inExpected && !excluded);
} }
/** /**
@@ -267,8 +291,8 @@ public class NodesImpl implements Nodes
private Type getType(QName type) private Type getType(QName type)
{ {
boolean isContainer = Boolean.valueOf((dictionaryService.isSubClass(type, ContentModel.TYPE_FOLDER) == true && boolean isContainer = Boolean.valueOf((dictionaryService.isSubClass(type, ContentModel.TYPE_FOLDER) == true
!dictionaryService.isSubClass(type, ContentModel.TYPE_SYSTEM_FOLDER))); && !dictionaryService.isSubClass(type, ContentModel.TYPE_SYSTEM_FOLDER)));
return isContainer ? Type.FOLDER : Type.DOCUMENT; return isContainer ? Type.FOLDER : Type.DOCUMENT;
} }
@@ -284,7 +308,7 @@ public class NodesImpl implements Nodes
Document doc = new Document(nodeRef, getParentNodeRef(nodeRef), properties, sr); Document doc = new Document(nodeRef, getParentNodeRef(nodeRef), properties, sr);
doc.setVersionLabel((String)properties.get(ContentModel.PROP_VERSION_LABEL)); doc.setVersionLabel((String) properties.get(ContentModel.PROP_VERSION_LABEL));
ContentData cd = (ContentData) properties.get(ContentModel.PROP_CONTENT); ContentData cd = (ContentData) properties.get(ContentModel.PROP_CONTENT);
if (cd != null) if (cd != null)
{ {
@@ -340,7 +364,8 @@ public class NodesImpl implements Nodes
return nodeService.getPrimaryParent(nodeRef).getParentRef(); return nodeService.getPrimaryParent(nodeRef).getParentRef();
} }
private NodeRef validateOrLookupNode(String nodeId, String path) { private NodeRef validateOrLookupNode(String nodeId, String path)
{
NodeRef parentNodeRef; NodeRef parentNodeRef;
if (nodeId.equals(PATH_ROOT)) if (nodeId.equals(PATH_ROOT))
@@ -356,16 +381,21 @@ public class NodesImpl implements Nodes
NodeRef person = repositoryHelper.getPerson(); NodeRef person = repositoryHelper.getPerson();
if (person == null) if (person == null)
{ {
throw new IllegalArgumentException("Unexpected: cannot use "+PATH_MY); throw new InvalidArgumentException("Unexpected: cannot use " + PATH_MY);
} }
parentNodeRef = repositoryHelper.getUserHome(person); parentNodeRef = repositoryHelper.getUserHome(person);
if (parentNodeRef == null)
{
throw new EntityNotFoundException(nodeId);
}
} }
else else
{ {
parentNodeRef = validateNode(nodeId); parentNodeRef = validateNode(nodeId);
} }
if (path != null) { if (path != null)
{
// resolve path relative to current nodeId // resolve path relative to current nodeId
parentNodeRef = resolveNodeByPath(parentNodeRef, path, true); parentNodeRef = resolveNodeByPath(parentNodeRef, path, true);
} }
@@ -431,13 +461,14 @@ public class NodesImpl implements Nodes
NodeRef nodeRef = validateOrLookupNode(nodeId, path); NodeRef nodeRef = validateOrLookupNode(nodeId, path);
QName typeQName = nodeService.getType(nodeRef); QName typeQName = nodeService.getType(nodeRef);
return getFolderOrDocument(nodeRef, getParentNodeRef(nodeRef), typeQName, false); List<QName> requestedProperties = createQNames(parameters.getSelectedProperties());
return getFolderOrDocument(nodeRef, getParentNodeRef(nodeRef), typeQName, requestedProperties, false);
} }
private Node getFolderOrDocument(final NodeRef nodeRef, NodeRef parentNodeRef, QName typeQName, boolean minimalnfo) private Node getFolderOrDocument(final NodeRef nodeRef, NodeRef parentNodeRef, QName typeQName, List<QName> selectedProperties, boolean minimalnfo)
{ {
PathInfo pathInfo = null; PathInfo pathInfo = null;
if (! minimalnfo) if (!minimalnfo)
{ {
pathInfo = lookupPathInfo(nodeRef); pathInfo = lookupPathInfo(nodeRef);
} }
@@ -461,8 +492,9 @@ public class NodesImpl implements Nodes
throw new InvalidArgumentException("Node is not a folder or file"); throw new InvalidArgumentException("Node is not a folder or file");
} }
if (! minimalnfo) { if (!minimalnfo)
node.setProperties(mapProperties(properties)); {
node.setProperties(mapProperties(properties, selectedProperties));
node.setAspectNames(mapAspects(nodeService.getAspects(nodeRef))); node.setAspectNames(mapAspects(nodeService.getAspects(nodeRef)));
} }
@@ -474,66 +506,124 @@ public class NodesImpl implements Nodes
protected PathInfo lookupPathInfo(NodeRef nodeRefIn) protected PathInfo lookupPathInfo(NodeRef nodeRefIn)
{ {
List<PathInfo.ElementInfo> elements = new ArrayList<>(5); // TODO which implementation?
return getPathInfo(nodeRefIn);
NodeRef companyHomeNodeRef = repositoryHelper.getCompanyHome(); // List<PathInfo.ElementInfo> elements = new ArrayList<>(5);
boolean isComplete = true; //
// NodeRef companyHomeNodeRef = repositoryHelper.getCompanyHome();
NodeRef pNodeRef = nodeRefIn; // boolean isComplete = true;
while (pNodeRef != null) //
{ // NodeRef pNodeRef = nodeRefIn;
if (pNodeRef.equals(companyHomeNodeRef)) // while (pNodeRef != null)
{ // {
pNodeRef = null; // if (pNodeRef.equals(companyHomeNodeRef))
// {
// pNodeRef = null;
// }
// else {
// pNodeRef = nodeService.getPrimaryParent(pNodeRef).getParentRef();
//
// if (pNodeRef == null)
// {
// // belts-and-braces - is it even possible to get here ?
// isComplete = false;
// }
// else
// {
// if (permissionService.hasPermission(pNodeRef, PermissionService.READ)
// == AccessStatus.ALLOWED)
// {
// String name = (String) nodeService.getProperty(pNodeRef,
// ContentModel.PROP_NAME);
// elements.add(0, new ElementInfo(pNodeRef, name));
// }
// else
// {
// isComplete = false;
// pNodeRef = null;
// }
// }
// }
// }
//
// StringBuilder sb = new StringBuilder();
// for (PathInfo.ElementInfo e : elements)
// {
// sb.append("/").append(e.getName());
// }
//
// return new PathInfo(sb.toString(), isComplete, elements);
} }
else {
pNodeRef = nodeService.getPrimaryParent(pNodeRef).getParentRef();
if (pNodeRef == null) private PathInfo getPathInfo(NodeRef nodeRef)
{ {
// belts-and-braces - is it even possible to get here ? final Path nodePath = nodeService.getPath(nodeRef);
isComplete = false;
List<ElementInfo> pathElements = new ArrayList<>();
Boolean isComplete = Boolean.TRUE;
// 2 => as we don't want to include the given node in the path as well.
for (int i = nodePath.size() - 2; i >= 0; i--)
{
Element element = nodePath.get(i);
if (element instanceof Path.ChildAssocElement)
{
ChildAssociationRef elementRef = ((Path.ChildAssocElement) element).getRef();
if (elementRef.getParentRef() != null)
{
NodeRef childNodeRef = elementRef.getChildRef();
if (permissionService.hasPermission(childNodeRef, PermissionService.READ) == AccessStatus.ALLOWED)
{
Serializable nameProp = nodeService.getProperty(childNodeRef, ContentModel.PROP_NAME);
pathElements.add(0, new ElementInfo(childNodeRef, nameProp.toString()));
} }
else else
{ {
if (permissionService.hasPermission(pNodeRef, PermissionService.READ) == AccessStatus.ALLOWED) // Just return the pathInfo up to the location where the user has access
{ isComplete = Boolean.FALSE;
String name = (String) nodeService.getProperty(pNodeRef, ContentModel.PROP_NAME); break;
elements.add(0, new PathInfo().new ElementInfo(pNodeRef.getId(), name));
}
else
{
isComplete = false;
pNodeRef = null;
} }
} }
} }
} }
StringBuilder sb = new StringBuilder(); String pathStr = null;
for (PathInfo.ElementInfo e : elements) if(pathElements.size() > 0)
{
StringBuilder sb = new StringBuilder(120);
for (PathInfo.ElementInfo e : pathElements)
{ {
sb.append("/").append(e.getName()); sb.append("/").append(e.getName());
} }
pathStr = sb.toString();
return new PathInfo(sb.toString(), isComplete, elements); }
else
{
// There is no path element, so set it to null in order to be
// ignored by Jackson during serialisation
isComplete = null;
}
return new PathInfo(pathStr, isComplete, pathElements);
} }
protected Map<String, Serializable> mapProperties(Map<QName, Serializable> nodeProps) protected Map<String, Object> mapProperties(Map<QName, Serializable> nodeProps, List<QName> selectedProperties)
{ {
Map<String, Serializable> props = new HashMap<>(nodeProps.size()); Map<String, Object> props = null;
if (!selectedProperties.isEmpty())
for (Map.Entry<QName, Serializable> entry : nodeProps.entrySet()) {
QName propQName = entry.getKey();
if (!EXCLUDED_PROPS.contains(propQName))
{ {
props.put(entry.getKey().toPrefixString(namespaceService), entry.getValue()); props = new HashMap<>(selectedProperties.size());
for (QName qName : selectedProperties)
{
Serializable value = nodeProps.get(qName);
if (value != null)
{
props.put(qName.toPrefixString(namespaceService), value);
} }
} }
if (props.isEmpty())
if (props.size() == 0)
{ {
props = null; // no props to return props = null; // set to null so it doesn't show up as an empty object in the JSON response.
}
} }
return props; return props;
@@ -561,12 +651,19 @@ public class NodesImpl implements Nodes
public CollectionWithPagingInfo<Node> getChildren(String parentFolderNodeId, Parameters parameters) public CollectionWithPagingInfo<Node> getChildren(String parentFolderNodeId, Parameters parameters)
{ {
// TODO do we want to support path with list folder children ?
String path = null;
// String path = parameters.getParameter("path");
final NodeRef parentNodeRef = validateOrLookupNode(parentFolderNodeId, path);
// TODO // TODO
// map - where (filter) properties - including isFolder // map - where (filter) properties - including isFolder
// map - orderBy (sort) properties - including isFolder // map - orderBy (sort) properties - including isFolder
// TODO refactor & fix ! // TODO refactor & fix !
final boolean minimalnfo = (parameters.getSelectedProperties().size() == 0); final boolean minimalnfo = (parameters.getSelectedProperties().size() == 0);
final List<QName> requestedProperties = createQNames(parameters.getSelectedProperties());
boolean includeFolders = true; boolean includeFolders = true;
boolean includeFiles = true; boolean includeFiles = true;
@@ -597,7 +694,7 @@ public class NodesImpl implements Nodes
QName propQname = MAP_PARAM_QNAME.get(sortCol.column); QName propQname = MAP_PARAM_QNAME.get(sortCol.column);
if (propQname == null) if (propQname == null)
{ {
propQname = QName.resolveToQName(namespaceService, sortCol.column); propQname = createQName(sortCol.column);
} }
if (propQname != null) if (propQname != null)
@@ -616,12 +713,6 @@ public class NodesImpl implements Nodes
Paging paging = parameters.getPaging(); Paging paging = parameters.getPaging();
// TODO do we want to support path with list folder children ?
String path = null;
//String path = parameters.getParameter("path");
final NodeRef parentNodeRef = validateOrLookupNode(parentFolderNodeId, path);
if (! nodeMatches(parentNodeRef, Collections.singleton(ContentModel.TYPE_FOLDER), null)) if (! nodeMatches(parentNodeRef, Collections.singleton(ContentModel.TYPE_FOLDER), null))
{ {
throw new InvalidArgumentException("NodeId of folder is expected"); throw new InvalidArgumentException("NodeId of folder is expected");
@@ -629,7 +720,7 @@ public class NodesImpl implements Nodes
PagingRequest pagingRequest = Util.getPagingRequest(paging); PagingRequest pagingRequest = Util.getPagingRequest(paging);
final PagingResults<FileInfo> pagingResults = fileFolderService.list(parentNodeRef, includeFiles, includeFolders, null, sortProps, pagingRequest); final PagingResults<FileInfo> pagingResults = fileFolderService.list(parentNodeRef, includeFiles, includeFolders, ignoreTypeQNames, sortProps, pagingRequest);
final List<FileInfo> page = pagingResults.getPage(); final List<FileInfo> page = pagingResults.getPage();
List<Node> nodes = new AbstractList<Node>() List<Node> nodes = new AbstractList<Node>()
@@ -640,7 +731,7 @@ public class NodesImpl implements Nodes
FileInfo fInfo = page.get(index); FileInfo fInfo = page.get(index);
// basic info by default (unless "select"ed otherwise) // basic info by default (unless "select"ed otherwise)
return getFolderOrDocument(fInfo.getNodeRef(), parentNodeRef, fInfo.getType(), minimalnfo); return getFolderOrDocument(fInfo.getNodeRef(), parentNodeRef, fInfo.getType(), requestedProperties, minimalnfo);
} }
@Override @Override
@@ -683,7 +774,7 @@ public class NodesImpl implements Nodes
} }
// check that requested type is a (sub-) type of folder or content // check that requested type is a (sub-) type of folder or content
QName nodeTypeQName = QName.resolveToQName(namespaceService, 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));
if (! typeMatches(nodeTypeQName, contentAndFolders, null)) { if (! typeMatches(nodeTypeQName, contentAndFolders, null)) {
@@ -696,7 +787,7 @@ public class NodesImpl implements Nodes
if (nodeInfo.getProperties() != null) if (nodeInfo.getProperties() != null)
{ {
for (Map.Entry entry : (Set<Map.Entry<String, Serializable>>)nodeInfo.getProperties().entrySet()) for (Entry<String, Object> entry : nodeInfo.getProperties().entrySet())
{ {
QName propQName = QName.createQName((String)entry.getKey(), namespaceService); QName propQName = QName.createQName((String)entry.getKey(), namespaceService);
props.put(propQName, (Serializable)entry.getValue()); props.put(propQName, (Serializable)entry.getValue());
@@ -734,7 +825,7 @@ public class NodesImpl implements Nodes
if (nodeInfo.getProperties() != null) if (nodeInfo.getProperties() != null)
{ {
for (Map.Entry entry : (Set<Map.Entry<String, Serializable>>)nodeInfo.getProperties().entrySet()) for (Entry<String, Object> entry : nodeInfo.getProperties().entrySet())
{ {
QName propQName = QName.createQName((String)entry.getKey(), namespaceService); QName propQName = QName.createQName((String)entry.getKey(), namespaceService);
props.put(propQName, (Serializable)entry.getValue()); props.put(propQName, (Serializable)entry.getValue());
@@ -800,4 +891,58 @@ public class NodesImpl implements Nodes
// TODO - hmm - we may wish to return json info !! // TODO - hmm - we may wish to return json info !!
return; return;
} }
/**
* Helper to create a QName from either a fully qualified or short-name QName string
*
* @param qnameStr Fully qualified or short-name QName string
* @return QName
*/
protected QName createQName(String qnameStr)
{
try
{
QName qname;
if (qnameStr.indexOf(QName.NAMESPACE_BEGIN) != -1)
{
qname = QName.createQName(qnameStr);
}
else
{
qname = QName.createQName(qnameStr, namespaceService);
}
return qname;
}
catch (Exception ex)
{
String msg = ex.getMessage();
if (msg == null)
{
msg = "";
}
throw new InvalidArgumentException(qnameStr + " isn't a valid QName. " + msg);
}
}
/**
* Helper to create a QName from either a fully qualified or short-name QName string
*
* @param qnameStrList list of fully qualified or short-name QName string
* @return a list of {@code QName} objects
*/
protected List<QName> createQNames(List<String> qnameStrList)
{
List<QName> result = new ArrayList<>(qnameStrList.size());
for (String str : qnameStrList)
{
str = str.replaceFirst("_", ":"); // FIXME remove this when we have fixed the framework.
QName name = createQName(str);
if (!EXCLUDED_PROPS.contains(name))
{
result.add(name);
}
}
return result;
}
} }

View File

@@ -39,6 +39,11 @@ public class Document extends Node
{ {
private ContentInfo contentInfo; private ContentInfo contentInfo;
// instance init block
{
this.isFolder = Boolean.FALSE;
}
public Document() { public Document() {
super(); super();
} }
@@ -57,16 +62,16 @@ public class Document extends Node
} }
} }
public Boolean getIsFolder()
{
return false;
}
public ContentInfo getContent() public ContentInfo getContent()
{ {
return contentInfo; return contentInfo;
} }
public void setContent(ContentInfo contentInfo)
{
this.contentInfo = contentInfo;
}
@Override @Override
public String toString() public String toString()
{ {

View File

@@ -16,6 +16,7 @@
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.alfresco.rest.api.model; package org.alfresco.rest.api.model;
import java.io.Serializable; import java.io.Serializable;
@@ -30,10 +31,14 @@ import org.alfresco.service.namespace.QName;
* *
* @author steveglover * @author steveglover
* @author janv * @author janv
*
*/ */
public class Folder extends Node public class Folder extends Node
{ {
// instance init block
{
this.isFolder = Boolean.TRUE;
}
public Folder() public Folder()
{ {
super(); super();
@@ -44,11 +49,6 @@ public class Folder extends Node
super(nodeRef, parentNodeRef, nodeProps, sr); super(nodeRef, parentNodeRef, nodeProps, sr);
} }
public Boolean getIsFolder()
{
return true;
}
@Override @Override
public String toString() public String toString()
{ {

View File

@@ -50,13 +50,15 @@ public class Node implements Comparable<Node>
protected UserInfo createdByUser; protected UserInfo createdByUser;
protected UserInfo modifiedByUser; protected UserInfo modifiedByUser;
protected Boolean isFolder;
protected NodeRef parentNodeRef; protected NodeRef parentNodeRef;
protected PathInfo pathInfo; protected PathInfo pathInfo;
protected String prefixTypeQName; protected String prefixTypeQName;
protected List<String> aspectNames; protected List<String> aspectNames;
protected Map<String, Serializable> props; protected Map<String, Object> properties;
// TODO fixme ! // TODO fixme !
// also need to optionally pass in user map - eg. when listing children (to avoid multiple lookups for same user) // also need to optionally pass in user map - eg. when listing children (to avoid multiple lookups for same user)
@@ -183,12 +185,12 @@ public class Node implements Comparable<Node>
this.prefixTypeQName = prefixType; this.prefixTypeQName = prefixType;
} }
public Map getProperties() { public Map<String, Object> getProperties() {
return this.props; return this.properties;
} }
public void setProperties(Map props) { public void setProperties(Map<String, Object> props) {
this.props = props; this.properties = props;
} }
public List<String> getAspectNames() { public List<String> getAspectNames() {
@@ -204,6 +206,21 @@ public class Node implements Comparable<Node>
return parentNodeRef; return parentNodeRef;
} }
public void setParentId(NodeRef parentNodeRef)
{
this.parentNodeRef = parentNodeRef;
}
public Boolean getIsFolder()
{
return isFolder;
}
public void setIsFolder(Boolean isFolder)
{
this.isFolder=isFolder;
}
public boolean equals(Object other) public boolean equals(Object other)
{ {
if(this == other) if(this == other)

View File

@@ -1,12 +1,14 @@
package org.alfresco.rest.api.model; package org.alfresco.rest.api.model;
import java.util.List; import java.util.List;
import org.alfresco.service.cmr.repository.NodeRef;
/** /**
* Representation of a path info * Representation of a path info
* *
* @author janv * @author janv
*
*/ */
public class PathInfo public class PathInfo
{ {
@@ -25,40 +27,66 @@ public class PathInfo
this.elements = elements; this.elements = elements;
} }
public String getName() { public String getName()
{
return name; return name;
} }
public Boolean getIsComplete() { public Boolean getIsComplete()
{
return isComplete; return isComplete;
} }
public List<ElementInfo> getElements() { public List<ElementInfo> getElements()
{
return elements; return elements;
} }
public class ElementInfo { @Override
public String toString()
{
final StringBuilder sb = new StringBuilder(120);
sb.append("PathInfo [name='").append(name)
.append(", isComplete=").append(isComplete)
.append(", elements=").append(elements)
.append(']');
return sb.toString();
}
private String id; public static class ElementInfo
{
private NodeRef id;
private String name; private String name;
public ElementInfo() public ElementInfo()
{ {
} }
public ElementInfo(String id, String name) public ElementInfo(NodeRef id, String name)
{ {
this.id = id; this.id = id;
this.name = name; this.name = name;
} }
public String getName() { public String getName()
{
return name; return name;
} }
public String getId() { public NodeRef getId()
{
return id; return id;
} }
@Override
public String toString()
{
final StringBuilder sb = new StringBuilder(250);
sb.append("PathElement [id=").append(id)
.append(", name='").append(name)
.append(']');
return sb.toString();
}
} }
} }

View File

@@ -16,13 +16,13 @@
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.alfresco.rest.api.model; package org.alfresco.rest.api.model;
/** /**
* Representation of a user info * Representation of a user info
* *
* @author janv * @author janv
*
*/ */
public class UserInfo public class UserInfo
{ {
@@ -36,18 +36,19 @@ public class UserInfo
public UserInfo(String userName, String firstName, String lastName) public UserInfo(String userName, String firstName, String lastName)
{ {
this.userName = userName; this.userName = userName;
this.displayName = ((firstName != null ? firstName + " " : "") + (lastName != null ? lastName : "")).replaceAll("^\\s+|\\s+$", ""); this.displayName = ((firstName != null ? firstName + " " : "") + (lastName != null ? lastName : "")).trim();
} }
public String getDisplayName() { public String getDisplayName()
{
return displayName; return displayName;
} }
public String getUserName() { public String getUserName()
{
return userName; return userName;
} }
@Override @Override
public String toString() public String toString()
{ {

View File

@@ -19,10 +19,17 @@
package org.alfresco.rest.api.tests; package org.alfresco.rest.api.tests;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import static org.junit.Assert.assertNotNull;
import org.alfresco.repo.tenant.TenantUtil;
import org.alfresco.rest.api.tests.RepoService.SiteInformation;
import org.alfresco.rest.api.tests.RepoService.TestNetwork;
import org.alfresco.rest.api.tests.RepoService.TestPerson;
import org.alfresco.rest.api.tests.RepoService.TestSite;
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;
import org.alfresco.rest.api.tests.client.RequestContext; import org.alfresco.rest.api.tests.client.RequestContext;
import org.alfresco.service.cmr.site.SiteVisibility;
import java.util.Map; import java.util.Map;
@@ -75,9 +82,14 @@ public abstract class AbstractBaseApiTest extends EnterpriseTestApi
} }
protected HttpResponse getAll(String url, String runAsUser, PublicApiClient.Paging paging, int expectedStatus) throws Exception protected HttpResponse getAll(String url, String runAsUser, PublicApiClient.Paging paging, int expectedStatus) throws Exception
{
return getAll(url, runAsUser, paging, null, expectedStatus);
}
protected HttpResponse getAll(String url, String runAsUser, PublicApiClient.Paging paging, Map<String, String> otherParams, int expectedStatus) throws Exception
{ {
publicApiClient.setRequestContext(new RequestContext(runAsUser)); publicApiClient.setRequestContext(new RequestContext(runAsUser));
Map<String, String> params = (paging == null) ? null : createParams(paging, null); Map<String, String> params = (paging == null) ? null : createParams(paging, otherParams);
HttpResponse response = publicApiClient.get(getScope(), url, null, null, null, params); HttpResponse response = publicApiClient.get(getScope(), url, null, null, null, params);
checkStatus(expectedStatus, response.getStatusCode()); checkStatus(expectedStatus, response.getStatusCode());
@@ -85,6 +97,16 @@ public abstract class AbstractBaseApiTest extends EnterpriseTestApi
return response; return response;
} }
protected HttpResponse getAll(Class<?> entityResource, String runAsUser, PublicApiClient.Paging paging, Map<String, String> otherParams, int expectedStatus) throws Exception
{
publicApiClient.setRequestContext(new RequestContext(runAsUser));
HttpResponse response = publicApiClient.get(entityResource, null, null, otherParams);
checkStatus(expectedStatus, response.getStatusCode());
return response;
}
protected HttpResponse getSingle(String url, String runAsUser, String entityId, int expectedStatus) throws Exception protected HttpResponse getSingle(String url, String runAsUser, String entityId, int expectedStatus) throws Exception
{ {
publicApiClient.setRequestContext(new RequestContext(runAsUser)); publicApiClient.setRequestContext(new RequestContext(runAsUser));
@@ -95,6 +117,16 @@ public abstract class AbstractBaseApiTest extends EnterpriseTestApi
return response; return response;
} }
protected HttpResponse getSingle(Class<?> entityResource, String runAsUser, String entityId, Map<String, String> params, int expectedStatus) throws Exception
{
publicApiClient.setRequestContext(new RequestContext(runAsUser));
HttpResponse response = publicApiClient.get(entityResource, entityId, null, params);
checkStatus(expectedStatus, response.getStatusCode());
return response;
}
protected HttpResponse put(String url, String runAsUser, String entityId, String body, String queryString, int expectedStatus) throws Exception protected HttpResponse put(String url, String runAsUser, String entityId, String body, String queryString, int expectedStatus) throws Exception
{ {
publicApiClient.setRequestContext(new RequestContext(runAsUser)); publicApiClient.setRequestContext(new RequestContext(runAsUser));
@@ -125,6 +157,23 @@ public abstract class AbstractBaseApiTest extends EnterpriseTestApi
return person.getId(); return person.getId();
} }
protected TestSite createSite(final TestNetwork testNetwork, TestPerson user, final SiteVisibility siteVisibility)
{
final String siteName = "RandomSite" + System.currentTimeMillis();
final TestSite site = TenantUtil.runAsUserTenant(new TenantUtil.TenantRunAsWork<TestSite>()
{
@Override
public TestSite doWork() throws Exception
{
SiteInformation siteInfo = new SiteInformation(siteName, siteName, siteName, siteVisibility);
return repoService.createSite(testNetwork, siteInfo);
}
}, user.getId(), testNetwork.getId());
assertNotNull(site);
return site;
}
protected void checkStatus(int expectedStatus, int actualStatus) protected void checkStatus(int expectedStatus, int actualStatus)
{ {
if (expectedStatus > 0 && expectedStatus != actualStatus) if (expectedStatus > 0 && expectedStatus != actualStatus)

View File

@@ -0,0 +1,485 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.rest.api.tests;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import org.alfresco.model.ContentModel;
import org.alfresco.model.ForumModel;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.model.Repository;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.rest.api.model.Document;
import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.api.model.PathInfo;
import org.alfresco.rest.api.model.PathInfo.ElementInfo;
import org.alfresco.rest.api.model.UserInfo;
import org.alfresco.rest.api.nodes.NodesEntityResource;
import org.alfresco.rest.api.tests.RepoService.TestNetwork;
import org.alfresco.rest.api.tests.RepoService.TestPerson;
import org.alfresco.rest.api.tests.RepoService.TestSite;
import org.alfresco.rest.api.tests.client.HttpResponse;
import org.alfresco.rest.api.tests.client.PublicApiClient.ExpectedPaging;
import org.alfresco.rest.api.tests.client.PublicApiClient.Paging;
import org.alfresco.rest.api.tests.client.data.SiteRole;
import org.alfresco.rest.api.tests.util.JacksonUtil;
import org.alfresco.rest.api.tests.util.RestApiUtil;
import org.alfresco.rest.framework.jacksonextensions.JacksonHelper;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.MutableAuthenticationService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.cmr.site.SiteVisibility;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* API tests for:
* <ul>
* <li> {@literal host:port/alfresco/api/{networkId}/public/alfresco/versions/1/nodes/{nodeId}} </li>
* <li> {@literal host:port/alfresco/api/{networkId}/public/alfresco/versions/1/nodes/{nodeId}/children} </li>
* </ul>
*
* @author Jamal Kaabi-Mofrad
*/
public class NodeApiTest extends AbstractBaseApiTest
{
/**
* User one from network one
*/
private TestPerson userOneN1;
/**
* User two from network one
*/
private TestPerson userTwoN1;
/**
* Private site of user one from network one
*/
private TestSite userOneN1Site;
private String user1;
private String user2;
private List<String> users = new ArrayList<>();
protected MutableAuthenticationService authenticationService;
protected PersonService personService;
protected Repository repositoryHelper;
protected JacksonUtil jacksonUtil;
protected PermissionService permissionService;
@Before
public void setup() throws Exception
{
authenticationService = applicationContext.getBean("authenticationService", MutableAuthenticationService.class);
personService = applicationContext.getBean("personService", PersonService.class);
repositoryHelper = applicationContext.getBean("repositoryHelper", Repository.class);
jacksonUtil = new JacksonUtil(applicationContext.getBean("jsonHelper", JacksonHelper.class));
permissionService = applicationContext.getBean("permissionService", PermissionService.class);
user1 = createUser("user1" + System.currentTimeMillis());
user2 = createUser("user2" + System.currentTimeMillis());
// We just need to clean the on-premise-users,
// so the tests for the specific network would work.
users.add(user1);
users.add(user2);
TestNetwork networkOne = getTestFixture().getRandomNetwork();
userOneN1 = networkOne.createUser();
userTwoN1 = networkOne.createUser();
userOneN1Site = createSite(networkOne, userOneN1, SiteVisibility.PRIVATE);
}
@After
public void tearDown() throws Exception
{
AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser();
for (final String user : users)
{
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
if (personService.personExists(user))
{
authenticationService.deleteAuthentication(user);
personService.deletePerson(user);
}
return null;
}
});
}
users.clear();
AuthenticationUtil.clearCurrentSecurityContext();
}
@Test
public void testListDocLibChildren() throws Exception
{
AuthenticationUtil.setFullyAuthenticatedUser(userOneN1.getId());
NodeRef docLibNodeRef = userOneN1Site.getContainerNodeRef(("documentLibrary"));
String folder1 = "folder" + System.currentTimeMillis() + "_1";
repoService.addToDocumentLibrary(userOneN1Site, folder1, ContentModel.TYPE_FOLDER);
String folder2 = "folder" + System.currentTimeMillis() + "_2";
repoService.addToDocumentLibrary(userOneN1Site, folder2, ContentModel.TYPE_FOLDER);
String content1 = "content" + System.currentTimeMillis() + "_1";
repoService.addToDocumentLibrary(userOneN1Site, content1, ContentModel.TYPE_CONTENT);
String content2 = "content" + System.currentTimeMillis() + "_2";
repoService.addToDocumentLibrary(userOneN1Site, content2, ContentModel.TYPE_CONTENT);
String forum1 = "forum" + System.currentTimeMillis() + "_1";
repoService.createObjectOfCustomType(docLibNodeRef, forum1, ForumModel.TYPE_TOPIC.toString());
Paging paging = getPaging(0, 100);
HttpResponse response = getAll(getChildrenUrl(docLibNodeRef), userOneN1.getId(), paging, 200);
List<Node> nodes = jacksonUtil.parseEntries(response.getJsonResponse(), Node.class);
assertEquals(4, nodes.size()); // forum is part of the default ignored types
// Paging
ExpectedPaging expectedPaging = RestApiUtil.parsePaging(response.getJsonResponse());
assertEquals(4, expectedPaging.getCount().intValue());
assertEquals(0, expectedPaging.getSkipCount().intValue());
assertEquals(100, expectedPaging.getMaxItems().intValue());
assertFalse(expectedPaging.getHasMoreItems().booleanValue());
// Order by folders and modified date first
Map<String, String> orderBy = Collections.singletonMap("orderBy", "isFolder DESC,modifiedAt DESC");
response = getAll(getChildrenUrl(docLibNodeRef), userOneN1.getId(), paging, orderBy, 200);
nodes = jacksonUtil.parseEntries(response.getJsonResponse(), Node.class);
assertEquals(4, nodes.size());
assertEquals(folder2, nodes.get(0).getName());
assertTrue(nodes.get(0).getIsFolder());
assertEquals(folder1, nodes.get(1).getName());
assertTrue(nodes.get(1).getIsFolder());
assertEquals(content2, nodes.get(2).getName());
assertFalse(nodes.get(2).getIsFolder());
assertEquals(content1, nodes.get(3).getName());
assertFalse(nodes.get(3).getIsFolder());
// Order by folders last and modified date first
orderBy = Collections.singletonMap("orderBy", "isFolder ASC,modifiedAt DESC");
response = getAll(getChildrenUrl(docLibNodeRef), userOneN1.getId(), paging, orderBy, 200);
nodes = jacksonUtil.parseEntries(response.getJsonResponse(), Node.class);
assertEquals(4, nodes.size());
assertEquals(content2, nodes.get(0).getName());
assertEquals(content1, nodes.get(1).getName());
assertEquals(folder2, nodes.get(2).getName());
assertEquals(folder1, nodes.get(3).getName());
// Order by folders and modified date last
orderBy = Collections.singletonMap("orderBy", "isFolder,modifiedAt");
response = getAll(getChildrenUrl(docLibNodeRef), userOneN1.getId(), paging, orderBy, 200);
nodes = jacksonUtil.parseEntries(response.getJsonResponse(), Node.class);
assertEquals(4, nodes.size());
assertEquals(content1, nodes.get(0).getName());
assertEquals(content2, nodes.get(1).getName());
assertEquals(folder1, nodes.get(2).getName());
assertEquals(folder2, nodes.get(3).getName());
// Order by folders and modified date first
orderBy = Collections.singletonMap("orderBy", "isFolder DESC,modifiedAt DESC");
// SkipCount=0,MaxItems=2
paging = getPaging(0, 2);
response = getAll(getChildrenUrl(docLibNodeRef), userOneN1.getId(), paging, orderBy, 200);
nodes = jacksonUtil.parseEntries(response.getJsonResponse(), Node.class);
assertEquals(2, nodes.size());
assertEquals(folder2, nodes.get(0).getName());
assertEquals(folder1, nodes.get(1).getName());
expectedPaging = RestApiUtil.parsePaging(response.getJsonResponse());
assertEquals(2, expectedPaging.getCount().intValue());
assertEquals(0, expectedPaging.getSkipCount().intValue());
assertEquals(2, expectedPaging.getMaxItems().intValue());
assertTrue(expectedPaging.getHasMoreItems().booleanValue());
// SkipCount=2,MaxItems=4
paging = getPaging(2, 4);
response = getAll(getChildrenUrl(docLibNodeRef), userOneN1.getId(), paging, orderBy, 200);
nodes = jacksonUtil.parseEntries(response.getJsonResponse(), Node.class);
assertEquals(2, nodes.size());
assertEquals(content2, nodes.get(0).getName());
assertEquals(content1, nodes.get(1).getName());
expectedPaging = RestApiUtil.parsePaging(response.getJsonResponse());
assertEquals(2, expectedPaging.getCount().intValue());
assertEquals(2, expectedPaging.getSkipCount().intValue());
assertEquals(4, expectedPaging.getMaxItems().intValue());
assertFalse(expectedPaging.getHasMoreItems().booleanValue());
// userTwoN1 tries to access userOneN1's docLib
AuthenticationUtil.setFullyAuthenticatedUser(userTwoN1.getId());
paging = getPaging(0, Integer.MAX_VALUE);
getAll(getChildrenUrl(docLibNodeRef), userTwoN1.getId(), paging, 403);
}
@Test
public void testListMyFilesChildren() throws Exception
{
AuthenticationUtil.setFullyAuthenticatedUser(user1);
NodeRef myFilesNodeRef = repositoryHelper.getUserHome(personService.getPerson(user1));
String folder1 = "folder" + System.currentTimeMillis() + "_1";
repoService.createFolder(myFilesNodeRef, folder1);
String folder2 = "folder" + System.currentTimeMillis() + "_2";
repoService.createFolder(myFilesNodeRef, folder2);
String content1 = "content" + System.currentTimeMillis() + "_1";
NodeRef contentNodeRef = repoService.createDocument(myFilesNodeRef, content1, "The quick brown fox jumps over the lazy dog.");
repoService.getNodeService().setProperty(contentNodeRef, ContentModel.PROP_OWNER, user1);
repoService.getNodeService().setProperty(contentNodeRef, ContentModel.PROP_LAST_THUMBNAIL_MODIFICATION_DATA,
(Serializable) Collections.singletonList("doclib:1444660852296"));
Paging paging = getPaging(0, Integer.MAX_VALUE);
HttpResponse response = getAll(getChildrenUrl(myFilesNodeRef), user1, paging, 200);
List<Document> nodes = jacksonUtil.parseEntries(response.getJsonResponse(), Document.class);
assertEquals(3, nodes.size());
// Order by folders and modified date first
Map<String, String> orderBy = Collections.singletonMap("orderBy", "isFolder DESC,modifiedAt DESC");
response = getAll(getChildrenUrl(myFilesNodeRef), user1, paging, orderBy, 200);
nodes = jacksonUtil.parseEntries(response.getJsonResponse(), Document.class);
assertEquals(3, nodes.size());
assertEquals(folder2, nodes.get(0).getName());
assertEquals(folder1, nodes.get(1).getName());
Document node = (Document) nodes.get(2);
assertEquals(content1, node.getName());
assertEquals("cm:content", node.getNodeType());
assertEquals(contentNodeRef.getId(), node.getNodeRef().getId());
UserInfo createdByUser = node.getCreatedByUser();
assertEquals(user1, createdByUser.getUserName());
assertEquals(user1 + " " + user1, createdByUser.getDisplayName());
UserInfo modifiedByUser = node.getModifiedByUser();
assertEquals(user1, modifiedByUser.getUserName());
assertEquals(user1 + " " + user1, modifiedByUser.getDisplayName());
assertEquals(MimetypeMap.MIMETYPE_BINARY, node.getContent().getMimeType());
assertNotNull(node.getContent().getMimeTypeName());
assertNotNull(node.getContent().getEncoding());
assertTrue(node.getContent().getSizeInBytes() > 0);
// Invalid QName (Namespace prefix cm... is not mapped to a namespace URI) for the orderBy parameter.
orderBy = Collections.singletonMap("orderBy", "isFolder DESC,cm" + System.currentTimeMillis() + ":modified DESC");
getAll(getChildrenUrl(myFilesNodeRef), user1, paging, orderBy, 400);
AuthenticationUtil.setFullyAuthenticatedUser(user2);
// user2 tries to access user1's home folder
getAll(getChildrenUrl(myFilesNodeRef), user2, paging, 403);
AuthenticationUtil.setFullyAuthenticatedUser(user1);
// request property via select
Map<String, String> params = new LinkedHashMap<>();
params.put("select", "cm_lastThumbnailModification");// TODO replace the underscore with colon when the framework is fixed.
params.put("orderBy", "isFolder DESC,modifiedAt DESC");
response = getAll(getChildrenUrl(myFilesNodeRef), user1, paging, params, 200);
nodes = jacksonUtil.parseEntries(response.getJsonResponse(), Document.class);
assertEquals(3, nodes.size());
assertNull("There shouldn't be a 'properties' object in the response.", nodes.get(0).getProperties());
assertNull("There shouldn't be a 'properties' object in the response.", nodes.get(1).getProperties());
assertNotNull("There should be a 'properties' object in the response.", nodes.get(2).getProperties());
Set<Entry<String, Object>> props = nodes.get(2).getProperties().entrySet();
assertEquals(1, props.size());
Entry<String, Object> entry = props.iterator().next();
assertEquals("cm:lastThumbnailModification", entry.getKey());
assertEquals("doclib:1444660852296", ((List<?>) entry.getValue()).get(0));
}
@Test
public void testGetPathElements_DocLib() throws Exception
{
AuthenticationUtil.setFullyAuthenticatedUser(userOneN1.getId());
userOneN1Site.inviteToSite(userTwoN1.getEmail(), SiteRole.SiteConsumer);
NodeRef docLibNodeRef = userOneN1Site.getContainerNodeRef(("documentLibrary"));
// /Company Home/Sites/RandomSite<timestamp>/documentLibrary/folder<timestamp>_A
String folderA = "folder" + System.currentTimeMillis() + "_A";
NodeRef folderA_Ref = repoService.createFolder(docLibNodeRef, folderA);
// /Company Home/Sites/RandomSite<timestamp>/documentLibrary/folder<timestamp>_A/folder<timestamp>_B
String folderB = "folder" + System.currentTimeMillis() + "_B";
NodeRef folderB_Ref = repoService.createFolder(folderA_Ref, folderB);
// /Company Home/Sites/RandomSite<timestamp>/documentLibrary/folder<timestamp>_A/folder<timestamp>_B/folder<timestamp>_C
String folderC = "folder" + System.currentTimeMillis() + "_C";
NodeRef folderC_Ref = repoService.createFolder(folderB_Ref, folderC);
// /Company Home/Sites/RandomSite<timestamp>/documentLibrary/folder<timestamp>_A/folder<timestamp>_B/folder<timestamp>_C/content<timestamp>
String content = "content" + System.currentTimeMillis();
NodeRef contentNodeRef = repoService.createDocument(folderC_Ref, content, "The quick brown fox jumps over the lazy dog.");
// Revoke folderB inherited permissions
permissionService.setInheritParentPermissions(folderB_Ref, false);
// Grant userTwoN1 permission for folderC
permissionService.setPermission(folderC_Ref, userTwoN1.getId(), PermissionService.CONSUMER, true);
//...nodes/nodeId?select=path
Map<String, String> params = Collections.singletonMap("select", "path");
HttpResponse response = getSingle(NodesEntityResource.class, userOneN1.getId(), contentNodeRef.getId(), params, 200);
Document node = jacksonUtil.parseEntry(response.getJsonResponse(), Document.class);
PathInfo path = node.getPath();
assertNotNull(path);
assertTrue(path.getIsComplete());
assertNotNull(path.getName());
// the path should only include the parents (not the requested node)
assertFalse(path.getName().endsWith(content));
assertTrue(path.getName().startsWith("/Company Home"));
List<ElementInfo> pathElements = path.getElements();
assertEquals(7, pathElements.size());
assertEquals("Company Home", pathElements.get(0).getName());
assertEquals("Sites", pathElements.get(1).getName());
assertEquals(userOneN1Site.getSiteId(), pathElements.get(2).getName());
assertEquals("documentLibrary", pathElements.get(3).getName());
assertEquals(folderA, pathElements.get(4).getName());
assertEquals(folderB, pathElements.get(5).getName());
assertEquals(folderC, pathElements.get(6).getName());
// Try the above tests with userTwoN1 (site consumer)
AuthenticationUtil.setFullyAuthenticatedUser(userTwoN1.getId());
response = getSingle(NodesEntityResource.class, userTwoN1.getId(), contentNodeRef.getId(), params, 200);
node = jacksonUtil.parseEntry(response.getJsonResponse(), Document.class);
path = node.getPath();
assertNotNull(path);
assertFalse("The path is not complete as the user doesn't have permission to access the full path.", path.getIsComplete());
assertNotNull(path.getName());
// site consumer (userTwoN1) dose not have access to the folderB
assertFalse("site consumer (userTwoN1) dose not have access to the folderB", path.getName().contains(folderB));
assertFalse(path.getName().startsWith("/Company Home"));
// Go up as far as they can, before getting access denied (i.e. "/folderC")
assertTrue(path.getName().endsWith(folderC));
pathElements = path.getElements();
assertEquals(1, pathElements.size());
assertEquals(folderC, pathElements.get(0).getName());
}
@Test
public void testGetPathElements_MyFiles() throws Exception
{
final String userNodeAlias = "-my-";
AuthenticationUtil.setFullyAuthenticatedUser(user1);
HttpResponse response = getSingle(NodesEntityResource.class, user1, userNodeAlias, null, 200);
Node node = jacksonUtil.parseEntry(response.getJsonResponse(), Node.class);
NodeRef myFilesNodeRef = node.getNodeRef();
assertNotNull(myFilesNodeRef);
assertEquals(user1, node.getName());
assertTrue(node.getIsFolder());
// /Company Home/User Homes/user<timestamp>/folder<timestamp>_A
String folderA = "folder" + System.currentTimeMillis() + "_A";
NodeRef folderA_Ref = repoService.createFolder(myFilesNodeRef, folderA);
// /Company Home/User Homes/user<timestamp>/folder<timestamp>_A/folder<timestamp>_B
String folderB = "folder" + System.currentTimeMillis() + "_B";
NodeRef folderB_Ref = repoService.createFolder(folderA_Ref, folderB);
// /Company Home/User Homes/user<timestamp>/folder<timestamp>_A/folder<timestamp>_B/folder<timestamp>_C
String folderC = "folder" + System.currentTimeMillis() + "_C";
NodeRef folderC_Ref = repoService.createFolder(folderB_Ref, folderC);
//...nodes/nodeId?select=pathInfo
Map<String, String> params = Collections.singletonMap("select", "path");
response = getSingle(NodesEntityResource.class, user1, folderC_Ref.getId(), params, 200);
node = jacksonUtil.parseEntry(response.getJsonResponse(), Node.class);
PathInfo pathInfo = node.getPath();
assertNotNull(pathInfo);
assertTrue(pathInfo.getIsComplete());
assertNotNull(pathInfo.getName());
// the pathInfo should only include the parents (not the requested node)
assertFalse(pathInfo.getName().endsWith(folderC));
assertTrue(pathInfo.getName().startsWith("/Company Home"));
List<ElementInfo> pathElements = pathInfo.getElements();
assertEquals(5, pathElements.size());
assertEquals("Company Home", pathElements.get(0).getName());
assertNotNull(pathElements.get(0).getId());
assertEquals("User Homes", pathElements.get(1).getName());
assertNotNull(pathElements.get(1).getId());
assertEquals(user1, pathElements.get(2).getName());
assertNotNull(pathElements.get(2).getId());
assertEquals(folderA, pathElements.get(3).getName());
assertNotNull(pathElements.get(3).getId());
assertEquals(folderB, pathElements.get(4).getName());
assertNotNull(pathElements.get(4).getId());
}
@Test
public void testGetNodeWithKnownAlias() throws Exception
{
final String rootNodeAlias = "-root-";
HttpResponse response = getSingle(NodesEntityResource.class, user1, rootNodeAlias, null, 200);
Node node = jacksonUtil.parseEntry(response.getJsonResponse(), Node.class);
assertEquals("Company Home", node.getName());
assertNotNull(node.getNodeRef());
PathInfo pathInfo = node.getPath();
// empty JSON object ("path":{})
assertNotNull(pathInfo);
// as this is the root node, there will be no name or path elements.
assertNull(pathInfo.getIsComplete());
assertNull(pathInfo.getName());
assertNull(pathInfo.getElements());
// unknown alias
getSingle(NodesEntityResource.class, user1, "testSomeUndefinedAlias", null, 404);
final String userNodeAlias = "-my-";
response = getSingle(NodesEntityResource.class, user1, userNodeAlias, null, 200);
node = jacksonUtil.parseEntry(response.getJsonResponse(), Node.class);
NodeRef myFilesNodeRef = node.getNodeRef();
assertNotNull(myFilesNodeRef);
assertEquals(user1, node.getName());
assertTrue(node.getIsFolder());
pathInfo = node.getPath();
assertNotNull(pathInfo);
assertTrue(pathInfo.getIsComplete());
//Delete user1's home
AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser();
repoService.getNodeService().deleteNode(myFilesNodeRef);
AuthenticationUtil.setFullyAuthenticatedUser(user1);
getSingle(NodesEntityResource.class, user1, userNodeAlias, null, 404); // Not found
}
private String getChildrenUrl(NodeRef nodeRef)
{
return "nodes/" + nodeRef.getId() + "/children";
}
@Override
public String getScope()
{
return "public";
}
}

View File

@@ -16,6 +16,7 @@
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.alfresco.rest.api.tests.client; package org.alfresco.rest.api.tests.client;
import java.io.IOException; import java.io.IOException;
@@ -59,13 +60,11 @@ import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.classreading.MetadataReaderFactory;
/** /**
* A http client for talking to the rest apis. * A http client for talking to the rest apis. The caller can pass in a rest api
* * implementation class to the http method (get, post, put, delete supported)
* The caller can pass in a rest api implementation class to the http method (get, post, put, delete supported)
* and the url will be generated. * and the url will be generated.
* *
* @author steveglover * @author steveglover
*
*/ */
public class PublicApiHttpClient public class PublicApiHttpClient
{ {
@@ -73,7 +72,7 @@ public class PublicApiHttpClient
private static final String OLD_BASE_URL = "{0}://{1}:{2}{3}{4}{5}/api/"; private static final String OLD_BASE_URL = "{0}://{1}:{2}{3}{4}{5}/api/";
private static final String INDEX_URL = "{0}://{1}:{2}{3}{4}"; private static final String INDEX_URL = "{0}://{1}:{2}{3}{4}";
private static final String BASE_URL = "{0}://{1}:{2}{3}{4}{5}/{6}/{7}/versions/1"; private static final String BASE_URL = "{0}://{1}:{2}{3}{4}{5}/{6}/{7}/versions/{8}/";
private static final String PUBLICAPI_CMIS_SERVICE_URL = "{0}://{1}:{2}{3}{4}cmis/versions/{5}/{6}"; private static final String PUBLICAPI_CMIS_SERVICE_URL = "{0}://{1}:{2}{3}{4}cmis/versions/{5}/{6}";
private static final String PUBLICAPI_CMIS_URL = "{0}://{1}:{2}{3}{4}{5}/{6}/cmis/versions/{7}/{8}"; private static final String PUBLICAPI_CMIS_URL = "{0}://{1}:{2}{3}{4}{5}/{6}/cmis/versions/{7}/{8}";
private static final String PUBLICAPI_CMIS_URL_SUFFIX = "{0}/{1}/cmis/versions/{2}/{3}"; private static final String PUBLICAPI_CMIS_URL_SUFFIX = "{0}/{1}/cmis/versions/{2}/{3}";
@@ -105,16 +104,16 @@ public class PublicApiHttpClient
this.host = host; this.host = host;
this.port = port; this.port = port;
this.contextPath = contextPath; this.contextPath = contextPath;
if(this.contextPath != null && !this.contextPath.isEmpty() && !this.contextPath.endsWith("/")) if (this.contextPath != null && !this.contextPath.isEmpty() && !this.contextPath.endsWith("/"))
{ {
this.contextPath = this.contextPath + "/"; this.contextPath = this.contextPath + "/";
} }
if(this.contextPath != null && !this.contextPath.startsWith("/")) if (this.contextPath != null && !this.contextPath.startsWith("/"))
{ {
this.contextPath = "/" + this.contextPath; this.contextPath = "/" + this.contextPath;
} }
this.servletName = servletName; this.servletName = servletName;
if(this.servletName != null && !this.servletName.isEmpty() && !this.servletName.endsWith("/")) if (this.servletName != null && !this.servletName.isEmpty() && !this.servletName.endsWith("/"))
{ {
this.servletName = this.servletName + "/"; this.servletName = this.servletName + "/";
} }
@@ -124,18 +123,18 @@ public class PublicApiHttpClient
public String getCmisUrl(String repositoryId, String operation) public String getCmisUrl(String repositoryId, String operation)
{ {
StringBuilder url = new StringBuilder(); StringBuilder url = new StringBuilder();
if(repositoryId == null) if (repositoryId == null)
{ {
url.append(MessageFormat.format(ATOM_PUB_URL, new Object[] { scheme, host, String.valueOf(port), contextPath})); url.append(MessageFormat.format(ATOM_PUB_URL, new Object[] { scheme, host, String.valueOf(port), contextPath }));
} }
else else
{ {
url.append(MessageFormat.format(ATOM_PUB_URL, new Object[] { scheme, host, String.valueOf(port), contextPath})); url.append(MessageFormat.format(ATOM_PUB_URL, new Object[] { scheme, host, String.valueOf(port), contextPath }));
url.append("/"); url.append("/");
url.append(repositoryId); url.append(repositoryId);
} }
if(operation != null) if (operation != null)
{ {
url.append("/"); url.append("/");
url.append(operation); url.append(operation);
@@ -147,18 +146,18 @@ public class PublicApiHttpClient
public String getPublicApiCmisUrl(String networkId, Binding binding, String version, String operation) public String getPublicApiCmisUrl(String networkId, Binding binding, String version, String operation)
{ {
StringBuilder url = new StringBuilder(); StringBuilder url = new StringBuilder();
if(networkId == null) if (networkId == null)
{ {
url.append(MessageFormat.format(PUBLICAPI_CMIS_SERVICE_URL, new Object[] { scheme, host, String.valueOf(port), contextPath, url.append(MessageFormat.format(PUBLICAPI_CMIS_SERVICE_URL,
servletName, version, binding.toString().toLowerCase()})); new Object[] { scheme, host, String.valueOf(port), contextPath, servletName, version, binding.toString().toLowerCase() }));
} }
else else
{ {
url.append(MessageFormat.format(PUBLICAPI_CMIS_URL, new Object[] { scheme, host, String.valueOf(port), contextPath, servletName, url.append(MessageFormat.format(PUBLICAPI_CMIS_URL, new Object[] { scheme, host, String.valueOf(port), contextPath, servletName,
networkId, "public", version, binding.toString().toLowerCase()})); networkId, "public", version, binding.toString().toLowerCase() }));
} }
if(operation != null) if (operation != null)
{ {
url.append("/"); url.append("/");
url.append(operation); url.append(operation);
@@ -171,10 +170,9 @@ public class PublicApiHttpClient
{ {
StringBuilder url = new StringBuilder(); StringBuilder url = new StringBuilder();
url.append(MessageFormat.format(PUBLICAPI_CMIS_URL_SUFFIX, url.append(MessageFormat.format(PUBLICAPI_CMIS_URL_SUFFIX, new Object[] { networkId, "public", version, binding.toString().toLowerCase() }));
new Object[] {networkId, "public", version, binding.toString().toLowerCase()}));
if(operation != null) if (operation != null)
{ {
url.append("/"); url.append("/");
url.append(operation); url.append(operation);
@@ -204,7 +202,7 @@ public class PublicApiHttpClient
private void log(String msg) private void log(String msg)
{ {
if(logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
logger.debug(msg); logger.debug(msg);
} }
@@ -252,7 +250,7 @@ public class PublicApiHttpClient
}; };
HttpResponse response = null; HttpResponse response = null;
if(rq.getPassword() != null) if (rq.getPassword() != null)
{ {
response = authenticatedHttp.executeHttpMethodAuthenticated(req, rq.getRunAsUser(), rq.getPassword(), callback); response = authenticatedHttp.executeHttpMethodAuthenticated(req, rq.getRunAsUser(), rq.getPassword(), callback);
} }
@@ -264,7 +262,7 @@ public class PublicApiHttpClient
} }
finally finally
{ {
if(req != null) if (req != null)
{ {
req.releaseConnection(); req.releaseConnection();
} }
@@ -280,7 +278,8 @@ public class PublicApiHttpClient
return submitRequest(req, rq); return submitRequest(req, rq);
} }
public HttpResponse get(final Class<?> c, final RequestContext rq, final Object entityId, final Object relationshipEntityId, Map<String, String> params) throws IOException public HttpResponse get(final Class<?> c, final RequestContext rq, final Object entityId, final Object relationshipEntityId,
Map<String, String> params) throws IOException
{ {
RestApiEndpoint endpoint = new RestApiEndpoint(c, rq.getNetworkId(), entityId, relationshipEntityId, params); RestApiEndpoint endpoint = new RestApiEndpoint(c, rq.getNetworkId(), entityId, relationshipEntityId, params);
String url = endpoint.getUrl(); String url = endpoint.getUrl();
@@ -289,18 +288,34 @@ public class PublicApiHttpClient
return submitRequest(req, rq); return submitRequest(req, rq);
} }
public HttpResponse get(final RequestContext rq, String scope, final String entityCollectionName, final Object entityId, final String relationCollectionName, final Object relationshipEntityId, Map<String, String> params) throws IOException public HttpResponse get(final RequestContext rq, String scope, final String entityCollectionName, final Object entityId,
final String relationCollectionName, final Object relationshipEntityId, Map<String, String> params) throws IOException
{ {
RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), scope, entityCollectionName, entityId, relationCollectionName, relationshipEntityId, params); return get(rq, scope, 1, entityCollectionName, entityId, relationCollectionName, relationshipEntityId, params);
}
public HttpResponse get(final RequestContext rq, final String scope, final int version, final String entityCollectionName, final Object entityId,
final String relationCollectionName, final Object relationshipEntityId, Map<String, String> params) throws IOException
{
RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), scope, version, entityCollectionName, entityId, relationCollectionName,
relationshipEntityId, params);
String url = endpoint.getUrl(); String url = endpoint.getUrl();
GetMethod req = new GetMethod(url); GetMethod req = new GetMethod(url);
return submitRequest(req, rq); return submitRequest(req, rq);
} }
public HttpResponse get(final RequestContext rq, String scope, String password, final String entityCollectionName, final Object entityId, final String relationCollectionName, final Object relationshipEntityId, Map<String, String> params) throws IOException public HttpResponse get(final RequestContext rq, String scope, String password, final String entityCollectionName, final Object entityId,
final String relationCollectionName, final Object relationshipEntityId, Map<String, String> params) throws IOException
{ {
RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), scope, entityCollectionName, entityId, relationCollectionName, relationshipEntityId, params); return get(rq, scope, 1, password, entityCollectionName, entityId, relationCollectionName, relationshipEntityId, params);
}
public HttpResponse get(final RequestContext rq, final String scope, final int version, final String password, final String entityCollectionName, final Object entityId,
final String relationCollectionName, final Object relationshipEntityId, Map<String, String> params) throws IOException
{
RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), scope, version, entityCollectionName, entityId, relationCollectionName,
relationshipEntityId, params);
String url = endpoint.getUrl(); String url = endpoint.getUrl();
GetMethod req = new GetMethod(url); GetMethod req = new GetMethod(url);
@@ -325,13 +340,14 @@ public class PublicApiHttpClient
return submitRequest(req, rq); return submitRequest(req, rq);
} }
public HttpResponse post(final Class<?> c, final RequestContext rq, final Object entityId, final Object relationshipEntityId, final String body) throws IOException public HttpResponse post(final Class<?> c, final RequestContext rq, final Object entityId, final Object relationshipEntityId, final String body)
throws IOException
{ {
RestApiEndpoint endpoint = new RestApiEndpoint(c, rq.getNetworkId(), entityId, relationshipEntityId, null); RestApiEndpoint endpoint = new RestApiEndpoint(c, rq.getNetworkId(), entityId, relationshipEntityId, null);
String url = endpoint.getUrl(); String url = endpoint.getUrl();
PostMethod req = new PostMethod(url.toString()); PostMethod req = new PostMethod(url.toString());
if(body != null) if (body != null)
{ {
StringRequestEntity requestEntity = new StringRequestEntity(body, "application/json", "UTF-8"); StringRequestEntity requestEntity = new StringRequestEntity(body, "application/json", "UTF-8");
req.setRequestEntity(requestEntity); req.setRequestEntity(requestEntity);
@@ -345,7 +361,7 @@ public class PublicApiHttpClient
String url = endpoint.getUrl(); String url = endpoint.getUrl();
PostMethod req = new PostMethod(url.toString()); PostMethod req = new PostMethod(url.toString());
if(body != null) if (body != null)
{ {
StringRequestEntity requestEntity = new StringRequestEntity(body, "application/json", "UTF-8"); StringRequestEntity requestEntity = new StringRequestEntity(body, "application/json", "UTF-8");
req.setRequestEntity(requestEntity); req.setRequestEntity(requestEntity);
@@ -359,14 +375,14 @@ public class PublicApiHttpClient
String url = endpoint.getUrl(); String url = endpoint.getUrl();
PostMethod req = new PostMethod(url.toString()); PostMethod req = new PostMethod(url.toString());
if(body != null) if (body != null)
{ {
StringRequestEntity requestEntity = null; StringRequestEntity requestEntity = null;
if(cmisBinding.equals(Binding.atom)) if (cmisBinding.equals(Binding.atom))
{ {
requestEntity = new StringRequestEntity(body, "text/xml", "UTF-8"); requestEntity = new StringRequestEntity(body, "text/xml", "UTF-8");
} }
else if(cmisBinding.equals(Binding.browser)) else if (cmisBinding.equals(Binding.browser))
{ {
requestEntity = new StringRequestEntity(body, "application/json", "UTF-8"); requestEntity = new StringRequestEntity(body, "application/json", "UTF-8");
} }
@@ -381,14 +397,14 @@ public class PublicApiHttpClient
String url = endpoint.getUrl(); String url = endpoint.getUrl();
PutMethod req = new PutMethod(url.toString()); PutMethod req = new PutMethod(url.toString());
if(body != null) if (body != null)
{ {
StringRequestEntity requestEntity = null; StringRequestEntity requestEntity = null;
if(cmisBinding.equals(Binding.atom)) if (cmisBinding.equals(Binding.atom))
{ {
requestEntity = new StringRequestEntity(body, "text/xml", "UTF-8"); requestEntity = new StringRequestEntity(body, "text/xml", "UTF-8");
} }
else if(cmisBinding.equals(Binding.browser)) else if (cmisBinding.equals(Binding.browser))
{ {
requestEntity = new StringRequestEntity(body, "application/json", "UTF-8"); requestEntity = new StringRequestEntity(body, "application/json", "UTF-8");
} }
@@ -397,7 +413,8 @@ public class PublicApiHttpClient
return submitRequest(req, rq); return submitRequest(req, rq);
} }
public HttpResponse get(final RequestContext rq, Binding cmisBinding, String version, String cmisOperation, Map<String, String> parameters) throws IOException public HttpResponse get(final RequestContext rq, Binding cmisBinding, String version, String cmisOperation, Map<String, String> parameters)
throws IOException
{ {
RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), cmisBinding, version, cmisOperation, parameters); RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), cmisBinding, version, cmisOperation, parameters);
String url = endpoint.getUrl(); String url = endpoint.getUrl();
@@ -460,7 +477,13 @@ public class PublicApiHttpClient
public HttpResponse post(final RequestContext rq, final String scope, final String entityCollectionName, final Object entityId, public HttpResponse post(final RequestContext rq, final String scope, final String entityCollectionName, final Object entityId,
final String relationCollectionName, final Object relationshipEntityId, final String body, String contentType) throws IOException final String relationCollectionName, final Object relationshipEntityId, final String body, String contentType) throws IOException
{ {
RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), scope, entityCollectionName, entityId, relationCollectionName, return post(rq, scope, 1, entityCollectionName, entityId, relationCollectionName, relationshipEntityId, body, contentType);
}
public HttpResponse post(final RequestContext rq, final String scope, final int version, final String entityCollectionName, final Object entityId,
final String relationCollectionName, final Object relationshipEntityId, final String body, String contentType) throws IOException
{
RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), scope, version, entityCollectionName, entityId, relationCollectionName,
relationshipEntityId, null); relationshipEntityId, null);
String url = endpoint.getUrl(); String url = endpoint.getUrl();
@@ -477,7 +500,6 @@ public class PublicApiHttpClient
return submitRequest(req, rq); return submitRequest(req, rq);
} }
public HttpResponse delete(final Class<?> c, final RequestContext rq, final Object entityId, final Object relationshipEntityId) throws IOException public HttpResponse delete(final Class<?> c, final RequestContext rq, final Object entityId, final Object relationshipEntityId) throws IOException
{ {
RestApiEndpoint endpoint = new RestApiEndpoint(c, rq.getNetworkId(), entityId, relationshipEntityId, null); RestApiEndpoint endpoint = new RestApiEndpoint(c, rq.getNetworkId(), entityId, relationshipEntityId, null);
@@ -487,22 +509,31 @@ public class PublicApiHttpClient
return submitRequest(req, rq); return submitRequest(req, rq);
} }
public HttpResponse delete(final RequestContext rq, final String scope, final String entityCollectionName, final Object entityId, final String relationCollectionName, final Object relationshipEntityId) throws IOException public HttpResponse delete(final RequestContext rq, final String scope, final String entityCollectionName, final Object entityId,
final String relationCollectionName, final Object relationshipEntityId) throws IOException
{ {
RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), scope, entityCollectionName, entityId, relationCollectionName, relationshipEntityId, null); return delete(rq, scope, 1, entityCollectionName, entityId, relationCollectionName, relationshipEntityId);
}
public HttpResponse delete(final RequestContext rq, final String scope, final int version, final String entityCollectionName, final Object entityId,
final String relationCollectionName, final Object relationshipEntityId) throws IOException
{
RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), scope, version, entityCollectionName, entityId, relationCollectionName,
relationshipEntityId, null);
String url = endpoint.getUrl(); String url = endpoint.getUrl();
DeleteMethod req = new DeleteMethod(url); DeleteMethod req = new DeleteMethod(url);
return submitRequest(req, rq); return submitRequest(req, rq);
} }
public HttpResponse put(final Class<?> c, final RequestContext rq, final Object entityId, final Object relationshipEntityId, final String body) throws IOException public HttpResponse put(final Class<?> c, final RequestContext rq, final Object entityId, final Object relationshipEntityId, final String body)
throws IOException
{ {
RestApiEndpoint endpoint = new RestApiEndpoint(c, rq.getNetworkId(), entityId, relationshipEntityId, null); RestApiEndpoint endpoint = new RestApiEndpoint(c, rq.getNetworkId(), entityId, relationshipEntityId, null);
String url = endpoint.getUrl(); String url = endpoint.getUrl();
PutMethod req = new PutMethod(url); PutMethod req = new PutMethod(url);
if(body != null) if (body != null)
{ {
StringRequestEntity requestEntity = new StringRequestEntity(body, "application/json", "UTF-8"); StringRequestEntity requestEntity = new StringRequestEntity(body, "application/json", "UTF-8");
req.setRequestEntity(requestEntity); req.setRequestEntity(requestEntity);
@@ -510,13 +541,21 @@ public class PublicApiHttpClient
return submitRequest(req, rq); return submitRequest(req, rq);
} }
public HttpResponse put(final RequestContext rq, final String scope, final String entityCollectionName, final Object entityId, final String relationCollectionName, final Object relationshipEntityId, final String body, final Map<String, String> params) throws IOException public HttpResponse put(final RequestContext rq, final String scope, final String entityCollectionName, final Object entityId,
final String relationCollectionName, final Object relationshipEntityId, final String body, final Map<String, String> params) throws IOException
{ {
RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), scope, entityCollectionName, entityId, relationCollectionName, relationshipEntityId, params); return put(rq, scope, 1, entityCollectionName, entityId, relationCollectionName, relationshipEntityId, body, params);
}
public HttpResponse put(final RequestContext rq, final String scope, final int version, final String entityCollectionName, final Object entityId,
final String relationCollectionName, final Object relationshipEntityId, final String body, Map<String, String> params) throws IOException
{
RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), scope, version, entityCollectionName, entityId, relationCollectionName,
relationshipEntityId, params);
String url = endpoint.getUrl(); String url = endpoint.getUrl();
PutMethod req = new PutMethod(url); PutMethod req = new PutMethod(url);
if(body != null) if (body != null)
{ {
StringRequestEntity requestEntity = new StringRequestEntity(body, "application/json", "UTF-8"); StringRequestEntity requestEntity = new StringRequestEntity(body, "application/json", "UTF-8");
req.setRequestEntity(requestEntity); req.setRequestEntity(requestEntity);
@@ -525,8 +564,8 @@ public class PublicApiHttpClient
} }
/* /*
* Encapsulates information relating to a rest api end point, generating and encoding urls * Encapsulates information relating to a rest api end point, generating and
* based on the rest api implementation class. * encoding urls based on the rest api implementation class.
*/ */
private class RestApiEndpoint private class RestApiEndpoint
{ {
@@ -534,8 +573,9 @@ public class PublicApiHttpClient
RestApiEndpoint(String url, Map<String, String> params) throws IOException RestApiEndpoint(String url, Map<String, String> params) throws IOException
{ {
StringBuilder sb = new StringBuilder(MessageFormat.format(INDEX_URL, new Object[] {scheme, host, String.valueOf(port), contextPath, servletName})); StringBuilder sb = new StringBuilder(
if(url != null) MessageFormat.format(INDEX_URL, new Object[] { scheme, host, String.valueOf(port), contextPath, servletName }));
if (url != null)
{ {
sb.append(url); sb.append(url);
} }
@@ -547,8 +587,8 @@ public class PublicApiHttpClient
RestApiEndpoint(String tenantDomain, String url, Map<String, String> params) throws IOException RestApiEndpoint(String tenantDomain, String url, Map<String, String> params) throws IOException
{ {
StringBuilder sb = new StringBuilder(MessageFormat.format(OLD_BASE_URL, new Object[] {scheme, host, String.valueOf(port), contextPath, servletName, StringBuilder sb = new StringBuilder(MessageFormat.format(OLD_BASE_URL, new Object[] { scheme, host, String.valueOf(port), contextPath,
tenantDomain == null ? TenantUtil.DEFAULT_TENANT : tenantDomain })); servletName, tenantDomain == null ? TenantUtil.DEFAULT_TENANT : tenantDomain }));
sb.append("/"); sb.append("/");
sb.append(url); sb.append(url);
@@ -557,18 +597,20 @@ public class PublicApiHttpClient
this.url = sb.toString(); this.url = sb.toString();
} }
RestApiEndpoint(Class<?> resourceClass, String tenantDomain, Object collectionEntityId, Object relationEntityId, Map<String, String> params) throws IOException RestApiEndpoint(Class<?> resourceClass, String tenantDomain, Object collectionEntityId, Object relationEntityId, Map<String, String> params)
throws IOException
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
Api api = ResourceInspector.inspectApi(resourceClass); Api api = ResourceInspector.inspectApi(resourceClass);
SCOPE scope = api.getScope(); SCOPE scope = api.getScope();
int version = api.getVersion();
Pair<String, String> relationshipCollectionInfo = getRelationCollectionInfo(resourceClass); Pair<String, String> relationshipCollectionInfo = getRelationCollectionInfo(resourceClass);
sb.append(MessageFormat.format(BASE_URL, new Object[] {scheme, host, String.valueOf(port), contextPath, servletName, sb.append(MessageFormat.format(BASE_URL, new Object[] { scheme, host, String.valueOf(port), contextPath, servletName,
tenantDomain == null ? TenantUtil.DEFAULT_TENANT : tenantDomain, scope.toString(), apiName})); tenantDomain == null ? TenantUtil.DEFAULT_TENANT : tenantDomain, scope.toString(), apiName, version }));
if(relationshipCollectionInfo != null) if (relationshipCollectionInfo != null)
{ {
String entityCollectionName = relationshipCollectionInfo.getFirst(); String entityCollectionName = relationshipCollectionInfo.getFirst();
String relationshipCollectionName = relationshipCollectionInfo.getSecond(); String relationshipCollectionName = relationshipCollectionInfo.getSecond();
@@ -577,7 +619,7 @@ public class PublicApiHttpClient
sb.append(entityCollectionName); sb.append(entityCollectionName);
sb.append("/"); sb.append("/");
if(collectionEntityIdString != null) if (collectionEntityIdString != null)
{ {
sb.append(collectionEntityIdString); sb.append(collectionEntityIdString);
sb.append("/"); sb.append("/");
@@ -585,7 +627,7 @@ public class PublicApiHttpClient
sb.append(relationshipCollectionName); sb.append(relationshipCollectionName);
sb.append("/"); sb.append("/");
if(relationEntityIdString != null) if (relationEntityIdString != null)
{ {
sb.append(relationEntityIdString); sb.append(relationEntityIdString);
sb.append("/"); sb.append("/");
@@ -594,13 +636,13 @@ public class PublicApiHttpClient
else else
{ {
String entityCollectionName = getEntityCollectionInfo(resourceClass); String entityCollectionName = getEntityCollectionInfo(resourceClass);
if(entityCollectionName != null) if (entityCollectionName != null)
{ {
String collectionEntityIdString = encodeToString(collectionEntityId); String collectionEntityIdString = encodeToString(collectionEntityId);
sb.append(entityCollectionName); sb.append(entityCollectionName);
sb.append("/"); sb.append("/");
if(collectionEntityIdString != null) if (collectionEntityIdString != null)
{ {
sb.append(collectionEntityIdString); sb.append(collectionEntityIdString);
sb.append("/"); sb.append("/");
@@ -621,7 +663,7 @@ public class PublicApiHttpClient
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
if(networkId != null) if (networkId != null)
{ {
sb.append(getPublicApiCmisUrl(networkId, cmisBinding, version, cmisOperation)); sb.append(getPublicApiCmisUrl(networkId, cmisBinding, version, cmisOperation));
} }
@@ -635,35 +677,38 @@ public class PublicApiHttpClient
this.url = sb.toString(); this.url = sb.toString();
} }
RestApiEndpoint(String tenantDomain, String scope, String collectionName, Object collectionEntityId, String relationName, Object relationEntityId, Map<String, String> params) throws IOException RestApiEndpoint(String tenantDomain, String scope, int version, String collectionName, Object collectionEntityId, String relationName,
Object relationEntityId, Map<String, String> params) throws IOException
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
if(tenantDomain == null || tenantDomain.equals(TenantService.DEFAULT_DOMAIN)) if (tenantDomain == null || tenantDomain.equals(TenantService.DEFAULT_DOMAIN))
{ {
tenantDomain = TenantUtil.DEFAULT_TENANT; tenantDomain = TenantUtil.DEFAULT_TENANT;
} }
sb.append(MessageFormat.format(BASE_URL, new Object[] {scheme, host, String.valueOf(port), contextPath, servletName, sb.append(MessageFormat.format(BASE_URL,
tenantDomain, scope, apiName})); new Object[] { scheme, host, String.valueOf(port), contextPath, servletName, tenantDomain, scope, apiName, version }));
if(collectionName != null) if (collectionName != null)
{ {
sb.append("/");
sb.append(collectionName); sb.append(collectionName);
if(collectionEntityId != null) if (collectionEntityId != null)
{ {
sb.append("/"); sb.append('/');
sb.append(collectionEntityId); sb.append(collectionEntityId);
} }
} }
if(relationName != null) if (relationName != null)
{ {
sb.append("/"); if (!sb.toString().endsWith("/"))
{
sb.append('/');
}
sb.append(relationName); sb.append(relationName);
if(relationEntityId != null) if (relationEntityId != null)
{ {
sb.append("/"); sb.append('/');
sb.append(relationEntityId); sb.append(relationEntityId);
} }
} }
@@ -673,13 +718,19 @@ public class PublicApiHttpClient
this.url = sb.toString(); this.url = sb.toString();
} }
RestApiEndpoint(String tenantDomain, String scope, String collectionName, Object collectionEntityId, String relationName,
Object relationEntityId, Map<String, String> params) throws IOException
{
this(tenantDomain, scope, 1, collectionName, collectionEntityId, relationName, relationEntityId, params);
}
private void addParams(StringBuilder sb, Map<String, String> params) throws UnsupportedEncodingException private void addParams(StringBuilder sb, Map<String, String> params) throws UnsupportedEncodingException
{ {
if(params != null && params.size() > 0) if (params != null && params.size() > 0)
{ {
sb.append("?"); sb.append("?");
for(String paramName : params.keySet()) for (String paramName : params.keySet())
{ {
sb.append(URLEncoder.encode(paramName, "UTF-8")); sb.append(URLEncoder.encode(paramName, "UTF-8"));
sb.append("="); sb.append("=");
@@ -695,9 +746,9 @@ public class PublicApiHttpClient
{ {
String ret = null; String ret = null;
if(o instanceof NodeRef) if (o instanceof NodeRef)
{ {
NodeRef nodeRef = (NodeRef)o; NodeRef nodeRef = (NodeRef) o;
ret = (o != null ? nodeRef.getId() : null); ret = (o != null ? nodeRef.getId() : null);
} }
else else
@@ -711,13 +762,13 @@ public class PublicApiHttpClient
private Pair<String, String> getRelationCollectionInfo(Class<?> resourceClass) throws IOException private Pair<String, String> getRelationCollectionInfo(Class<?> resourceClass) throws IOException
{ {
AnnotationMetadata annotationMetaData = getAnnotationMetadata(resourceClass.getCanonicalName()); AnnotationMetadata annotationMetaData = getAnnotationMetadata(resourceClass.getCanonicalName());
if(annotationMetaData.isConcrete() && annotationMetaData.isIndependent()) if (annotationMetaData.isConcrete() && annotationMetaData.isIndependent())
{ {
if(annotationMetaData.getAnnotationTypes().contains(RelationshipResource.class.getCanonicalName())) if (annotationMetaData.getAnnotationTypes().contains(RelationshipResource.class.getCanonicalName()))
{ {
Map<String, Object> attrs = annotationMetaData.getAnnotationAttributes(RelationshipResource.class.getName()); Map<String, Object> attrs = annotationMetaData.getAnnotationAttributes(RelationshipResource.class.getName());
String relationshipCollectionName = (String)attrs.get("name"); String relationshipCollectionName = (String) attrs.get("name");
Class<?> entityResource = (Class<?>)attrs.get("entityResource"); Class<?> entityResource = (Class<?>) attrs.get("entityResource");
String entityCollectionName = getEntityCollectionInfo(entityResource.getCanonicalName()); String entityCollectionName = getEntityCollectionInfo(entityResource.getCanonicalName());
@@ -743,12 +794,12 @@ public class PublicApiHttpClient
private String getEntityCollectionInfo(String className) throws IOException private String getEntityCollectionInfo(String className) throws IOException
{ {
AnnotationMetadata annotationMetaData = getAnnotationMetadata(className); AnnotationMetadata annotationMetaData = getAnnotationMetadata(className);
if(annotationMetaData.isConcrete() && annotationMetaData.isIndependent()) if (annotationMetaData.isConcrete() && annotationMetaData.isIndependent())
{ {
if(annotationMetaData.getAnnotationTypes().contains(EntityResource.class.getCanonicalName())) if (annotationMetaData.getAnnotationTypes().contains(EntityResource.class.getCanonicalName()))
{ {
Map<String, Object> attrs = annotationMetaData.getAnnotationAttributes(EntityResource.class.getName()); Map<String, Object> attrs = annotationMetaData.getAnnotationAttributes(EntityResource.class.getName());
return (String)attrs.get("name"); return (String) attrs.get("name");
} }
else else
{ {

View File

@@ -0,0 +1,78 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.rest.api.tests.util;
import static org.junit.Assert.assertNotNull;
import org.alfresco.rest.framework.jacksonextensions.JacksonHelper;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
/**
* @author Jamal Kaabi-Mofrad
*/
public class JacksonUtil
{
private JacksonHelper jsonHelper;
public JacksonUtil(JacksonHelper jsonHelper)
{
this.jsonHelper = jsonHelper;
}
public <T> List<T> parseEntries(JSONObject jsonObject, Class<T> clazz) throws IOException
{
assertNotNull(jsonObject);
assertNotNull(clazz);
List<T> models = new ArrayList<>();
JSONObject jsonList = (JSONObject) jsonObject.get("list");
assertNotNull(jsonList);
JSONArray jsonEntries = (JSONArray) jsonList.get("entries");
assertNotNull(jsonEntries);
for (Object entry : jsonEntries)
{
JSONObject jsonEntry = (JSONObject) entry;
T pojoModel = parseEntry(jsonEntry, clazz);
models.add(pojoModel);
}
return models;
}
public <T> T parseEntry(JSONObject jsonObject, Class<T> clazz) throws IOException
{
assertNotNull(jsonObject);
assertNotNull(clazz);
JSONObject entry = (JSONObject) jsonObject.get("entry");
T pojoModel = jsonHelper.construct(new StringReader(entry.toJSONString()), clazz);
assertNotNull(pojoModel);
return pojoModel;
}
}