com.googlecode.jgenhtml.JGenHtmlUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.googlecode.jgenhtml.JGenHtmlUtils.java

Source

/*
   Copyright (C) 2012  Rick Brown
    
   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.
    
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
    
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.googlecode.jgenhtml;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.ProcessingInstruction;
import org.xml.sax.SAXException;

/**
 * Helpers for doing common JGenHtml stuff...
 * @author Rick Brown
 */
public class JGenHtmlUtils {
    private final static Logger LOGGER = Logger.getLogger(JGenHtmlUtils.class.getName());
    private static final byte MIN_DIRECTORIES = 1;
    public static final String XSLT_NAME = "jgenhtml.xsl";
    public static final String CSS_NAME = "jgenhtml.css";
    public static final String JS_NAME = "jgenhtml.js";

    public static void setGlobalRootAttributes(final Element root, final String testName) {
        root.setAttribute("testname", testName);
        root.setAttribute("date", getDate());
        root.setAttribute("version", JGenHtml.VERSION);
    }

    /**
     * @return The current date in the correct format for the coverage "date" attribute.
     */
    private static String getDate() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.format(new Date());
    }

    /**
     *
     * @param line The line with any leading whitespace removed.
     * @return
     */
    public static int[] getLineValues(String line) {
        String[] values = extractLineValues(line);
        int result[] = null;
        if (values != null) {
            result = new int[values.length];
            try {
                for (int i = 0; i < values.length; i++) {
                    result[i] = Integer.parseInt(values[i]);
                }
            } catch (NumberFormatException nfe) {
                LOGGER.log(Level.FINE, "Could not parse value from line: {0}", line);
            }
        }
        return result;
    }

    /**
     *
     * @param line The line with any leading whitespace removed.
     * @return
     */
    public static String[] extractLineValues(String line) {
        String[] result = null;
        int tokenIdx = line.indexOf(":");
        if (tokenIdx > 0 && (line.length() > tokenIdx + 1)) {
            String values = line.substring(tokenIdx + 1);
            result = values.split(",");
        }
        return result;
    }

    /**
     * Unzips a file.
     * @param gzippedFile A gzipped file.
     * @return The gunzipped version of the file.
     * @throws IOException If you screw up.
     */
    public static File gunzip(File gzippedFile) throws IOException {
        OutputStream out = null;
        GZIPInputStream gzipInputStream = null;
        File gunzippedFile = new File(System.getProperty("java.io.tmpdir") + File.separatorChar
                + gzippedFile.getName().replace(".gz", ""));
        try {
            InputStream in = new FileInputStream(gzippedFile);
            gzipInputStream = new GZIPInputStream(in);
            out = new FileOutputStream(gunzippedFile);

            byte[] buf = new byte[1024];
            int len;
            while ((len = gzipInputStream.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
        } finally {
            if (gzipInputStream != null) {
                gzipInputStream.close();
            }
            if (out != null) {
                out.close();
            }
        }
        return gunzippedFile;
    }

    public static void setLogFormatter(final Logger logger) {
        logger.setUseParentHandlers(false);
        JGenHtmlLogFormatter formatter = new JGenHtmlLogFormatter();
        ConsoleHandler handler = new ConsoleHandler();
        handler.setFormatter(formatter);
        logger.addHandler(handler);
    }

    /**
     * Writes a resource (e.g. CSS file) to the destination directory.
     * @param resourceName The name of a resource (which the classloader can find).
     * @param destDir The destination directory.
     */
    protected static void writeResource(final String resourceName, final File destDir) {
        writeResource(resourceName, destDir, null, null);
    }

    /**
     * Writes a resource (e.g. CSS file) to the destination directory.
     * @param resourceName The name of a resource (which the classloader can find).
     * @param destDir The destination directory.
     */
    protected static void writeResource(final String resourceName, final File destDir, String token,
            String substitute) {
        InputStream in = JGenHtml.class.getResourceAsStream('/' + resourceName);
        writeStreamToFileAndReplace(in, new File(destDir, resourceName), token, substitute);
    }

    /**
     * Writes a resource (e.g. CSS file) to the destination directory.
     * @param resourceName The name of a resource (which the classloader can find).
     * @param destDir The destination directory.
     */
    protected static void writeResource(final File resource, final File destDir) {
        try {
            LOGGER.log(Level.FINE, "Copying resource {0}", resource.getName());
            FileUtils.copyFileToDirectory(resource, destDir);
        } catch (IOException ex) {
            LOGGER.log(Level.SEVERE, ex.getLocalizedMessage());
        }
    }

    private static void writeStreamToFileAndReplace(final InputStream in, final File targetFile, String token,
            String substitute) {
        try {
            OutputStream out = null;
            try {
                out = new FileOutputStream(targetFile);
                if (token != null && substitute != null) {
                    String input = IOUtils.toString(in);
                    input = input.replace(token, substitute);
                    IOUtils.write(input, out);
                } else {
                    IOUtils.copy(in, out);
                }
            } finally {
                if (out != null) {
                    out.close();
                }
                in.close();
            }
        } catch (IOException ex) {
            LOGGER.log(Level.SEVERE, ex.getLocalizedMessage());
        }
    }

    /**
     * Same algorithm as the LCOV genhtml tool so it should always yield the same result.
     * @param indexPages
     * @return The prefix to remove or null.
     */
    public static String getPrefix(Collection<TestCaseSourceFile> indexPages) {
        Map<String, Integer> prefix = new HashMap<String, Integer>();
        for (CoveragePage page : indexPages) {
            String current = page.getPath();
            while ((current = shortenPrefix(current)) != null) {
                String next = current + '/';
                if (!prefix.containsKey(next)) {
                    prefix.put(next, 0);
                }
            }
        }

        for (CoveragePage page : indexPages) {
            String dir = page.getPath();
            for (int i = 0; i < MIN_DIRECTORIES; i++) {
                prefix.remove(dir + '/');
                dir = shortenPrefix(dir);
            }
        }

        Set<String> keys = prefix.keySet();
        for (String current : keys) {
            for (CoveragePage page : indexPages) {
                String path = page.getPath();
                prefix.put(current, prefix.get(current) + path.length());
                if (path.startsWith(current)) {
                    prefix.put(current, prefix.get(current) - current.length());
                }
            }
        }

        String result = null;
        //Find and return prefix with minimal sum
        for (String current : keys) {
            if (result == null) {
                result = current;
            } else if (prefix.get(current) < prefix.get(result)) {
                result = current;
            }
        }
        return result;
    }

    private static String shortenPrefix(String prefix) {
        String result = null;
        int idx = prefix.lastIndexOf('/');
        if (idx > 0) {
            result = prefix.substring(0, idx);
        }
        return result;
    }

    public static void transformToFile(final File targetFile, final boolean asXml, final Document doc)
            throws TransformerConfigurationException, TransformerException, IOException {
        Transformer transformer;
        Config config = CoverageReport.getConfig();
        if (asXml) {
            transformer = getTransformer(null);
        } else {
            transformer = getTransformer('/' + JGenHtmlUtils.XSLT_NAME);
            transformer.setParameter("ext", config.getHtmlExt());
            File cssFile = config.getCssFile();
            if (cssFile != null) {
                transformer.setParameter("cssName", cssFile.getName());
            }
        }
        DOMSource src = new DOMSource(doc);
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        StreamResult res;
        if (config.isGzip()) {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            GZIPOutputStream gzos = new GZIPOutputStream(new FileOutputStream(targetFile));
            res = new StreamResult(bos);
            transformer.transform(src, res);
            IOUtils.write(bos.toByteArray(), gzos);
            IOUtils.closeQuietly(gzos);
        } else {
            res = new StreamResult(targetFile);
            transformer.transform(src, res);
        }
    }

    /**
     * @return An instance of Transformer
     */
    private static Transformer getTransformer(final String xsltPath) {
        Transformer transformer;
        try {
            TransformerFactory tFactory = TransformerFactory.newInstance();
            if (xsltPath != null) {
                Document xslt = loadXmlDoc(TestCaseSourceFile.class.getResourceAsStream(xsltPath));
                transformer = tFactory.newTransformer(new DOMSource(xslt));
            } else {
                transformer = tFactory.newTransformer();
            }
        } catch (TransformerConfigurationException ex) {
            transformer = null;
            LOGGER.log(Level.SEVERE, ex.getLocalizedMessage());
        }
        return transformer;
    }

    public static void linkToXsl(Document doc, final String xslPath) {
        ProcessingInstruction xsltLink = doc.createProcessingInstruction("xml-stylesheet",
                "type=\"text/xsl\" href=\"" + xslPath + '"');
        Element documentElement = doc.getDocumentElement();
        doc.insertBefore(xsltLink, documentElement);
    }

    public static Document loadXmlDoc(final InputStream stream) {
        Document result = null;
        try {
            DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
            domFactory.setExpandEntityReferences(false);
            domFactory.setNamespaceAware(true);
            DocumentBuilder builder = domFactory.newDocumentBuilder();
            result = builder.parse(stream);

        } catch (SAXException ex) {
            LOGGER.log(Level.SEVERE, ex.getLocalizedMessage());
        } catch (IOException ex) {
            LOGGER.log(Level.SEVERE, ex.getLocalizedMessage());
        } catch (ParserConfigurationException ex) {
            LOGGER.log(Level.SEVERE, ex.getLocalizedMessage());
        }
        return result;
    }

    /**
     * Creates (if necessary) and returns either the HTML or XML output directory.
     * @param rootDir The output root directory.
     * @param asXml If true will return the XML output directory, otherwise the HTML directory.
     * @return Either the XML or HTML output directory.
     */
    public static File getTargetDir(final File rootDir, final boolean asXml) {
        return getTargetDir(rootDir, asXml, null);
    }

    /**
     * Creates and returns a descendent directory within either the HTML or XML output directory found in the given root directory.
     * @param rootDir The output root directory (which will contain an HTML and/or XML output directory).
     * @param asXml If true will use the XML output directory, otherwise the HTML directory.
     * @param subPath the relative path within the XML/HTML directory.
     * @return The directory represented by subPath. If it did not exist it is created.
     * @example getTargetDir(tmpDir, true, "foo/bar");
     * Would return the directory "bar" within tmpDir/xml.
     * @example getTargetDir(tmpDir, false, "foo/bar");
     * Would return the directory "bar" within tmpDir/html.
     */
    public static File getTargetDir(final File rootDir, final boolean asXml, final String subPath) {
        File targetDir = new File(rootDir, asXml ? "xml" : "html");
        return getTargetDir(targetDir, subPath);
    }

    /**
     * Creates and returns a descendent directory within the given root directory.
     * @param rootDir The directory in which to create the subdirectory.
     * @param subPath the relative path within the directory.
     * @return The directory represented by subPath. If it did not exist it is created.
     * @example getTargetDir(tmpDir, "foo/bar");
     * Would return the directory "bar" within tmpDir.
     */
    public static File getTargetDir(final File rootDir, final String subPath) {
        File result;
        if (subPath != null && subPath.length() > 0) {
            result = new File(rootDir, subPath);
        } else {
            result = rootDir;
        }
        if (!result.exists()) {
            result.mkdirs();
        }
        return result;
    }

    public static Element getHitElement(final Document document, final String name, final int hits) {
        Element result = document.createElement("hit");
        result.setAttribute("name", name);
        result.setAttribute("count", String.valueOf(hits));
        return result;
    }
}