cancel
Showing results for 
Search instead for 
Did you mean: 

How to add a new (and custom) thumbnail/rendition to the rendition 2 service with java

4535992
Star Collaborator
Star Collaborator

Hi i need to add a new (and custom) thumbnail "original" to the list supported from alfresco 7.2.1 Community.

I have created a local transformer for convert files to "original" ( you can think thata as a alternative pdf thumbnail),

for the sourcemimetype = "text/plain" and the target mimetype "application/original".

Here i define my thumbnaildefinition for the auto registry:

@Component
public class ThumbnailDefinitionOriginal extends org.alfresco.repo.thumbnail.ThumbnailDefinition implements InitializingBean{

	private static final transient org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(ThumbnailDefinitionOriginal.class);	

	@Autowired
	private ThumbnailRegistry thumbnailRegistry;
	public void setThumbnailRegistry(ThumbnailRegistry thumbnailRegistry) {
		this.thumbnailRegistry = thumbnailRegistry;
	}

	@Override
	public void afterPropertiesSet() {
		super.setName(this.name);
		super.setMimetype(this.mimetype);
		super.setTransformationOptions(this.transformationOptions);				
		super.setRunAs(this.runAs);
		super.setFailureHandlingOptions(this.failureHandlingOptions);
		super.setThumbnailRegistry(this.thumbnailRegistry);
		
		Map<String, Serializable> parameters = new HashMap<String, Serializable>();
			
		// All TransformationOptions-based renditions are considered to be "thumbnails".
		// Therefore they should be created with a node type of cm:thumbnail
		parameters.put(RenditionService.PARAM_RENDITION_NODETYPE, ContentModel.TYPE_THUMBNAIL);

		// parameters common to all transformations
		
		putParameterIfNotNull(AbstractRenderingEngine.PARAM_SOURCE_CONTENT_PROPERTY, transformationOptions.getSourceContentProperty(), parameters);
		putParameterIfNotNull(AbstractRenderingEngine.PARAM_TARGET_CONTENT_PROPERTY, transformationOptions.getTargetContentProperty(), parameters);
		putParameterIfNotNull(RenditionService.PARAM_DESTINATION_NODE, transformationOptions.getTargetNodeRef(), parameters);

//			        putParameterIfNotNull(ImageRenderingEngine.PARAM_ASSOC_NAME, assocDetails.getAssociationName(), parameters);
//			        putParameterIfNotNull(ImageRenderingEngine.PARAM_ASSOC_TYPE, assocDetails.getAssociationType(), parameters);

		putParameterIfNotNull(AbstractTransformationRenderingEngine.PARAM_TIMEOUT_MS, transformationOptions.getTimeoutMs(), parameters);
		putParameterIfNotNull(AbstractTransformationRenderingEngine.PARAM_READ_LIMIT_TIME_MS, transformationOptions.getReadLimitTimeMs(), parameters);
		putParameterIfNotNull(AbstractTransformationRenderingEngine.PARAM_MAX_SOURCE_SIZE_K_BYTES, transformationOptions.getMaxSourceSizeKBytes(), parameters);
		putParameterIfNotNull(AbstractTransformationRenderingEngine.PARAM_READ_LIMIT_K_BYTES, transformationOptions.getReadLimitKBytes(), parameters);
		putParameterIfNotNull(AbstractTransformationRenderingEngine.PARAM_MAX_PAGES, transformationOptions.getMaxPages(), parameters);
		putParameterIfNotNull(AbstractTransformationRenderingEngine.PARAM_PAGE_LIMIT, transformationOptions.getPageLimit(), parameters);

		putParameterIfNotNull(AbstractTransformationRenderingEngine.PARAM_USE, transformationOptions.getUse(), parameters);

		
		if (transformationOptions.getSourceOptionsList() != null)
		{
			for (TransformationSourceOptions sourceOptions : transformationOptions.getSourceOptionsList())
			{
				sourceOptions.getSerializer().serialize(sourceOptions, parameters);
			}
		}
		
		// Auto self registry
		this.thumbnailRegistry.addThumbnailDefinition(this);		
	}
	
    private void putParameterIfNotNull(String paramName, Serializable paramValue, Map<String, Serializable> params)
    {
        if (paramValue != null)
        {
            params.put(paramName, paramValue);
        }
    }
	
	@Autowired
	private ThumbnailService thumbnailService;
	public void setThumbnailService(ThumbnailService thumbnailService) {
		this.thumbnailService = thumbnailService;
	}
	
	// ======================
	// CUSTOM
	// ======================

	private String name = "original";
	public void setName(String name) {
		this.name = name;
	}

	private String mimetype = "application/original";
	public void setMimetype(String mimetype) {
		this.mimetype = mimetype;
	}
	
	private TransformationOptions transformationOptions = new RuntimeExecutableContentTransformerOptions();
	public void setTransformationOptions(TransformationOptions transformationOptions) {
		this.transformationOptions = transformationOptions;
	}
	
	private String runAs = AuthenticationUtil.getSystemUserName();
	public void setRunAs(String runAs) {
		this.runAs = runAs;
	}
	
	/**
	 * The placeholder is a graphic that the thumbnail service can return as the thumbnail if the thumbnail for a given 
	 * node has not been generated. In my example I just copied one of the out-of-the-box placeholders and renamed it 
	 * but you could use anything you want there.
	 */
    private String placeHolderResourcePath = "alfresco/module/xxx/thumbnail/thumbnail_placeholder_scImageThumbnail.png";
    public void setPlaceHolderResourcePath(String placeHolderResourcePath) {
		this.placeHolderResourcePath = placeHolderResourcePath;
	}

	private String mimeAwarePlaceHolderResourcePath = "alfresco/module/xxx/thumbnail/thumbnail_placeholder_scImageThumbnail.png";
	public void setMimeAwarePlaceHolderResourcePath(String mimeAwarePlaceHolderResourcePath) {
		this.mimeAwarePlaceHolderResourcePath = mimeAwarePlaceHolderResourcePath;
	}
	
	@Autowired
	@Qualifier("standardFailureOptions")
	private FailureHandlingOptions failureHandlingOptions;
	public void setFailureHandlingOptions(FailureHandlingOptions failureHandlingOptions) {
		this.failureHandlingOptions = failureHandlingOptions;
	}
	
}

Now i set up a lillte behaviour for launch the rendition2Service when updating a content:

/**
 * Rendition Behaviour using RenditionService v2, as Share is still using RenditionService V1
 * Performs ORIGINAL renditions on created and modified Markdown content nodes using Rendition Service V2.
 * Share Web App is still using Rendition Service V1, so in order to get the rendition done with this
 * new transformer this additional operation is required.
 * @href https://github.com/aborroy/alf-tengine-markdown
 * @author aborroy
 * 
 */
@Component
public class OriginalRenditionBehaviour implements 
	NodeServicePolicies.OnCreateNodePolicy, 
	ContentServicePolicies.OnContentUpdatePolicy, 
	NodeServicePolicies.OnCreateChildAssociationPolicy,
	InitializingBean
{
    
    private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(OriginalRenditionBehaviour.class);
    private boolean enable = true;
    
	@Autowired
	@Qualifier("configurazioniBeanCompleto")
	private ConfigurazioniBean configurazioniBean;
	public void setConfigurazioniBean(ConfigurazioniBean configurazioniBean) {
		this.configurazioniBean = configurazioniBean;
	}
		
	@Autowired
    private PolicyComponent policyComponent;
    public void setPolicyComponent(PolicyComponent policyComponent) {
        this.policyComponent = policyComponent;
    }
    
    @Autowired
    @Qualifier("NodeService")
    private NodeService nodeService;
    public void setNodeService(NodeService nodeService)
    {
        this.nodeService = nodeService;
    }
    
    /**
     * Use the new Rendition Service V2 in order to use "localTransform.original" transformer 
     */
    @Autowired
    @Qualifier("RenditionService2")
    private RenditionService2 renditionService2;
    public void setRenditionService2(RenditionService2 renditionService2)
    {
        this.renditionService2 = renditionService2;
    }
    
    @Autowired
    @Qualifier("RenditionService")
    private RenditionService renditionService;
    public void setRenditionService(RenditionService renditionService)
    {
        this.renditionService = renditionService;
    }
    
    @Override
	public void afterPropertiesSet() {
                 init();
	}
    
    public void init() {
    		logger.debug("START BEHAVIOUR '" + this.getClass().getSimpleName()+"' '"+new Object(){}.getClass().getEnclosingMethod().getName()+"'");

            policyComponent.bindClassBehaviour(
                    NodeServicePolicies.OnCreateNodePolicy.QNAME,
                    ContentModel.TYPE_CONTENT,
                    new JavaBehaviour(this, "onCreateNode", NotificationFrequency.TRANSACTION_COMMIT));
            
            policyComponent.bindClassBehaviour(
                    ContentServicePolicies.OnContentUpdatePolicy.QNAME,
                    ContentModel.TYPE_CONTENT,
                    new JavaBehaviour(this, "onContentUpdate", NotificationFrequency.TRANSACTION_COMMIT));
            
            policyComponent.bindAssociationBehaviour(
                    NodeServicePolicies.OnCreateChildAssociationPolicy.QNAME,
                    ContentModel.TYPE_CONTENT,
                    //ContentModel.ASSOC_THUMBNAILS,
                    RenditionModel.ASSOC_RENDITION,
            		new JavaBehaviour(this, "onCreateChildAssociation", NotificationFrequency.TRANSACTION_COMMIT));
			
			logger.debug("END BEHAVIOUR '" + this.getClass().getSimpleName()+"' '"+new Object(){}.getClass().getEnclosingMethod().getName()+"'");
		}else {
			logger.warn("Can't invoke the '"+new Object(){}.getClass().getEnclosingMethod().getName()+"' because the property 'enable' is false");
		}
    }

    @Override
    public void onContentUpdate(NodeRef nodeRef, boolean newContent)
    {
    	for(String targetMimetype : TARGET_MIMETYPES) {
    		requestRendition(nodeRef,targetMimetype);
    	}
    }

    @Override
    public void onCreateNode(ChildAssociationRef childAssocRef)
    {
    	for(String targetMimetype : TARGET_MIMETYPES) {
    		requestRendition(childAssocRef.getChildRef(),targetMimetype);
    	}       
    }
    
	@Override
	public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean isNewNode) {
//    	for(String targetMimetype : TARGET_MIMETYPES) {
//    		requestRendition(childAssocRef.getChildRef(),targetMimetype);
//    	} 
	}
    
    public static final List<String> SOURCE_MIMETYPES= Arrays.asList(new String[] {
		"text/plain"
    });
    
    public static final List<String> TARGET_MIMETYPES = Arrays.asList(new String[] {
    	"application/original"
    });
    
    public boolean isTransformable(String sourceMimetype, String targetMimetype)
    {
    	if(sourceMimetype==null || targetMimetype == null) {
    		return false;
    	}
    	if(this.enable && SOURCE_MIMETYPES.contains(sourceMimetype.toLowerCase()) && TARGET_MIMETYPES.contains(targetMimetype.toLowerCase()) 
    			&& !sourceMimetype.equalsIgnoreCase(targetMimetype)){
    		//logger.debug("sourceMimetype=" + sourceMimetype+", targetMimetype=" + targetMimetype+", check="+SOURCE_MIMETYPES.contains(sourceMimetype)+", nodeRef="+options.getSourceNodeRef());       
    		return true;
    	}else {    		
    		return false;
    	}
    }
 
    /**
     * Performs a specific Rendition on sourceNodeRef if mime type is transformable
     * @param sourceNodeRef The node to be renditioned
     */
    private void requestRendition(NodeRef sourceNodeRef, String targetMimetype)
    {
    	try {
    		//logger.debug("START TRANSFORMER LOCAL '" + this.getClass().getSimpleName() + "'" + " with stargetMimetype '"+targetMimetype+"'" + " on node '"+sourceNodeRef+"|"+nodeService.getProperty(sourceNodeRef, ContentModel.PROP_NAME)+"'");
    		AuthenticationUtil.pushAuthentication();
    		Boolean FINALE = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Boolean>() {
				@Override
				public Boolean doWork() throws Exception {
					return TenantUtil.runAsTenant(new TenantUtil.TenantRunAsWork<Boolean>()
		            {
		                public Boolean doWork() throws Exception
		                {	
		                	if (nodeService.exists(sourceNodeRef))
		                    {
		                    	ContentData contentData = (ContentData) nodeService.getProperty(sourceNodeRef, ContentModel.PROP_CONTENT);
		                    	if(contentData == null) {
		                    		return false;
		                    	}

		                        String mimeType = contentData.getMimetype();
		                        if (isTransformable(mimeType, targetMimetype))
		                        {
		                        	String thumbnailName = ThumbnailServiceUtilities.retrieveThumbnailNameFromMimetype(targetMimetype);
		                        	if(StringUtils.isBlank(thumbnailName)) {
		                        		return false;
		                        	}
		                        	logger.debug("START TRANSFORMER LOCAL '" + this.getClass().getSimpleName() + "'" + " with stargetMimetype '"+targetMimetype+"'" + " on node '"+sourceNodeRef+"|"+nodeService.getProperty(sourceNodeRef, ContentModel.PROP_NAME)+"'");
		                        	long size = contentData.getSize();
		                            RenditionDefinitionRegistry2 renditionDefinitionRegistry2 = renditionService2.getRenditionDefinitionRegistry2();
		                            Set<String> availableRenditions = renditionDefinitionRegistry2.getRenditionNamesFrom(mimeType, size);
		                            if(availableRenditions==null || availableRenditions.isEmpty()) {
		                            	logger.warn("No rendition2 is enabled for sourceMimetype="+mimeType+" and targetMimetype="+targetMimetype+"");
		                            	return false;
		                            }
		                            logger.debug("Found these renditions/thumbnails "+Arrays.toString(availableRenditions.toArray())+" for sourceMimetype="+mimeType+" and targetMimetype="+targetMimetype+"");
		                            try
		                            {
		                                if (!availableRenditions.contains(thumbnailName))
		                                {
		                                    logger.warn("Unable to create rendition '"+thumbnailName+"' for " + mimeType
		                                            + " as no transformer is currently available.");
		                                    return false;
		                                }
		                                logger.debug("Run local transformer on node '"+sourceNodeRef+"' ");
		                                renditionService2.render(sourceNodeRef, thumbnailName);                                    
		                                //renditionService.render(sourceNodeRef, "pdf");
		                                logger.debug("END TRANSFORMER LOCAL '" + this.getClass().getSimpleName() + "'" + " with stargetMimetype '"+targetMimetype+"'" + " on node '"+sourceNodeRef+"|"+nodeService.getProperty(sourceNodeRef, ContentModel.PROP_NAME)+"'");
		                                return true;
		                            } catch (Exception ex)
		                            {
		                                // Don't throw the exception as we don't want the the upload to fail, just log it
		                                logger.warn("Asynchronous request to create a rendition upon upload failed: " + ex.getMessage(), ex);
		                                return false;
		                            }
		                        }
		                        return false;
		                    }
		                	return false;
		                }
		            }, TenantUtil.getCurrentDomain());
				}
			} , AuthenticationUtil.getSystemUserName());
    		//logger.debug("END TRANSFORMER LOCAL '" + this.getClass().getSimpleName() + "'" + " with stargetMimetype '"+targetMimetype+"'" + " on node '"+sourceNodeRef+"|"+nodeService.getProperty(sourceNodeRef, ContentModel.PROP_NAME)+"'");
    	}finally {
    		AuthenticationUtil.popAuthentication();
    	}
        
    }

}

but here the result of the line of code:

Set<String> availableRenditions = renditionDefinitionRegistry2.getRenditionNamesFrom(mimeType, size);

it's seem not have the rendition "original" on the list, here the result catch on debug:

renditionService2.getRenditionDefinitionRegistry2().getRenditionNamesFrom(mimeType, contentData.getSize())
	 (java.util.HashSet<E>) [imgpreview, doclib, pdf, medium, avatar, avatar32]

Anyone can tell me what i missing ?

0 REPLIES 0