From 88b0a9159f02eddc10db5fed71f8d12c89e3e3eb Mon Sep 17 00:00:00 2001 From: Ancuta Morarasu Date: Wed, 11 May 2016 11:35:46 +0000 Subject: [PATCH] Merged HEAD (5.2) to 5.2.N (5.2.1) 126472 jkaabimofrad: Merged FILE-FOLDER-API (5.2.0) to HEAD (5.2) 122394 jkaabimofrad: RA-677: Added node's renditions REST API. - Retrieve information about a rendition of a node + test git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.2.N/root@126816 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../org/alfresco/rest/api/Renditions.java | 11 +++ .../rest/api/impl/RenditionsImpl.java | 79 ++++++++++++++--- .../api/nodes/NodeRenditionsRelation.java | 7 ++ .../rest/api/tests/RenditionsTest.java | 88 +++++++++++++++++-- .../api/tests/client/data/ContentInfo.java | 49 +++++++++-- .../rest/api/tests/client/data/Rendition.java | 8 +- 6 files changed, 215 insertions(+), 27 deletions(-) diff --git a/source/java/org/alfresco/rest/api/Renditions.java b/source/java/org/alfresco/rest/api/Renditions.java index bef1014b29..4bbeb8d612 100644 --- a/source/java/org/alfresco/rest/api/Renditions.java +++ b/source/java/org/alfresco/rest/api/Renditions.java @@ -40,6 +40,17 @@ public interface Renditions CollectionWithPagingInfo getRenditions(String nodeId, Parameters parameters); /** + * Gets information about a rendition of a node in the repository. + * If there is no rendition, then returns the available/registered rendition. + * + * @param nodeId the source node id + * @param renditionId the rendition id + * @param parameters the {@link Parameters} object to get the parameters passed into the request + * @return the {@link Rendition} object + */ + Rendition getRendition(String nodeId, String renditionId, Parameters parameters); + + /** * Creates a rendition for the given node asynchronously. * * @param nodeId the source node id diff --git a/source/java/org/alfresco/rest/api/impl/RenditionsImpl.java b/source/java/org/alfresco/rest/api/impl/RenditionsImpl.java index 96af6401a2..717e241cb8 100644 --- a/source/java/org/alfresco/rest/api/impl/RenditionsImpl.java +++ b/source/java/org/alfresco/rest/api/impl/RenditionsImpl.java @@ -30,6 +30,7 @@ import org.alfresco.rest.api.Renditions; import org.alfresco.rest.api.model.ContentInfo; import org.alfresco.rest.api.model.Rendition; import org.alfresco.rest.api.model.Rendition.RenditionStatus; +import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException; import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException; import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; import org.alfresco.rest.framework.resource.parameters.Paging; @@ -47,7 +48,10 @@ import org.alfresco.service.cmr.repository.MimetypeService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.thumbnail.ThumbnailService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; import org.alfresco.util.PropertyCheck; +import org.apache.commons.lang.StringUtils; import java.util.Collections; import java.util.List; @@ -69,6 +73,7 @@ public class RenditionsImpl implements Renditions private RenditionService renditionService; private MimetypeService mimetypeService; private ActionService actionService; + private NamespaceService namespaceService; private ServiceRegistry serviceRegistry; public void setNodes(Nodes nodes) @@ -96,16 +101,13 @@ public class RenditionsImpl implements Renditions this.actionService = serviceRegistry.getActionService(); this.renditionService = serviceRegistry.getRenditionService(); this.mimetypeService = serviceRegistry.getMimetypeService(); + this.namespaceService = serviceRegistry.getNamespaceService(); } @Override public CollectionWithPagingInfo getRenditions(String nodeId, Parameters parameters) { - final NodeRef nodeRef = nodes.validateNode(nodeId); - if (!nodes.isSubClass(nodeRef, ContentModel.PROP_CONTENT, false)) - { - throw new InvalidArgumentException("Node id '" + nodeId + "' does not represent a file."); - } + final NodeRef nodeRef = validateSourceNode(nodeId); ContentData contentData = (ContentData) nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT); String contentMimeType = contentData.getMimetype(); @@ -141,13 +143,7 @@ public class RenditionsImpl implements Renditions List thumbnailDefinitions = thumbnailService.getThumbnailRegistry().getThumbnailDefinitions(contentMimeType, -1); for (ThumbnailDefinition thumbnailDefinition : thumbnailDefinitions) { - ContentInfo contentInfo = new ContentInfo(thumbnailDefinition.getMimetype(), - getMimeTypeDisplayName(thumbnailDefinition.getMimetype()), null, null); - Rendition apiRendition = new Rendition(); - apiRendition.setId(thumbnailDefinition.getName()); - apiRendition.setContent(contentInfo); - apiRendition.setStatus(RenditionStatus.NOT_CREATED); - apiRenditions.put(thumbnailDefinition.getName(), apiRendition); + apiRenditions.put(thumbnailDefinition.getName(), toApiRendition(thumbnailDefinition)); } } @@ -179,6 +175,26 @@ public class RenditionsImpl implements Renditions return CollectionWithPagingInfo.asPaged(paging, results.getPage(), results.hasMoreItems(), results.getTotalResultCount().getFirst()); } + @Override + public Rendition getRendition(String nodeId, String renditionId, Parameters parameters) + { + final NodeRef nodeRef = validateSourceNode(nodeId); + NodeRef renditionNodeRef = getRenditionByName(nodeRef, renditionId, parameters); + + // if there is no rendition, then try to find the available/registered rendition (yet to be created). + if (renditionNodeRef == null) + { + ThumbnailDefinition thumbnailDefinition = thumbnailService.getThumbnailRegistry().getThumbnailDefinition(renditionId); + if (thumbnailDefinition == null) + { + throw new EntityNotFoundException(renditionId); + } + return toApiRendition(thumbnailDefinition); + } + + return toApiRendition(renditionNodeRef); + } + @Override public void createRendition(String nodeId, Rendition rendition, Parameters parameters) { @@ -214,6 +230,23 @@ public class RenditionsImpl implements Renditions } } + protected NodeRef getRenditionByName(NodeRef nodeRef, String renditionId, Parameters parameters) + { + if (StringUtils.isEmpty(renditionId)) + { + throw new InvalidArgumentException("renditionId can't be null or empty."); + } + // Thumbnails have a cm: prefix. + QName renditionQName = QName.resolveToQName(namespaceService, renditionId); + + ChildAssociationRef nodeRefRendition = renditionService.getRenditionByName(nodeRef, renditionQName); + if (nodeRefRendition == null) + { + return null; + } + return nodeRefRendition.getChildRef(); + } + protected Rendition toApiRendition(NodeRef renditionNodeRef) { Rendition apiRendition = new Rendition(); @@ -229,6 +262,28 @@ public class RenditionsImpl implements Renditions return apiRendition; } + protected Rendition toApiRendition(ThumbnailDefinition thumbnailDefinition) + { + ContentInfo contentInfo = new ContentInfo(thumbnailDefinition.getMimetype(), + getMimeTypeDisplayName(thumbnailDefinition.getMimetype()), null, null); + Rendition apiRendition = new Rendition(); + apiRendition.setId(thumbnailDefinition.getName()); + apiRendition.setContent(contentInfo); + apiRendition.setStatus(RenditionStatus.NOT_CREATED); + + return apiRendition; + } + + protected NodeRef validateSourceNode(String nodeId) + { + final NodeRef nodeRef = nodes.validateNode(nodeId); + if (!nodes.isSubClass(nodeRef, ContentModel.PROP_CONTENT, false)) + { + throw new InvalidArgumentException("Node id '" + nodeId + "' does not represent a file."); + } + return nodeRef; + } + private String getMimeTypeDisplayName(String mimeType) { return mimetypeService.getDisplaysByMimetype().get(mimeType); diff --git a/source/java/org/alfresco/rest/api/nodes/NodeRenditionsRelation.java b/source/java/org/alfresco/rest/api/nodes/NodeRenditionsRelation.java index 31f29ea2fe..4b32c46cee 100644 --- a/source/java/org/alfresco/rest/api/nodes/NodeRenditionsRelation.java +++ b/source/java/org/alfresco/rest/api/nodes/NodeRenditionsRelation.java @@ -38,6 +38,7 @@ import java.util.List; */ @RelationshipResource(name = "renditions", entityResource = NodesEntityResource.class, title = "Node renditions") public class NodeRenditionsRelation implements RelationshipResourceAction.Read, + RelationshipResourceAction.ReadById, RelationshipResourceAction.Create, InitializingBean { @@ -61,6 +62,12 @@ public class NodeRenditionsRelation implements RelationshipResourceAction.Read create(String nodeId, List entity, Parameters parameters) { diff --git a/source/test-java/org/alfresco/rest/api/tests/RenditionsTest.java b/source/test-java/org/alfresco/rest/api/tests/RenditionsTest.java index 159e6963b5..bf3ee49eb8 100644 --- a/source/test-java/org/alfresco/rest/api/tests/RenditionsTest.java +++ b/source/test-java/org/alfresco/rest/api/tests/RenditionsTest.java @@ -23,6 +23,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import com.google.common.collect.Ordering; import org.alfresco.model.ContentModel; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.security.authentication.AuthenticationUtil; @@ -165,11 +166,8 @@ public class RenditionsTest extends AbstractBaseApiTest assertEquals(3, expectedPaging.getMaxItems().intValue()); assertTrue(expectedPaging.getTotalItems() >= 5); - // Create rendition - Rendition renditionRequest = new Rendition(); - renditionRequest.setId(docLib.getId()); - // FIXME the response status code should be changed to 202 when we fix the fwk - post(getRenditionsUrl(contentNodeId), userOneN1.getId(), RestApiUtil.toJsonAsString(renditionRequest), 201); + // Create 'doclib' rendition + createRendition(contentNodeId, docLib.getId()); // This should be long enough for compensating the action to run. Thread.sleep(3000); @@ -201,6 +199,16 @@ public class RenditionsTest extends AbstractBaseApiTest docLib = getRendition(renditions, "doclib"); assertNull("'doclib' rendition has already been created.", docLib); + // Test returned renditions are ordered (natural sort order) + // List all renditions + response = getAll(getRenditionsUrl(contentNodeId), userOneN1.getId(), paging, params, 200); + renditions = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Rendition.class); + assertTrue(Ordering.natural().isOrdered(renditions)); + // Try again to make sure the ordering wasn't coincidental + response = getAll(getRenditionsUrl(contentNodeId), userOneN1.getId(), paging, params, 200); + renditions = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Rendition.class); + assertTrue(Ordering.natural().isOrdered(renditions)); + // nodeId in the path parameter does not represent a file getAll(getRenditionsUrl(folder_Id), userOneN1.getId(), paging, params, 400); @@ -208,6 +216,68 @@ public class RenditionsTest extends AbstractBaseApiTest getAll(getRenditionsUrl(UUID.randomUUID().toString()), userOneN1.getId(), paging, params, 404); } + /** + * Tests get node rendition. + *

GET:

+ * {@literal :/alfresco/api//public/alfresco/versions/1/nodes//renditions/} + */ + @Test + public void testGetNodeRendition() throws Exception + { + // Create a folder within the site document's library + String folderName = "folder" + System.currentTimeMillis(); + String folder_Id = addNode(userOneN1Site, folderName, ContentModel.TYPE_FOLDER, userOneN1.getId()); + + // Create multipart request + String fileName = "quick.pdf"; + File file = getResourceFile(fileName); + MultiPartBuilder multiPartBuilder = MultiPartBuilder.create().setFileData(new FileData(fileName, file, MimetypeMap.MIMETYPE_PDF)); + MultiPartRequest reqBody = multiPartBuilder.build(); + + // Upload quick.pdf file into 'folder' + HttpResponse response = post("nodes/" + folder_Id + "/children", userOneN1.getId(), reqBody.getBody(), null, reqBody.getContentType(), 201); + Document document = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Document.class); + String contentNodeId = document.getId(); + + // Get rendition (not created yet) information for node + response = getSingle(getRenditionsUrl(contentNodeId), userOneN1.getId(), "doclib", 200); + Rendition rendition = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Rendition.class); + assertNotNull(rendition); + assertEquals(RenditionStatus.NOT_CREATED, rendition.getStatus()); + ContentInfo contentInfo = rendition.getContent(); + assertNotNull(contentInfo); + assertEquals(MimetypeMap.MIMETYPE_IMAGE_PNG, contentInfo.getMimeType()); + assertEquals("PNG Image", contentInfo.getMimeTypeName()); + assertNull("Shouldn't have returned the encoding, as the rendition hasn't been created yet.", contentInfo.getEncoding()); + assertNull("Shouldn't have returned the size, as the rendition hasn't been created yet.", contentInfo.getSizeInBytes()); + + // Create 'doclib' rendition + createRendition(contentNodeId, "doclib"); + + // This should be long enough for compensating the action to run. + Thread.sleep(3000); + // Get rendition information for node + response = getSingle(getRenditionsUrl(contentNodeId), userOneN1.getId(), "doclib", 200); + rendition = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Rendition.class); + assertNotNull(rendition); + assertEquals(RenditionStatus.CREATED, rendition.getStatus()); + contentInfo = rendition.getContent(); + assertNotNull(contentInfo); + assertEquals(MimetypeMap.MIMETYPE_IMAGE_PNG, contentInfo.getMimeType()); + assertEquals("PNG Image", contentInfo.getMimeTypeName()); + assertNotNull(contentInfo.getEncoding()); + assertTrue(contentInfo.getSizeInBytes() > 0); + + // nodeId in the path parameter does not represent a file + getSingle(getRenditionsUrl(folder_Id), userOneN1.getId(), "doclib", 400); + + // nodeId in the path parameter does not exist + getSingle(getRenditionsUrl(UUID.randomUUID().toString()), userOneN1.getId(), "doclib", 404); + + // renditionId in the path parameter is not registered/available + getSingle(getRenditionsUrl(contentNodeId), userOneN1.getId(), ("renditionId" + System.currentTimeMillis()), 404); + } + private String addNode(final TestSite testSite, final String name, final QName type, String user) { return TenantUtil.runAsUserTenant(new TenantUtil.TenantRunAsWork() @@ -220,6 +290,14 @@ public class RenditionsTest extends AbstractBaseApiTest }, user, testSite.getNetworkId()); } + private void createRendition(String sourceNodeId, String renditionId) throws Exception + { + Rendition renditionRequest = new Rendition(); + renditionRequest.setId(renditionId); + // FIXME the response status code should be changed to 202 when we fix the fwk + post(getRenditionsUrl(sourceNodeId), userOneN1.getId(), RestApiUtil.toJsonAsString(renditionRequest), 201); + } + private Rendition getRendition(List renditions, String renditionName) { for (Rendition rn : renditions) diff --git a/source/test-java/org/alfresco/rest/api/tests/client/data/ContentInfo.java b/source/test-java/org/alfresco/rest/api/tests/client/data/ContentInfo.java index 1b3bfe7cb6..689e6b1727 100644 --- a/source/test-java/org/alfresco/rest/api/tests/client/data/ContentInfo.java +++ b/source/test-java/org/alfresco/rest/api/tests/client/data/ContentInfo.java @@ -1,3 +1,22 @@ +/* + * Copyright (C) 2005-2016 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + package org.alfresco.rest.api.tests.client.data; import static org.junit.Assert.assertTrue; @@ -10,22 +29,22 @@ import static org.junit.Assert.assertTrue; */ public class ContentInfo { - private String mimeType; + private String mimeType; private String mimeTypeName; - private Long sizeInBytes; - private String encoding; + private Long sizeInBytes; + private String encoding; - public ContentInfo() - { - } + public ContentInfo() + { + } public String getMimeType() { return mimeType; } - public void setMimeType(String mimeType) { - this.mimeType = mimeType; - } + public void setMimeType(String mimeType) { + this.mimeType = mimeType; + } public String getMimeTypeName() { return mimeTypeName; @@ -62,4 +81,16 @@ public class ContentInfo AssertUtil.assertEquals("sizeInBytes", sizeInBytes, other.getSizeInBytes()); AssertUtil.assertEquals("encoding", encoding, other.getEncoding()); } + + @Override + public String toString() + { + final StringBuilder sb = new StringBuilder(150); + sb.append("ContentInfo [mimeType='").append(mimeType) + .append(", mimeTypeName='").append(mimeTypeName) + .append(", sizeInBytes=").append(sizeInBytes) + .append(", encoding='").append(encoding) + .append(']'); + return sb.toString(); + } } diff --git a/source/test-java/org/alfresco/rest/api/tests/client/data/Rendition.java b/source/test-java/org/alfresco/rest/api/tests/client/data/Rendition.java index 48c7b8197e..0e99bc54c8 100644 --- a/source/test-java/org/alfresco/rest/api/tests/client/data/Rendition.java +++ b/source/test-java/org/alfresco/rest/api/tests/client/data/Rendition.java @@ -28,7 +28,7 @@ import static org.junit.Assert.assertTrue; * * @author Jamal Kaabi-Mofrad */ -public class Rendition implements ExpectedComparison +public class Rendition implements ExpectedComparison, Comparable { public enum RenditionStatus { @@ -98,6 +98,12 @@ public class Rendition implements ExpectedComparison } } + @Override + public int compareTo(Rendition other) + { + return this.id.compareTo(other.getId()); + } + @Override public String toString() {