All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.greenpepper.runner.dialect.MarkdownDialect Maven / Gradle / Ivy

The newest version!
package com.greenpepper.runner.dialect;

import com.greenpepper.dialect.SpecificationDialect;
import com.greenpepper.dialect.SpecificationDialectException;
import com.greenpepper.shaded.com.vladsch.flexmark.ast.Node;
import com.greenpepper.shaded.com.vladsch.flexmark.ext.tables.TablesExtension;
import com.greenpepper.shaded.com.vladsch.flexmark.html.HtmlRenderer;
import com.greenpepper.shaded.com.vladsch.flexmark.parser.Parser;
import com.greenpepper.shaded.com.vladsch.flexmark.util.options.MutableDataSet;
import com.greenpepper.shaded.org.apache.commons.io.IOUtils;
import com.greenpepper.shaded.org.jsoup.Jsoup;
import com.greenpepper.shaded.org.jsoup.nodes.Document;
import com.greenpepper.shaded.org.slf4j.Logger;
import com.greenpepper.shaded.org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Collection;
import java.util.Collections;

import static java.lang.String.format;
import static com.greenpepper.shaded.org.apache.commons.lang3.StringUtils.isBlank;
import static com.greenpepper.shaded.org.apache.commons.lang3.StringUtils.isNotBlank;

public class MarkdownDialect implements SpecificationDialect {

    private static final Logger LOGGER = LoggerFactory.getLogger(MarkdownDialect.class);
    private static final String EMPTY_STRING = "";

    private final Parser parser;
    private final HtmlRenderer renderer;

    private String cssPath;
    private String jsPath;
    private Charset usedCharset;

    public MarkdownDialect() {
        MutableDataSet options = new MutableDataSet()
                .set(Parser.EXTENSIONS, Collections.singletonList(TablesExtension.create()));
        parser = Parser.builder(options).build();
        renderer = HtmlRenderer.builder(options).build();
    }

    public MarkdownDialect(String ... args) {
        this();
        if (args.length > 0) {
            cssPath = args[0];
        }
        if (args.length > 1) {
            jsPath = args[1];
        }
    }

    @Override
    public String convert(InputStream input) throws SpecificationDialectException {
        try {
            usedCharset = Charset.forName("UTF-8");
            ByteArrayOutputStream duplicated = new ByteArrayOutputStream();
            IOUtils.copy(input, duplicated);
            // test the UTF8 charset
            byte[] bytes = duplicated.toByteArray();

            usedCharset = CharsetDetector.detectCharset(new ByteArrayInputStream(bytes), usedCharset);
            if (usedCharset == null) {
                Collection charsets = Charset.availableCharsets().values();
                usedCharset = CharsetDetector.detectCharset(new ByteArrayInputStream(bytes), charsets);
            }
            if (usedCharset == null) {
                usedCharset = Charset.defaultCharset();
            }
            LOGGER.debug("Using charset {}", usedCharset);
            InputStreamReader streamReader = new InputStreamReader(new ByteArrayInputStream(bytes), usedCharset);
            if (!streamReader.ready()) {
                return EMPTY_STRING;
            }
            Node document = parser.parseReader(streamReader);
            String render = renderer.render(document);
            // Ensure the result starts with html tags
            Document jsoupDoc = Jsoup.parse(render);
            jsoupDoc.head().appendElement("style");
            if (isNotBlank(jsPath)) {
                jsoupDoc.head().appendElement("script");
            }

            org.w3c.dom.Document w3cDoc = parse(jsoupDoc.toString());
            w3cDoc.getElementsByTagName("style").item(0).setTextContent(readMDCss());
            if (isNotBlank(jsPath)) {
                w3cDoc.getElementsByTagName("script").item(0).setTextContent(readMDJs());
            }
            String htmlPage = toString(w3cDoc);
            LOGGER.debug("converted HTML:\n {}", htmlPage);
            return htmlPage;
        } catch (SpecificationDialectException e) {
            throw e;
        } catch (Exception e) {
            throw new SpecificationDialectException("Can't parse the input.", e);
        }
    }

    private String readMDCss() throws IOException {
        String cssFileContent;

        if (isBlank(cssPath)) {
            InputStream resourceAsStream = getClass().getResourceAsStream("mddialect.css");
            cssFileContent = IOUtils.toString(resourceAsStream, usedCharset);
        } else  {
            cssFileContent = readFromResource(cssPath);
        }
        LOGGER.debug("Read CSS content:\n{}", cssFileContent);
        return cssFileContent;
    }

    private String readMDJs() throws IOException {
        if (isBlank(jsPath)) {
            return "";
        }
        String jsContent = readFromResource(jsPath);
        LOGGER.debug("Read JSContent:\n{}", jsContent);
        return jsContent;
    }

    private String readFromResource(String jsPath) throws IOException {
        String jsContent;
        if (jsPath.contains(":")) {
            jsContent = IOUtils.toString(new URL(jsPath), usedCharset);
        } else {
            // search in classpath
            InputStream stream = getClass().getClassLoader().getResourceAsStream(jsPath);
            if (stream == null) {
                throw new SpecificationDialectException(format("Unable to get the specified resource in the classpath: %s", jsPath));
            }
            jsContent = IOUtils.toString(stream, usedCharset);
        }
        return jsContent;
    }

    private org.w3c.dom.Document parse(String xml) throws ParserConfigurationException, IOException, SAXException {
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        documentBuilderFactory.setNamespaceAware(false);
        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
        return documentBuilder.parse(new ByteArrayInputStream(xml.getBytes(usedCharset)));
    }

    private String toString(org.w3c.dom.Document document) throws TransformerException {
        StringWriter writer = new StringWriter();
        StreamResult result = new StreamResult(writer);
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer transformer = tf.newTransformer();
        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
        DOMSource domSource = new DOMSource(document);
        transformer.transform(domSource, result);
        return writer.toString();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy