true then the rendition will be re-rendered any time any
     * property changes occur on the source node. This parameter defaults to
     * false.
     */
    public static final String PARAM_UPDATE_RENDITIONS_ON_ANY_PROPERTY_CHANGE = "update-renditions-on-any-property-change";
    /**
     * This optional {@link String} parameter specifies what user permissions
     * are used when creating a rendition. By default the system user is used.
     */
    public static final String PARAM_RUN_AS = "runAs";
    // mime-type is not a common parameter on all Rendering Actions, but it is
    // common to many and is used in some common handling code in this class.
    /**
     * This optional {@link String} parameter specifies the mime type of the
     * rendition content. This defaults to the mime type of the source node
     * content.
     */
    public static final String PARAM_MIME_TYPE = "mime-type";
    /**
     * This optional {@link String} paramter specifies the encoding used to
     * create the rendition content. The derfault encoding is UTF-8.
     */
    public static final String PARAM_ENCODING = "encoding";
    /**
     * Default {@link NodeLocator} simply returns the source node.
     */
    private final static NodeLocator defaultNodeLocator = new SelfNodeLocator();
    
    /*
     * Injected beans
     */
    private RenditionLocationResolver renditionLocationResolver;
    protected NodeService nodeService;
    private RenditionService renditionService;
    private BehaviourFilter behaviourFilter;
    
    private final NodeLocator temporaryParentNodeLocator;
    private final QName temporaryRenditionLinkType;
    /**
     * Injects the nodeService bean.
     * 
     * @param nodeService
     *            the nodeService.
     */
    public void setNodeService(NodeService nodeService)
    {
        this.nodeService = nodeService;
    }
    /**
     * Injects the renditionService bean.
     * 
     * @param renditionService
     */
    public void setRenditionService(RenditionService renditionService)
    {
        this.renditionService = renditionService;
    }
    /**
     * @param behaviourFilter  policy behaviour filter 
     */
    public void setBehaviourFilter(BehaviourFilter behaviourFilter)
    {
        this.behaviourFilter = behaviourFilter;
    }
    public void setRenditionLocationResolver(RenditionLocationResolver renditionLocationResolver)
    {
        this.renditionLocationResolver = renditionLocationResolver;
    }
    
    public AbstractRenderingEngine(NodeLocator temporaryParentNodeLocator, QName temporaryRenditionLinkType)
    {
        this.publicAction = false;
        this.temporaryParentNodeLocator = temporaryParentNodeLocator != null ? temporaryParentNodeLocator
                    : defaultNodeLocator;
        this.temporaryRenditionLinkType = temporaryRenditionLinkType != null ? temporaryRenditionLinkType
                    : RenditionModel.ASSOC_RENDITION;
    }
    public AbstractRenderingEngine()
    {
        this(null, null);
    }
    
    /**
     * Sets the default rendition-node type.
     * 
     * @param type
     */
    public void setDefaultRenditionNodeType(String type)
    {
        QName qname;
        try
        {
            qname = QName.createQName(type);
        }
        catch (NamespaceException nx)
        {
            if (logger.isErrorEnabled())
            {
                logger.error("Error when setting default rendition node type: ", nx);
            }
            throw nx;
        }
        if (logger.isInfoEnabled())
        {
            logger.info("Using default rendition node type: " + qname);
        }
        this.defaultRenditionNodeType = qname;
    }
    /**
     * This method returns the type of the default rendition node type.
     * 
     * @return the QName representing the type of the default rendition node
     *         type.
     */
    protected QName getDefaultRenditionNodeType()
    {
        return defaultRenditionNodeType;
    }
    protected String getTargetMimeType(RenderingContext context)
    {
        return context.getParamWithDefault(PARAM_MIME_TYPE, DEFAULT_MIMETYPE);
    }
    protected String getTargetEncoding(RenderingContext context)
    {
        return context.getParamWithDefault(PARAM_ENCODING, DEFAULT_ENCODING);
    }
    /**
     * Sets the default rendition content property.
     * 
     * @param prop
     */
    public void setDefaultRenditionContentProp(String prop)
    {
        QName qname;
        try
        {
            qname = QName.createQName(prop);
        }
        catch (NamespaceException nx)
        {
            if (logger.isErrorEnabled())
            {
                logger.error("Error when setting default rendition content property: ", nx);
            }
            throw nx;
        }
        if (logger.isInfoEnabled())
        {
            logger.info("Using default rendition content property: " + qname);
        }
        this.defaultRenditionContentProp = qname;
    }
    /**
     * This method returns the QName of the property that defines the location
     * of the rendition content. An example would be cm:content.
     * 
     * @return the QName the property defining the location of the rendition
     *         content.
     */
    protected QName getDefaultRenditionContentProp()
    {
        return defaultRenditionContentProp;
    }
    /**
     * Set the content service
     * 
     * @param contentService the content service
     */
    public void setContentService(ContentService contentService)
    {
        this.contentService = contentService;
    }
    public void setMimetypeMap(MimetypeMap mimetypeMap)
    {
        this.mimetypeMap = mimetypeMap;
    }
    public void setActionTrackingService(ActionTrackingService actionTrackingService)
    {
        this.actionTrackingService = actionTrackingService;
    }
    @Override
    protected ActionDefinition createActionDefinition(String definitionName)
    {
        return new RenderingEngineDefinitionImpl(definitionName);
    }
    @Override
    protected void executeImpl(final Action action, final NodeRef sourceNode)
    {
        executeImpl( (RenditionDefinition)action, sourceNode );
    }
        
    protected void executeImpl(final RenditionDefinition renditionDef, final NodeRef sourceNode)
    {
        // Don't render the nodes without content.
        // MNT-10178
        if (!nodeService.exists(sourceNode))
        {
            if (logger.isDebugEnabled() == true)
            {
                logger.debug("Rendition has not been created, because the node no longer exists.  (sourceNode=" + sourceNode + ")");
            }
            notifyCallbackOfException(renditionDef, new RenditionCancelledException("Rendition was cancelled, because the node no longer exists."));
            return;
        }
        else if (nodeService.getProperty(sourceNode, ContentModel.PROP_CONTENT) == null)
        {
            if (logger.isDebugEnabled() == true)
            {
                logger.debug("Rendition has not been created, because the node has no content to render.  (sourceNode=" + sourceNode + ")");
            }
            notifyCallbackOfException(renditionDef, new RenditionCancelledException("Rendition was cancelled, because the node has no content to render."));
            return;
        }
        if (logger.isDebugEnabled())
        {
            StringBuilder msg = new StringBuilder();
            msg.append("Rendering node ").append(sourceNode).append(" with rendition definition ").append(
                    renditionDef.getRenditionName());
            msg.append("\n").append("  parameters:").append("\n");
            if (renditionDef.getParameterValues().isEmpty() == false)
            {
                for (String paramKey : renditionDef.getParameterValues().keySet())
                {
                    msg.append("    ").append(paramKey).append("=").append(renditionDef.getParameterValue(paramKey)).append("\n");
                }
            }
            else
            {
                msg.append("    [None]");
            }
            logger.debug(msg.toString());
        }
        Serializable runAsParam = renditionDef.getParameterValue(AbstractRenderingEngine.PARAM_RUN_AS);
        String runAsName = runAsParam == null ? DEFAULT_RUN_AS_NAME : (String) runAsParam;
        // Renditions should all be created by system by default.
        // When renditions are created by a user and are to be created under a
        // node
        // other than the source node, it is possible that the user will not
        // have
        // permissions to create content under that node.
        // For that reason, we execute all rendition actions as system
        // by default.
        AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWorknull if the parameter value is null
     * 
     * @param paramName the name of the parameter being checked.
     * @param clazz the expected {@link Class} of the parameter value.
     * @param definition the {@link RenditionDefinition} containing the
     *            parameters.
     * @return the parameter value or null.
     */
    @SuppressWarnings("unchecked")
    public static defaultValue and throws a
     * {@link RenditionServiceException} if it isn't. Returns
     * defaultValue if the parameter value is null
     * 
     * @param rn:rendition aspects on the rendition node. It applies the
     * correct rendition aspect based on the rendition node's location and removes any out-of-date rendition
     * aspect.
     */
    private void manageRenditionAspects(NodeRef sourceNode, ChildAssociationRef renditionParentAssoc)
    {
        NodeRef renditionNode = renditionParentAssoc.getChildRef();
        NodeRef primaryParent = renditionParentAssoc.getParentRef();
        // If the rendition is located directly underneath its own source node
        if (primaryParent.equals(sourceNode))
        {
            // It should be a 'hidden' rendition.
            // Ensure we do not update the 'modifier' due to rendition addition
            behaviourFilter.disableBehaviour(renditionNode, ContentModel.ASPECT_AUDITABLE);
            try
            {
                nodeService.addAspect(renditionNode, RenditionModel.ASPECT_HIDDEN_RENDITION, null);
                nodeService.removeAspect(renditionNode, RenditionModel.ASPECT_VISIBLE_RENDITION);
            }
            finally
            {
                behaviourFilter.enableBehaviour(renditionNode, ContentModel.ASPECT_AUDITABLE);
            }
            // We remove the other aspect to cover the potential case where a
            // rendition
            // has been updated in a different location.
        } else
        {
            // Renditions stored underneath any node other than their source are
            // 'visible'.
            behaviourFilter.disableBehaviour(renditionNode, ContentModel.ASPECT_AUDITABLE);
            try
            {
                nodeService.addAspect(renditionNode, RenditionModel.ASPECT_VISIBLE_RENDITION, null);
                nodeService.removeAspect(renditionNode, RenditionModel.ASPECT_HIDDEN_RENDITION);
            }
            finally
            {
                behaviourFilter.enableBehaviour(renditionNode, ContentModel.ASPECT_AUDITABLE);
            }
        }
    }
    /**
     * This method calculates the name for a rendition node. The following approaches are attempted in
     * the order given below.
     * cm:name value, then that is used.ExecutionSummary for the given renderingContext
     * from the {@link ActionTrackingService}.
     * 
     * Note that multiple summaries of the same action instance are not currently supported.
     * @param renderingContext      the rendering context
     * @return                      the found summary or null
     */
    protected ExecutionSummary getExecutionSummary(RenderingContext renderingContext)
    {
        List