diff --git a/config/alfresco/content-services-context.xml b/config/alfresco/content-services-context.xml index 03e8823f5a..486ba26938 100644 --- a/config/alfresco/content-services-context.xml +++ b/config/alfresco/content-services-context.xml @@ -235,7 +235,14 @@ + parent="baseContentTransformer"> + + + + + + + shtml body + + mw + xhtml diff --git a/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java b/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java index f6baa43976..a1f2926c57 100644 --- a/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java +++ b/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java @@ -24,7 +24,9 @@ */ package org.alfresco.repo.action.executer; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.alfresco.model.ContentModel; import org.alfresco.repo.action.ParameterDefinitionImpl; @@ -73,6 +75,9 @@ public class TransformActionExecuter extends ActionExecuterAbstractBase public static final String PARAM_ASSOC_QNAME = "assoc-name"; public static final String PARAM_OVERWRITE_COPY = "overwrite-copy"; + /** + * Injected services + */ private DictionaryService dictionaryService; private NodeService nodeService; private ContentService contentService; @@ -281,7 +286,7 @@ public class TransformActionExecuter extends ActionExecuterAbstractBase // TODO: Check failure patterns for actions. try { - doTransform(ruleAction, contentReader, contentWriter); + doTransform(ruleAction, actionedUponNodeRef, contentReader, copyNodeRef, contentWriter); } catch(NoTransformerException e) { @@ -299,14 +304,23 @@ public class TransformActionExecuter extends ActionExecuterAbstractBase /** * Executed in a new transaction so that failures don't cause the entire transaction to rollback. */ - protected void doTransform(Action ruleAction, ContentReader contentReader, ContentWriter contentWriter) + protected void doTransform( Action ruleAction, + NodeRef sourceNodeRef, ContentReader contentReader, + NodeRef destinationNodeRef, ContentWriter contentWriter) { // try to pre-empt the lack of a transformer if (!this.contentService.isTransformable(contentReader, contentWriter)) { throw new NoTransformerException(contentReader.getMimetype(), contentWriter.getMimetype()); } - this.contentService.transform(contentReader, contentWriter); + + // build map of options + Map options = new HashMap(2); + options.put(ContentTransformer.OPT_SOURCE_NODEREF, sourceNodeRef); + options.put(ContentTransformer.OPT_DESTINATION_NODEREF, destinationNodeRef); + + // transform + this.contentService.transform(contentReader, contentWriter, options); } /** diff --git a/source/java/org/alfresco/repo/content/MimetypeMap.java b/source/java/org/alfresco/repo/content/MimetypeMap.java index 2bd1b820bb..ec80768e98 100644 --- a/source/java/org/alfresco/repo/content/MimetypeMap.java +++ b/source/java/org/alfresco/repo/content/MimetypeMap.java @@ -56,6 +56,7 @@ public class MimetypeMap implements MimetypeService public static final String EXTENSION_BINARY = "bin"; public static final String MIMETYPE_TEXT_PLAIN = "text/plain"; + public static final String MIMETYPE_TEXT_MEDIAWIKI = "text/mediawiki"; public static final String MIMETYPE_TEXT_CSS = "text/css"; public static final String MIMETYPE_TEXT_JAVASCRIPT = "text/javascript"; public static final String MIMETYPE_XML = "text/xml"; diff --git a/source/java/org/alfresco/repo/content/RoutingContentService.java b/source/java/org/alfresco/repo/content/RoutingContentService.java index a57cd08d2e..d0433402be 100644 --- a/source/java/org/alfresco/repo/content/RoutingContentService.java +++ b/source/java/org/alfresco/repo/content/RoutingContentService.java @@ -444,8 +444,19 @@ public class RoutingContentService implements ContentService /** * @see org.alfresco.repo.content.transform.ContentTransformerRegistry * @see org.alfresco.repo.content.transform.ContentTransformer + * @see org.alfresco.service.cmr.repository.ContentService#transform(org.alfresco.service.cmr.repository.ContentReader, org.alfresco.service.cmr.repository.ContentWriter) */ public void transform(ContentReader reader, ContentWriter writer) + { + // Call transform with not options + this.transform(reader, writer, null); + } + + /** + * @see org.alfresco.repo.content.transform.ContentTransformerRegistry + * @see org.alfresco.repo.content.transform.ContentTransformer + */ + public void transform(ContentReader reader, ContentWriter writer, Map options) throws NoTransformerException, ContentIOException { // check that source and target mimetypes are available @@ -466,7 +477,7 @@ public class RoutingContentService implements ContentService throw new NoTransformerException(sourceMimetype, targetMimetype); } // we have a transformer, so do it - transformer.transform(reader, writer); + transformer.transform(reader, writer, options); // done } diff --git a/source/java/org/alfresco/repo/content/transform/ContentTransformer.java b/source/java/org/alfresco/repo/content/transform/ContentTransformer.java index 3a0eec3ab6..4f362ee07a 100644 --- a/source/java/org/alfresco/repo/content/transform/ContentTransformer.java +++ b/source/java/org/alfresco/repo/content/transform/ContentTransformer.java @@ -38,6 +38,16 @@ import org.alfresco.service.cmr.repository.ContentWriter; */ public interface ContentTransformer extends ContentWorker { + /** + * Transform option constants + * + * It is up to the transformation implementation whether these + * options are used, but they should be considered optional and their absence + * should not interfere with the execution of the transformer. + */ + public static final String OPT_SOURCE_NODEREF = "sourceNodeRef"; + public static final String OPT_DESTINATION_NODEREF = "destinationNodeRef"; + /** * Provides the approximate accuracy with which this transformer can * transform from one mimetype to another. diff --git a/source/java/org/alfresco/repo/content/transform/MediaWikiContentTransformer.java b/source/java/org/alfresco/repo/content/transform/MediaWikiContentTransformer.java index f7eee9b872..a97d59c101 100644 --- a/source/java/org/alfresco/repo/content/transform/MediaWikiContentTransformer.java +++ b/source/java/org/alfresco/repo/content/transform/MediaWikiContentTransformer.java @@ -24,13 +24,21 @@ */ package org.alfresco.repo.content.transform; +import info.bliki.wiki.filter.Encoder; import info.bliki.wiki.model.WikiModel; +import info.bliki.wiki.tags.ATag; +import java.util.List; import java.util.Map; import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.service.cmr.model.FileFolderService; +import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.htmlcleaner.ContentToken; /** * MediaWiki content transformer. Converts mediawiki markup into HTML. @@ -41,17 +49,41 @@ import org.alfresco.service.cmr.repository.ContentWriter; */ public class MediaWikiContentTransformer extends AbstractContentTransformer { - //private static final Log logger = LogFactory.getLog(MediaWikiContentTransformer.class); + /** The file folder service */ + private FileFolderService fileFolderService; + + /** The node service */ + private NodeService nodeService; /** - * Only support TEXT to HTML + * Sets the file folder service + * + * @param fileFolderService the file folder service + */ + public void setFileFolderService(FileFolderService fileFolderService) + { + this.fileFolderService = fileFolderService; + } + + /** + * Sets the node service + * + * @param nodeService the node service + */ + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + /** + * Only support MEDIAWIKI to HTML */ public double getReliability(String sourceMimetype, String targetMimetype) { - if (!MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(sourceMimetype) || + if (!MimetypeMap.MIMETYPE_TEXT_MEDIAWIKI.equals(sourceMimetype) || !MimetypeMap.MIMETYPE_HTML.equals(targetMimetype)) { - // only support TEXT -> HTML + // only support MEDIAWIKI -> HTML return 0.0; } else @@ -66,10 +98,60 @@ public class MediaWikiContentTransformer extends AbstractContentTransformer public void transformInternal(ContentReader reader, ContentWriter writer, Map options) throws Exception { + String imageURL = "{$image}"; + String pageURL = "${title}"; + + if (options.containsKey(ContentTransformer.OPT_DESTINATION_NODEREF) == true) + { + NodeRef destinationNodeRef = (NodeRef)options.get(ContentTransformer.OPT_DESTINATION_NODEREF); + NodeRef parentNodeRef = this.nodeService.getPrimaryParent(destinationNodeRef).getParentRef(); + + StringBuffer folderPath = new StringBuffer(256); + List fileInfos = this.fileFolderService.getNamePath(null, parentNodeRef); + for (FileInfo fileInfo : fileInfos) + { + folderPath.append(fileInfo.getName()).append("/"); + } + + pageURL = "/alfresco/d/d?path=" + folderPath + "${title}.html"; + imageURL = "/alfresco/d/d?path=" + folderPath + "Images/${image}"; + } + // Create the wikiModel and set the title and image link URL's - WikiModel wikiModel = new WikiModel("${image}", "${title}"); + AlfrescoWikiModel wikiModel = new AlfrescoWikiModel(imageURL, pageURL); // Render the wiki content as HTML writer.putContent(wikiModel.render(reader.getContentString())); } + + private class AlfrescoWikiModel extends WikiModel + { + public AlfrescoWikiModel(String imageBaseURL, String linkBaseURL) + { + super(imageBaseURL, linkBaseURL); + } + + @Override + public void appendInternalLink(String link, String hashSection, String linkText) + { + link = link.replaceAll(":", " - "); + String encodedtopic = Encoder.encodeTitleUrl(link); + encodedtopic = encodedtopic.replaceAll("_", " "); + + String hrefLink = fExternalWikiBaseURL.replace("${title}", encodedtopic); + + ATag aTagNode = new ATag(); + append(aTagNode); + aTagNode.addAttribute("id", "w"); + String href = hrefLink; + if (hashSection != null) { + href = href + '#' + hashSection; + } + aTagNode.addAttribute("href", href); + aTagNode.addObjectAttribute("wikilink", hrefLink); + + ContentToken text = new ContentToken(linkText); + aTagNode.addChild(text); + } + } } diff --git a/source/java/org/alfresco/repo/content/transform/MediaWikiContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/MediaWikiContentTransformerTest.java index e758e13dbb..38c196aac7 100644 --- a/source/java/org/alfresco/repo/content/transform/MediaWikiContentTransformerTest.java +++ b/source/java/org/alfresco/repo/content/transform/MediaWikiContentTransformerTest.java @@ -88,17 +88,17 @@ public class MediaWikiContentTransformerTest extends AbstractContentTransformerT public void checkReliability() throws Exception { // check reliability - double reliability = transformer.getReliability(MimetypeMap.MIMETYPE_TEXT_PLAIN, MimetypeMap.MIMETYPE_HTML); + double reliability = transformer.getReliability(MimetypeMap.MIMETYPE_TEXT_MEDIAWIKI, MimetypeMap.MIMETYPE_HTML); assertEquals("Reliability incorrect", 1.0, reliability); // plain text to html is 100% // check other way around - reliability = transformer.getReliability(MimetypeMap.MIMETYPE_HTML, MimetypeMap.MIMETYPE_TEXT_PLAIN); + reliability = transformer.getReliability(MimetypeMap.MIMETYPE_HTML, MimetypeMap.MIMETYPE_TEXT_MEDIAWIKI); assertEquals("Reliability incorrect", 0.0, reliability); // html to plain text is 0% } public void testMediaWikiToHTML() throws Exception { - File input = File.createTempFile("mediaWikiTest", ".txt"); + File input = File.createTempFile("mediaWikiTest", ".mw"); FileOutputStream fos = new FileOutputStream(input); fos.write(WIKI_TEXT.getBytes()); fos.close(); @@ -106,7 +106,7 @@ public class MediaWikiContentTransformerTest extends AbstractContentTransformerT File output = File.createTempFile("mediaWikiTest", ".htm"); ContentReader contentReader = new FileContentReader(input); - contentReader.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); + contentReader.setMimetype(MimetypeMap.MIMETYPE_TEXT_MEDIAWIKI); contentReader.setEncoding("UTF-8"); ContentWriter contentWriter = new FileContentWriter(output); diff --git a/source/java/org/alfresco/service/cmr/repository/ContentService.java b/source/java/org/alfresco/service/cmr/repository/ContentService.java index 03bc970d16..bdfdae3a7b 100644 --- a/source/java/org/alfresco/service/cmr/repository/ContentService.java +++ b/source/java/org/alfresco/service/cmr/repository/ContentService.java @@ -24,6 +24,8 @@ */ package org.alfresco.service.cmr.repository; +import java.util.Map; + import org.alfresco.repo.content.transform.ContentTransformer; import org.alfresco.service.Auditable; import org.alfresco.service.PublicService; @@ -142,6 +144,23 @@ public interface ContentService public void transform(ContentReader reader, ContentWriter writer) throws NoTransformerException, ContentIOException; + + /** + * @see org.aflresco.service.cmr.repository.ContentService.transform(ContentReader, ContentReader) + * + * A map of transform options can be provided. + * + * @param reader the source content location and mimetype + * @param writer the target content location and mimetype + * @param options the options for the transformation + * @throws NoTransformerException if no transformer exists for the + * given source and target mimetypes of the reader and writer + * @throws ContentIOException if the transformation fails + */ + @Auditable(parameters = {"reader", "writer", "options"}) + public void transform(ContentReader reader, ContentWriter writer, Map options) + throws NoTransformerException, ContentIOException; + /** * Fetch the transformer that is capable of transforming the content in the * given source mimetype to the given target mimetype.