001/*
002 * (C) Copyright 2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Florent Guillaume
018 */
019package org.nuxeo.apidoc.documentation;
020
021import java.util.LinkedList;
022
023import org.apache.commons.lang.StringUtils;
024import org.nuxeo.ecm.platform.htmlsanitizer.HtmlSanitizerService;
025import org.nuxeo.runtime.api.Framework;
026
027/**
028 * Helper to generate HTML for documentation strings.
029 */
030public class DocumentationHelper {
031
032    private static final String BR = "<br/>";
033
034    private static final String BR2 = "<br />";
035
036    private static final String BR3 = "<br>";
037
038    private static final String P = "<p/>";
039
040    private static final String P2 = "<p />";
041
042    // private static final String CODE_START = "<div class=\"code\"><pre>";
043    private static final String CODE_START = "<code><pre>";
044
045    // private static final String CODE_END = "</pre></div>";
046    private static final String CODE_END = "</pre></code>";
047
048    private static final String AUTHOR = "@author";
049
050    // utility class
051    private DocumentationHelper() {
052    }
053
054    /**
055     * Transforms Nuxeo extension point {@code <documentation>} content into HTML.
056     * <p>
057     * <ul>
058     * <li>standalone newlines are turned into {@code <br/>}</li>
059     * <li>{@code <code>} blocks are turned into a {@code <div class="code">} with a {@code <pre>}</li>
060     * <li>{@code @author} blocks are removed</li>
061     * </ul>
062     */
063    public static String getHtml(String doc) {
064        if (doc == null) {
065            return "";
066        }
067        HtmlSanitizerService sanitizer = Framework.getService(HtmlSanitizerService.class);
068        if (sanitizer == null && !Framework.isTestModeSet()) {
069            throw new RuntimeException("Cannot find HtmlSanitizerService");
070        }
071
072        LinkedList<String> lines = new LinkedList<String>();
073        lines.add(P);
074        boolean newline = true;
075        boolean firstcode = false;
076        boolean code = false;
077        for (String line : doc.split("\n")) {
078            if (!code) {
079                line = line.trim();
080                if ("".equals(line) || BR.equals(line) || BR2.equals(line) || BR3.equals(line) || P.equals(line)
081                        || P2.equals(line)) {
082                    if (!newline) {
083                        lines.add(P);
084                        newline = true;
085                    }
086                } else {
087                    if ("<code>".equals(line)) {
088                        code = true;
089                        firstcode = true;
090                        line = CODE_START;
091                        if (!newline) {
092                            line = P + line;
093                        }
094                        lines.add(line);
095                        newline = false;
096                    } else if (line.startsWith(AUTHOR)) {
097                        if (!newline) {
098                            lines.add(P);
099                        }
100                        newline = true;
101                    } else {
102                        lines.add(line);
103                        newline = false;
104                    }
105                }
106            } else { // code
107                if ("</code>".equals(line.trim())) {
108                    code = false;
109                    line = CODE_END + P;
110                    newline = true;
111                } else {
112                    line = line.replace("&", "&amp;").replace("<", "&lt;");
113                }
114                if (firstcode) {
115                    // don't add a \n at the start of the code
116                    firstcode = false;
117                    line = lines.removeLast() + line;
118                }
119                lines.add(line);
120            }
121        }
122        if (code) {
123            lines.add(CODE_END);
124        }
125        String html = StringUtils.join(lines, "\n");
126        if (sanitizer != null) {
127            html = sanitizer.sanitizeString(html, null);
128        }
129        return secureXML(html);
130    }
131
132    /**
133     * Makes sure no passwords are embedded in the XML.
134     */
135    public static String secureXML(String xml) {
136        if (xml == null || !xml.contains("assword")) {
137            return xml;
138        }
139        xml = xml.replaceAll("<([a-zA-Z]*[pP])assword>[^<]*</([a-zA-Z]*)assword>", "<$1assword>********</$2assword>");
140        // attributes: nuxeo-core-auth
141        xml = xml.replaceAll("([a-zA-Z]*[pP])assword=\"[^\"]*\"", "$1assword=\"********\"");
142        // property: default-repository-config
143        xml = xml.replaceAll("([a-zA-Z]*[pP])assword\">[^<]*<", "$1assword\">********<");
144        return xml;
145    }
146
147}