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