ReportOutputFolder.java

    1/*******************************************************************************
    2 * Copyright (c) 2009 Mountainminds GmbH & Co. KG and others
    3 * All rights reserved. This program and the accompanying materials
    4 * are made available under the terms of the Eclipse Public License v1.0
    5 * which accompanies this distribution, and is available at
    6 * http://www.eclipse.org/legal/epl-v10.html
    7 *
    8 * Contributors:
    9 *    Marc R. Hoffmann - initial API and implementation
   10 *    
   11 * $Id: $
   12 *******************************************************************************/
   13package org.jacoco.report;
   14
   15import java.io.IOException;
   16import java.io.OutputStream;
   17import java.util.HashMap;
   18import java.util.Map;
   19
   20/**
   21 * Logical representation of a folder in the output structure. This utility
   22 * ensures valid and unique file names and helps to create relative links.
   23 * 
   24 * @author Marc R. Hoffmann
   25 * @version $Revision: $
   26 */
   27public class ReportOutputFolder {
   28
   29    private final IMultiReportOutput output;
   30
   31    private final ReportOutputFolder parent;
   32
   33    private final String path;
   34
   35    /** Cached sub-folder instances to guarantee stable normalization */
   36    private final Map<String, ReportOutputFolder> subFolders = new HashMap<String, ReportOutputFolder>();
   37
   38    /**
   39     * Creates a new root folder for the given output.
   40     * 
   41     * @param output
   42     *            output for generated files
   43     */
   44    public ReportOutputFolder(final IMultiReportOutput output) {
   45        this(output, null, "");
   46    }
   47
   48    /**
   49     * Creates a new root folder for the given output.
   50     * 
   51     * @param output
   52     *            output for generated files
   53     */
   54    private ReportOutputFolder(final IMultiReportOutput output,
   55            final ReportOutputFolder parent, final String path) {
   56        this.output = output;
   57        this.parent = parent;
   58        this.path = path;
   59    }
   60
   61    /**
   62     * Creates a sub-folder with the given name.
   63     * 
   64     * @param name
   65     *            name of the sub-folder
   66     * @return handle for output into the sub-folder
   67     */
   68    public ReportOutputFolder subFolder(final String name) {
   69        final String normalizedName = normalize(name);
   70        ReportOutputFolder folder = subFolders.get(normalizedName);
   71        if (folder != null) {
   72            return folder;
   73        }
   74        folder = new ReportOutputFolder(output, this, path + normalizedName
   75                + "/");
   76        subFolders.put(normalizedName, folder);
   77        return folder;
   78    }
   79
   80    /**
   81     * Creates a new file in this folder with the given local name.
   82     * 
   83     * @param name
   84     *            name of the sub-folder
   85     * @return handle for output into the sub-folder
   86     * @throws IOException
   87     *             if the file creation fails
   88     */
   89    public OutputStream createFile(final String name) throws IOException {
   90        return output.createFile(path + normalize(name));
   91    }
   92
   93    /**
   94     * Returns a link relative to this folder to the given resource within this
   95     * folder.
   96     * 
   97     * @param name
   98     *            name of the file or folder
   99     * @return relative link
  100     */
  101    public String getLink(final String name) {
  102        return normalize(name);
  103    }
  104
  105    /**
  106     * Returns a link relative to a given base to a resource within this folder.
  107     * 
  108     * @param base
  109     *            base to create the relative link from
  110     * @param name
  111     *            name of the file or folder in this folder
  112     * @return relative link
  113     * @throws IllegalArgumentException
  114     *             if this folder and the base do not have the same root
  115     */
  116    public String getLink(final ReportOutputFolder base, final String name) {
  117        if (base.isAncestorOf(this)) {
  118            return this.path.substring(base.path.length()) + normalize(name);
  119        }
  120        if (base.parent == null) {
  121            throw new IllegalArgumentException("Folders with different roots.");
  122        }
  123        return "../" + this.getLink(base.parent, name);
  124    }
  125
  126    private boolean isAncestorOf(final ReportOutputFolder folder) {
  127        if (this == folder) {
  128            return true;
  129        }
  130        return folder.parent == null ? false : isAncestorOf(folder.parent);
  131    }
  132
  133    private String normalize(final String name) {
  134        // TODO: escape unsafe characters, case awareness, ensure unique names
  135        return name;
  136    }
  137
  138}