001package com.monochromeroad.grails.plugins.xwiki;
002
003import groovy.lang.Closure;
004import org.xwiki.rendering.block.XDOM;
005import org.xwiki.rendering.parser.ParseException;
006import org.xwiki.rendering.parser.StreamParser;
007import org.xwiki.rendering.renderer.Renderer;
008import org.xwiki.rendering.syntax.Syntax;
009import org.xwiki.rendering.transformation.Transformation;
010
011import java.io.Reader;
012import java.util.Collections;
013
014/**
015 * XWiki Rendering System -- streaming based
016 *
017 * <p>
018 * If you use some macros or transformations, it needs to create a XDOM that represents the whole document structure in a memory.
019 * </p>
020 *
021 * <dl>
022 *     <dt>Default Syntax</dt>
023 *     <dd>xwiki/2.1</dd>
024 *     <dt>Output</dt>
025 *     <dd>xhtml/1.0</dd>
026 * </dl>
027 *
028 * @author Masatoshi Hayashi
029 */
030public class XWikiStreamRenderer extends XWikiRenderingSystem {
031
032    public XWikiStreamRenderer(XWikiComponentManager componentManager, XWikiConfigurationProvider configuration) {
033        super(componentManager, configuration);
034    }
035
036    /**
037     * For the Grails Default XWiki Rendering System.
038     * It need to be initialized after construction.
039     */
040    XWikiStreamRenderer() {}
041
042    /**
043     * XWiki rendering
044     *
045     * @param source source text reader
046     * @param inputSyntax inputSyntax
047     * @param outputSyntax outputSyntax
048     * @param preTransformations transforms applied before macros
049     * @param postTransformations transforms applied after macros
050     * @param callback a callback function processed on parsing a text
051     */
052    public void render(Reader source, Syntax inputSyntax, Syntax outputSyntax, Iterable<Transformation> preTransformations, Iterable<Transformation> postTransformations, Closure callback) {
053        if (configurationProvider.isMacrosEnabled() || preTransformations.iterator().hasNext() || postTransformations.iterator().hasNext()) {
054            renderOnXDOM(source, inputSyntax, outputSyntax, preTransformations, postTransformations, callback);
055        } else {
056            renderOnStream(source, inputSyntax, outputSyntax, callback);
057        }
058    }
059
060    /**
061     * XWiki rendering
062     *
063     * @param source source text reader
064     * @param inputSyntax inputSyntax
065     * @param outputSyntax outputSyntax
066     * @param callback a callback function processed on parsing a text
067     */
068    public void render(Reader source, Syntax inputSyntax, Syntax outputSyntax, Closure callback) {
069        render(source, inputSyntax, outputSyntax, Collections.<Transformation>emptyList(), Collections.<Transformation>emptyList(), callback);
070    }
071
072    /**
073     * XWiki XHTML rendering
074     *
075     * @param source source text reader
076     * @param inputSyntax inputSyntax
077     * @param callback a callback function processed on parsing a text
078     */
079    public void render(Reader source, Syntax inputSyntax, Closure callback) {
080        Syntax outputSyntax = configurationProvider.getDefaultOutputSyntax();
081        render(source, inputSyntax, outputSyntax, callback);
082    }
083
084    /**
085     * XWiki XHTML rendering using the default syntax
086     *
087     * @param source source text reader
088     * @param callback a callback function processed on parsing a text
089     */
090    public void render(Reader source, Closure callback) {
091        Syntax inputSyntax = configurationProvider.getDefaultInputSyntax();
092        Syntax outputSyntax = configurationProvider.getDefaultOutputSyntax();
093        render(source, inputSyntax, outputSyntax, callback);
094    }
095
096    /**
097     * XWiki rendering
098     *
099     * @param source source text reader
100     * @param inputSyntax inputSyntax
101     * @param outputSyntax outputSyntax
102     * @param transformations transforms applied after macros
103     * @param callback a callback function processed on parsing a text
104     */
105    public void render(Reader source, Syntax inputSyntax, Syntax outputSyntax, Iterable<Transformation> transformations, Closure callback) {
106        render(source, inputSyntax, outputSyntax, Collections.<Transformation>emptyList(), transformations, callback);
107    }
108
109    /**
110     * XWiki XHTML rendering
111     *
112     * @param source source text reader
113     * @param inputSyntax inputSyntax
114     * @param transformations transforms applied after macros
115     * @param callback a callback function processed on parsing a text
116     */
117    public void render(Reader source, Syntax inputSyntax, Iterable<Transformation> transformations, Closure callback) {
118        Syntax outputSyntax = configurationProvider.getDefaultOutputSyntax();
119        render(source, inputSyntax, outputSyntax, transformations, callback);
120    }
121
122    /**
123     * XWiki XHTML rendering
124     *
125     * @param source source text reader
126     * @param inputSyntax inputSyntax
127     * @param preTransformations transforms applied before macros
128     * @param postTransformations transforms applied after macros
129     * @param callback a callback function processed on parsing a text
130     */
131    public void render(Reader source, Syntax inputSyntax, Iterable<Transformation> preTransformations, Iterable<Transformation> postTransformations, Closure callback) {
132        Syntax outputSyntax = configurationProvider.getDefaultOutputSyntax();
133        render(source, inputSyntax, outputSyntax, preTransformations, postTransformations, callback);
134    }
135
136    /**
137     * XWiki XHTML rendering using the default syntax
138     *
139     * @param source source text reader
140     * @param transformations transforms applied after macros
141     * @param callback a callback function processed on parsing a text
142     */
143    public void render(Reader source, Iterable<Transformation> transformations, Closure callback) {
144        Syntax inputSyntax = configurationProvider.getDefaultInputSyntax();
145        Syntax outputSyntax = configurationProvider.getDefaultOutputSyntax();
146        render(source, inputSyntax, outputSyntax, transformations, callback);
147    }
148
149    /**
150     * XWiki XHTML rendering using the default syntax
151     *
152     * @param source source text reader
153     * @param preTransformations transforms applied before macros
154     * @param postTransformations transforms applied after macros
155     * @param callback a callback function processed on parsing a text
156     */
157    public void render(Reader source, Iterable<Transformation> preTransformations, Iterable<Transformation> postTransformations, Closure callback) {
158        Syntax inputSyntax = configurationProvider.getDefaultInputSyntax();
159        Syntax outputSyntax = configurationProvider.getDefaultOutputSyntax();
160        render(source, inputSyntax, outputSyntax, preTransformations, postTransformations, callback);
161    }
162
163    private void renderOnXDOM(Reader source, Syntax inputSyntax, Syntax outputSyntax, Iterable<Transformation> preTransformations, Iterable<Transformation> postTransformations, Closure callback) {
164        XDOM xdom = buildXDOM(source, inputSyntax);
165        transform(xdom, inputSyntax, preTransformations, postTransformations);
166        applyRenderer(xdom, outputSyntax, new XWikiCallbackPrinter(callback));
167    }
168
169    private void renderOnStream(Reader source, Syntax inputSyntax, Syntax outputSyntax, Closure callback) {
170        StreamParser streamParser = componentManager.getInstance(StreamParser.class, inputSyntax.toIdString());
171        XWikiCallbackPrinter printer = new XWikiCallbackPrinter(callback);
172        Renderer renderer = createRenderer(outputSyntax, printer);
173        try {
174            streamParser.parse(source, renderer);
175        } catch (ParseException e) {
176            throw new IllegalStateException(e);
177        }
178    }
179}
180