REPO-3766 Renditions: Simplified Async Rendition Service

REPO-3688 Renditions: Deprecation of public Java APIs
This commit is contained in:
alandavis
2018-09-25 18:31:32 +01:00
committed by GitHub
parent 8dc5c52c9a
commit aa24cc2333
6 changed files with 89 additions and 77 deletions

View File

@@ -37,7 +37,7 @@
<dependency.alfresco-repository.version>7.10</dependency.alfresco-repository.version>
<dependency.alfresco-core.version>7.4</dependency.alfresco-core.version>
<dependency.alfresco-data-model.version>8.10</dependency.alfresco-data-model.version>
<dependency.alfresco-data-model.version>8.15</dependency.alfresco-data-model.version>
<dependency.alfresco-pdf-renderer.version>1.1</dependency.alfresco-pdf-renderer.version>
<dependency.jackson.version>2.9.5</dependency.jackson.version>

View File

@@ -29,10 +29,10 @@ package org.alfresco.rest.api.impl;
import org.alfresco.heartbeat.RenditionsDataCollector;
import org.alfresco.model.ContentModel;
import org.alfresco.query.PagingResults;
import org.alfresco.repo.rendition2.RenditionDefinition2;
import org.alfresco.repo.rendition2.RenditionDefinitionRegistry2;
import org.alfresco.repo.rendition2.RenditionService2;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.repo.thumbnail.ThumbnailDefinition;
import org.alfresco.repo.thumbnail.ThumbnailHelper;
import org.alfresco.repo.thumbnail.ThumbnailRegistry;
import org.alfresco.repo.thumbnail.script.ScriptThumbnailService;
import org.alfresco.rest.antlr.WhereClauseParser;
import org.alfresco.rest.api.Nodes;
@@ -45,6 +45,7 @@ import org.alfresco.rest.framework.core.exceptions.ConstraintViolatedException;
import org.alfresco.rest.framework.core.exceptions.DisabledServiceException;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.core.exceptions.NotFoundException;
import org.alfresco.rest.framework.core.exceptions.StaleEntityException;
import org.alfresco.rest.framework.resource.content.BinaryResource;
import org.alfresco.rest.framework.resource.content.CacheDirective;
import org.alfresco.rest.framework.resource.content.ContentInfoImpl;
@@ -57,17 +58,12 @@ import org.alfresco.rest.framework.resource.parameters.where.Query;
import org.alfresco.rest.framework.resource.parameters.where.QueryHelper;
import org.alfresco.rest.workflow.api.impl.MapBasedQueryWalker;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.rendition.RenditionService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
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.repository.StoreRef;
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.alfresco.util.TempFileProvider;
@@ -98,15 +94,12 @@ public class RenditionsImpl implements Renditions, ResourceLoaderAware
private Nodes nodes;
private NodeService nodeService;
private ThumbnailService thumbnailService;
private ScriptThumbnailService scriptThumbnailService;
private RenditionService renditionService;
private MimetypeService mimetypeService;
private ActionService actionService;
private NamespaceService namespaceService;
private ServiceRegistry serviceRegistry;
private ResourceLoader resourceLoader;
private TenantService tenantService;
private RenditionService2 renditionService2;
private RenditionsDataCollector renditionsDataCollector;
public void setNodes(Nodes nodes)
@@ -114,11 +107,6 @@ public class RenditionsImpl implements Renditions, ResourceLoaderAware
this.nodes = nodes;
}
public void setThumbnailService(ThumbnailService thumbnailService)
{
this.thumbnailService = thumbnailService;
}
public void setScriptThumbnailService(ScriptThumbnailService scriptThumbnailService)
{
this.scriptThumbnailService = scriptThumbnailService;
@@ -140,6 +128,11 @@ public class RenditionsImpl implements Renditions, ResourceLoaderAware
this.tenantService = tenantService;
}
public void setRenditionService2(RenditionService2 renditionService2)
{
this.renditionService2 = renditionService2;
}
public void setRenditionsDataCollector(RenditionsDataCollector renditionsDataCollector)
{
this.renditionsDataCollector = renditionsDataCollector;
@@ -148,26 +141,23 @@ public class RenditionsImpl implements Renditions, ResourceLoaderAware
public void init()
{
PropertyCheck.mandatory(this, "nodes", nodes);
PropertyCheck.mandatory(this, "thumbnailService", thumbnailService);
PropertyCheck.mandatory(this, "scriptThumbnailService", scriptThumbnailService);
PropertyCheck.mandatory(this, "serviceRegistry", serviceRegistry);
PropertyCheck.mandatory(this, "tenantService", tenantService);
PropertyCheck.mandatory(this, "renditionService2", renditionService2);
PropertyCheck.mandatory(this, "renditionsDataCollector", renditionsDataCollector);
this.nodeService = serviceRegistry.getNodeService();
this.actionService = serviceRegistry.getActionService();
this.renditionService = serviceRegistry.getRenditionService();
this.mimetypeService = serviceRegistry.getMimetypeService();
this.namespaceService = serviceRegistry.getNamespaceService();
}
@Override
public CollectionWithPagingInfo<Rendition> getRenditions(NodeRef nodeRef, Parameters parameters)
{
final NodeRef validatedNodeRef = validateNode(nodeRef.getStoreRef(), nodeRef.getId());
String contentMimeType = getMimeType(validatedNodeRef);
ContentData contentData = getContentData(nodeRef, true);
String sourceMimetype = contentData.getMimetype();
Query query = parameters.getQuery();
boolean includeCreated = true;
boolean includeNotCreated = true;
String status = getStatus(parameters);
@@ -180,15 +170,17 @@ public class RenditionsImpl implements Renditions, ResourceLoaderAware
Map<String, Rendition> apiRenditions = new TreeMap<>();
if (includeNotCreated)
{
// List all available thumbnail definitions
List<ThumbnailDefinition> thumbnailDefinitions = thumbnailService.getThumbnailRegistry().getThumbnailDefinitions(contentMimeType, -1);
for (ThumbnailDefinition thumbnailDefinition : thumbnailDefinitions)
// List all available rendition definitions
long size = contentData.getSize();
RenditionDefinitionRegistry2 renditionDefinitionRegistry2 = renditionService2.getRenditionDefinitionRegistry2();
Set<String> renditionNames = renditionDefinitionRegistry2.getRenditionNamesFrom(sourceMimetype, size);
for (String renditionName : renditionNames)
{
apiRenditions.put(thumbnailDefinition.getName(), toApiRendition(thumbnailDefinition));
apiRenditions.put(renditionName, toApiRendition(renditionName));
}
}
List<ChildAssociationRef> nodeRefRenditions = renditionService.getRenditions(validatedNodeRef);
List<ChildAssociationRef> nodeRefRenditions = renditionService2.getRenditions(validatedNodeRef);
if (!nodeRefRenditions.isEmpty())
{
for (ChildAssociationRef childAssociationRef : nodeRefRenditions)
@@ -231,21 +223,23 @@ public class RenditionsImpl implements Renditions, ResourceLoaderAware
// if there is no rendition, then try to find the available/registered rendition (yet to be created).
if (renditionNodeRef == null && includeNotCreated)
{
ThumbnailDefinition thumbnailDefinition = thumbnailService.getThumbnailRegistry().getThumbnailDefinition(renditionId);
if (thumbnailDefinition == null)
ContentData contentData = getContentData(validatedNodeRef, true);
String sourceMimetype = contentData.getMimetype();
long size = contentData.getSize();
RenditionDefinitionRegistry2 renditionDefinitionRegistry2 = renditionService2.getRenditionDefinitionRegistry2();
RenditionDefinition2 renditionDefinition = renditionDefinitionRegistry2.getRenditionDefinition(renditionId);
if (renditionDefinition == null)
{
throw new NotFoundException(renditionId + " is not registered.");
}
else
{
String contentMimeType = getMimeType(validatedNodeRef);
// List all available thumbnail definitions for the source node
List<ThumbnailDefinition> thumbnailDefinitions = thumbnailService.getThumbnailRegistry().getThumbnailDefinitions(contentMimeType, -1);
Set<String> renditionNames = renditionDefinitionRegistry2.getRenditionNamesFrom(sourceMimetype, size);
boolean found = false;
for (ThumbnailDefinition td : thumbnailDefinitions)
for (String renditionName : renditionNames)
{
// Check the registered renditionId is applicable for the node's mimeType
if (renditionId.equals(td.getName()))
if (renditionId.equals(renditionName))
{
found = true;
break;
@@ -253,10 +247,10 @@ public class RenditionsImpl implements Renditions, ResourceLoaderAware
}
if (!found)
{
throw new NotFoundException(renditionId + " is not applicable for the node's mimeType " + contentMimeType);
throw new NotFoundException(renditionId + " is not applicable for the node's mimeType " + sourceMimetype);
}
}
return toApiRendition(thumbnailDefinition);
return toApiRendition(renditionId);
}
if (renditionNodeRef == null)
@@ -277,9 +271,9 @@ public class RenditionsImpl implements Renditions, ResourceLoaderAware
public void createRendition(NodeRef nodeRef, Rendition rendition, boolean executeAsync, Parameters parameters)
{
// If thumbnail generation has been configured off, then don't bother.
if (!thumbnailService.getThumbnailsEnabled())
if (!renditionService2.isEnabled())
{
throw new DisabledServiceException("Thumbnail generation has been disabled.");
throw new DisabledServiceException("Rendition generation has been disabled.");
}
final NodeRef sourceNodeRef = validateNode(nodeRef.getStoreRef(), nodeRef.getId());
@@ -289,29 +283,22 @@ public class RenditionsImpl implements Renditions, ResourceLoaderAware
throw new ConstraintViolatedException(rendition.getId() + " rendition already exists.");
}
// Use the thumbnail registry to get the details of the thumbnail
ThumbnailRegistry registry = thumbnailService.getThumbnailRegistry();
ThumbnailDefinition thumbnailDefinition = registry.getThumbnailDefinition(rendition.getId());
if (thumbnailDefinition == null)
try
{
throw new NotFoundException(rendition.getId() + " is not registered.");
renditionService2.render(sourceNodeRef, rendition.getId());
}
ContentData contentData = getContentData(sourceNodeRef, true);
// Check if anything is currently available to generate thumbnails for the specified mimeType
String sourceMimetype = contentData.getMimetype();
if (!registry.isThumbnailDefinitionAvailable(contentData.getContentUrl(), sourceMimetype, contentData.getSize(), sourceNodeRef,
thumbnailDefinition))
catch (IllegalArgumentException e)
{
throw new InvalidArgumentException("Unable to create thumbnail '" + thumbnailDefinition.getName() + "' for " +
sourceMimetype + " as no transformer is currently available.");
throw new NotFoundException(rendition.getId() + " is not registered."); // 404
}
catch (UnsupportedOperationException e)
{
throw new IllegalArgumentException((e.getMessage())); // 400
}
catch (IllegalStateException e)
{
throw new StaleEntityException(e.getMessage()); // 409
}
Action action = ThumbnailHelper.createCreateThumbnailAction(thumbnailDefinition, serviceRegistry);
renditionsDataCollector.recordRenditionRequest(thumbnailDefinition, sourceMimetype);
// Create thumbnail - or else queue for async creation
actionService.executeAction(action, sourceNodeRef, true, executeAsync);
}
@Override
@@ -423,10 +410,8 @@ public class RenditionsImpl implements Renditions, ResourceLoaderAware
{
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);
ChildAssociationRef nodeRefRendition = renditionService2.getRenditionByName(nodeRef, renditionId);
if (nodeRefRendition == null)
{
return null;
@@ -457,12 +442,15 @@ public class RenditionsImpl implements Renditions, ResourceLoaderAware
return apiRendition;
}
protected Rendition toApiRendition(ThumbnailDefinition thumbnailDefinition)
protected Rendition toApiRendition(String renditionName)
{
ContentInfo contentInfo = new ContentInfo(thumbnailDefinition.getMimetype(),
getMimeTypeDisplayName(thumbnailDefinition.getMimetype()), null, null);
RenditionDefinitionRegistry2 renditionDefinitionRegistry2 = renditionService2.getRenditionDefinitionRegistry2();
RenditionDefinition2 renditionDefinition = renditionDefinitionRegistry2.getRenditionDefinition(renditionName);
ContentInfo contentInfo = new ContentInfo(renditionDefinition.getTargetMimetype(),
getMimeTypeDisplayName(renditionDefinition.getTargetMimetype()), null, null);
Rendition apiRendition = new Rendition();
apiRendition.setId(thumbnailDefinition.getName());
apiRendition.setId(renditionName);
apiRendition.setContent(contentInfo);
apiRendition.setStatus(RenditionStatus.NOT_CREATED);

View File

@@ -1359,10 +1359,10 @@
<!-- -->
<bean id="renditions" class="org.alfresco.rest.api.impl.RenditionsImpl" init-method="init">
<property name="nodes" ref="nodes" />
<property name="thumbnailService" ref="ThumbnailService" />
<property name="scriptThumbnailService" ref="thumbnailServiceScript" />
<property name="serviceRegistry" ref="ServiceRegistry" />
<property name="tenantService" ref="tenantService"/>
<property name="renditionService2" ref="RenditionService2"/>
<property name="renditionsDataCollector" ref="renditionsDataCollector"/>
</bean>

View File

@@ -36,6 +36,7 @@ import static org.junit.Assert.assertTrue;
import com.google.common.collect.Ordering;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.content.transform.ContentTransformer;
import org.alfresco.repo.rendition2.RenditionService2Impl;
import org.alfresco.rest.api.model.Site;
import org.alfresco.rest.api.nodes.NodesEntityResource;
import org.alfresco.rest.api.tests.RepoService.TestNetwork;
@@ -469,9 +470,9 @@ public class RenditionsTest extends AbstractBaseApiTest
multipleRenditionRequest.add(new Rendition().setId("imgpreview"));
post(getNodeRenditionsUrl(contentNodeId), toJsonAsString(multipleRenditionRequest), 400);
ThumbnailService thumbnailService = applicationContext.getBean("thumbnailService", ThumbnailService.class);
RenditionService2Impl renditionService2 = applicationContext.getBean("renditionService2", RenditionService2Impl.class);
// Disable thumbnail generation
thumbnailService.setThumbnailsEnabled(false);
renditionService2.setThumbnailsEnabled(false);
try
{
// Create multipart request
@@ -494,7 +495,7 @@ public class RenditionsTest extends AbstractBaseApiTest
}
finally
{
thumbnailService.setThumbnailsEnabled(true);
renditionService2.setThumbnailsEnabled(true);
}
}

View File

@@ -85,6 +85,7 @@ import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import static java.lang.Thread.sleep;
import static org.alfresco.repo.security.authentication.ResetPasswordServiceImplTest.getWorkflowIdAndKeyFromUrl;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -2059,7 +2060,7 @@ public class TestPeople extends AbstractBaseApiTest
{
try
{
Thread.sleep(requiredDelay);
sleep(requiredDelay);
}
catch (InterruptedException e)
{
@@ -2129,7 +2130,7 @@ public class TestPeople extends AbstractBaseApiTest
}
@Test
public void updateAvatar() throws PublicApiException, IOException
public void updateAvatar() throws PublicApiException, IOException, InterruptedException
{
final String person1 = account1PersonIt.next();
final String person2 = account1PersonIt.next();
@@ -2243,7 +2244,8 @@ public class TestPeople extends AbstractBaseApiTest
@Test
public void removeAvatar() throws IOException, PublicApiException{
public void removeAvatar() throws IOException, PublicApiException, InterruptedException
{
final String person1 = account1PersonIt.next();
final String person2 = account1PersonIt.next();

View File

@@ -1411,17 +1411,17 @@ public class PublicApiClient
remove("people", personId, "activities", String.valueOf(activity.getId()), "Failed to remove activity");
}
public HttpResponse getAvatar(String personId, boolean placeholder, int expectedStatus) throws PublicApiException
public HttpResponse getAvatar(String personId, boolean placeholder, int expectedStatus) throws PublicApiException, InterruptedException
{
return getAvatar(personId, null, placeholder, null, expectedStatus);
}
public HttpResponse getAvatar(String personId, String ifModifiedSince, int expectedStatus) throws PublicApiException
public HttpResponse getAvatar(String personId, String ifModifiedSince, int expectedStatus) throws PublicApiException, InterruptedException
{
return getAvatar(personId, null, false, ifModifiedSince, expectedStatus);
}
public HttpResponse getAvatar(String personId, Boolean attachment, boolean placeholder, String ifModifiedSince, int expectedStatus) throws PublicApiException
public HttpResponse getAvatar(String personId, Boolean attachment, boolean placeholder, String ifModifiedSince, int expectedStatus) throws PublicApiException, InterruptedException
{
// Binary response expected
Map<String, String> params = new HashMap<>();
@@ -1438,12 +1438,33 @@ public class PublicApiClient
headers.put("If-Modified-Since", ifModifiedSince);
}
HttpResponse response = getSingle("people", personId, "avatar", null, params, headers, "Failed to get avatar", expectedStatus);
// As renditions are now done async, we generally need to wait.
HttpResponse response = getSingleWithDelayRetry("people", personId, "avatar",
null, params, headers, "Failed to get avatar", 40, 2500, expectedStatus);
checkStatus("Unexpected response", expectedStatus, response);
return response;
}
private HttpResponse getSingleWithDelayRetry(String entityCollectionName, String entityId, String relationCollectionName, String relationId, Map<String, String> params,
Map<String, String> headers, String errorMessage, int repeat, long pauseInMillisecond, int expectedStatus) throws PublicApiException, InterruptedException
{
int retryCount = 0;
while (retryCount < repeat)
{
try
{
return getSingle(entityCollectionName, entityId, relationCollectionName, relationId, params, headers, errorMessage, expectedStatus);
}
catch (PublicApiException ex)
{
retryCount++;
Thread.sleep(pauseInMillisecond);
}
}
return null;
}
public HttpResponse updateAvatar(String personId, File avatar, int expectedStatus) throws PublicApiException
{
try