/*
* Copyright (C) 2005-2010 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.repo.rendition;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.model.RenditionModel;
import org.alfresco.repo.action.executer.ActionExecuter;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.action.ActionDefinition;
import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.rendition.CompositeRenditionDefinition;
import org.alfresco.service.cmr.rendition.RenderCallback;
import org.alfresco.service.cmr.rendition.RenderingEngineDefinition;
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.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.util.GUID;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/*
* @author Nick Smith
* @author Neil McErlean
* @since 3.3
*/
public class RenditionServiceImpl implements RenditionService, RenditionDefinitionPersister
{
private static final Log log = LogFactory.getLog(RenditionServiceImpl.class);
private ActionService actionService;
private ContentService contentService;
private DictionaryService dictionaryService;
private NodeService nodeService;
private RenditionDefinitionPersisterImpl renditionDefinitionPersister;
/**
* Injects the RenditionDefinitionPersister bean.
* @param renditionDefinitionPersister
*/
public void setRenditionDefinitionPersister(RenditionDefinitionPersisterImpl renditionDefinitionPersister)
{
this.renditionDefinitionPersister = renditionDefinitionPersister;
}
/**
* Injects the ServiceRegistry bean.
* @param serviceRegistry
*/
public void setServiceRegistry(ServiceRegistry serviceRegistry)
{
this.contentService = serviceRegistry.getContentService();
this.nodeService = serviceRegistry.getNodeService();
}
/**
* Injects the ActionService bean.
* @param actionService
*/
public void setActionService(ActionService actionService)
{
this.actionService = actionService;
}
/**
* Injects the DictionaryService bean.
* @param dictionaryService
*/
public void setDictionaryService(DictionaryService dictionaryService)
{
this.dictionaryService = dictionaryService;
}
/*
* (non-Javadoc)
* @see org.alfresco.service.cmr.rendition.RenditionService#getRenderingEngineDefinition(java.lang.String)
*/
public RenderingEngineDefinition getRenderingEngineDefinition(String name)
{
ActionDefinition actionDefinition = actionService.getActionDefinition(name);
if (actionDefinition instanceof RenderingEngineDefinition)
{
return (RenderingEngineDefinition) actionDefinition;
}
else
return null;
}
/*
* (non-Javadoc)
* @see org.alfresco.service.cmr.rendition.RenditionService#getRenderingEngineDefinitions()
*/
public List getRenderingEngineDefinitions()
{
List results = new ArrayList();
List actionDefs = actionService.getActionDefinitions();
for (ActionDefinition actionDef : actionDefs)
{
if (actionDef instanceof RenderingEngineDefinition)
{
RenderingEngineDefinition renderingDef = (RenderingEngineDefinition) actionDef;
results.add(renderingDef);
}
}
return results;
}
/*
* (non-Javadoc)
* @see
* org.alfresco.service.cmr.rendition.RenditionService#createRenditionDefinition
* (org.alfresco.service.namespace.QName, java.lang.String)
*/
public RenditionDefinition createRenditionDefinition(QName renditionDefinitionName, String renderingEngineName)
{
if (log.isDebugEnabled())
{
StringBuilder msg = new StringBuilder();
msg.append("Creating rendition definition ")
.append(renditionDefinitionName)
.append(" ")
.append(renderingEngineName);
log.debug(msg.toString());
}
return new RenditionDefinitionImpl(GUID.generate(), renditionDefinitionName, renderingEngineName);
}
/*
* (non-Javadoc)
* @see org.alfresco.service.cmr.rendition.RenditionService#createCompositeRenditionDefinition(org.alfresco.service.namespace.QName)
*/
public CompositeRenditionDefinition createCompositeRenditionDefinition(QName renditionName)
{
if (log.isDebugEnabled())
{
StringBuilder msg = new StringBuilder();
msg.append("Creating composite rendition definition ")
.append(renditionName);
log.debug(msg.toString());
}
return new CompositeRenditionDefinitionImpl(GUID.generate(), renditionName);
}
/*
* (non-Javadoc)
* @see org.alfresco.service.cmr.rendition.RenditionService#render(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.rendition.RenditionDefinition)
*/
public ChildAssociationRef render(NodeRef sourceNode, RenditionDefinition definition)
{
ChildAssociationRef result = executeRenditionAction(sourceNode, definition, false);
if (log.isDebugEnabled())
{
log.debug("Produced rendition " + result);
}
return result;
}
public void render(NodeRef sourceNode, RenditionDefinition definition,
RenderCallback callback)
{
// The asynchronous render can't return a ChildAssociationRef as it is created
// asynchronously after this method returns.
definition.setCallback(callback);
executeRenditionAction(sourceNode, definition, true);
return;
}
/**
* This method delegates the execution of the specified RenditionDefinition
* to the {@link ActionService action service}.
*
* @param sourceNode the source node which is to be rendered.
* @param definition the rendition definition to be used.
* @param asynchronous true
for asynchronous execution,
* false
for synchronous.
* @return the ChildAssociationRef whose child is the rendition node.
*/
private ChildAssociationRef executeRenditionAction(NodeRef sourceNode,
RenditionDefinition definition, boolean asynchronous)
{
if (log.isDebugEnabled())
{
StringBuilder msg = new StringBuilder();
if (asynchronous)
{
msg.append("Asynchronously");
}
else
{
msg.append("Synchronously");
}
msg.append(" rendering node ").append(sourceNode)
.append(" with ").append(definition.getRenditionName());
log.debug(msg.toString());
}
final boolean checkConditions = false;
actionService.executeAction(definition, sourceNode, checkConditions, asynchronous);
ChildAssociationRef result = (ChildAssociationRef)definition.getParameterValue(ActionExecuter.PARAM_RESULT);
return result;
}
/*
* (non-Javadoc)
* @see
* org.alfresco.service.cmr.rendition.RenditionService#saveRenditionDefinition
* (org.alfresco.service.cmr.rendition.RenditionDefinition)
*/
public void saveRenditionDefinition(RenditionDefinition renderingAction)
{
this.renditionDefinitionPersister.saveRenditionDefinition(renderingAction);
}
/*
* @see
* org.alfresco.service.cmr.rendition.RenditionService#loadRenderingAction
* (org.alfresco.service.namespace.QName)
*/
public RenditionDefinition loadRenditionDefinition(QName renditionDefinitionName)
{
return this.renditionDefinitionPersister.loadRenditionDefinition(renditionDefinitionName);
}
/*
* (non-Javadoc)
* @see org.alfresco.service.cmr.rendition.RenditionService#loadRenditionDefinitions()
*/
public List loadRenditionDefinitions()
{
return this.renditionDefinitionPersister.loadRenditionDefinitions();
}
/*
* (non-Javadoc)
* @see
* org.alfresco.service.cmr.rendition.RenditionService#loadRenderingActions
* (java.lang.String)
*/
public List loadRenditionDefinitions(String renditionEngineName)
{
return this.loadRenditionDefinitions(renditionEngineName);
}
/*
* (non-Javadoc)
* @see
* org.alfresco.service.cmr.rendition.RenditionService#getRenditions(org
* .alfresco.service.cmr.repository.NodeRef)
*/
public List getRenditions(NodeRef node)
{
List result = Collections.emptyList();
// Check that the node has the renditioned aspect applied
if (nodeService.hasAspect(node, RenditionModel.ASPECT_RENDITIONED) == true)
{
// Get all the renditions that match the given rendition name
result = nodeService.getChildAssocs(node, RenditionModel.ASSOC_RENDITION, RegexQNamePattern.MATCH_ALL);
}
return result;
}
/*
* (non-Javadoc)
* @see
* org.alfresco.service.cmr.rendition.RenditionService#getRenditions(org
* .alfresco.service.cmr.repository.NodeRef, java.lang.String)
*/
public List getRenditions(NodeRef node, String mimeTypePrefix)
{
List allRenditions = this.getRenditions(node);
List filteredResults = new ArrayList();
for (ChildAssociationRef chAssRef : allRenditions)
{
NodeRef renditionNode = chAssRef.getChildRef();
QName contentProperty = ContentModel.PROP_CONTENT;
Serializable contentPropertyName = nodeService.getProperty(renditionNode,
ContentModel.PROP_CONTENT_PROPERTY_NAME);
if (contentPropertyName != null)
{
contentProperty = (QName) contentPropertyName;
}
ContentReader reader = contentService.getReader(renditionNode, contentProperty);
if (reader != null && reader.exists())
{
String readerMimeType = reader.getMimetype();
if (readerMimeType.startsWith(mimeTypePrefix))
{
filteredResults.add(chAssRef);
}
}
}
return filteredResults;
}
/*
* (non-Javadoc)
* @see org.alfresco.service.cmr.rendition.RenditionService#getRenditionByName(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName)
*/
public ChildAssociationRef getRenditionByName(NodeRef node, QName renditionName)
{
List renditions = Collections.emptyList();
// Check that the node has the renditioned aspect applied
if (nodeService.hasAspect(node, RenditionModel.ASPECT_RENDITIONED) == true)
{
// Get all the renditions that match the given rendition name -
// there should only be 1 (or 0)
renditions = this.nodeService.getChildAssocs(node, RenditionModel.ASSOC_RENDITION, renditionName);
}
if (renditions.isEmpty())
{
return null;
}
else
{
if (renditions.size() > 1 && log.isDebugEnabled())
{
log.debug("Unexpectedly found " + renditions.size() + " renditions of name " + renditionName + " on node " + node);
}
return renditions.get(0);
}
}
/*
* (non-Javadoc)
* @see org.alfresco.service.cmr.rendition.RenditionService#isRendition(org.alfresco.service.cmr.repository.NodeRef)
*/
public boolean isRendition(NodeRef node)
{
final QName aspectToCheckFor = RenditionModel.ASPECT_RENDITION;
Set existingAspects = nodeService.getAspects(node);
for (QName nextAspect : existingAspects)
{
if (nextAspect.equals(aspectToCheckFor) || dictionaryService.isSubClass(nextAspect, aspectToCheckFor))
{
return true;
}
}
return false;
}
/*
* (non-Javadoc)
* @see org.alfresco.service.cmr.rendition.RenditionService#getSourceNode(org.alfresco.service.cmr.repository.NodeRef)
*/
public ChildAssociationRef getSourceNode(NodeRef renditionNode)
{
// In normal circumstances only a node which is itself a rendition can have
// a source node - as linked by the rn:rendition association.
//
// However there are some circumstances where a node which is not
// technically a rendition can still have a source. One such example is the case
// of thumbnail nodes created in a pre-3.3 Alfresco which have not been patched
// to have the correct rendition aspect applied.
// This will also occur *during* execution of the webscript patch and so the
// decision was made not to throw an exception or log a warning if such a
// situation is encountered.
// A rendition node should have 1 and only 1 source node.
List parents = nodeService.getParentAssocs(renditionNode,
RenditionModel.ASSOC_RENDITION, RegexQNamePattern.MATCH_ALL);
if (parents.size() > 1)
{
StringBuilder msg = new StringBuilder();
msg.append("NodeRef ")
.append(renditionNode)
.append(" unexpectedly has ")
.append(parents.size())
.append(" rendition parents.");
if (log.isWarnEnabled())
{
log.warn(msg.toString());
}
throw new RenditionServiceException(msg.toString());
}
else
{
return parents.isEmpty() ? null : parents.get(0);
}
}
}