diff --git a/config/alfresco/public-rest-context.xml b/config/alfresco/public-rest-context.xml index f4985b72d9..8f53dd0e32 100644 --- a/config/alfresco/public-rest-context.xml +++ b/config/alfresco/public-rest-context.xml @@ -428,10 +428,23 @@ - - + + + + + cm:systemfolder + fm:forums + fm:forum + fm:topic + fm:post + + + + + + diff --git a/source/java/org/alfresco/rest/api/impl/NodesImpl.java b/source/java/org/alfresco/rest/api/impl/NodesImpl.java index 843290f6d7..734adc5247 100644 --- a/source/java/org/alfresco/rest/api/impl/NodesImpl.java +++ b/source/java/org/alfresco/rest/api/impl/NodesImpl.java @@ -36,6 +36,7 @@ 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.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.InvalidArgumentException; import org.alfresco.rest.framework.resource.content.BasicContentInfo; @@ -53,11 +54,14 @@ 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.model.FileNotFoundException; +import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.InvalidNodeRefException; import org.alfresco.service.cmr.repository.NodeRef; 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.security.AccessStatus; import org.alfresco.service.cmr.security.PermissionService; @@ -76,6 +80,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; /** @@ -83,6 +88,7 @@ import java.util.Set; * * @author steveglover * @author janv + * @author Jamal Kaabi-Mofrad * * @since publicapi1.0 */ @@ -90,22 +96,36 @@ public class NodesImpl implements Nodes { private static enum Type { - // Note: ordered - DOCUMENT, FOLDER; + // Note: ordered + DOCUMENT, FOLDER; }; - + private final static String PATH_ROOT = "-root-"; private final static String PATH_MY = "-my-"; private final static String PATH_SHARED = "-shared-"; - - private NodeService nodeService; + + private NodeService nodeService; private DictionaryService dictionaryService; private FileFolderService fileFolderService; private NamespaceService namespaceService; private PermissionService permissionService; private Repository repositoryHelper; private ServiceRegistry sr; + private Set defaultIgnoreTypes; + private Set 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) { this.sr = sr; @@ -121,6 +141,11 @@ public class NodesImpl implements Nodes this.repositoryHelper = repositoryHelper; } + public void setIgnoreTypes(Set ignoreTypes) + { + this.defaultIgnoreTypes = ignoreTypes; + } + private static final List EXCLUDED_ASPECTS = Arrays.asList( ContentModel.ASPECT_REFERENCEABLE, ContentModel.ASPECT_LOCALIZED); @@ -176,47 +201,46 @@ public class NodesImpl implements Nodes new HashSet<>(Arrays.asList(new String[] {PARAM_ISFOLDER})); /* - * - * Note: assumes workspace://SpacesStore - */ - public NodeRef validateNode(String nodeId) - { - return validateNode(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, nodeId); - } - - public NodeRef validateNode(StoreRef storeRef, String nodeId) - { - String versionLabel = null; - - int idx = nodeId.indexOf(";"); - if(idx != -1) - { - versionLabel = nodeId.substring(idx + 1); - nodeId = nodeId.substring(0, idx); - if(versionLabel.equals("pwc")) - { - // TODO correct exception? - throw new EntityNotFoundException(nodeId); - } - } - - NodeRef nodeRef = new NodeRef(storeRef, nodeId); - return validateNode(nodeRef); - } - - public NodeRef validateNode(NodeRef nodeRef) - { - if (! nodeService.exists(nodeRef)) - { - throw new EntityNotFoundException(nodeRef.getId()); - } - - return nodeRef; - } - - public boolean nodeMatches(NodeRef nodeRef, Set expectedTypes, Set excludedTypes) + * Note: assumes workspace://SpacesStore + */ + public NodeRef validateNode(String nodeId) { - if (! nodeService.exists(nodeRef)) + return validateNode(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, nodeId); + } + + public NodeRef validateNode(StoreRef storeRef, String nodeId) + { + String versionLabel = null; + + int idx = nodeId.indexOf(";"); + if (idx != -1) + { + versionLabel = nodeId.substring(idx + 1); + nodeId = nodeId.substring(0, idx); + if (versionLabel.equals("pwc")) + { + // TODO correct exception? + throw new EntityNotFoundException(nodeId); + } + } + + NodeRef nodeRef = new NodeRef(storeRef, nodeId); + return validateNode(nodeRef); + } + + public NodeRef validateNode(NodeRef nodeRef) + { + if (!nodeService.exists(nodeRef)) + { + throw new EntityNotFoundException(nodeRef.getId()); + } + + return nodeRef; + } + + public boolean nodeMatches(NodeRef nodeRef, Set expectedTypes, Set excludedTypes) + { + if (!nodeService.exists(nodeRef)) { throw new EntityNotFoundException(nodeRef.getId()); } @@ -226,35 +250,35 @@ public class NodesImpl implements Nodes protected boolean typeMatches(QName type, Set expectedTypes, Set excludedTypes) { - Set allExpectedTypes = new HashSet<>(); - if (expectedTypes != null) - { - for (QName expectedType : expectedTypes) - { - allExpectedTypes.addAll(dictionaryService.getSubTypes(expectedType, true)); - } - } + Set allExpectedTypes = new HashSet<>(); + if (expectedTypes != null) + { + for (QName expectedType : expectedTypes) + { + allExpectedTypes.addAll(dictionaryService.getSubTypes(expectedType, true)); + } + } - Set allExcludedTypes = new HashSet<>(); - if (excludedTypes != null) - { - for (QName excludedType : excludedTypes) - { - allExcludedTypes.addAll(dictionaryService.getSubTypes(excludedType, true)); - } - } + Set allExcludedTypes = new HashSet<>(); + if (excludedTypes != null) + { + for (QName excludedType : excludedTypes) + { + allExcludedTypes.addAll(dictionaryService.getSubTypes(excludedType, true)); + } + } - boolean inExpected = allExpectedTypes.contains(type); - boolean excluded = allExcludedTypes.contains(type); - return(inExpected && !excluded); - } + boolean inExpected = allExpectedTypes.contains(type); + boolean excluded = allExcludedTypes.contains(type); + return (inExpected && !excluded); + } /** * @deprecated review usage (backward compat') */ public Node getNode(String nodeId) { - NodeRef nodeRef = validateNode(nodeId); + NodeRef nodeRef = validateNode(nodeId); return new Node(nodeRef, null, nodeService.getProperties(nodeRef), sr); } @@ -266,17 +290,17 @@ public class NodesImpl implements Nodes { return new Node(nodeRef, null, nodeService.getProperties(nodeRef), sr); } - + private Type getType(NodeRef 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; + boolean isContainer = Boolean.valueOf((dictionaryService.isSubClass(type, ContentModel.TYPE_FOLDER) == true + && !dictionaryService.isSubClass(type, ContentModel.TYPE_SYSTEM_FOLDER))); + return isContainer ? Type.FOLDER : Type.DOCUMENT; } /** @@ -284,14 +308,14 @@ public class NodesImpl implements Nodes */ public Document getDocument(NodeRef nodeRef) { - Type type = getType(nodeRef); - if (type.equals(Type.DOCUMENT)) + Type type = getType(nodeRef); + if (type.equals(Type.DOCUMENT)) { Map properties = nodeService.getProperties(nodeRef); 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); if (cd != null) { @@ -300,12 +324,12 @@ public class NodesImpl implements Nodes } setCommonProps(doc, nodeRef, properties); - return doc; - } - else - { - throw new InvalidArgumentException("Node is not a file"); - } + return doc; + } + else + { + throw new InvalidArgumentException("Node is not a file"); + } } private void setCommonProps(Node node, NodeRef nodeRef, Map properties) @@ -316,25 +340,25 @@ public class NodesImpl implements Nodes node.setModifiedBy((String)properties.get(ContentModel.PROP_MODIFIER)); node.setCreatedBy((String)properties.get(ContentModel.PROP_CREATOR)); } - + /** * @deprecated note: currently required for backwards compat' (Favourites API) */ public Folder getFolder(NodeRef nodeRef) { - Type type = getType(nodeRef); - if (type.equals(Type.FOLDER)) - { + Type type = getType(nodeRef); + if (type.equals(Type.FOLDER)) + { Map properties = nodeService.getProperties(nodeRef); - Folder folder = new Folder(nodeRef, getParentNodeRef(nodeRef), properties, sr); + Folder folder = new Folder(nodeRef, getParentNodeRef(nodeRef), properties, sr); setCommonProps(folder, nodeRef, properties); - return folder; - } - else - { - throw new InvalidArgumentException("Node is not a folder"); - } + return folder; + } + else + { + throw new InvalidArgumentException("Node is not a folder"); + } } private NodeRef getParentNodeRef(final NodeRef nodeRef) { @@ -346,38 +370,44 @@ public class NodesImpl implements Nodes return nodeService.getPrimaryParent(nodeRef).getParentRef(); } - - private NodeRef validateOrLookupNode(String nodeId, String path) { - NodeRef parentNodeRef; - if (nodeId.equals(PATH_ROOT)) - { - parentNodeRef = repositoryHelper.getCompanyHome(); - } + private NodeRef validateOrLookupNode(String nodeId, String path) + { + NodeRef parentNodeRef; + + if (nodeId.equals(PATH_ROOT)) + { + parentNodeRef = repositoryHelper.getCompanyHome(); + } else if (nodeId.equals(PATH_SHARED)) { parentNodeRef = repositoryHelper.getSharedHome(); } - 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); - } + else if (nodeId.equals(PATH_MY)) + { + NodeRef person = repositoryHelper.getPerson(); + if (person == null) + { + throw new InvalidArgumentException("Unexpected: cannot use " + PATH_MY); + } + parentNodeRef = repositoryHelper.getUserHome(person); + if (parentNodeRef == null) + { + throw new EntityNotFoundException(nodeId); + } + } + else + { + parentNodeRef = validateNode(nodeId); + } - if (path != null) { + if (path != null) + { // resolve path relative to current nodeId parentNodeRef = resolveNodeByPath(parentNodeRef, path, true); } - return parentNodeRef; + return parentNodeRef; } protected NodeRef resolveNodeByPath(final NodeRef parentNodeRef, String path, boolean checkForCompanyHome) @@ -431,116 +461,176 @@ public class NodesImpl implements Nodes return fileInfo.getNodeRef(); } - - public Node getFolderOrDocument(String nodeId, Parameters parameters) - { - String path = parameters.getParameter("path"); - NodeRef nodeRef = validateOrLookupNode(nodeId, path); - QName typeQName = nodeService.getType(nodeRef); - return getFolderOrDocument(nodeRef, getParentNodeRef(nodeRef), typeQName, false); - } - - private Node getFolderOrDocument(final NodeRef nodeRef, NodeRef parentNodeRef, QName typeQName, boolean minimalnfo) + public Node getFolderOrDocument(String nodeId, Parameters parameters) { - PathInfo pathInfo = null; - if (! minimalnfo) + String path = parameters.getParameter("path"); + NodeRef nodeRef = validateOrLookupNode(nodeId, path); + + QName typeQName = nodeService.getType(nodeRef); + List requestedProperties = createQNames(parameters.getSelectedProperties()); + return getFolderOrDocument(nodeRef, getParentNodeRef(nodeRef), typeQName, requestedProperties, false); + } + + private Node getFolderOrDocument(final NodeRef nodeRef, NodeRef parentNodeRef, QName typeQName, List selectedProperties, boolean minimalnfo) + { + PathInfo pathInfo = null; + if (!minimalnfo) { pathInfo = lookupPathInfo(nodeRef); } - + Type type = getType(typeQName); Node node; Map properties = nodeService.getProperties(nodeRef); - if (type.equals(Type.DOCUMENT)) - { - node = new Document(nodeRef, parentNodeRef, properties, sr); - } - else if (type.equals(Type.FOLDER)) - { - // container/folder - node = new Folder(nodeRef, parentNodeRef, properties, sr); - } - else - { - throw new InvalidArgumentException("Node is not a folder or file"); - } + if (type.equals(Type.DOCUMENT)) + { + node = new Document(nodeRef, parentNodeRef, properties, sr); + } + else if (type.equals(Type.FOLDER)) + { + // container/folder + node = new Folder(nodeRef, parentNodeRef, properties, sr); + } + else + { + throw new InvalidArgumentException("Node is not a folder or file"); + } - if (! minimalnfo) { - node.setProperties(mapProperties(properties)); + if (!minimalnfo) + { + node.setProperties(mapProperties(properties, selectedProperties)); node.setAspectNames(mapAspects(nodeService.getAspects(nodeRef))); } node.setNodeType(typeQName.toPrefixString(namespaceService)); - node.setPath(pathInfo); + node.setPath(pathInfo); - return node; + return node; } protected PathInfo lookupPathInfo(NodeRef nodeRefIn) { - List elements = new ArrayList<>(5); + // TODO which implementation? + return getPathInfo(nodeRefIn); - NodeRef companyHomeNodeRef = repositoryHelper.getCompanyHome(); - boolean isComplete = true; + // List elements = new ArrayList<>(5); + // + // NodeRef companyHomeNodeRef = repositoryHelper.getCompanyHome(); + // boolean isComplete = true; + // + // NodeRef pNodeRef = nodeRefIn; + // while (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); + } - NodeRef pNodeRef = nodeRefIn; - while (pNodeRef != null) + private PathInfo getPathInfo(NodeRef nodeRef) + { + final Path nodePath = nodeService.getPath(nodeRef); + + List 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--) { - if (pNodeRef.equals(companyHomeNodeRef)) + Element element = nodePath.get(i); + if (element instanceof Path.ChildAssocElement) { - pNodeRef = null; - } - else { - pNodeRef = nodeService.getPrimaryParent(pNodeRef).getParentRef(); - - if (pNodeRef == null) + ChildAssociationRef elementRef = ((Path.ChildAssocElement) element).getRef(); + if (elementRef.getParentRef() != null) { - // belts-and-braces - is it even possible to get here ? - isComplete = false; - } - else - { - if (permissionService.hasPermission(pNodeRef, PermissionService.READ) == AccessStatus.ALLOWED) + NodeRef childNodeRef = elementRef.getChildRef(); + if (permissionService.hasPermission(childNodeRef, PermissionService.READ) == AccessStatus.ALLOWED) { - String name = (String) nodeService.getProperty(pNodeRef, ContentModel.PROP_NAME); - elements.add(0, new PathInfo().new ElementInfo(pNodeRef.getId(), name)); + Serializable nameProp = nodeService.getProperty(childNodeRef, ContentModel.PROP_NAME); + pathElements.add(0, new ElementInfo(childNodeRef, nameProp.toString())); } else { - isComplete = false; - pNodeRef = null; + // Just return the pathInfo up to the location where the user has access + isComplete = Boolean.FALSE; + break; } } } } - StringBuilder sb = new StringBuilder(); - for (PathInfo.ElementInfo e : elements) + String pathStr = null; + if(pathElements.size() > 0) { - sb.append("/").append(e.getName()); + StringBuilder sb = new StringBuilder(120); + for (PathInfo.ElementInfo e : pathElements) + { + 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 mapProperties(Map nodeProps) + protected Map mapProperties(Map nodeProps, List selectedProperties) { - Map 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()); - } - } - - if (props.size() == 0) + Map props = null; + if (!selectedProperties.isEmpty()) { - props = null; // no props to return + 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()) + { + props = null; // set to null so it doesn't show up as an empty object in the JSON response. + } } return props; @@ -568,12 +658,19 @@ public class NodesImpl implements Nodes public CollectionWithPagingInfo getChildren(String parentFolderNodeId, Parameters parameters) { - // TODO + // 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 // map - where (filter) properties - including isFolder // map - orderBy (sort) properties - including isFolder // TODO refactor & fix ! final boolean minimalnfo = (parameters.getSelectedProperties().size() == 0); + final List requestedProperties = createQNames(parameters.getSelectedProperties()); boolean includeFolders = true; boolean includeFiles = true; @@ -604,7 +701,7 @@ public class NodesImpl implements Nodes QName propQname = MAP_PARAM_QNAME.get(sortCol.column); if (propQname == null) { - propQname = QName.resolveToQName(namespaceService, sortCol.column); + propQname = createQName(sortCol.column); } if (propQname != null) @@ -623,46 +720,40 @@ public class NodesImpl implements Nodes 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)) { throw new InvalidArgumentException("NodeId of folder is expected"); } - PagingRequest pagingRequest = Util.getPagingRequest(paging); - - final PagingResults pagingResults = fileFolderService.list(parentNodeRef, includeFiles, includeFolders, null, sortProps, pagingRequest); - - final List page = pagingResults.getPage(); - List nodes = new AbstractList() - { - @Override - public Node get(int index) - { - FileInfo fInfo = page.get(index); + PagingRequest pagingRequest = Util.getPagingRequest(paging); + + final PagingResults pagingResults = fileFolderService.list(parentNodeRef, includeFiles, includeFolders, ignoreTypeQNames, sortProps, pagingRequest); + + final List page = pagingResults.getPage(); + List nodes = new AbstractList() + { + @Override + public Node get(int index) + { + FileInfo fInfo = page.get(index); // 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 - public int size() - { - return page.size(); - } - }; + @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); + NodeRef nodeRef = validateNode(nodeId); fileFolderService.delete(nodeRef); } @@ -689,8 +780,8 @@ public class NodesImpl implements Nodes throw new InvalidArgumentException("Node type is expected: "+parentNodeRef+","+nodeName); } - // check that requested type is a (sub-) type of folder or content - QName nodeTypeQName = QName.resolveToQName(namespaceService, nodeType); + // check that requested type is a (sub-) type of folder or content + QName nodeTypeQName = createQName(nodeType); Set contentAndFolders = new HashSet<>(Arrays.asList(ContentModel.TYPE_FOLDER, ContentModel.TYPE_CONTENT)); if (! typeMatches(nodeTypeQName, contentAndFolders, null)) { @@ -703,7 +794,7 @@ public class NodesImpl implements Nodes if (nodeInfo.getProperties() != null) { - for (Map.Entry entry : (Set>)nodeInfo.getProperties().entrySet()) + for (Entry entry : nodeInfo.getProperties().entrySet()) { QName propQName = QName.createQName((String)entry.getKey(), namespaceService); props.put(propQName, (Serializable)entry.getValue()); @@ -741,7 +832,7 @@ public class NodesImpl implements Nodes if (nodeInfo.getProperties() != null) { - for (Map.Entry entry : (Set>)nodeInfo.getProperties().entrySet()) + for (Entry entry : nodeInfo.getProperties().entrySet()) { QName propQName = QName.createQName((String)entry.getKey(), namespaceService); props.put(propQName, (Serializable)entry.getValue()); @@ -807,4 +898,58 @@ public class NodesImpl implements Nodes // TODO - hmm - we may wish to return json info !! 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 createQNames(List qnameStrList) + { + List 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; + } + } diff --git a/source/java/org/alfresco/rest/api/model/Document.java b/source/java/org/alfresco/rest/api/model/Document.java index a658dfa05f..37bacccaaf 100644 --- a/source/java/org/alfresco/rest/api/model/Document.java +++ b/source/java/org/alfresco/rest/api/model/Document.java @@ -46,6 +46,11 @@ public class Document extends Node { private ContentInfo contentInfo; + // instance init block + { + this.isFolder = Boolean.FALSE; + } + public Document() { super(); } @@ -64,76 +69,76 @@ public class Document extends Node } } - public Boolean getIsFolder() - { - return false; - } - public ContentInfo getContent() { return contentInfo; } - @Override - public String toString() - { - return "Document [contentInfo=" + contentInfo.toString() + ", nodeRef=" - + nodeRef + ", name=" + name + ", createdAt=" + createdAt - + ", modifiedAt=" + modifiedAt + ", createdBy=" + createdBy - + ", modifiedBy=" + modifiedBy + "]"; - } + public void setContent(ContentInfo contentInfo) + { + this.contentInfo = contentInfo; + } - // TODO for backwards compat' - set explicitly when needed (ie. favourites) - private String mimeType; - private BigInteger sizeInBytes; - private String versionLabel; + @Override + public String toString() + { + return "Document [contentInfo=" + contentInfo.toString() + ", nodeRef=" + + nodeRef + ", name=" + name + ", createdAt=" + createdAt + + ", modifiedAt=" + modifiedAt + ", createdBy=" + createdBy + + ", modifiedBy=" + modifiedBy + "]"; + } - /** - * @deprecated + // TODO for backwards compat' - set explicitly when needed (ie. favourites) + private String mimeType; + private BigInteger sizeInBytes; + private String versionLabel; + + /** + * @deprecated */ - public String getMimeType() - { - return mimeType; - } + public String getMimeType() + { + return mimeType; + } - /** - * @deprecated - */ - public BigInteger getSizeInBytes() - { - return sizeInBytes; - } + /** + * @deprecated + */ + public BigInteger getSizeInBytes() + { + return sizeInBytes; + } - /** - * @deprecated - */ - public String getVersionLabel() - { - return versionLabel; - } + /** + * @deprecated + */ + public String getVersionLabel() + { + return versionLabel; + } - /** - * @deprecated - */ - public void setMimeType(String mimeType) - { - this.mimeType = mimeType; - } + /** + * @deprecated + */ + public void setMimeType(String mimeType) + { + this.mimeType = mimeType; + } - /** - * @deprecated - */ - public void setSizeInBytes(BigInteger sizeInBytes) - { - this.sizeInBytes = sizeInBytes; - } + /** + * @deprecated + */ + public void setSizeInBytes(BigInteger sizeInBytes) + { + this.sizeInBytes = sizeInBytes; + } - /** - * @deprecated - */ - public void setVersionLabel(String versionLabel) - { - this.versionLabel = versionLabel; - } + /** + * @deprecated + */ + public void setVersionLabel(String versionLabel) + { + this.versionLabel = versionLabel; + } } diff --git a/source/java/org/alfresco/rest/api/model/Folder.java b/source/java/org/alfresco/rest/api/model/Folder.java index 17a6af9af3..f6cb3dfbde 100644 --- a/source/java/org/alfresco/rest/api/model/Folder.java +++ b/source/java/org/alfresco/rest/api/model/Folder.java @@ -23,6 +23,7 @@ * along with Alfresco. If not, see . * #L% */ + package org.alfresco.rest.api.model; import java.io.Serializable; @@ -37,31 +38,30 @@ import org.alfresco.service.namespace.QName; * * @author steveglover * @author janv - * */ public class Folder extends Node { - public Folder() - { - super(); - } + // instance init block + { + this.isFolder = Boolean.TRUE; + } + public Folder() + { + super(); + } + public Folder(NodeRef nodeRef, NodeRef parentNodeRef, Map nodeProps, ServiceRegistry sr) { super(nodeRef, parentNodeRef, nodeProps, sr); } - public Boolean getIsFolder() - { - return true; - } - - @Override - public String toString() - { - return "Folder [nodeRef=" + nodeRef + ", name=" + name + ", title=" - + title + ", description=" + description + ", createdAt=" - + createdAt + ", modifiedAt=" + modifiedAt + ", createdBy=" - + createdBy + ", modifiedBy=" + modifiedBy + "]"; - } + @Override + public String toString() + { + return "Folder [nodeRef=" + nodeRef + ", name=" + name + ", title=" + + title + ", description=" + description + ", createdAt=" + + createdAt + ", modifiedAt=" + modifiedAt + ", createdBy=" + + createdBy + ", modifiedBy=" + modifiedBy + "]"; + } } diff --git a/source/java/org/alfresco/rest/api/model/Node.java b/source/java/org/alfresco/rest/api/model/Node.java index 36bebed44b..a08decd3bd 100644 --- a/source/java/org/alfresco/rest/api/model/Node.java +++ b/source/java/org/alfresco/rest/api/model/Node.java @@ -57,13 +57,15 @@ public class Node implements Comparable protected UserInfo createdByUser; protected UserInfo modifiedByUser; + protected Boolean isFolder; + protected NodeRef parentNodeRef; protected PathInfo pathInfo; protected String prefixTypeQName; protected List aspectNames; - protected Map props; + protected Map properties; // TODO fixme ! // also need to optionally pass in user map - eg. when listing children (to avoid multiple lookups for same user) @@ -190,12 +192,12 @@ public class Node implements Comparable this.prefixTypeQName = prefixType; } - public Map getProperties() { - return this.props; + public Map getProperties() { + return this.properties; } - public void setProperties(Map props) { - this.props = props; + public void setProperties(Map props) { + this.properties = props; } public List getAspectNames() { @@ -211,6 +213,21 @@ public class Node implements Comparable 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) { if(this == other) diff --git a/source/java/org/alfresco/rest/api/model/PathInfo.java b/source/java/org/alfresco/rest/api/model/PathInfo.java index 8c0f96e06f..07763aaffa 100644 --- a/source/java/org/alfresco/rest/api/model/PathInfo.java +++ b/source/java/org/alfresco/rest/api/model/PathInfo.java @@ -1,64 +1,92 @@ + package org.alfresco.rest.api.model; import java.util.List; +import org.alfresco.service.cmr.repository.NodeRef; + /** * Representation of a path info * * @author janv - * */ public class PathInfo { - private String name; - private Boolean isComplete; - private List elements; + private String name; + private Boolean isComplete; + private List elements; - public PathInfo() - { - } + public PathInfo() + { + } - public PathInfo(String name, Boolean isComplete, List elements) - { - this.name = name; - this.isComplete = isComplete; - this.elements = elements; - } + public PathInfo(String name, Boolean isComplete, List elements) + { + this.name = name; + this.isComplete = isComplete; + this.elements = elements; + } - public String getName() { - return name; - } + public String getName() + { + return name; + } - public Boolean getIsComplete() { - return isComplete; - } + public Boolean getIsComplete() + { + return isComplete; + } - public List getElements() { - return elements; - } + public List getElements() + { + 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 String name; + private NodeRef id; + private String name; - public ElementInfo() - { - } + public ElementInfo() + { + } - public ElementInfo(String id, String name) - { - this.id = id; - this.name = name; - } + public ElementInfo(NodeRef id, String name) + { + this.id = id; + this.name = name; + } - public String getName() { - return name; - } + public String getName() + { + return name; + } - public String getId() { - return id; - } - } + public NodeRef getId() + { + 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(); + } + } } diff --git a/source/java/org/alfresco/rest/api/model/UserInfo.java b/source/java/org/alfresco/rest/api/model/UserInfo.java index fe78dc204b..c8d4950927 100644 --- a/source/java/org/alfresco/rest/api/model/UserInfo.java +++ b/source/java/org/alfresco/rest/api/model/UserInfo.java @@ -16,41 +16,42 @@ * You should have received a copy of the GNU Lesser General Public License * along with Alfresco. If not, see . */ + package org.alfresco.rest.api.model; /** * Representation of a user info * * @author janv - * */ public class UserInfo { - private String userName; - private String displayName; + private String userName; + private String displayName; - public UserInfo() - { - } + public UserInfo() + { + } - public UserInfo(String userName, String firstName, String lastName) - { - this.userName = userName; - this.displayName = ((firstName != null ? firstName + " " : "") + (lastName != null ? lastName : "")).replaceAll("^\\s+|\\s+$", ""); - } + public UserInfo(String userName, String firstName, String lastName) + { + this.userName = userName; + this.displayName = ((firstName != null ? firstName + " " : "") + (lastName != null ? lastName : "")).trim(); + } - public String getDisplayName() { - return displayName; - } + public String getDisplayName() + { + return displayName; + } - public String getUserName() { - return userName; - } + public String getUserName() + { + return userName; + } - - @Override - public String toString() - { - return "User [userName=" + userName + ", displayName=" + displayName + "]"; - } + @Override + public String toString() + { + return "User [userName=" + userName + ", displayName=" + displayName + "]"; + } } diff --git a/source/test-java/org/alfresco/rest/api/tests/AbstractBaseApiTest.java b/source/test-java/org/alfresco/rest/api/tests/AbstractBaseApiTest.java index a4007b54b8..00510410b4 100644 --- a/source/test-java/org/alfresco/rest/api/tests/AbstractBaseApiTest.java +++ b/source/test-java/org/alfresco/rest/api/tests/AbstractBaseApiTest.java @@ -26,10 +26,17 @@ package org.alfresco.rest.api.tests; 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.PublicApiClient; import org.alfresco.rest.api.tests.client.RequestContext; +import org.alfresco.service.cmr.site.SiteVisibility; import java.util.Map; @@ -82,9 +89,14 @@ public abstract class AbstractBaseApiTest extends EnterpriseTestApi } 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 otherParams, int expectedStatus) throws Exception { publicApiClient.setRequestContext(new RequestContext(runAsUser)); - Map params = (paging == null) ? null : createParams(paging, null); + Map params = (paging == null) ? null : createParams(paging, otherParams); HttpResponse response = publicApiClient.get(getScope(), url, null, null, null, params); checkStatus(expectedStatus, response.getStatusCode()); @@ -92,6 +104,16 @@ public abstract class AbstractBaseApiTest extends EnterpriseTestApi return response; } + protected HttpResponse getAll(Class entityResource, String runAsUser, PublicApiClient.Paging paging, Map 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 { publicApiClient.setRequestContext(new RequestContext(runAsUser)); @@ -102,6 +124,16 @@ public abstract class AbstractBaseApiTest extends EnterpriseTestApi return response; } + protected HttpResponse getSingle(Class entityResource, String runAsUser, String entityId, Map 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 { publicApiClient.setRequestContext(new RequestContext(runAsUser)); @@ -132,6 +164,23 @@ public abstract class AbstractBaseApiTest extends EnterpriseTestApi 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() + { + @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) { if (expectedStatus > 0 && expectedStatus != actualStatus) diff --git a/source/test-java/org/alfresco/rest/api/tests/NodeApiTest.java b/source/test-java/org/alfresco/rest/api/tests/NodeApiTest.java new file mode 100644 index 0000000000..6d16885058 --- /dev/null +++ b/source/test-java/org/alfresco/rest/api/tests/NodeApiTest.java @@ -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 . + */ + +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: + *
    + *
  • {@literal host:port/alfresco/api/{networkId}/public/alfresco/versions/1/nodes/{nodeId}}
  • + *
  • {@literal host:port/alfresco/api/{networkId}/public/alfresco/versions/1/nodes/{nodeId}/children}
  • + *
+ * + * @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 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() + { + @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 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 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 nodes = jacksonUtil.parseEntries(response.getJsonResponse(), Document.class); + assertEquals(3, nodes.size()); + + // Order by folders and modified date first + Map 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 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> props = nodes.get(2).getProperties().entrySet(); + assertEquals(1, props.size()); + Entry 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/documentLibrary/folder_A + String folderA = "folder" + System.currentTimeMillis() + "_A"; + NodeRef folderA_Ref = repoService.createFolder(docLibNodeRef, folderA); + + // /Company Home/Sites/RandomSite/documentLibrary/folder_A/folder_B + String folderB = "folder" + System.currentTimeMillis() + "_B"; + NodeRef folderB_Ref = repoService.createFolder(folderA_Ref, folderB); + + // /Company Home/Sites/RandomSite/documentLibrary/folder_A/folder_B/folder_C + String folderC = "folder" + System.currentTimeMillis() + "_C"; + NodeRef folderC_Ref = repoService.createFolder(folderB_Ref, folderC); + + // /Company Home/Sites/RandomSite/documentLibrary/folder_A/folder_B/folder_C/content + 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 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 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/folder_A + String folderA = "folder" + System.currentTimeMillis() + "_A"; + NodeRef folderA_Ref = repoService.createFolder(myFilesNodeRef, folderA); + + // /Company Home/User Homes/user/folder_A/folder_B + String folderB = "folder" + System.currentTimeMillis() + "_B"; + NodeRef folderB_Ref = repoService.createFolder(folderA_Ref, folderB); + + // /Company Home/User Homes/user/folder_A/folder_B/folder_C + String folderC = "folder" + System.currentTimeMillis() + "_C"; + NodeRef folderC_Ref = repoService.createFolder(folderB_Ref, folderC); + + //...nodes/nodeId?select=pathInfo + Map 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 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"; + } +} diff --git a/source/test-java/org/alfresco/rest/api/tests/client/PublicApiHttpClient.java b/source/test-java/org/alfresco/rest/api/tests/client/PublicApiHttpClient.java index 3a23f337f4..6bb2291197 100644 --- a/source/test-java/org/alfresco/rest/api/tests/client/PublicApiHttpClient.java +++ b/source/test-java/org/alfresco/rest/api/tests/client/PublicApiHttpClient.java @@ -23,6 +23,7 @@ * along with Alfresco. If not, see . * #L% */ + package org.alfresco.rest.api.tests.client; import java.io.IOException; @@ -66,27 +67,25 @@ import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; /** - * 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) + * 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) * and the url will be generated. * * @author steveglover - * */ public class PublicApiHttpClient { private static final Log logger = LogFactory.getLog(PublicApiHttpClient.class); 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 BASE_URL = "{0}://{1}:{2}{3}{4}{5}/{6}/{7}/versions/1"; - 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 INDEX_URL = "{0}://{1}:{2}{3}{4}"; + 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_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 ATOM_PUB_URL = "{0}://{1}:{2}{3}cmisatom"; + private static final String ATOM_PUB_URL = "{0}://{1}:{2}{3}cmisatom"; - private String scheme = "http"; + private String scheme = "http"; private String host = "localhost"; private int port = 8081; @@ -94,94 +93,93 @@ public class PublicApiHttpClient private String servletName; private AuthenticatedHttp authenticatedHttp; - private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); - private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver); + private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); + private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver); - // can be overriden by other clients like the workflow client - protected String apiName = "alfresco"; - - public PublicApiHttpClient(String host, int port, String contextPath, String servletName, AuthenticatedHttp authenticatedHttp) - { - this("http", host, port, contextPath, servletName, authenticatedHttp); - } + // can be overriden by other clients like the workflow client + protected String apiName = "alfresco"; - public PublicApiHttpClient(String scheme, String host, int port, String contextPath, String servletName, AuthenticatedHttp authenticatedHttp) - { - super(); - this.scheme = scheme; - this.host = host; - this.port = port; - this.contextPath = contextPath; - if(this.contextPath != null && !this.contextPath.isEmpty() && !this.contextPath.endsWith("/")) - { - this.contextPath = this.contextPath + "/"; - } - if(this.contextPath != null && !this.contextPath.startsWith("/")) - { - this.contextPath = "/" + this.contextPath; - } - this.servletName = servletName; - if(this.servletName != null && !this.servletName.isEmpty() && !this.servletName.endsWith("/")) - { - this.servletName = this.servletName + "/"; - } - this.authenticatedHttp = authenticatedHttp; - } + public PublicApiHttpClient(String host, int port, String contextPath, String servletName, AuthenticatedHttp authenticatedHttp) + { + this("http", host, port, contextPath, servletName, authenticatedHttp); + } - public String getCmisUrl(String repositoryId, String operation) - { - StringBuilder url = new StringBuilder(); - if(repositoryId == null) - { - url.append(MessageFormat.format(ATOM_PUB_URL, new Object[] { scheme, host, String.valueOf(port), contextPath})); - } - else - { - url.append(MessageFormat.format(ATOM_PUB_URL, new Object[] { scheme, host, String.valueOf(port), contextPath})); - url.append("/"); - url.append(repositoryId); - } + public PublicApiHttpClient(String scheme, String host, int port, String contextPath, String servletName, AuthenticatedHttp authenticatedHttp) + { + super(); + this.scheme = scheme; + this.host = host; + this.port = port; + this.contextPath = contextPath; + if (this.contextPath != null && !this.contextPath.isEmpty() && !this.contextPath.endsWith("/")) + { + this.contextPath = this.contextPath + "/"; + } + if (this.contextPath != null && !this.contextPath.startsWith("/")) + { + this.contextPath = "/" + this.contextPath; + } + this.servletName = servletName; + if (this.servletName != null && !this.servletName.isEmpty() && !this.servletName.endsWith("/")) + { + this.servletName = this.servletName + "/"; + } + this.authenticatedHttp = authenticatedHttp; + } - if(operation != null) - { - url.append("/"); - url.append(operation); - } + public String getCmisUrl(String repositoryId, String operation) + { + StringBuilder url = new StringBuilder(); + if (repositoryId == null) + { + url.append(MessageFormat.format(ATOM_PUB_URL, new Object[] { scheme, host, String.valueOf(port), contextPath })); + } + else + { + url.append(MessageFormat.format(ATOM_PUB_URL, new Object[] { scheme, host, String.valueOf(port), contextPath })); + url.append("/"); + url.append(repositoryId); + } - return url.toString(); - } + if (operation != null) + { + url.append("/"); + url.append(operation); + } - public String getPublicApiCmisUrl(String networkId, Binding binding, String version, String operation) - { - StringBuilder url = new StringBuilder(); - if(networkId == null) - { - url.append(MessageFormat.format(PUBLICAPI_CMIS_SERVICE_URL, new Object[] { scheme, host, String.valueOf(port), contextPath, - servletName, version, binding.toString().toLowerCase()})); - } - else - { - url.append(MessageFormat.format(PUBLICAPI_CMIS_URL, new Object[] { scheme, host, String.valueOf(port), contextPath, servletName, - networkId, "public", version, binding.toString().toLowerCase()})); - } + return url.toString(); + } - if(operation != null) - { - url.append("/"); - url.append(operation); - } + public String getPublicApiCmisUrl(String networkId, Binding binding, String version, String operation) + { + StringBuilder url = new StringBuilder(); + if (networkId == null) + { + url.append(MessageFormat.format(PUBLICAPI_CMIS_SERVICE_URL, + new Object[] { scheme, host, String.valueOf(port), contextPath, servletName, version, binding.toString().toLowerCase() })); + } + else + { + url.append(MessageFormat.format(PUBLICAPI_CMIS_URL, new Object[] { scheme, host, String.valueOf(port), contextPath, servletName, + networkId, "public", version, binding.toString().toLowerCase() })); + } - return url.toString(); - } + if (operation != null) + { + url.append("/"); + url.append(operation); + } + return url.toString(); + } + public String getPublicApiCmisUrlSuffix(String networkId, Binding binding, String version, String operation) { StringBuilder url = new StringBuilder(); - url.append(MessageFormat.format(PUBLICAPI_CMIS_URL_SUFFIX, - new Object[] {networkId, "public", version, binding.toString().toLowerCase()})); + url.append(MessageFormat.format(PUBLICAPI_CMIS_URL_SUFFIX, new Object[] { networkId, "public", version, binding.toString().toLowerCase() })); - if(operation != null) + if (operation != null) { url.append("/"); url.append(operation); @@ -189,275 +187,294 @@ public class PublicApiHttpClient return url.toString(); } - - public void setHost(String host) - { - this.host = host; - } - public void setPort(int port) - { - this.port = port; - } - - public void setContextPath(String contextPath) - { - this.contextPath = contextPath; - } + public void setHost(String host) + { + this.host = host; + } - public void init() - { - } + public void setPort(int port) + { + this.port = port; + } - private void log(String msg) - { - if(logger.isDebugEnabled()) - { - logger.debug(msg); - } - } - + public void setContextPath(String contextPath) + { + this.contextPath = contextPath; + } + + public void init() + { + } + + private void log(String msg) + { + if (logger.isDebugEnabled()) + { + logger.debug(msg); + } + } + protected AnnotationMetadata getAnnotationMetadata(String classname) throws IOException { - MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(classname); - AnnotationMetadata annotationMetaData = metadataReader.getAnnotationMetadata(); - return annotationMetaData; + MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(classname); + AnnotationMetadata annotationMetaData = metadataReader.getAnnotationMetadata(); + return annotationMetaData; } - public HttpResponse submitRequest(HttpMethod req, final RequestContext rq) throws HttpException, IOException + public HttpResponse submitRequest(HttpMethod req, final RequestContext rq) throws HttpException, IOException { - try - { - final long start = System.currentTimeMillis(); + try + { + final long start = System.currentTimeMillis(); - final HttpRequestCallback callback = new HttpRequestCallback() - { - @Override - public HttpResponse onCallSuccess(HttpMethod method) throws Exception - { - long end = System.currentTimeMillis(); - - Map headersMap = null; - Header[] headers = method.getResponseHeaders(); - if (headers != null) - { - headersMap = new HashMap(headers.length); - for (Header header : headers) + final HttpRequestCallback callback = new HttpRequestCallback() + { + @Override + public HttpResponse onCallSuccess(HttpMethod method) throws Exception + { + long end = System.currentTimeMillis(); + + Map headersMap = null; + Header[] headers = method.getResponseHeaders(); + if (headers != null) + { + headersMap = new HashMap(headers.length); + for (Header header : headers) { headersMap.put(header.getName(), header.getValue()); } - } - - return new HttpResponse(method, rq.getRunAsUser(), method.getResponseBodyAsString(), headersMap, (end - start)); - } + } - @Override - public boolean onError(HttpMethod method, Throwable t) - { - return false; - } - }; + return new HttpResponse(method, rq.getRunAsUser(), method.getResponseBodyAsString(), headersMap, (end - start)); + } - HttpResponse response = null; - if(rq.getPassword() != null) - { - response = authenticatedHttp.executeHttpMethodAuthenticated(req, rq.getRunAsUser(), rq.getPassword(), callback); - } - else - { - response = authenticatedHttp.executeHttpMethodAuthenticated(req, rq.getRunAsUser(), callback); - } - return response; - } - finally - { - if(req != null) - { - req.releaseConnection(); - } - } + @Override + public boolean onError(HttpMethod method, Throwable t) + { + return false; + } + }; + + HttpResponse response = null; + if (rq.getPassword() != null) + { + response = authenticatedHttp.executeHttpMethodAuthenticated(req, rq.getRunAsUser(), rq.getPassword(), callback); + } + else + { + response = authenticatedHttp.executeHttpMethodAuthenticated(req, rq.getRunAsUser(), callback); + } + return response; + } + finally + { + if (req != null) + { + req.releaseConnection(); + } + } } public HttpResponse get(final RequestContext rq, final String urlSuffix, Map params) throws IOException - { - RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), urlSuffix, params); - String url = endpoint.getUrl(); + { + RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), urlSuffix, params); + String url = endpoint.getUrl(); - GetMethod req = new GetMethod(url); - return submitRequest(req, rq); - } + GetMethod req = new GetMethod(url); + return submitRequest(req, rq); + } - public HttpResponse get(final Class c, final RequestContext rq, final Object entityId, final Object relationshipEntityId, Map params) throws IOException - { - RestApiEndpoint endpoint = new RestApiEndpoint(c, rq.getNetworkId(), entityId, relationshipEntityId, params); - String url = endpoint.getUrl(); + public HttpResponse get(final Class c, final RequestContext rq, final Object entityId, final Object relationshipEntityId, + Map params) throws IOException + { + RestApiEndpoint endpoint = new RestApiEndpoint(c, rq.getNetworkId(), entityId, relationshipEntityId, params); + String url = endpoint.getUrl(); - GetMethod req = new GetMethod(url); - 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 params) throws IOException - { - RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), scope, entityCollectionName, entityId, relationCollectionName, relationshipEntityId, params); - String url = endpoint.getUrl(); + GetMethod req = new GetMethod(url); + return submitRequest(req, rq); + } - GetMethod req = new GetMethod(url); - 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 params) throws IOException - { - RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), scope, entityCollectionName, entityId, relationCollectionName, relationshipEntityId, params); - String url = endpoint.getUrl(); + public HttpResponse get(final RequestContext rq, String scope, final String entityCollectionName, final Object entityId, + final String relationCollectionName, final Object relationshipEntityId, Map params) throws IOException + { + return get(rq, scope, 1, entityCollectionName, entityId, relationCollectionName, relationshipEntityId, params); + } - GetMethod req = new GetMethod(url); - return submitRequest(req, rq); - } + 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 params) throws IOException + { + RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), scope, version, entityCollectionName, entityId, relationCollectionName, + relationshipEntityId, params); + String url = endpoint.getUrl(); + GetMethod req = new GetMethod(url); + 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 params) throws IOException + { + 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 params) throws IOException + { + RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), scope, version, entityCollectionName, entityId, relationCollectionName, + relationshipEntityId, params); + String url = endpoint.getUrl(); + + GetMethod req = new GetMethod(url); + return submitRequest(req, rq); + } + public HttpResponse get(final String urlSuffix, final RequestContext rq, Map params) throws IOException - { - RestApiEndpoint endpoint = new RestApiEndpoint(urlSuffix, params); - String url = endpoint.getUrl(); - - GetMethod req = new GetMethod(url); - return submitRequest(req, rq); - } - + { + RestApiEndpoint endpoint = new RestApiEndpoint(urlSuffix, params); + String url = endpoint.getUrl(); + + GetMethod req = new GetMethod(url); + return submitRequest(req, rq); + } + public HttpResponse getWithPassword(final String urlSuffix, final RequestContext rq, Map params) throws IOException - { - RestApiEndpoint endpoint = new RestApiEndpoint(urlSuffix, params); - String url = endpoint.getUrl(); - - GetMethod req = new GetMethod(url); - return submitRequest(req, rq); - } + { + RestApiEndpoint endpoint = new RestApiEndpoint(urlSuffix, params); + String url = endpoint.getUrl(); - 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); - String url = endpoint.getUrl(); + GetMethod req = new GetMethod(url); + return submitRequest(req, rq); + } - PostMethod req = new PostMethod(url.toString()); - if(body != null) - { - StringRequestEntity requestEntity = new StringRequestEntity(body, "application/json", "UTF-8"); - req.setRequestEntity(requestEntity); - } - return submitRequest(req, rq); - } - + 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); + String url = endpoint.getUrl(); + + PostMethod req = new PostMethod(url.toString()); + if (body != null) + { + StringRequestEntity requestEntity = new StringRequestEntity(body, "application/json", "UTF-8"); + req.setRequestEntity(requestEntity); + } + return submitRequest(req, rq); + } + public HttpResponse post(final RequestContext rq, final String urlSuffix, String body) throws IOException - { - RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), urlSuffix, null); - String url = endpoint.getUrl(); + { + RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), urlSuffix, null); + String url = endpoint.getUrl(); - PostMethod req = new PostMethod(url.toString()); - if(body != null) - { - StringRequestEntity requestEntity = new StringRequestEntity(body, "application/json", "UTF-8"); - req.setRequestEntity(requestEntity); - } - return submitRequest(req, rq); - } - - public HttpResponse post(final RequestContext rq, Binding cmisBinding, String version, String cmisOperation, final String body) throws IOException - { - RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), cmisBinding, version, cmisOperation, null); - String url = endpoint.getUrl(); - - PostMethod req = new PostMethod(url.toString()); - if(body != null) - { - StringRequestEntity requestEntity = null; - if(cmisBinding.equals(Binding.atom)) - { - requestEntity = new StringRequestEntity(body, "text/xml", "UTF-8"); - } - else if(cmisBinding.equals(Binding.browser)) - { - requestEntity = new StringRequestEntity(body, "application/json", "UTF-8"); - } - req.setRequestEntity(requestEntity); - } - return submitRequest(req, rq); - } - - public HttpResponse put(final RequestContext rq, Binding cmisBinding, String version, String cmisOperation, final String body) throws IOException - { - RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), cmisBinding, version, cmisOperation, null); - String url = endpoint.getUrl(); - - PutMethod req = new PutMethod(url.toString()); - if(body != null) - { - StringRequestEntity requestEntity = null; - if(cmisBinding.equals(Binding.atom)) - { - requestEntity = new StringRequestEntity(body, "text/xml", "UTF-8"); - } - else if(cmisBinding.equals(Binding.browser)) - { - requestEntity = new StringRequestEntity(body, "application/json", "UTF-8"); - } - req.setRequestEntity(requestEntity); - } - return submitRequest(req, rq); - } - - public HttpResponse get(final RequestContext rq, Binding cmisBinding, String version, String cmisOperation, Map parameters) throws IOException - { - RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), cmisBinding, version, cmisOperation, parameters); - String url = endpoint.getUrl(); - - GetMethod req = new GetMethod(url.toString()); - return submitRequest(req, rq); - } + PostMethod req = new PostMethod(url.toString()); + if (body != null) + { + StringRequestEntity requestEntity = new StringRequestEntity(body, "application/json", "UTF-8"); + req.setRequestEntity(requestEntity); + } + return submitRequest(req, rq); + } - public HttpResponse delete(final RequestContext rq, Binding cmisBinding, String version, String cmisOperation) throws IOException - { - RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), cmisBinding, version, cmisOperation, null); - String url = endpoint.getUrl(); - - DeleteMethod req = new DeleteMethod(url.toString()); - return submitRequest(req, rq); - } + public HttpResponse post(final RequestContext rq, Binding cmisBinding, String version, String cmisOperation, final String body) throws IOException + { + RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), cmisBinding, version, cmisOperation, null); + String url = endpoint.getUrl(); - public HttpResponse head(final RequestContext rq, Binding cmisBinding, String version, String cmisOperation) throws IOException - { - RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), cmisBinding, version, cmisOperation, null); - String url = endpoint.getUrl(); - - HeadMethod req = new HeadMethod(url.toString()); - return submitRequest(req, rq); - } - - public HttpResponse options(final RequestContext rq, Binding cmisBinding, String version, String cmisOperation) throws IOException - { - RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), cmisBinding, version, cmisOperation, null); - String url = endpoint.getUrl(); - - OptionsMethod req = new OptionsMethod(url.toString()); - return submitRequest(req, rq); - } - - public HttpResponse trace(final RequestContext rq, Binding cmisBinding, String version, String cmisOperation) throws IOException - { - RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), cmisBinding, version, cmisOperation, null); - String url = endpoint.getUrl(); - - TraceMethod req = new TraceMethod(url.toString()); - return submitRequest(req, rq); - } - - public HttpResponse patch(final RequestContext rq, Binding cmisBinding, String version, String cmisOperation) throws IOException - { - RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), cmisBinding, version, cmisOperation, null); - String url = endpoint.getUrl(); - - PatchMethod req = new PatchMethod(url.toString()); - return submitRequest(req, rq); - } + PostMethod req = new PostMethod(url.toString()); + if (body != null) + { + StringRequestEntity requestEntity = null; + if (cmisBinding.equals(Binding.atom)) + { + requestEntity = new StringRequestEntity(body, "text/xml", "UTF-8"); + } + else if (cmisBinding.equals(Binding.browser)) + { + requestEntity = new StringRequestEntity(body, "application/json", "UTF-8"); + } + req.setRequestEntity(requestEntity); + } + return submitRequest(req, rq); + } + public HttpResponse put(final RequestContext rq, Binding cmisBinding, String version, String cmisOperation, final String body) throws IOException + { + RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), cmisBinding, version, cmisOperation, null); + String url = endpoint.getUrl(); + + PutMethod req = new PutMethod(url.toString()); + if (body != null) + { + StringRequestEntity requestEntity = null; + if (cmisBinding.equals(Binding.atom)) + { + requestEntity = new StringRequestEntity(body, "text/xml", "UTF-8"); + } + else if (cmisBinding.equals(Binding.browser)) + { + requestEntity = new StringRequestEntity(body, "application/json", "UTF-8"); + } + req.setRequestEntity(requestEntity); + } + return submitRequest(req, rq); + } + + public HttpResponse get(final RequestContext rq, Binding cmisBinding, String version, String cmisOperation, Map parameters) + throws IOException + { + RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), cmisBinding, version, cmisOperation, parameters); + String url = endpoint.getUrl(); + + GetMethod req = new GetMethod(url.toString()); + return submitRequest(req, rq); + } + + public HttpResponse delete(final RequestContext rq, Binding cmisBinding, String version, String cmisOperation) throws IOException + { + RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), cmisBinding, version, cmisOperation, null); + String url = endpoint.getUrl(); + + DeleteMethod req = new DeleteMethod(url.toString()); + return submitRequest(req, rq); + } + + public HttpResponse head(final RequestContext rq, Binding cmisBinding, String version, String cmisOperation) throws IOException + { + RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), cmisBinding, version, cmisOperation, null); + String url = endpoint.getUrl(); + + HeadMethod req = new HeadMethod(url.toString()); + return submitRequest(req, rq); + } + + public HttpResponse options(final RequestContext rq, Binding cmisBinding, String version, String cmisOperation) throws IOException + { + RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), cmisBinding, version, cmisOperation, null); + String url = endpoint.getUrl(); + + OptionsMethod req = new OptionsMethod(url.toString()); + return submitRequest(req, rq); + } + + public HttpResponse trace(final RequestContext rq, Binding cmisBinding, String version, String cmisOperation) throws IOException + { + RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), cmisBinding, version, cmisOperation, null); + String url = endpoint.getUrl(); + + TraceMethod req = new TraceMethod(url.toString()); + return submitRequest(req, rq); + } + + public HttpResponse patch(final RequestContext rq, Binding cmisBinding, String version, String cmisOperation) throws IOException + { + RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), cmisBinding, version, cmisOperation, null); + String url = endpoint.getUrl(); + + PatchMethod req = new PatchMethod(url.toString()); + return submitRequest(req, rq); + } + public HttpResponse post(final RequestContext rq, final String scope, final String entityCollectionName, final Object entityId, final String relationCollectionName, final Object relationshipEntityId, final String body) throws IOException { @@ -467,7 +484,13 @@ public class PublicApiHttpClient 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 { - 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); String url = endpoint.getUrl(); @@ -484,293 +507,321 @@ public class PublicApiHttpClient return submitRequest(req, rq); } + 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); + String url = endpoint.getUrl(); - 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); - String url = endpoint.getUrl(); + DeleteMethod req = new DeleteMethod(url); + return submitRequest(req, rq); + } - DeleteMethod req = new DeleteMethod(url); - 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 - { - RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), scope, entityCollectionName, entityId, relationCollectionName, relationshipEntityId, null); - String url = endpoint.getUrl(); + public HttpResponse delete(final RequestContext rq, final String scope, final String entityCollectionName, final Object entityId, + final String relationCollectionName, final Object relationshipEntityId) throws IOException + { + return delete(rq, scope, 1, entityCollectionName, entityId, relationCollectionName, relationshipEntityId); + } - DeleteMethod req = new DeleteMethod(url); - return submitRequest(req, rq); - } + 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(); - 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); - String url = endpoint.getUrl(); + DeleteMethod req = new DeleteMethod(url); + return submitRequest(req, rq); + } - PutMethod req = new PutMethod(url); - if(body != null) - { - StringRequestEntity requestEntity = new StringRequestEntity(body, "application/json", "UTF-8"); - req.setRequestEntity(requestEntity); - } - 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 params) throws IOException - { - RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), scope, entityCollectionName, entityId, relationCollectionName, relationshipEntityId, params); - String url = endpoint.getUrl(); + 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); + String url = endpoint.getUrl(); - PutMethod req = new PutMethod(url); - if(body != null) - { - StringRequestEntity requestEntity = new StringRequestEntity(body, "application/json", "UTF-8"); - req.setRequestEntity(requestEntity); - } - return submitRequest(req, rq); - } + PutMethod req = new PutMethod(url); + if (body != null) + { + StringRequestEntity requestEntity = new StringRequestEntity(body, "application/json", "UTF-8"); + req.setRequestEntity(requestEntity); + } + return submitRequest(req, rq); + } - /* - * Encapsulates information relating to a rest api end point, generating and encoding urls - * based on the rest api implementation class. - */ + 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 params) throws IOException + { + 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 params) throws IOException + { + RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), scope, version, entityCollectionName, entityId, relationCollectionName, + relationshipEntityId, params); + String url = endpoint.getUrl(); + + PutMethod req = new PutMethod(url); + if (body != null) + { + StringRequestEntity requestEntity = new StringRequestEntity(body, "application/json", "UTF-8"); + req.setRequestEntity(requestEntity); + } + return submitRequest(req, rq); + } + + /* + * Encapsulates information relating to a rest api end point, generating and + * encoding urls based on the rest api implementation class. + */ private class RestApiEndpoint { - private String url; + private String url; - RestApiEndpoint(String url, Map params) throws IOException - { - StringBuilder sb = new StringBuilder(MessageFormat.format(INDEX_URL, new Object[] {scheme, host, String.valueOf(port), contextPath, servletName})); - if(url != null) - { - sb.append(url); - } + RestApiEndpoint(String url, Map params) throws IOException + { + StringBuilder sb = new StringBuilder( + MessageFormat.format(INDEX_URL, new Object[] { scheme, host, String.valueOf(port), contextPath, servletName })); + if (url != null) + { + sb.append(url); + } - addParams(sb, params); + addParams(sb, params); - this.url = sb.toString(); - } + this.url = sb.toString(); + } - RestApiEndpoint(String tenantDomain, String url, Map params) throws IOException - { - StringBuilder sb = new StringBuilder(MessageFormat.format(OLD_BASE_URL, new Object[] {scheme, host, String.valueOf(port), contextPath, servletName, - tenantDomain == null ? TenantUtil.DEFAULT_TENANT : tenantDomain })); - sb.append("/"); - sb.append(url); + RestApiEndpoint(String tenantDomain, String url, Map params) throws IOException + { + StringBuilder sb = new StringBuilder(MessageFormat.format(OLD_BASE_URL, new Object[] { scheme, host, String.valueOf(port), contextPath, + servletName, tenantDomain == null ? TenantUtil.DEFAULT_TENANT : tenantDomain })); + sb.append("/"); + sb.append(url); - addParams(sb, params); + addParams(sb, params); - this.url = sb.toString(); - } + this.url = sb.toString(); + } - RestApiEndpoint(Class resourceClass, String tenantDomain, Object collectionEntityId, Object relationEntityId, Map params) throws IOException - { - StringBuilder sb = new StringBuilder(); + RestApiEndpoint(Class resourceClass, String tenantDomain, Object collectionEntityId, Object relationEntityId, Map params) + throws IOException + { + StringBuilder sb = new StringBuilder(); - Api api = ResourceInspector.inspectApi(resourceClass); - SCOPE scope = api.getScope(); - Pair relationshipCollectionInfo = getRelationCollectionInfo(resourceClass); + Api api = ResourceInspector.inspectApi(resourceClass); + SCOPE scope = api.getScope(); + int version = api.getVersion(); + Pair relationshipCollectionInfo = getRelationCollectionInfo(resourceClass); - sb.append(MessageFormat.format(BASE_URL, new Object[] {scheme, host, String.valueOf(port), contextPath, servletName, - tenantDomain == null ? TenantUtil.DEFAULT_TENANT : tenantDomain, scope.toString(), apiName})); + sb.append(MessageFormat.format(BASE_URL, new Object[] { scheme, host, String.valueOf(port), contextPath, servletName, + tenantDomain == null ? TenantUtil.DEFAULT_TENANT : tenantDomain, scope.toString(), apiName, version })); - if(relationshipCollectionInfo != null) - { - String entityCollectionName = relationshipCollectionInfo.getFirst(); - String relationshipCollectionName = relationshipCollectionInfo.getSecond(); - String relationEntityIdString = encodeToString(relationEntityId); - String collectionEntityIdString = encodeToString(collectionEntityId); + if (relationshipCollectionInfo != null) + { + String entityCollectionName = relationshipCollectionInfo.getFirst(); + String relationshipCollectionName = relationshipCollectionInfo.getSecond(); + String relationEntityIdString = encodeToString(relationEntityId); + String collectionEntityIdString = encodeToString(collectionEntityId); - sb.append(entityCollectionName); - sb.append("/"); - if(collectionEntityIdString != null) - { - sb.append(collectionEntityIdString); - sb.append("/"); - } + sb.append(entityCollectionName); + sb.append("/"); + if (collectionEntityIdString != null) + { + sb.append(collectionEntityIdString); + sb.append("/"); + } - sb.append(relationshipCollectionName); - sb.append("/"); - if(relationEntityIdString != null) - { - sb.append(relationEntityIdString); - sb.append("/"); - } - } - else - { - String entityCollectionName = getEntityCollectionInfo(resourceClass); - if(entityCollectionName != null) - { - String collectionEntityIdString = encodeToString(collectionEntityId); + sb.append(relationshipCollectionName); + sb.append("/"); + if (relationEntityIdString != null) + { + sb.append(relationEntityIdString); + sb.append("/"); + } + } + else + { + String entityCollectionName = getEntityCollectionInfo(resourceClass); + if (entityCollectionName != null) + { + String collectionEntityIdString = encodeToString(collectionEntityId); - sb.append(entityCollectionName); - sb.append("/"); - if(collectionEntityIdString != null) - { - sb.append(collectionEntityIdString); - sb.append("/"); - } - } - else - { - throw new RuntimeException(); - } - } + sb.append(entityCollectionName); + sb.append("/"); + if (collectionEntityIdString != null) + { + sb.append(collectionEntityIdString); + sb.append("/"); + } + } + else + { + throw new RuntimeException(); + } + } - addParams(sb, params); + addParams(sb, params); - this.url = sb.toString(); - } - - RestApiEndpoint(String networkId, Binding cmisBinding, String version, String cmisOperation, Map params) throws IOException - { - StringBuilder sb = new StringBuilder(); + this.url = sb.toString(); + } - if(networkId != null) - { - sb.append(getPublicApiCmisUrl(networkId, cmisBinding, version, cmisOperation)); - } - else - { - throw new IllegalArgumentException(); - } + RestApiEndpoint(String networkId, Binding cmisBinding, String version, String cmisOperation, Map params) throws IOException + { + StringBuilder sb = new StringBuilder(); - addParams(sb, params); + if (networkId != null) + { + sb.append(getPublicApiCmisUrl(networkId, cmisBinding, version, cmisOperation)); + } + else + { + throw new IllegalArgumentException(); + } - this.url = sb.toString(); - } + addParams(sb, params); - RestApiEndpoint(String tenantDomain, String scope, String collectionName, Object collectionEntityId, String relationName, Object relationEntityId, Map params) throws IOException - { - StringBuilder sb = new StringBuilder(); + this.url = sb.toString(); + } - if(tenantDomain == null || tenantDomain.equals(TenantService.DEFAULT_DOMAIN)) - { - tenantDomain = TenantUtil.DEFAULT_TENANT; - } - sb.append(MessageFormat.format(BASE_URL, new Object[] {scheme, host, String.valueOf(port), contextPath, servletName, - tenantDomain, scope, apiName})); + RestApiEndpoint(String tenantDomain, String scope, int version, String collectionName, Object collectionEntityId, String relationName, + Object relationEntityId, Map params) throws IOException + { + StringBuilder sb = new StringBuilder(); - if(collectionName != null) - { - sb.append("/"); - sb.append(collectionName); - if(collectionEntityId != null) - { - sb.append("/"); - sb.append(collectionEntityId); - } - } + if (tenantDomain == null || tenantDomain.equals(TenantService.DEFAULT_DOMAIN)) + { + tenantDomain = TenantUtil.DEFAULT_TENANT; + } + sb.append(MessageFormat.format(BASE_URL, + new Object[] { scheme, host, String.valueOf(port), contextPath, servletName, tenantDomain, scope, apiName, version })); - if(relationName != null) - { - sb.append("/"); - sb.append(relationName); - if(relationEntityId != null) - { - sb.append("/"); - sb.append(relationEntityId); - } - } + if (collectionName != null) + { + sb.append(collectionName); + if (collectionEntityId != null) + { + sb.append('/'); + sb.append(collectionEntityId); + } + } - addParams(sb, params); + if (relationName != null) + { + if (!sb.toString().endsWith("/")) + { + sb.append('/'); + } + sb.append(relationName); + if (relationEntityId != null) + { + sb.append('/'); + sb.append(relationEntityId); + } + } - this.url = sb.toString(); - } + addParams(sb, params); - private void addParams(StringBuilder sb, Map params) throws UnsupportedEncodingException - { - if(params != null && params.size() > 0) - { - sb.append("?"); + this.url = sb.toString(); + } - for(String paramName : params.keySet()) - { - sb.append(URLEncoder.encode(paramName, "UTF-8")); - sb.append("="); - sb.append(URLEncoder.encode(params.get(paramName), "UTF-8")); - sb.append("&"); - } + RestApiEndpoint(String tenantDomain, String scope, String collectionName, Object collectionEntityId, String relationName, + Object relationEntityId, Map params) throws IOException + { + this(tenantDomain, scope, 1, collectionName, collectionEntityId, relationName, relationEntityId, params); + } - sb.deleteCharAt(sb.length() - 1); - } - } + private void addParams(StringBuilder sb, Map params) throws UnsupportedEncodingException + { + if (params != null && params.size() > 0) + { + sb.append("?"); + for (String paramName : params.keySet()) + { + sb.append(URLEncoder.encode(paramName, "UTF-8")); + sb.append("="); + sb.append(URLEncoder.encode(params.get(paramName), "UTF-8")); + sb.append("&"); + } + + sb.deleteCharAt(sb.length() - 1); + } + } + private String encodeToString(Object o) throws UnsupportedEncodingException { - String ret = null; - - if(o instanceof NodeRef) - { - NodeRef nodeRef = (NodeRef)o; - ret = (o != null ? nodeRef.getId() : null); - } - else - { - ret = (o != null ? o.toString() : null); - } - - return ret; + String ret = null; + + if (o instanceof NodeRef) + { + NodeRef nodeRef = (NodeRef) o; + ret = (o != null ? nodeRef.getId() : null); + } + else + { + ret = (o != null ? o.toString() : null); + } + + return ret; } - + private Pair getRelationCollectionInfo(Class resourceClass) throws IOException { - AnnotationMetadata annotationMetaData = getAnnotationMetadata(resourceClass.getCanonicalName()); - if(annotationMetaData.isConcrete() && annotationMetaData.isIndependent()) - { - if(annotationMetaData.getAnnotationTypes().contains(RelationshipResource.class.getCanonicalName())) - { - Map attrs = annotationMetaData.getAnnotationAttributes(RelationshipResource.class.getName()); - String relationshipCollectionName = (String)attrs.get("name"); - Class entityResource = (Class)attrs.get("entityResource"); + AnnotationMetadata annotationMetaData = getAnnotationMetadata(resourceClass.getCanonicalName()); + if (annotationMetaData.isConcrete() && annotationMetaData.isIndependent()) + { + if (annotationMetaData.getAnnotationTypes().contains(RelationshipResource.class.getCanonicalName())) + { + Map attrs = annotationMetaData.getAnnotationAttributes(RelationshipResource.class.getName()); + String relationshipCollectionName = (String) attrs.get("name"); + Class entityResource = (Class) attrs.get("entityResource"); - String entityCollectionName = getEntityCollectionInfo(entityResource.getCanonicalName()); - - Pair ret = new Pair(entityCollectionName, relationshipCollectionName); - return ret; - } - else - { - return null; - } - } - else - { - throw new AlfrescoRuntimeException(""); - } + String entityCollectionName = getEntityCollectionInfo(entityResource.getCanonicalName()); + + Pair ret = new Pair(entityCollectionName, relationshipCollectionName); + return ret; + } + else + { + return null; + } + } + else + { + throw new AlfrescoRuntimeException(""); + } } private String getEntityCollectionInfo(Class resourceClass) throws IOException { - return getEntityCollectionInfo(resourceClass.getCanonicalName()); + return getEntityCollectionInfo(resourceClass.getCanonicalName()); } private String getEntityCollectionInfo(String className) throws IOException { - AnnotationMetadata annotationMetaData = getAnnotationMetadata(className); - if(annotationMetaData.isConcrete() && annotationMetaData.isIndependent()) - { - if(annotationMetaData.getAnnotationTypes().contains(EntityResource.class.getCanonicalName())) - { - Map attrs = annotationMetaData.getAnnotationAttributes(EntityResource.class.getName()); - return (String)attrs.get("name"); - } - else - { - return null; - } - } - else - { - throw new AlfrescoRuntimeException(""); - } + AnnotationMetadata annotationMetaData = getAnnotationMetadata(className); + if (annotationMetaData.isConcrete() && annotationMetaData.isIndependent()) + { + if (annotationMetaData.getAnnotationTypes().contains(EntityResource.class.getCanonicalName())) + { + Map attrs = annotationMetaData.getAnnotationAttributes(EntityResource.class.getName()); + return (String) attrs.get("name"); + } + else + { + return null; + } + } + else + { + throw new AlfrescoRuntimeException(""); + } } - - public String getUrl() throws UnsupportedEncodingException - { - return url; - } + + public String getUrl() throws UnsupportedEncodingException + { + return url; + } } } diff --git a/source/test-java/org/alfresco/rest/api/tests/util/JacksonUtil.java b/source/test-java/org/alfresco/rest/api/tests/util/JacksonUtil.java new file mode 100644 index 0000000000..88bab45e4b --- /dev/null +++ b/source/test-java/org/alfresco/rest/api/tests/util/JacksonUtil.java @@ -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 . + */ + +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 List parseEntries(JSONObject jsonObject, Class clazz) throws IOException + { + assertNotNull(jsonObject); + assertNotNull(clazz); + + List 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 parseEntry(JSONObject jsonObject, Class 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; + } +}