View Javadoc

    1   /*
    2    * This file is part of dependency-check-core.
    3    *
    4    * Dependency-check-core is free software: you can redistribute it and/or modify it
    5    * under the terms of the GNU General Public License as published by the Free
    6    * Software Foundation, either version 3 of the License, or (at your option) any
    7    * later version.
    8    *
    9    * Dependency-check-core is distributed in the hope that it will be useful, but
    10   * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    11   * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
    12   * details.
    13   *
    14   * You should have received a copy of the GNU General Public License along with
    15   * dependency-check-core. If not, see http://www.gnu.org/licenses/.
    16   *
    17   * Copyright (c) 2012 Jeremy Long. All Rights Reserved.
    18   */
    19  package org.owasp.dependencycheck.reporting;
    20
    21  import java.io.FileInputStream;
    22  import java.io.File;
    23  import java.io.FileNotFoundException;
    24  import java.io.FileOutputStream;
    25  import java.io.IOException;
    26  import java.io.InputStream;
    27  import java.io.InputStreamReader;
    28  import java.io.OutputStream;
    29  import java.io.OutputStreamWriter;
    30  import java.util.List;
    31  import java.util.logging.Level;
    32  import java.util.logging.Logger;
    33  import org.apache.velocity.app.VelocityEngine;
    34  import org.apache.velocity.context.Context;
    35  import org.apache.velocity.runtime.RuntimeConstants;
    36  import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
    37  import org.apache.velocity.tools.ToolManager;
    38  import org.apache.velocity.tools.config.EasyFactoryConfiguration;
    39  import org.owasp.dependencycheck.analyzer.Analyzer;
    40  import org.owasp.dependencycheck.dependency.Dependency;
    41
    42  /**
    43   * The ReportGenerator is used to, as the name implies, generate reports.
    44   * Internally the generator uses the Velocity Templating Engine. The
    45   * ReportGenerator exposes a list of Dependencies to the template when
    46   * generating the report.
    47   *
    48   * @author Jeremy Long (jeremy.long@owasp.org)
    49   */
    50  public class ReportGenerator {
    51
    52      /**
    53       * An enumeration of the report formats.
    54       */
    55      public enum Format {
    56
    57          /**
    58           * Generate all reports.
    59           */
    60          ALL,
    61          /**
    62           * Generate XML report.
    63           */
    64          XML,
    65          /**
    66           * Generate HTML report.
    67           */
    68          HTML,
    69          /**
    70           * Generate HTML Vulnerability report.
    71           */
    72          VULN
    73      }
    74      /**
    75       * The Velocity Engine.
    76       */
    77      private final VelocityEngine engine;
    78      /**
    79       * The Velocity Engine Context.
    80       */
    81      private final Context context;
    82
    83      /**
    84       * Constructs a new ReportGenerator.
    85       *
    86       * @param applicationName the application name being analyzed
    87       * @param dependencies the list of dependencies
    88       * @param analyzers the list of analyzers used.
    89       */
    90      public ReportGenerator(String applicationName, List<Dependency> dependencies, List<Analyzer> analyzers) {
    91          engine = createVelocityEngine();
    92          context = createContext();
    93
    94          engine.init();
    95
    96          context.put("applicationName", applicationName);
    97          context.put("dependencies", dependencies);
    98          context.put("analyzers", analyzers);
    99      }
    100
    101     /**
    102      * Creates a new Velocity Engine.
    103      *
    104      * @return a velocity engine.
    105      */
    106     private VelocityEngine createVelocityEngine() {
    107         final VelocityEngine ve = new VelocityEngine();
    108         ve.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, VelocityLoggerRedirect.class.getName());
    109         ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
    110         ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
    111         return ve;
    112     }
    113
    114     /**
    115      * Creates a new Velocity Context initialized with escape and date tools.
    116      *
    117      * @return a Velocity Context.
    118      */
    119     @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RV_RETURN_VALUE_IGNORED_INFERRED",
    120             justification = "No plan to fix this style issue")
    121     private Context createContext() {
    122         final ToolManager manager = new ToolManager();
    123         final Context c = manager.createContext();
    124         final EasyFactoryConfiguration config = new EasyFactoryConfiguration();
    125         config.addDefaultTools();
    126         config.toolbox("application").tool("esc", "org.apache.velocity.tools.generic.EscapeTool").tool("org.apache.velocity.tools.generic.DateTool");
    127         manager.configure(config);
    128         return c;
    129     }
    130
    131     /**
    132      * Generates the Dependency Reports for the identified dependencies.
    133      *
    134      * @param outputDir the path where the reports should be written
    135      * @param format the format the report should be written in
    136      * @throws IOException is thrown when the template file does not exist
    137      * @throws Exception is thrown if there is an error writing out the reports.
    138      */
    139     public void generateReports(String outputDir, Format format) throws IOException, Exception {
    140         if (format == Format.XML || format == Format.ALL) {
    141             generateReport("XmlReport", outputDir + File.separator + "DependencyCheck-Report.xml");
    142         }
    143         if (format == Format.HTML || format == Format.ALL) {
    144             generateReport("HtmlReport", outputDir + File.separator + "DependencyCheck-Report.html");
    145         }
    146         if (format == Format.VULN || format == Format.ALL) {
    147             generateReport("VulnerabilityReport", outputDir + File.separator + "DependencyCheck-Vulnerability.html");
    148         }
    149     }
    150
    151     /**
    152      * Generates the Dependency Reports for the identified dependencies.
    153      *
    154      * @param outputDir the path where the reports should be written
    155      * @param outputFormat the format the report should be written in (XML,
    156      * HTML, ALL)
    157      * @throws IOException is thrown when the template file does not exist
    158      * @throws Exception is thrown if there is an error writing out the reports.
    159      */
    160     public void generateReports(String outputDir, String outputFormat) throws IOException, Exception {
    161         final String format = outputFormat.toUpperCase();
    162         if (format.matches("^(XML|HTML|VULN|ALL)$")) {
    163             if ("XML".equalsIgnoreCase(format)) {
    164                 generateReports(outputDir, Format.XML);
    165             }
    166             if ("HTML".equalsIgnoreCase(format)) {
    167                 generateReports(outputDir, Format.HTML);
    168             }
    169             if ("VULN".equalsIgnoreCase(format)) {
    170                 generateReports(outputDir, Format.VULN);
    171             }
    172             if ("ALL".equalsIgnoreCase(format)) {
    173                 generateReports(outputDir, Format.ALL);
    174             }
    175         }
    176     }
    177
    178     /**
    179      * Generates a report from a given Velocity Template. The template name
    180      * provided can be the name of a template contained in the jar file, such as
    181      * 'XmlReport' or 'HtmlReport', or the template name can be the path to a
    182      * template file.
    183      *
    184      * @param templateName the name of the template to load.
    185      * @param outFileName the filename and path to write the report to.
    186      * @throws IOException is thrown when the template file does not exist.
    187      * @throws Exception is thrown when an exception occurs.
    188      */
    189     protected void generateReport(String templateName, String outFileName) throws IOException, Exception {
    190         InputStream input = null;
    191         String templatePath = null;
    192         final File f = new File(templateName);
    193         if (f.exists() && f.isFile()) {
    194             try {
    195                 templatePath = templateName;
    196                 input = new FileInputStream(f);
    197             } catch (FileNotFoundException ex) {
    198                 final String msg = "Unable to generate the report, the report template file could not be found.";
    199                 Logger.getLogger(ReportGenerator.class.getName()).log(Level.SEVERE, msg);
    200                 Logger.getLogger(ReportGenerator.class.getName()).log(Level.FINE, null, ex);
    201             }
    202         } else {
    203             templatePath = "templates/" + templateName + ".vsl";
    204             input = this.getClass().getClassLoader().getResourceAsStream(templatePath);
    205         }
    206         if (input == null) {
    207             throw new IOException("Template file doesn't exist");
    208         }
    209
    210         final InputStreamReader reader = new InputStreamReader(input, "UTF-8");
    211         OutputStreamWriter writer = null;
    212         OutputStream outputStream = null;
    213
    214         try {
    215             final File outDir = new File(outFileName).getParentFile();
    216             if (!outDir.exists()) {
    217                 final boolean created = outDir.mkdirs();
    218                 if (!created) {
    219                     throw new Exception("Unable to create directory '" + outDir.getAbsolutePath() + "'.");
    220                 }
    221             }
    222
    223             outputStream = new FileOutputStream(outFileName);
    224             writer = new OutputStreamWriter(outputStream, "UTF-8");
    225
    226             if (!engine.evaluate(context, writer, templatePath, reader)) {
    227                 throw new Exception("Failed to convert the template into html.");
    228             }
    229             writer.flush();
    230         } finally {
    231             if (writer != null) {
    232                 try {
    233                     writer.close();
    234                 } catch (Exception ex) {
    235                     Logger.getLogger(ReportGenerator.class.getName()).log(Level.FINEST, null, ex);
    236                 }
    237             }
    238             if (outputStream != null) {
    239                 try {
    240                     outputStream.close();
    241                 } catch (Exception ex) {
    242                     Logger.getLogger(ReportGenerator.class.getName()).log(Level.FINEST, null, ex);
    243                 }
    244             }
    245             try {
    246                 reader.close();
    247             } catch (Exception ex) {
    248                 Logger.getLogger(ReportGenerator.class.getName()).log(Level.FINEST, null, ex);
    249             }
    250         }
    251     }
    252 }