diff --git a/config/alfresco/rendition-services-context.xml b/config/alfresco/rendition-services-context.xml
index 8620dee4f5..ce6cb81787 100644
--- a/config/alfresco/rendition-services-context.xml
+++ b/config/alfresco/rendition-services-context.xml
@@ -131,6 +131,12 @@
+
+
+
+
diff --git a/source/java/org/alfresco/repo/rendition/StandardRenditionLocationResolverImpl.java b/source/java/org/alfresco/repo/rendition/StandardRenditionLocationResolverImpl.java
index 9774f22fe1..36b7932c3e 100644
--- a/source/java/org/alfresco/repo/rendition/StandardRenditionLocationResolverImpl.java
+++ b/source/java/org/alfresco/repo/rendition/StandardRenditionLocationResolverImpl.java
@@ -79,7 +79,7 @@ public class StandardRenditionLocationResolverImpl implements RenditionLocationR
*/
public RenditionLocation getRenditionLocation(NodeRef sourceNode, RenditionDefinition definition, NodeRef tempRenditionLocation)
{
- // If a destination NodeRef is specified then don't botther to find the location as one has already been specified.
+ // If a destination NodeRef is specified then don't bother to find the location as one has already been specified.
NodeRef destination = AbstractRenderingEngine.getCheckedParam(RenditionService.PARAM_DESTINATION_NODE, NodeRef.class, definition);
if(destination!=null)
{
diff --git a/source/java/org/alfresco/repo/rendition/executer/AbstractRenderingEngine.java b/source/java/org/alfresco/repo/rendition/executer/AbstractRenderingEngine.java
index 05e0dd814b..89f84db4a9 100644
--- a/source/java/org/alfresco/repo/rendition/executer/AbstractRenderingEngine.java
+++ b/source/java/org/alfresco/repo/rendition/executer/AbstractRenderingEngine.java
@@ -1054,7 +1054,7 @@ public abstract class AbstractRenderingEngine extends ActionExecuterAbstractBase
* Given a rendition definition, a source node and a temporary rendition node, this method uses a
* {@link RenditionLocationResolver} to calculate the {@link RenditionLocation} of the rendition.
*/
- private RenditionLocation resolveRenditionLocation(NodeRef sourceNode, RenditionDefinition definition,
+ protected RenditionLocation resolveRenditionLocation(NodeRef sourceNode, RenditionDefinition definition,
NodeRef tempRendition)
{
return renditionLocationResolver.getRenditionLocation(sourceNode, definition, tempRendition);
diff --git a/source/java/org/alfresco/repo/rendition/executer/HTMLRenderingEngine.java b/source/java/org/alfresco/repo/rendition/executer/HTMLRenderingEngine.java
new file mode 100644
index 0000000000..dfb7243187
--- /dev/null
+++ b/source/java/org/alfresco/repo/rendition/executer/HTMLRenderingEngine.java
@@ -0,0 +1,186 @@
+/*
+ * 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.Serializable;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.repo.action.ParameterDefinitionImpl;
+import org.alfresco.repo.rendition.RenditionLocation;
+import org.alfresco.service.cmr.action.ParameterDefinition;
+import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
+import org.alfresco.service.cmr.dictionary.DictionaryService;
+import org.alfresco.service.cmr.rendition.RenditionServiceException;
+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.namespace.QName;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * This class provides a way to turn documents supported by the
+ * {@link ContentService} standard transformers into basic, clean
+ * HTML.
+ *
+ * The HTML that is produced probably isn't going to be suitable
+ * for direct web publishing, as it's likely going to be too
+ * basic. Instead, it should be simple and clean HTML, suitable
+ * for being the basis of some web-friendly HTML once edited
+ * / further transformed.
+ *
+ * @author Nick Burch
+ * @since 3.4
+ */
+public class HTMLRenderingEngine extends AbstractRenderingEngine
+{
+ private static Log logger = LogFactory.getLog(HTMLRenderingEngine.class);
+
+ /*
+ * Action constants
+ */
+ public static final String NAME = "htmlRenderingEngine";
+
+ protected static final QName PRIMARY_IMAGE = QName.createQName(
+ "http://www.alfresco.org/model/website/1.0", "primaryImage");
+ protected static final QName SECONDARY_IMAGE = QName.createQName(
+ "http://www.alfresco.org/model/website/1.0", "secondaryImage");
+
+ private DictionaryService dictionaryService;
+
+ public void setDictionaryService(DictionaryService dictionaryService) {
+ this.dictionaryService = dictionaryService;
+ }
+
+ /*
+ * (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();
+ String sourceMimeType = contentReader.getMimetype();
+ String targetMimeType = "text/html";
+
+ // Check that Tika supports it
+ // TODO
+
+ // Make the HTML Version
+ ContentWriter contentWriter = context.makeContentWriter();
+ // TODO
+ contentWriter.putContent(
+ "\n" +
+ "Test!
"
+ );
+
+ // Extract out any images
+ // TODO
+ boolean hasImages = true; // TODO
+ if(hasImages)
+ {
+ Map properties = new HashMap();
+ NodeRef imgFolder = null;
+
+ // Extract into it
+ boolean donePrimary = false;
+ for(String fakeContent : new String[] {"Test1","Test2"})
+ {
+ if(imgFolder == null)
+ imgFolder = createImagesDirectory(context);
+
+ // Create the node
+ properties.clear();
+ properties.put(ContentModel.PROP_NAME, fakeContent);
+ NodeRef img = nodeService.createNode(
+ imgFolder,
+ ContentModel.ASSOC_CONTAINS,
+ QName.createQName(fakeContent),
+ ContentModel.TYPE_CONTENT,
+ properties
+ ).getChildRef();
+
+ // If we can, associate it with the rendered HTML, so
+ // that they're properly linked
+ QName assocType = SECONDARY_IMAGE;
+ if(!donePrimary)
+ {
+ assocType = PRIMARY_IMAGE;
+ donePrimary = true;
+ }
+ if(dictionaryService.getAssociation(assocType) != null)
+ {
+ nodeService.createAssociation(
+ context.getDestinationNode(), img, assocType
+ );
+ }
+
+ // Put the image into the node
+ ContentWriter writer = contentService.getWriter(
+ img, ContentModel.PROP_CONTENT, true
+ );
+ writer.putContent(fakeContent);
+ }
+ }
+ }
+
+ /**
+ * Creates a directory to store the images in.
+ * The directory will be a sibling of the rendered
+ * HTML, and named similar to it.
+ */
+ private NodeRef createImagesDirectory(RenderingContext context)
+ {
+ // It should be a sibling of the HTML in it's eventual location
+ // (not it's current temporary one!)
+ RenditionLocation location = resolveRenditionLocation(
+ context.getSourceNode(), context.getDefinition(), context.getDestinationNode()
+ );
+ NodeRef parent = location.getParentRef();
+
+ // Figure out what to call it, based on the HTML node
+ String folderName = nodeService.getProperty(
+ context.getSourceNode(),
+ ContentModel.PROP_NAME
+ ).toString();
+ if(folderName.lastIndexOf('.') > -1)
+ {
+ folderName = folderName.substring(0, folderName.lastIndexOf('.'));
+ }
+ folderName = folderName + "_files";
+
+ // Create the directory
+ Map properties = new HashMap();
+ properties.put(ContentModel.PROP_NAME, folderName);
+ NodeRef imgFolder = nodeService.createNode(
+ parent,
+ ContentModel.ASSOC_CONTAINS,
+ QName.createQName(folderName),
+ ContentModel.TYPE_FOLDER,
+ properties
+ ).getChildRef();
+
+ return imgFolder;
+ }
+}
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/rendition/executer/HTMLRenderingEngineTest.java b/source/java/org/alfresco/repo/rendition/executer/HTMLRenderingEngineTest.java
new file mode 100644
index 0000000000..8b844aafc7
--- /dev/null
+++ b/source/java/org/alfresco/repo/rendition/executer/HTMLRenderingEngineTest.java
@@ -0,0 +1,261 @@
+/*
+ * 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.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.repo.model.Repository;
+import org.alfresco.repo.security.authentication.AuthenticationUtil;
+import org.alfresco.service.cmr.rendition.RenditionDefinition;
+import org.alfresco.service.cmr.rendition.RenditionService;
+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.namespace.QName;
+import org.alfresco.util.BaseAlfrescoSpringTest;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Unit tests for the HTML Rendering Engine
+ *
+ * @author Nick Burch
+ */
+public class HTMLRenderingEngineTest extends BaseAlfrescoSpringTest
+{
+ private final static Log log = LogFactory.getLog(HTMLRenderingEngineTest.class);
+ private NodeRef companyHome;
+ private RenditionService renditionService;
+ private Repository repositoryHelper;
+
+ private NodeRef sourceDoc;
+ private NodeRef targetFolder;
+ private String targetFolderPath;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.alfresco.util.BaseAlfrescoSpringTest#onSetUpInTransaction()
+ */
+ @SuppressWarnings("deprecation")
+ @Override
+ protected void onSetUpInTransaction() throws Exception
+ {
+ super.onSetUpInTransaction();
+ this.nodeService = (NodeService) this.applicationContext.getBean("NodeService");
+ this.contentService = (ContentService) this.applicationContext.getBean("ContentService");
+ this.renditionService = (RenditionService) this.applicationContext.getBean("RenditionService");
+ this.repositoryHelper = (Repository) this.applicationContext.getBean("repositoryHelper");
+ this.companyHome = repositoryHelper.getCompanyHome();
+
+ createTargetFolder();
+ }
+
+ @Override
+ protected void onTearDownInTransaction() throws Exception {
+ super.onTearDownInTransaction();
+
+ tidyUpSourceDoc();
+ }
+
+ private void createTargetFolder()
+ {
+ // Set the current security context as admin
+ AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
+
+ Map properties = new HashMap();
+ properties.put(ContentModel.PROP_NAME, "TestFolder");
+ targetFolder = nodeService.createNode(
+ companyHome, ContentModel.ASSOC_CONTAINS,
+ QName.createQName("TestFolder"),
+ ContentModel.TYPE_FOLDER,
+ properties
+ ).getChildRef();
+
+ targetFolderPath = "/" +
+ (String) nodeService.getProperty(companyHome, ContentModel.PROP_NAME) +
+ "/" +
+ (String) nodeService.getProperty(targetFolder, ContentModel.PROP_NAME)
+ ;
+ }
+ private void tidyUpSourceDoc()
+ {
+ // Set the current security context as admin
+ AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
+
+ // Clean up the source
+ if(sourceDoc != null)
+ {
+ nodeService.deleteNode(sourceDoc);
+ }
+
+ // Clean up the target folder
+ nodeService.deleteNode(targetFolder);
+ targetFolder = null;
+
+ // All done
+ sourceDoc = null;
+ createTargetFolder();
+ }
+
+ private NodeRef createForDoc(String docname)
+ {
+ // Create the node
+ Map properties = new HashMap();
+ properties.put(ContentModel.PROP_NAME, docname);
+
+ NodeRef node = nodeService.createNode(
+ companyHome, ContentModel.ASSOC_CONTAINS,
+ QName.createQName(docname),
+ ContentModel.TYPE_CONTENT,
+ properties
+ ).getChildRef();
+
+ // Put the sample doc into it
+ ContentWriter writer = contentService.getWriter(
+ node, ContentModel.PROP_CONTENT, true
+ );
+ writer.putContent("TESTING");
+
+ // All done
+ return node;
+ }
+
+ public void testBasics() throws Exception
+ {
+ RenditionDefinition def = renditionService.createRenditionDefinition(
+ QName.createQName("Test"), HTMLRenderingEngine.NAME);
+ def.setParameterValue(
+ RenditionService.PARAM_DESTINATION_PATH_TEMPLATE,
+ targetFolderPath + "/${name}.html"
+ );
+
+ sourceDoc = createForDoc("quick.doc");
+
+ ChildAssociationRef rendition = renditionService.render(sourceDoc, def);
+ assertNotNull(rendition);
+
+ // Check it was created
+ NodeRef htmlNode = rendition.getChildRef();
+ assertEquals(true, nodeService.exists(htmlNode));
+
+ // Check it got the right name
+ assertEquals(
+ "quick.html",
+ nodeService.getProperty(htmlNode, ContentModel.PROP_NAME)
+ );
+
+ // Check it got the right contents
+ ContentReader reader = contentService.getReader(
+ htmlNode, ContentModel.PROP_CONTENT
+ );
+ String html = reader.getContentString();
+ assertEquals("