mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-10-08 14:51:49 +00:00
Merged DEV/SG/MNT15135 to 5.2.N
MNT-15135 "Alfresco Media Management: Rendition Concurrency Failure on Property update" git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.2.N/root@130692 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -25,60 +25,69 @@
|
||||
*/
|
||||
package org.alfresco.repo.rendition.executer;
|
||||
|
||||
import static org.alfresco.service.cmr.rendition.RenditionService.PARAM_DESTINATION_PATH_TEMPLATE;
|
||||
import static org.alfresco.service.cmr.rendition.RenditionService.PARAM_IS_COMPONENT_RENDITION;
|
||||
import static org.alfresco.service.cmr.rendition.RenditionService.PARAM_ORPHAN_EXISTING_RENDITION;
|
||||
import static org.alfresco.service.cmr.rendition.RenditionService.PARAM_RENDITION_NODETYPE;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.model.RenditionModel;
|
||||
import org.alfresco.repo.action.ParameterDefinitionImpl;
|
||||
import org.alfresco.repo.action.executer.ActionExecuterAbstractBase;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.content.transform.UnimportantTransformException;
|
||||
import org.alfresco.repo.nodelocator.NodeLocator;
|
||||
import org.alfresco.repo.nodelocator.SelfNodeLocator;
|
||||
import org.alfresco.repo.policy.BehaviourFilter;
|
||||
import org.alfresco.repo.rendition.RenderingEngineDefinitionImpl;
|
||||
import org.alfresco.repo.rendition.RenditionDefinitionImpl;
|
||||
import org.alfresco.repo.rendition.RenditionLocation;
|
||||
import org.alfresco.repo.rendition.RenditionLocationResolver;
|
||||
import org.alfresco.repo.rendition.RenditionNodeManager;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.action.ActionDefinition;
|
||||
import org.alfresco.service.cmr.action.ActionServiceException;
|
||||
import org.alfresco.service.cmr.action.ActionTrackingService;
|
||||
import org.alfresco.service.cmr.action.ExecutionSummary;
|
||||
import org.alfresco.service.cmr.action.ParameterDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenderCallback;
|
||||
import org.alfresco.service.cmr.rendition.RenditionDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenditionService;
|
||||
import org.alfresco.service.cmr.rendition.RenditionServiceException;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.SerializedTransformationOptionsAccessor;
|
||||
import org.alfresco.service.namespace.NamespaceException;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
|
||||
import static org.alfresco.service.cmr.rendition.RenditionService.PARAM_DESTINATION_PATH_TEMPLATE;
|
||||
import static org.alfresco.service.cmr.rendition.RenditionService.PARAM_IS_COMPONENT_RENDITION;
|
||||
import static org.alfresco.service.cmr.rendition.RenditionService.PARAM_ORPHAN_EXISTING_RENDITION;
|
||||
import static org.alfresco.service.cmr.rendition.RenditionService.PARAM_RENDITION_NODETYPE;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.model.RenditionModel;
|
||||
import org.alfresco.repo.action.ParameterDefinitionImpl;
|
||||
import org.alfresco.repo.action.executer.ActionExecuterAbstractBase;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.content.transform.UnimportantTransformException;
|
||||
import org.alfresco.repo.nodelocator.NodeLocator;
|
||||
import org.alfresco.repo.nodelocator.SelfNodeLocator;
|
||||
import org.alfresco.repo.policy.BehaviourFilter;
|
||||
import org.alfresco.repo.rendition.RenderingEngineDefinitionImpl;
|
||||
import org.alfresco.repo.rendition.RenditionDefinitionImpl;
|
||||
import org.alfresco.repo.rendition.RenditionLocation;
|
||||
import org.alfresco.repo.rendition.RenditionLocationResolver;
|
||||
import org.alfresco.repo.rendition.RenditionNodeManager;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.repo.transaction.TransactionalResourceHelper;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.action.ActionDefinition;
|
||||
import org.alfresco.service.cmr.action.ActionServiceException;
|
||||
import org.alfresco.service.cmr.action.ActionTrackingService;
|
||||
import org.alfresco.service.cmr.action.ExecutionSummary;
|
||||
import org.alfresco.service.cmr.action.ParameterDefinition;
|
||||
import org.alfresco.service.cmr.attributes.AttributeService;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenderCallback;
|
||||
import org.alfresco.service.cmr.rendition.RenditionDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenditionService;
|
||||
import org.alfresco.service.cmr.rendition.RenditionServiceException;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.SerializedTransformationOptionsAccessor;
|
||||
import org.alfresco.service.cmr.version.Version;
|
||||
import org.alfresco.service.cmr.version.VersionService;
|
||||
import org.alfresco.service.namespace.NamespaceException;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.alfresco.util.transaction.TransactionListener;
|
||||
import org.alfresco.util.transaction.TransactionSupportUtil;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
|
||||
import com.sun.star.lang.NullPointerException;
|
||||
|
||||
/**
|
||||
@@ -89,11 +98,13 @@ import com.sun.star.lang.NullPointerException;
|
||||
* @author Nick Smith
|
||||
* @since 3.3
|
||||
*/
|
||||
public abstract class AbstractRenderingEngine extends ActionExecuterAbstractBase
|
||||
public abstract class AbstractRenderingEngine extends ActionExecuterAbstractBase implements TransactionListener
|
||||
{
|
||||
|
||||
/** Logger */
|
||||
private static Log logger = LogFactory.getLog(AbstractRenderingEngine.class);
|
||||
|
||||
private static final String RENDITIONED_CONTENT = "RENDITIONED_CONTENT";
|
||||
private static final String RENDERING_CONTEXTS = "RenderingEngine.Contexts";
|
||||
|
||||
protected static final String CONTENT_READER_NOT_FOUND_MESSAGE = "Cannot find Content Reader for document. Operation can't be performed";
|
||||
protected static final String DEFAULT_RUN_AS_NAME = AuthenticationUtil.getSystemUserName();
|
||||
@@ -144,7 +155,10 @@ public abstract class AbstractRenderingEngine extends ActionExecuterAbstractBase
|
||||
/* Injected Services */
|
||||
protected ContentService contentService;
|
||||
protected MimetypeMap mimetypeMap;
|
||||
protected ActionTrackingService actionTrackingService;
|
||||
protected ActionTrackingService actionTrackingService;
|
||||
protected AttributeService attributeService;
|
||||
protected TransactionService transactionService;
|
||||
protected VersionService versionService;
|
||||
|
||||
/* Parameter names common to all Rendering Actions */
|
||||
/**
|
||||
@@ -215,7 +229,22 @@ public abstract class AbstractRenderingEngine extends ActionExecuterAbstractBase
|
||||
|
||||
private final NodeLocator temporaryParentNodeLocator;
|
||||
private final QName temporaryRenditionLinkType;
|
||||
|
||||
|
||||
public void setVersionService(VersionService versionService)
|
||||
{
|
||||
this.versionService = versionService;
|
||||
}
|
||||
|
||||
public void setAttributeService(AttributeService attributeService)
|
||||
{
|
||||
this.attributeService = attributeService;
|
||||
}
|
||||
|
||||
public void setTransactionService(TransactionService transactionService)
|
||||
{
|
||||
this.transactionService = transactionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects the nodeService bean.
|
||||
*
|
||||
@@ -526,11 +555,13 @@ public abstract class AbstractRenderingEngine extends ActionExecuterAbstractBase
|
||||
|
||||
RenderingContext context = new RenderingContext(sourceNode,
|
||||
renditionDefinition,
|
||||
targetContentProp);
|
||||
render(context);
|
||||
targetContentProp);
|
||||
|
||||
render(context);
|
||||
|
||||
// This is a workaround for the fact that actions don't have return
|
||||
// values.
|
||||
action.getParameterValues().put(PARAM_RESULT, context.getChildAssociationRef());
|
||||
action.getParameterValues().put(PARAM_RESULT, context.getChildAssociationRef());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -759,111 +790,220 @@ public abstract class AbstractRenderingEngine extends ActionExecuterAbstractBase
|
||||
result = defaultValue;
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String getRenderedContentKey(NodeRef sourceNode, VersionService versionService)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(sourceNode.toString());
|
||||
sb.append(".");
|
||||
Version version = versionService.getCurrentVersion(sourceNode);
|
||||
sb.append(version != null ? version.getVersionLabel() : "1.0");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
protected class RenderingContext implements SerializedTransformationOptionsAccessor
|
||||
{
|
||||
private final String guid = GUID.generate();
|
||||
|
||||
private final NodeRef sourceNode;
|
||||
private final RenditionDefinition definition;
|
||||
private final QName renditionContentProperty;
|
||||
private String renderedContentKey;
|
||||
private ChildAssociationRef caNodeRef;
|
||||
|
||||
/**
|
||||
* @param sourceNode NodeRef
|
||||
* @param definition RenditionDefinition
|
||||
* @param renditionContentProperty QName
|
||||
*/
|
||||
RenderingContext(NodeRef sourceNode, RenditionDefinition definition, QName renditionContentProperty)
|
||||
{
|
||||
this.sourceNode = sourceNode;
|
||||
this.definition = definition;
|
||||
this.renditionContentProperty = renditionContentProperty;
|
||||
this.renderedContentKey = AbstractRenderingEngine.getRenderedContentKey(sourceNode, versionService);
|
||||
}
|
||||
|
||||
public String getRenderedContentKey()
|
||||
{
|
||||
return renderedContentKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + getOuterType().hashCode();
|
||||
result = prime * result + ((guid == null) ? 0 : guid.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
RenderingContext other = (RenderingContext) obj;
|
||||
if (!getOuterType().equals(other.getOuterType()))
|
||||
return false;
|
||||
if (guid == null) {
|
||||
if (other.guid != null)
|
||||
return false;
|
||||
} else if (!guid.equals(other.guid))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save an existing transformed content url for this rendition and node
|
||||
*
|
||||
* @param existingTransformedContentUrl
|
||||
*/
|
||||
void setExistingTransformedContentUrl(final String existingTransformedContentUrl)
|
||||
{
|
||||
// add the rendering context to the txn listener so that we can clean up
|
||||
// any rendering context data saved using the AttributeService
|
||||
TransactionalResourceHelper.getSet(RENDERING_CONTEXTS).add(this);
|
||||
TransactionSupportUtil.bindListener(AbstractRenderingEngine.this, 0);
|
||||
|
||||
if(logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("setExistingTransformedContentUrl for renderedContentKey " + renderedContentKey
|
||||
+ ", rendition " + getDefinition().getRenditionName());
|
||||
}
|
||||
|
||||
// make sure this is saved in a new transaction
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
attributeService.setAttribute(existingTransformedContentUrl, RENDITIONED_CONTENT, renderedContentKey,
|
||||
getDefinition().getRenditionName());
|
||||
return null;
|
||||
}
|
||||
}, false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an existing transformed content/rendition url for this rendition and node
|
||||
*
|
||||
* @return content url of transformed content/rendition
|
||||
*/
|
||||
String getExistingTransformedContentUrl()
|
||||
{
|
||||
// add the rendering context to the txn listener so that we can clean up
|
||||
// any rendering context data saved using the AttributeService
|
||||
TransactionalResourceHelper.getSet(RENDERING_CONTEXTS).add(this);
|
||||
TransactionSupportUtil.bindListener(AbstractRenderingEngine.this, 0);
|
||||
|
||||
String contentUrl = (String)attributeService.getAttribute(RENDITIONED_CONTENT, renderedContentKey,
|
||||
getDefinition().getRenditionName());
|
||||
return contentUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the sourceNode
|
||||
*/
|
||||
public NodeRef getSourceNode()
|
||||
{
|
||||
return this.sourceNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazily instantiation of the ChildAssociationRef
|
||||
* @return ChildAssociationRef
|
||||
*/
|
||||
public synchronized ChildAssociationRef getChildAssociationRef()
|
||||
{
|
||||
if (this.caNodeRef == null)
|
||||
{
|
||||
this.caNodeRef = createRenditionNodeAssoc(sourceNode, definition);
|
||||
}
|
||||
|
||||
return this.caNodeRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the destinationNode
|
||||
*/
|
||||
public NodeRef getDestinationNode()
|
||||
{
|
||||
return getChildAssociationRef().getChildRef();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the definition
|
||||
*/
|
||||
public RenditionDefinition getDefinition()
|
||||
{
|
||||
return this.definition;
|
||||
}
|
||||
|
||||
public <T> T getCheckedParam(String paramName, Class<T> clazz)
|
||||
{
|
||||
return AbstractRenderingEngine.getCheckedParam(paramName, clazz, definition);
|
||||
}
|
||||
|
||||
public <T> T getParamWithDefault(String paramName, T defaultValue)
|
||||
{
|
||||
return AbstractRenderingEngine.getParamWithDefault(paramName, defaultValue, definition);
|
||||
}
|
||||
|
||||
public ContentReader makeContentReader()
|
||||
{
|
||||
QName srcContentProp = getParamWithDefault(PARAM_SOURCE_CONTENT_PROPERTY, DEFAULT_CONTENT_PROPERTY);
|
||||
ContentReader contentReader = contentService.getReader(sourceNode, srcContentProp);
|
||||
if (contentReader == null || !contentReader.exists())
|
||||
{
|
||||
throw new UnimportantTransformException(CONTENT_READER_NOT_FOUND_MESSAGE);
|
||||
}
|
||||
return contentReader;
|
||||
}
|
||||
|
||||
public ContentWriter makeContentWriter()
|
||||
{
|
||||
ContentWriter contentWriter = contentService.getWriter(getDestinationNode(), renditionContentProperty, true);
|
||||
String mimetype = getTargetMimeType(this);
|
||||
contentWriter.setMimetype(mimetype);
|
||||
String encoding = getTargetEncoding(this);
|
||||
contentWriter.setEncoding(encoding);
|
||||
return contentWriter;
|
||||
}
|
||||
|
||||
public int getIntegerParam(String key, int defaultValue)
|
||||
{
|
||||
Serializable serializable = definition.getParameterValue(key);
|
||||
if (serializable == null)
|
||||
return defaultValue;
|
||||
else
|
||||
{
|
||||
Number number = (Number) serializable;
|
||||
return number.intValue();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "RenderingContext [sourceNode=" + sourceNode + ", renderedContentKey=" + renderedContentKey
|
||||
+ ", definition=" + definition + ", renditionContentProperty=" + renditionContentProperty + ", caNodeRef=" + caNodeRef
|
||||
+ ", actionDefinitionName=" + definition.getActionDefinitionName()
|
||||
+ ", renditionName=" + definition.getRenditionName()
|
||||
+ "]";
|
||||
}
|
||||
|
||||
private AbstractRenderingEngine getOuterType()
|
||||
{
|
||||
return AbstractRenderingEngine.this;
|
||||
}
|
||||
}
|
||||
|
||||
protected class RenderingContext implements SerializedTransformationOptionsAccessor
|
||||
{
|
||||
private final NodeRef sourceNode;
|
||||
private final RenditionDefinition definition;
|
||||
private final QName renditionContentProperty;
|
||||
|
||||
private ChildAssociationRef caNodeRef;
|
||||
|
||||
/**
|
||||
* @param sourceNode NodeRef
|
||||
* @param definition RenditionDefinition
|
||||
* @param renditionContentProperty QName
|
||||
*/
|
||||
public RenderingContext(NodeRef sourceNode,//
|
||||
RenditionDefinition definition,//
|
||||
QName renditionContentProperty)
|
||||
{
|
||||
this.sourceNode = sourceNode;
|
||||
this.definition = definition;
|
||||
this.renditionContentProperty = renditionContentProperty;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the sourceNode
|
||||
*/
|
||||
public NodeRef getSourceNode()
|
||||
{
|
||||
return this.sourceNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazily instantiation of the ChildAssociationRef
|
||||
* @return ChildAssociationRef
|
||||
*/
|
||||
public synchronized ChildAssociationRef getChildAssociationRef()
|
||||
{
|
||||
if (this.caNodeRef == null)
|
||||
{
|
||||
this.caNodeRef = createRenditionNodeAssoc(sourceNode, definition);
|
||||
}
|
||||
return this.caNodeRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the destinationNode
|
||||
*/
|
||||
public NodeRef getDestinationNode()
|
||||
{
|
||||
return getChildAssociationRef().getChildRef();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the definition
|
||||
*/
|
||||
public RenditionDefinition getDefinition()
|
||||
{
|
||||
return this.definition;
|
||||
}
|
||||
|
||||
public <T> T getCheckedParam(String paramName, Class<T> clazz)
|
||||
{
|
||||
return AbstractRenderingEngine.getCheckedParam(paramName, clazz, definition);
|
||||
}
|
||||
|
||||
public <T> T getParamWithDefault(String paramName, T defaultValue)
|
||||
{
|
||||
return AbstractRenderingEngine.getParamWithDefault(paramName, defaultValue, definition);
|
||||
}
|
||||
|
||||
public ContentReader makeContentReader()
|
||||
{
|
||||
QName srcContentProp = getParamWithDefault(PARAM_SOURCE_CONTENT_PROPERTY, DEFAULT_CONTENT_PROPERTY);
|
||||
ContentReader contentReader = contentService.getReader(sourceNode, srcContentProp);
|
||||
if (contentReader == null || !contentReader.exists())
|
||||
{
|
||||
throw new UnimportantTransformException(CONTENT_READER_NOT_FOUND_MESSAGE);
|
||||
}
|
||||
return contentReader;
|
||||
}
|
||||
|
||||
public ContentWriter makeContentWriter()
|
||||
{
|
||||
ContentWriter contentWriter = contentService.getWriter(getDestinationNode(), renditionContentProperty, true);
|
||||
String mimetype = getTargetMimeType(this);
|
||||
contentWriter.setMimetype(mimetype);
|
||||
String encoding = getTargetEncoding(this);
|
||||
contentWriter.setEncoding(encoding);
|
||||
return contentWriter;
|
||||
}
|
||||
|
||||
public int getIntegerParam(String key, int defaultValue)
|
||||
{
|
||||
Serializable serializable = definition.getParameterValue(key);
|
||||
if (serializable == null)
|
||||
return defaultValue;
|
||||
else
|
||||
{
|
||||
Number number = (Number) serializable;
|
||||
return number.intValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void tagSourceNodeAsRenditioned(final RenditionDefinition renditionDef, final NodeRef actionedUponNodeRef)
|
||||
{
|
||||
// Adds the 'Renditioned' aspect to the source node if it
|
||||
@@ -1120,5 +1260,69 @@ public abstract class AbstractRenderingEngine extends ActionExecuterAbstractBase
|
||||
"multiple instances of the same action");
|
||||
}
|
||||
return executionSummaries.iterator().next();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void beforeCommit(boolean readOnly)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void beforeCompletion()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void afterCommit()
|
||||
{
|
||||
// clear saved rendition data if we are successful
|
||||
|
||||
final Set<RenderingContext> renderingContexts = TransactionalResourceHelper.getSet(RENDERING_CONTEXTS);
|
||||
|
||||
if(logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Cleaning up " + renderingContexts.size() + " rendering contexts");
|
||||
}
|
||||
|
||||
if(!renderingContexts.isEmpty())
|
||||
{
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
for(RenderingContext context : renderingContexts)
|
||||
{
|
||||
if(logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Cleaning up rendering context for source node " + context.getSourceNode()
|
||||
+ ", rendition " + context.getDefinition().getRenditionName());
|
||||
}
|
||||
|
||||
attributeService.removeAttributes(RENDITIONED_CONTENT, context.getRenderedContentKey(),
|
||||
context.getDefinition().getRenditionName());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void afterRollback()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@@ -26,43 +26,50 @@
|
||||
|
||||
package org.alfresco.repo.rendition.executer;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
import org.alfresco.repo.action.ParameterDefinitionImpl;
|
||||
import org.alfresco.repo.content.transform.ContentTransformer;
|
||||
import org.alfresco.repo.content.transform.TransformerConfig;
|
||||
import org.alfresco.repo.content.transform.TransformerDebug;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
import org.alfresco.repo.action.ParameterDefinitionImpl;
|
||||
import org.alfresco.repo.content.ContentContext;
|
||||
import org.alfresco.repo.content.ContentStore;
|
||||
import org.alfresco.repo.content.filestore.FileContentStore;
|
||||
import org.alfresco.repo.content.transform.ContentTransformer;
|
||||
import org.alfresco.repo.content.transform.TransformerConfig;
|
||||
import org.alfresco.repo.content.transform.TransformerDebug;
|
||||
import org.alfresco.repo.content.transform.UnsupportedTransformationException;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.service.cmr.action.ActionServiceException;
|
||||
import org.alfresco.service.cmr.action.ActionTrackingService;
|
||||
import org.alfresco.service.cmr.action.ExecutionDetails;
|
||||
import org.alfresco.service.cmr.action.ExecutionSummary;
|
||||
import org.alfresco.service.cmr.action.ParameterDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenditionCancelledException;
|
||||
import org.alfresco.service.cmr.rendition.RenditionServiceException;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NoTransformerException;
|
||||
import org.alfresco.service.cmr.repository.TransformationOptionLimits;
|
||||
import org.alfresco.service.cmr.repository.TransformationOptions;
|
||||
import org.alfresco.service.cmr.repository.TransformationSourceOptions;
|
||||
import org.alfresco.service.cmr.repository.TransformationSourceOptions.TransformationSourceOptionsSerializer;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.service.cmr.action.ActionServiceException;
|
||||
import org.alfresco.service.cmr.action.ActionTrackingService;
|
||||
import org.alfresco.service.cmr.action.ExecutionDetails;
|
||||
import org.alfresco.service.cmr.action.ExecutionSummary;
|
||||
import org.alfresco.service.cmr.action.ParameterDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenditionCancelledException;
|
||||
import org.alfresco.service.cmr.rendition.RenditionServiceException;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NoTransformerException;
|
||||
import org.alfresco.service.cmr.repository.TransformationOptionLimits;
|
||||
import org.alfresco.service.cmr.repository.TransformationOptions;
|
||||
import org.alfresco.service.cmr.repository.TransformationSourceOptions;
|
||||
import org.alfresco.service.cmr.repository.TransformationSourceOptions.TransformationSourceOptionsSerializer;
|
||||
import org.alfresco.util.TempFileProvider;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
|
||||
/**
|
||||
* @author Nick Smith
|
||||
*/
|
||||
public abstract class AbstractTransformationRenderingEngine extends AbstractRenderingEngine
|
||||
public abstract class AbstractTransformationRenderingEngine extends AbstractRenderingEngine implements ApplicationContextAware
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(AbstractTransformationRenderingEngine.class);
|
||||
|
||||
@@ -112,6 +119,8 @@ public abstract class AbstractTransformationRenderingEngine extends AbstractRend
|
||||
* This optional {@link String} parameter specifies the type (or use) of the rendition.
|
||||
*/
|
||||
public static final String PARAM_USE = TransformerConfig.USE.replaceAll("\\.", "");
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
/* Error messages */
|
||||
private static final String TRANSFORMER_NOT_EXISTS_MESSAGE_PATTERN = "Transformer for '%s' source mime type and '%s' target mime type was not found. Operation can't be performed";
|
||||
@@ -119,11 +128,18 @@ public abstract class AbstractTransformationRenderingEngine extends AbstractRend
|
||||
private static final String TRANSFORMING_ERROR_MESSAGE = "Some error occurred during document transforming. Error message: ";
|
||||
|
||||
private Collection<TransformationSourceOptionsSerializer> sourceOptionsSerializers;
|
||||
|
||||
|
||||
private ContentStore tempStore;
|
||||
|
||||
public Collection<TransformationSourceOptionsSerializer> getSourceOptionsSerializers()
|
||||
{
|
||||
return sourceOptionsSerializers;
|
||||
}
|
||||
|
||||
public void setApplicationContext(ApplicationContext applicationContext)
|
||||
{
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
public void setSourceOptionsSerializers(Collection<TransformationSourceOptionsSerializer> sourceOptionsSerializers)
|
||||
{
|
||||
@@ -157,166 +173,198 @@ public abstract class AbstractTransformationRenderingEngine extends AbstractRend
|
||||
if (executorService == null)
|
||||
{
|
||||
executorService = Executors.newCachedThreadPool();
|
||||
}
|
||||
}
|
||||
|
||||
this.tempStore = new FileContentStore(this.applicationContext, TempFileProvider.getTempDir().getAbsolutePath());
|
||||
}
|
||||
|
||||
|
||||
private void copyTransformedContent(ContentReader transformedContentReader, RenderingContext context)
|
||||
{
|
||||
// Copy content from temp writer to real writer
|
||||
ContentWriter writer = context.makeContentWriter();
|
||||
writer.putContent(transformedContentReader.getContentInputStream());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.rendition.executer.AbstractRenderingEngine#render(org.alfresco.repo.rendition.executer.AbstractRenderingEngine.RenderingContext)
|
||||
*/
|
||||
@Override
|
||||
protected void render(RenderingContext context)
|
||||
{
|
||||
ContentReader contentReader = context.makeContentReader();
|
||||
// There will have been an exception if there is no content data so contentReader is not null.
|
||||
String sourceUrl = contentReader.getContentUrl();
|
||||
String sourceMimeType = contentReader.getMimetype();
|
||||
String targetMimeType = getTargetMimeType(context);
|
||||
|
||||
// The child NodeRef gets created here
|
||||
TransformationOptions options = getTransformOptions(context);
|
||||
|
||||
// Log the following getTransform() as trace so we can see the wood for the trees
|
||||
ContentTransformer transformer;
|
||||
boolean orig = TransformerDebug.setDebugOutput(false);
|
||||
try
|
||||
{
|
||||
transformer = this.contentService.getTransformer(sourceUrl, sourceMimeType, contentReader.getSize(), targetMimeType, options);
|
||||
}
|
||||
finally
|
||||
{
|
||||
TransformerDebug.setDebugOutput(orig);
|
||||
}
|
||||
|
||||
if (null == transformer)
|
||||
{
|
||||
// There's no transformer available for the requested rendition!
|
||||
throw new RenditionServiceException(String.format(TRANSFORMER_NOT_EXISTS_MESSAGE_PATTERN, sourceMimeType,
|
||||
targetMimeType));
|
||||
}
|
||||
|
||||
if (!transformer.isTransformable(sourceMimeType, contentReader.getSize(), targetMimeType, options))
|
||||
{
|
||||
throw new RenditionServiceException(String.format(NOT_TRANSFORMABLE_MESSAGE_PATTERN, sourceMimeType, targetMimeType));
|
||||
}
|
||||
|
||||
long startTime = new Date().getTime();
|
||||
boolean actionCancelled = false;
|
||||
boolean actionCompleted = false;
|
||||
|
||||
// Cache the execution summary to get details later
|
||||
ExecutionSummary executionSummary = null;
|
||||
try
|
||||
{
|
||||
executionSummary = getExecutionSummary(context);
|
||||
}
|
||||
catch (ActionServiceException e)
|
||||
{
|
||||
if (logger.isInfoEnabled())
|
||||
{
|
||||
// check for existing transformed content and reuse if present to avoid re-rendering
|
||||
String existingTransformedContentUrl = context.getExistingTransformedContentUrl();
|
||||
if(existingTransformedContentUrl != null)
|
||||
{
|
||||
if(logger.isDebugEnabled())
|
||||
{
|
||||
logger.info("Cancelling of multiple concurrent action instances " +
|
||||
"currently unsupported, this action can't be cancelled");
|
||||
logger.debug("Reusing existing rendered content " + existingTransformedContentUrl
|
||||
+ " for rendering context " + context);
|
||||
}
|
||||
}
|
||||
|
||||
// Call the transform in a different thread so we can move on if cancelled
|
||||
FutureTask<ContentWriter> transformTask = new FutureTask<ContentWriter>(
|
||||
new TransformationCallable(contentReader, targetMimeType, options, context,
|
||||
AuthenticationUtil.getFullyAuthenticatedUser()));
|
||||
getExecutorService().execute(transformTask);
|
||||
|
||||
// Start checking for cancellation or timeout
|
||||
while (true)
|
||||
{
|
||||
ContentReader existingTransformedContent = tempStore.getReader(existingTransformedContentUrl);
|
||||
copyTransformedContent(existingTransformedContent, context);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Rendering for rendering context " + context);
|
||||
}
|
||||
|
||||
ContentReader contentReader = context.makeContentReader();
|
||||
// There will have been an exception if there is no content data so contentReader is not null.
|
||||
String sourceUrl = contentReader.getContentUrl();
|
||||
String sourceMimeType = contentReader.getMimetype();
|
||||
String targetMimeType = getTargetMimeType(context);
|
||||
|
||||
// The child NodeRef gets created here
|
||||
TransformationOptions options = getTransformOptions(context);
|
||||
|
||||
// Log the following getTransform() as trace so we can see the wood for the trees
|
||||
ContentTransformer transformer;
|
||||
boolean orig = TransformerDebug.setDebugOutput(false);
|
||||
try
|
||||
{
|
||||
Thread.sleep(CANCELLED_ACTION_POLLING_INTERVAL);
|
||||
if (transformTask.isDone())
|
||||
transformer = this.contentService.getTransformer(sourceUrl, sourceMimeType, contentReader.getSize(), targetMimeType, options);
|
||||
}
|
||||
finally
|
||||
{
|
||||
TransformerDebug.setDebugOutput(orig);
|
||||
}
|
||||
|
||||
if (null == transformer)
|
||||
{
|
||||
// There's no transformer available for the requested rendition!
|
||||
throw new RenditionServiceException(String.format(TRANSFORMER_NOT_EXISTS_MESSAGE_PATTERN, sourceMimeType,
|
||||
targetMimeType));
|
||||
}
|
||||
|
||||
if (!transformer.isTransformable(sourceMimeType, contentReader.getSize(), targetMimeType, options))
|
||||
{
|
||||
throw new RenditionServiceException(String.format(NOT_TRANSFORMABLE_MESSAGE_PATTERN, sourceMimeType, targetMimeType));
|
||||
}
|
||||
|
||||
long startTime = new Date().getTime();
|
||||
boolean actionCancelled = false;
|
||||
boolean actionCompleted = false;
|
||||
|
||||
// Cache the execution summary to get details later
|
||||
ExecutionSummary executionSummary = null;
|
||||
try
|
||||
{
|
||||
executionSummary = getExecutionSummary(context);
|
||||
}
|
||||
catch (ActionServiceException e)
|
||||
{
|
||||
if (logger.isInfoEnabled())
|
||||
{
|
||||
actionCompleted = true;
|
||||
break;
|
||||
logger.info("Cancelling of multiple concurrent action instances " +
|
||||
"currently unsupported, this action can't be cancelled");
|
||||
}
|
||||
// Check timeout in case transformer doesn't obey it
|
||||
if (options.getTimeoutMs() > 0 &&
|
||||
new Date().getTime() - startTime > (options.getTimeoutMs() + CANCELLED_ACTION_POLLING_INTERVAL))
|
||||
}
|
||||
|
||||
// Call the transform in a different thread so we can move on if cancelled
|
||||
FutureTask<ContentWriter> transformTask = new FutureTask<ContentWriter>(
|
||||
new TransformationCallable(contentReader, targetMimeType, options, context,
|
||||
AuthenticationUtil.getFullyAuthenticatedUser()));
|
||||
getExecutorService().execute(transformTask);
|
||||
|
||||
// Start checking for cancellation or timeout
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
// We hit a timeout, let the transform thread continue but results will be ignored
|
||||
if (logger.isDebugEnabled())
|
||||
Thread.sleep(CANCELLED_ACTION_POLLING_INTERVAL);
|
||||
if (transformTask.isDone())
|
||||
{
|
||||
logger.debug("Transformation did not obey timeout limit, " +
|
||||
"rendition action is moving on");
|
||||
actionCompleted = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (executionSummary != null)
|
||||
{
|
||||
ExecutionDetails executionDetails =
|
||||
actionTrackingService.getExecutionDetails(executionSummary);
|
||||
if (executionDetails != null)
|
||||
// Check timeout in case transformer doesn't obey it
|
||||
if (options.getTimeoutMs() > 0 &&
|
||||
new Date().getTime() - startTime > (options.getTimeoutMs() + CANCELLED_ACTION_POLLING_INTERVAL))
|
||||
{
|
||||
actionCancelled = executionDetails.isCancelRequested();
|
||||
if (actionCancelled)
|
||||
// We hit a timeout, let the transform thread continue but results will be ignored
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Transformation did not obey timeout limit, " +
|
||||
"rendition action is moving on");
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (executionSummary != null)
|
||||
{
|
||||
ExecutionDetails executionDetails =
|
||||
actionTrackingService.getExecutionDetails(executionSummary);
|
||||
if (executionDetails != null)
|
||||
{
|
||||
actionCancelled = executionDetails.isCancelRequested();
|
||||
if (actionCancelled)
|
||||
{
|
||||
logger.debug("Cancelling transformation");
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Cancelling transformation");
|
||||
}
|
||||
transformTask.cancel(true);
|
||||
break;
|
||||
}
|
||||
transformTask.cancel(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
// entire thread was asked to stop
|
||||
actionCancelled = true;
|
||||
transformTask.cancel(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (actionCancelled)
|
||||
{
|
||||
throw new RenditionCancelledException("Rendition action cancelled");
|
||||
}
|
||||
|
||||
if (!actionCompleted && !actionCancelled)
|
||||
{
|
||||
throw new RenditionServiceException("Transformation failed to obey timeout limit");
|
||||
}
|
||||
|
||||
if (actionCompleted)
|
||||
{
|
||||
// Copy content from temp writer to real writer
|
||||
ContentWriter writer = context.makeContentWriter();
|
||||
try
|
||||
{
|
||||
// We should not need another timeout here, things should be ready for us
|
||||
ContentWriter tempTarget = transformTask.get();
|
||||
if (tempTarget == null)
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
// We should never be in this state, but just in case
|
||||
throw new RenditionServiceException("Target of transformation not present");
|
||||
// entire thread was asked to stop
|
||||
actionCancelled = true;
|
||||
transformTask.cancel(true);
|
||||
break;
|
||||
}
|
||||
writer.putContent(tempTarget.getReader().getContentInputStream());
|
||||
}
|
||||
catch (ExecutionException e)
|
||||
|
||||
if (actionCancelled)
|
||||
{
|
||||
// Unwrap our cause and throw that
|
||||
Throwable transformException = e.getCause();
|
||||
if (transformException instanceof RuntimeException)
|
||||
{
|
||||
throw (RuntimeException) e.getCause();
|
||||
}
|
||||
throw new RenditionServiceException(TRANSFORMING_ERROR_MESSAGE + e.getCause().getMessage(), e.getCause());
|
||||
throw new RenditionCancelledException("Rendition action cancelled");
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
|
||||
if (!actionCompleted && !actionCancelled)
|
||||
{
|
||||
// We were asked to stop
|
||||
transformTask.cancel(true);
|
||||
}
|
||||
}
|
||||
throw new RenditionServiceException("Transformation failed to obey timeout limit");
|
||||
}
|
||||
|
||||
if (actionCompleted)
|
||||
{
|
||||
try
|
||||
{
|
||||
// We should not need another timeout here, things should be ready for us
|
||||
ContentWriter tempTarget = transformTask.get();
|
||||
if (tempTarget == null)
|
||||
{
|
||||
// We should never be in this state, but just in case
|
||||
throw new RenditionServiceException("Target of transformation not present");
|
||||
}
|
||||
|
||||
// save transform result in case we need to retry
|
||||
context.setExistingTransformedContentUrl(tempTarget.getReader().getContentUrl());
|
||||
|
||||
copyTransformedContent(tempTarget.getReader(), context);
|
||||
}
|
||||
catch (ExecutionException e)
|
||||
{
|
||||
// Unwrap our cause and throw that
|
||||
Throwable transformException = e.getCause();
|
||||
if (transformException instanceof RuntimeException)
|
||||
{
|
||||
throw (RuntimeException) e.getCause();
|
||||
}
|
||||
throw new RenditionServiceException(TRANSFORMING_ERROR_MESSAGE + e.getCause().getMessage(), e.getCause());
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
// We were asked to stop
|
||||
transformTask.cancel(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract TransformationOptions getTransformOptions(RenderingContext context);
|
||||
@@ -404,7 +452,7 @@ public abstract class AbstractTransformationRenderingEngine extends AbstractRend
|
||||
|
||||
return paramList;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of <code>Callable</code> for doing the work of the transformation
|
||||
* which returns the temporary content writer if successful.
|
||||
@@ -440,7 +488,7 @@ public abstract class AbstractTransformationRenderingEngine extends AbstractRend
|
||||
public ContentWriter doWork() throws Exception
|
||||
{
|
||||
// ALF-15715: Use temporary write to avoid operating on the real node for fear of row locking while long transforms are in progress
|
||||
ContentWriter tempContentWriter = contentService.getTempWriter();
|
||||
ContentWriter tempContentWriter = tempStore.getWriter(ContentContext.NULL_CONTEXT);
|
||||
tempContentWriter.setMimetype(targetMimeType);
|
||||
try
|
||||
{
|
||||
|
@@ -265,8 +265,8 @@ public class ThumbnailServiceImpl implements ThumbnailService,
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Thumbnail created " + childAssoc + " for sourceNodeRef " + sourceNodeRef + ", thumbnail " + thumbnailName
|
||||
+ ", thumbnailNodeRef " + thumbnailNodeRef);
|
||||
logger.debug("Thumbnail created " + childAssoc + " for sourceNodeRef " + sourceNodeRef + ", thumbnail "
|
||||
+ thumbnailName + ", thumbnailNodeRef " + thumbnailNodeRef);
|
||||
}
|
||||
|
||||
// MNT-15135: Cache the associations between parent nodes and updated thumbnails,
|
||||
@@ -382,6 +382,12 @@ public class ThumbnailServiceImpl implements ThumbnailService,
|
||||
//We can be in a read-only transaction, so force a new transaction
|
||||
requiresNew = true;
|
||||
}
|
||||
|
||||
// Get the name of the thumbnail and add to properties map
|
||||
QName thumbnailQName = getThumbnailQName(thumbnailName);
|
||||
final RenditionDefinition definition = createRenditionDefinition(contentProperty, mimetype,
|
||||
transformationOptions, thumbnailQName, assocDetails);
|
||||
|
||||
return txnHelper.doInTransaction(new RetryingTransactionCallback<NodeRef>()
|
||||
{
|
||||
|
||||
@@ -392,18 +398,12 @@ public class ThumbnailServiceImpl implements ThumbnailService,
|
||||
{
|
||||
public NodeRef doWork() throws Exception
|
||||
{
|
||||
return createThumbnailNode( node,
|
||||
contentProperty,
|
||||
mimetype,
|
||||
transformationOptions,
|
||||
thumbnailName,
|
||||
assocDetails);
|
||||
return createThumbnailNode(node, definition, thumbnailName);
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
}
|
||||
|
||||
}, false, requiresNew);
|
||||
|
||||
}
|
||||
|
||||
private QName getThumbnailQName(String localThumbnailName)
|
||||
@@ -717,14 +717,8 @@ public class ThumbnailServiceImpl implements ThumbnailService,
|
||||
return definition;
|
||||
}
|
||||
|
||||
private NodeRef createThumbnailNode(final NodeRef node, final QName contentProperty,
|
||||
final String mimetype, final TransformationOptions transformationOptions, final String thumbnailName,
|
||||
final ThumbnailParentAssociationDetails assocDetails)
|
||||
private NodeRef createThumbnailNode(final NodeRef node, final RenditionDefinition definition, final String thumbnailName)
|
||||
{
|
||||
// Get the name of the thumbnail and add to properties map
|
||||
QName thumbnailQName = getThumbnailQName(thumbnailName);
|
||||
RenditionDefinition definition = createRenditionDefinition(contentProperty, mimetype,
|
||||
transformationOptions, thumbnailQName, assocDetails);
|
||||
try
|
||||
{
|
||||
ChildAssociationRef thumbnailAssoc = renditionService.render(node, definition);
|
||||
|
Reference in New Issue
Block a user