Package org.apache.cayenne.maven.plugin.confluence

Source Code of org.apache.cayenne.maven.plugin.confluence.DocPageRenderer

/*****************************************************************
*   Licensed to the Apache Software Foundation (ASF) under one
*  or more contributor license agreements.  See the NOTICE file
*  distributed with this work for additional information
*  regarding copyright ownership.  The ASF licenses this file
*  to you under the Apache License, Version 2.0 (the
*  "License"); you may not use this file except in compliance
*  with the License.  You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing,
*  software distributed under the License is distributed on an
*  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
*  KIND, either express or implied.  See the License for the
*  specific language governing permissions and limitations
*  under the License.
****************************************************************/

package org.apache.cayenne.maven.plugin.confluence;

import java.io.Writer;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.log.NullLogSystem;
import org.objectstyle.confluence.rpc.soap_axis.confluenceservice_v1.ConfluenceSoapService;

/**
* Extracts embedded links from Confluence documentation and converts them to local fs
* references
*
*/
public class DocPageRenderer {

    private static final String URL_PREFIX = "/confluence";

    /**
     * Only attachments within the page are supported right now. This could easily be
     * adjusted to find attachments in external documents if necessary.
     */
    private static final Pattern attachmentPattern = Pattern.compile("(href|src)=\""
            + URL_PREFIX
            + "/download/attachments/(.*?)/(.*?)\"");

    /**
     * When browsing the local filesystem, browsers like %20 (hex encoded) instead of +
     * (legacy HTTP 0.9) for spaces.
     */
    private static final Pattern spaceEncoderPattern = Pattern
            .compile("href=\"(?!http://).*?\\+.*?\"");

    /**
     * Not all images are supported - only the ones referenced by current docs.
     */
    private static final Pattern confluenceImagePattern = Pattern.compile("src=\""
            + URL_PREFIX
            + "/images/icons/(.*?)\"");

    /**
     * Take any confluence links to non-doc content and add the url
     */
    private Pattern confluenceLinkPattern = Pattern.compile("href=\"("
            + URL_PREFIX
            + "/display/.*?)\"");

    private Pattern embeddedLinkPattern;

    private ConfluenceSoapService service;

    private String token;

    private String spaceKey;

    private String baseUrl;

    private VelocityContext velCtxt;

    private Template pageTemplate;

    public DocPageRenderer(ConfluenceSoapService service, String baseUrl, String token,
            String spaceKey, String template) throws Exception {

        // Note that these regexps have a fairly narrow capture - since the HTML
        // is
        // machine-generated,
        // we're kind of assuming it is well-formed
        embeddedLinkPattern = Pattern.compile("href=\""
                + URL_PREFIX
                + "/display/"
                + spaceKey
                + "/(.*?)\"");

        this.service = service;
        this.baseUrl = baseUrl;
        this.token = token;
        this.spaceKey = spaceKey;

        velCtxt = new VelocityContext();

        initializeClassTemplate(template);
    }

    private void initializeClassTemplate(String template) throws Exception {
        VelocityEngine velocityEngine = new VelocityEngine();
        try {

            // use ClasspathResourceLoader for velocity templates lookup
            // if Cayenne URL is not null, load resource from this URL
            Properties props = new Properties();

            // null logger that will prevent velocity.log from being generated
            props.put(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, NullLogSystem.class
                    .getName());

            props.put("resource.loader", "cayenne");

            props.put(
                    "cayenne.resource.loader.class",
                    "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");

            velocityEngine.init(props);
        }
        catch (Exception ex) {
            throw new RuntimeException("Can't initialize Velocity", ex);
        }

        pageTemplate = velocityEngine.getTemplate(template);
    }

    public void render(DocPage page, Writer out) throws Exception {

        // Add the TOC, unless this is the top-level page
        StringBuffer toc = new StringBuffer();
        if (page.getParentRef() != null) {
            toc.append("<div id=\"cayenne_toc\">\n");

            DocPage root = page.getRoot();

            iterateChildren(toc, page, root);
            toc.append("</div>\n");
        }

        // Figure out the level of nesting for relative links
        String basePath = "";
        for (int i = 1; i <= page.getDepth(); i++) {
            basePath += "../";
        }

        String renderedContent = null;
        try {
            renderedContent = service.renderContent(token, spaceKey, page.getId(), page
                    .getRawContent(), new HashMap(Collections.singletonMap(
                    "style",
                    "clean")));
        }
        catch (Throwable t) {
            // could have hit a DOS prevention bit so
            // sleep for 250ms and try again
            Thread.sleep(250);
            renderedContent = service.renderContent(token, spaceKey, page.getId(), page
                    .getRawContent(), new HashMap(Collections.singletonMap(
                    "style",
                    "clean")));
        }
        // Replace cross-doc links
        Matcher linkMatcher = embeddedLinkPattern.matcher(renderedContent);
        StringBuffer replacementBuffer = new StringBuffer();
        while (linkMatcher.find()) {
            DocPage destPage = DocPage.getPageByTitle(linkMatcher.group(1).replace(
                    '+',
                    ' '));

            // If we don't understand the link, just leave it alone to be safe
            if (destPage == null) {
                continue;
            }
            linkMatcher.appendReplacement(replacementBuffer, "href=\""
                    + basePath
                    + destPage.getLinkPath()
                    + "/index.html\"");
        }
        linkMatcher.appendTail(replacementBuffer);

        renderedContent = replacementBuffer.toString();

        // renderedContent =
        // embeddedLinkPattern.matcher(renderedContent).replaceAll("href=\"$1/index.html\"");

        // Replace attachment links
        renderedContent = attachmentPattern.matcher(renderedContent).replaceAll(
                "$1=\"$3\"");

        // Convert confluence images to relative links
        renderedContent = confluenceImagePattern.matcher(renderedContent).replaceAll(
                "src=\"" + basePath + "images/$1\"");

        // Replace wiki links
        renderedContent = confluenceLinkPattern.matcher(renderedContent).replaceAll(
                "href=\"" + baseUrl + "$1\"");

        // Convert local links with + to %20 to make browsers happy (wtf?)
        Matcher matcher = spaceEncoderPattern.matcher(renderedContent);

        replacementBuffer = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(replacementBuffer, matcher.group(0).replaceAll(
                    "\\+",
                    "%20"));
        }
        matcher.appendTail(replacementBuffer);

        renderedContent = replacementBuffer.toString();

        velCtxt.put("page", page);
        velCtxt.put("basePath", basePath);
        velCtxt.put("pageContent", toc.toString() + renderedContent);

        pageTemplate.merge(velCtxt, out);

    }

    private void iterateChildren(StringBuffer toc, DocPage currentPage, DocPage basePage) {
        toc.append("<ul>\n");
        for (Iterator baseIter = basePage.getChildren().iterator(); baseIter.hasNext();) {

            DocPage child = (DocPage) baseIter.next();

            toc.append("<li>").append("<a href=\"");
            for (int i = 1; i <= currentPage.getDepth(); i++) {
                toc.append("../");
            }
            toc.append(child.getLinkPath()).append("/index.html\">");
            toc.append(child.getTitle()).append("</a>");
            if (child.hasDescendent(currentPage)) {
                // render children
                iterateChildren(toc, currentPage, child);
            }

            toc.append("</li>\n");
        }

        toc.append("</ul>\n");
    }
}
TOP

Related Classes of org.apache.cayenne.maven.plugin.confluence.DocPageRenderer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.