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 = "<pre><code>";
044
045    // private static final String CODE_END = "</pre></div>";
046    private static final String CODE_END = "</code></pre>";
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
056     * HTML.
057     * <p>
058     * <ul>
059     * <li>standalone newlines are turned into {@code 
060     * <p/>
061     * }</li>
062     * <li>{@code <code>} blocks are turned into a {@code <div class="code">}
063     * with a {@code
064     *
065     * 
066    
067    <pre>
068     * <code>}</li>
069     * <li>{@code @author} blocks are removed</li>
070     * </ul>
071     */
072    public static String getHtml(String doc) {
073        if (doc == null) {
074            return "";
075        }
076        HtmlSanitizerService sanitizer = Framework.getService(HtmlSanitizerService.class);
077        if (sanitizer == null && !Framework.isTestModeSet()) {
078            throw new RuntimeException("Cannot find HtmlSanitizerService");
079        }
080
081        LinkedList<String> lines = new LinkedList<>();
082        lines.add(P);
083        boolean newline = true;
084        boolean firstcode = false;
085        boolean code = false;
086        for (String line : doc.split("\n")) {
087            if (!code) {
088                line = line.trim();
089                if ("".equals(line) || BR.equals(line) || BR2.equals(line) || BR3.equals(line) || P.equals(line)
090                        || P2.equals(line)) {
091                    if (!newline) {
092                        lines.add(P);
093                        newline = true;
094                    }
095                } else {
096                    if ("<code>".equals(line)) {
097                        code = true;
098                        firstcode = true;
099                        line = CODE_START;
100                        if (!newline) {
101                            line = P + line;
102                        }
103                        lines.add(line);
104                        newline = false;
105                    } else if (line.startsWith(AUTHOR)) {
106                        if (!newline) {
107                            lines.add(P);
108                        }
109                        newline = true;
110                    } else {
111                        lines.add(line);
112                        newline = false;
113                    }
114                }
115            } else { // code
116                if ("</code>".equals(line.trim())) {
117                    code = false;
118                    line = CODE_END + P;
119                    newline = true;
120                } else {
121                    line = line.replace("&", "&amp;").replace("<", "&lt;");
122                }
123                if (firstcode) {
124                    // don't add a \n at the start of the code
125                    firstcode = false;
126                    line = lines.removeLast() + line;
127                }
128                lines.add(line);
129            }
130        }
131        if (code) {
132            lines.add(CODE_END);
133        }
134        String html = StringUtils.join(lines, "\n");
135        if (sanitizer != null) {
136            html = sanitizer.sanitizeString(html, null);
137        }
138        return secureXML(html);
139    }
140
141    /**
142     * Makes sure no passwords are embedded in the XML.
143     */
144    public static String secureXML(String xml) {
145        if (xml == null || !xml.contains("assword")) {
146            return xml;
147        }
148        xml = xml.replaceAll("<([a-zA-Z]*[pP])assword>[^<]*</([a-zA-Z]*)assword>", "<$1assword>********</$2assword>");
149        // attributes: nuxeo-core-auth
150        xml = xml.replaceAll("([a-zA-Z]*[pP])assword=\"[^\"]*\"", "$1assword=\"********\"");
151        // property: default-repository-config
152        xml = xml.replaceAll("([a-zA-Z]*[pP])assword\">[^<]*<", "$1assword\">********<");
153        return xml;
154    }
155
156}