001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2012-2015 ForgeRock AS.
015 */
016
017package org.forgerock.doc.maven.utils;
018
019import org.apache.commons.io.FileUtils;
020import org.apache.commons.io.filefilter.FileFilterUtils;
021import org.apache.commons.io.filefilter.HiddenFileFilter;
022import org.apache.commons.io.filefilter.IOFileFilter;
023
024import java.io.File;
025import java.io.FileFilter;
026import java.io.IOException;
027import java.util.HashMap;
028import java.util.List;
029import java.util.Map;
030import java.util.Set;
031
032/**
033 * Utility methods to prepare built HTML docs for publication.
034 */
035public final class HtmlUtils {
036    /**
037     * Add a <code>.htaccess</code> file to the base directory, for publication
038     * on an Apache HTTPD server.
039     * <p>
040     * According to Apache documentation on <a
041     * href="http://httpd.apache.org/docs/2.4/howto/htaccess.html#how">How
042     * directives are applied</a>, "The configuration directives found in a
043     * .htaccess file are applied to the directory in which the .htaccess file
044     * is found, and to all subdirectories thereof." So there is no need to copy
045     * the file recursively to all directories.
046     *
047     * @param baseDir
048     *            Base directory under which to add the file
049     * @param htaccess
050     *            <code>.htaccess</code> file to copy
051     * @throws IOException
052     *             Something went wrong during copy procedure.
053     */
054    public static void addHtaccess(final String baseDir, final File htaccess) throws IOException {
055        FileUtils.copyFileToDirectory(htaccess, new File(baseDir));
056    }
057
058    /**
059     * Add custom CSS with XML wrapper to document source directories.
060     *
061     * <p>
062     *
063     * See <a href="http://docbook.sourceforge.net/release/xsl/current/doc/html/custom.css.source.html"
064     * >custom.css.source</a> for details.
065     *
066     * @param cssFile         The CSS file to wrap in XML.
067     * @param srcDir          The source directory for DocBook XML documents.
068     * @param documentSrcName The top-level entry file to DocBook XML documents.
069     * @throws IOException Something went wrong adding CSS.
070     */
071    public static void addCustomCss(final File cssFile,
072                                    final File srcDir,
073                                    final String documentSrcName)
074            throws IOException {
075        if (!cssFile.exists()) {
076            throw new IOException(cssFile.getPath() + " not found");
077        }
078
079        final String cssString = FileUtils.readFileToString(cssFile);
080
081        Set<String> docNames = NameUtils.getDocumentNames(
082                srcDir, documentSrcName);
083        if (docNames.isEmpty()) {
084            throw new IOException("No document names found.");
085        }
086
087        for (String docName : docNames) {
088
089            final File parent = new File(srcDir, docName);
090            final File xmlFile = new File(parent, cssFile.getName() + ".xml");
091
092            if (!xmlFile.exists()) { // Do not append the document again to the same file.
093                FileUtils.write(xmlFile, "<?xml version=\"1.0\"?>\n", true);
094                FileUtils.write(xmlFile, "<style>\n", true);
095                FileUtils.write(xmlFile, cssString, true);
096                FileUtils.write(xmlFile, "</style>\n", true);
097            }
098        }
099    }
100
101    /**
102     * Replace HTML tags with additional content.
103     *
104     * @param baseDir
105     *            Base directory under which to find HTML files recursively
106     * @param replacements
107     *            Keys are tags to replace. Values are replacements, including
108     *            the original tag.
109     * @return List of files updated
110     * @throws IOException
111     *             Something went wrong reading or writing files.
112     */
113    public static List<File> updateHtml(final String baseDir,
114                                 final Map<String, String> replacements)
115            throws IOException {
116        // Match normal directories, and HTML files.
117        IOFileFilter dirFilter = FileFilterUtils
118                .and(FileFilterUtils.directoryFileFilter(),
119                        HiddenFileFilter.VISIBLE);
120        IOFileFilter fileFilter = FileFilterUtils.and(
121                FileFilterUtils.fileFileFilter(),
122                FileFilterUtils.suffixFileFilter(".html"));
123        FileFilter filter = FileFilterUtils.or(dirFilter, fileFilter);
124
125        FilteredFileUpdater ffu = new FilteredFileUpdater(replacements, filter);
126        return ffu.update(new File(baseDir));
127    }
128
129
130    /**
131     * Fix links to arbitrary resources in HTML files.
132     *
133     * <p>
134     *
135     * Chunked HTML and webhelp have extra directories in the path.
136     * Links like {@code ../resources/file.txt} that work in the source
137     * do not work as is in these formats.
138     * Instead the links need an extra .. as in {@code ../../resources/file.txt}.
139     *
140     * @param htmlDir              Path to a directory containing HTML.
141     * @param resourcesDirBaseName Base name of the resources directory.
142     * @throws IOException Something went wrong updating links.
143     */
144    public static void fixResourceLinks(final String htmlDir, final String resourcesDirBaseName)
145            throws IOException {
146
147        HashMap<String, String> replacements = new HashMap<String, String>();
148        replacements.put("href=\'../" + resourcesDirBaseName, "href=\'../../" + resourcesDirBaseName);
149        replacements.put("href=\"../" + resourcesDirBaseName, "href=\"../../" + resourcesDirBaseName);
150
151        updateHtml(htmlDir, replacements);
152    }
153
154    /**
155     * Not used.
156     */
157    private HtmlUtils() {
158    }
159}