diff --git a/source/java/org/alfresco/repo/rendition/executer/BaseTemplateRenderingEngine.java b/source/java/org/alfresco/repo/rendition/executer/BaseTemplateRenderingEngine.java
new file mode 100644
index 0000000000..45124ebaf2
--- /dev/null
+++ b/source/java/org/alfresco/repo/rendition/executer/BaseTemplateRenderingEngine.java
@@ -0,0 +1,214 @@
+/*
+ * 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.executer;
+
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.Collection;
+
+import org.alfresco.repo.action.ParameterDefinitionImpl;
+import org.alfresco.service.cmr.action.ParameterDefinition;
+import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
+import org.alfresco.service.cmr.rendition.RenditionServiceException;
+import org.alfresco.service.cmr.repository.ContentWriter;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.StoreRef;
+import org.alfresco.service.cmr.repository.TemplateService;
+import org.alfresco.service.cmr.search.ResultSet;
+import org.alfresco.service.cmr.search.SearchService;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * This abstract class forms a basis for all rendering engines that are built around
+ * the Template Service.
+ * @author Brian Remmington
+ * @since 3.3
+ */
+public abstract class BaseTemplateRenderingEngine extends AbstractRenderingEngine
+{
+ private static final Log log = LogFactory.getLog(BaseTemplateRenderingEngine.class);
+
+ public static final String NAME = "xsltRenderingEngine";
+ public static final String PARAM_MODEL = "model";
+ public static final String PARAM_TEMPLATE = "template_string";
+ public static final String PARAM_TEMPLATE_NODE = "template_node";
+ public static final String PARAM_TEMPLATE_PATH = "template_path";
+
+ private TemplateService templateService;
+ private SearchService searchService;
+
+ /*
+ * @see org.alfresco.repo.rendition.executer.AbstractRenderingEngine#render(org
+ * .alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.rendition.RenditionDefinition,
+ * org.alfresco.service.cmr.repository.ContentReader, org.alfresco.service.cmr.repository.ChildAssociationRef)
+ */
+ @Override
+ protected void render(RenderingContext context)
+ {
+ NodeRef templateNode = getTemplateNode(context);
+ Writer writer = null;
+ try
+ {
+ Object model = buildModel(context);
+ ContentWriter contentWriter = context.makeContentWriter();
+ writer = new OutputStreamWriter(contentWriter.getContentOutputStream());
+ processTemplate(context, templateNode, model, writer);
+ }
+ catch (RuntimeException ex)
+ {
+ throw ex;
+ }
+ catch (Exception ex)
+ {
+ log.warn("Unexpected error while rendering through XSLT rendering engine.", ex);
+ }
+ finally
+ {
+ if (writer != null)
+ {
+ try
+ {
+ writer.flush();
+ writer.close();
+ }
+ catch (IOException ex)
+ {
+ log.warn("Failed to correctly close content writer.", ex);
+ }
+ }
+ }
+ }
+
+ private void processTemplate(RenderingContext context, NodeRef templateNode, Object model, Writer out)
+ {
+ String templateType = getTemplateType();
+ String template = context.getCheckedParam(PARAM_TEMPLATE, String.class);
+ if (template != null)
+ {
+ templateService.processTemplateString(templateType, (String)template, model, out);
+ }
+ else if (templateNode != null)
+ {
+ templateService.processTemplate(templateType, templateNode.toString(), model, out);
+ }
+ else
+ {
+ throwTemplateParamsNotFoundException();
+ }
+ }
+
+
+ private void throwTemplateParamsNotFoundException()
+ {
+ StringBuilder msg = new StringBuilder("This action requires that either the ");
+ msg.append(PARAM_TEMPLATE);
+ msg.append(" parameter or the ");
+ msg.append(PARAM_TEMPLATE_NODE);
+ msg.append(" parameter be specified. ");
+ throw new RenditionServiceException(msg.toString());
+ }
+
+ protected NodeRef getTemplateNode(RenderingContext context)
+ {
+ NodeRef node = context.getCheckedParam(PARAM_TEMPLATE_NODE, NodeRef.class);
+ if (node == null)
+ {
+ String path = context.getCheckedParam(PARAM_TEMPLATE_PATH, String.class);
+ if (path != null && path.length() > 0)
+ {
+ StoreRef storeRef = context.getDestinationNode().getStoreRef();
+ ResultSet result = searchService.query(storeRef, SearchService.LANGUAGE_XPATH, path);
+ if (result.length() != 1)
+ {
+ throw new RenditionServiceException("Could not find template node for path: " + path);
+ }
+ node = result.getNodeRef(0);
+ }
+ }
+ return node;
+ }
+
+ /**
+ * Create the model that will be passed to the template service for rendering
+ * with the appropriate template.
+ * @param context The context of the rendering request
+ * @return The model that is to be passed to the template service
+ */
+ protected abstract Object buildModel(RenderingContext context);
+
+ /**
+ * Get the type of template that is to be used. This identifies the name of the template
+ * processor that should be used, such as "freemarker" or "xslt".
+ * @return
+ */
+ protected abstract String getTemplateType();
+
+ /*
+ * @seeorg.alfresco.repo.rendition.executer.AbstractRenderingEngine# getParameterDefinitions()
+ */
+ @Override
+ protected Collection getParameterDefinitions()
+ {
+ Collection paramList = super.getParameterDefinitions();
+ ParameterDefinitionImpl modelParamDef = new ParameterDefinitionImpl(PARAM_MODEL, DataTypeDefinition.ANY, false,
+ getParamDisplayLabel(PARAM_MODEL));
+ ParameterDefinitionImpl templateParamDef = new ParameterDefinitionImpl(//
+ PARAM_TEMPLATE, DataTypeDefinition.TEXT, false, getParamDisplayLabel(PARAM_TEMPLATE));
+ ParameterDefinitionImpl templateNodeParamDef = new ParameterDefinitionImpl(PARAM_TEMPLATE_NODE,
+ DataTypeDefinition.NODE_REF, false, getParamDisplayLabel(PARAM_TEMPLATE_NODE));
+ ParameterDefinitionImpl templatePathParamDef = new ParameterDefinitionImpl(PARAM_TEMPLATE_PATH,
+ DataTypeDefinition.TEXT, false, getParamDisplayLabel(PARAM_TEMPLATE_PATH));
+ paramList.add(modelParamDef);
+ paramList.add(templateParamDef);
+ paramList.add(templateNodeParamDef);
+ paramList.add(templatePathParamDef);
+ return paramList;
+ }
+
+ /**
+ * @param templateService
+ * the templateService to set
+ */
+ public void setTemplateService(TemplateService templateService)
+ {
+ this.templateService = templateService;
+ }
+
+ /**
+ * @param searchService
+ * the searchService to set
+ */
+ public void setSearchService(SearchService searchService)
+ {
+ this.searchService = searchService;
+ }
+
+ public TemplateService getTemplateService()
+ {
+ return templateService;
+ }
+
+ public SearchService getSearchService()
+ {
+ return searchService;
+ }
+}