View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one   *
3    * or more contributor license agreements.  See the NOTICE file *
4    * distributed with this work for additional information        *
5    * regarding copyright ownership.  The ASF licenses this file   *
6    * to you under the Apache License, Version 2.0 (the            *
7    * "License"); you may not use this file except in compliance   *
8    * with the License.  You may obtain a copy of the License at   *
9    *                                                              *
10   *   http://www.apache.org/licenses/LICENSE-2.0                 *
11   *                                                              *
12   * Unless required by applicable law or agreed to in writing,   *
13   * software distributed under the License is distributed on an  *
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15   * KIND, either express or implied.  See the License for the    *
16   * specific language governing permissions and limitations      *
17   * under the License.                                           *
18   */
19  package org.apache.rat;
20  
21  import java.io.ByteArrayInputStream;
22  import java.io.ByteArrayOutputStream;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.io.OutputStream;
26  import java.io.OutputStreamWriter;
27  import java.io.PrintWriter;
28  import java.io.Writer;
29  import java.nio.charset.StandardCharsets;
30  
31  import javax.xml.parsers.DocumentBuilderFactory;
32  import javax.xml.transform.OutputKeys;
33  import javax.xml.transform.Transformer;
34  import javax.xml.transform.TransformerException;
35  import javax.xml.transform.TransformerFactory;
36  import javax.xml.transform.dom.DOMSource;
37  import javax.xml.transform.stream.StreamResult;
38  import javax.xml.transform.stream.StreamSource;
39  
40  import org.apache.commons.io.function.IOSupplier;
41  import org.apache.rat.api.RatException;
42  import org.apache.rat.license.LicenseSetFactory.LicenseFilter;
43  import org.apache.rat.report.RatReport;
44  import org.apache.rat.report.claim.ClaimStatistic;
45  import org.apache.rat.report.xml.XmlReportFactory;
46  import org.apache.rat.report.xml.writer.IXmlWriter;
47  import org.apache.rat.report.xml.writer.XmlWriter;
48  import org.w3c.dom.Document;
49  
50  /**
51   * Class that executes the report as defined in a {@link ReportConfiguration} and stores
52   * the result for later handling.
53   */
54  public class Reporter {
55  
56      /**  Format used for listing licenses. */
57      private static final String LICENSE_FORMAT = "%s:\t%s%n\t\t%s%n";
58  
59      /** The XML output document */
60      private Document document;
61  
62      /** Statistics generated as the report was built */
63      private ClaimStatistic statistic;
64  
65      /** The configuration for the report */
66      private final ReportConfiguration configuration;
67  
68      /**
69       * Create the reporter.
70       *
71       * @param configuration the configuration to use.
72       */
73      public Reporter(final ReportConfiguration configuration) {
74          this.configuration = configuration;
75      }
76  
77      /**
78       * Executes the report and builds the output.
79       * This method will build the internal XML document if it does not already exist.
80       * If this method or either of the {@link #output()} methods have already been called this method will return
81       * the previous results.
82       * @return the claim statistics.
83       * @throws RatException on error.
84       */
85      public ClaimStatistic execute() throws RatException  {
86          if (document == null || statistic == null) {
87              try {
88                  if (configuration.hasSource()) {
89                      ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
90                      Writer outputWriter = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
91                      try (IXmlWriter writer = new XmlWriter(outputWriter)) {
92                          statistic = new ClaimStatistic();
93                          RatReport report = XmlReportFactory.createStandardReport(writer, statistic, configuration);
94                          report.startReport();
95                          configuration.getSources().build().run(report);
96                          report.endReport();
97  
98                          InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
99                          document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(inputStream);
100                     }
101                 } else {
102                     document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
103                     statistic = new ClaimStatistic();
104                 }
105             }  catch (Exception e) {
106                 throw RatException.makeRatException(e);
107             }
108         }
109         return statistic;
110     }
111 
112     /**
113      * Get the claim statistics from the run.
114      *
115      * @return the claim statistics.
116      */
117     public ClaimStatistic getClaimsStatistic() {
118         return statistic;
119     }
120 
121     /**
122      * Outputs the report using the stylesheet and output specified in the configuration.
123      *
124      * @throws RatException on error.
125      */
126     public void output() throws RatException {
127         output(configuration.getStyleSheet(), configuration.getOutput());
128     }
129 
130     /**
131      * Outputs the report to the specified output using the stylesheet. It is safe to call this method more than once
132      * in order to generate multiple reports from the same run.
133      *
134      * @param stylesheet the style sheet to use for XSLT formatting.
135      * @param output the output stream to write to.
136      * @throws RatException on error.
137      */
138     public void output(final IOSupplier<InputStream> stylesheet, final IOSupplier<OutputStream> output) throws RatException {
139         execute();
140         TransformerFactory tf = TransformerFactory.newInstance();
141         Transformer transformer;
142         try (OutputStream out = output.get();
143              InputStream styleIn = stylesheet.get()) {
144             transformer = tf.newTransformer(new StreamSource(styleIn));
145             transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
146             transformer.setOutputProperty(OutputKeys.METHOD, "xml");
147             transformer.setOutputProperty(OutputKeys.INDENT, "yes");
148             transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
149             transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
150             transformer.transform(new DOMSource(document),
151                     new StreamResult(new OutputStreamWriter(out, StandardCharsets.UTF_8)));
152         } catch (TransformerException | IOException e) {
153             throw new RatException(e);
154         }
155     }
156 
157     /**
158      * Lists the licenses on the configured output stream.
159      * @param configuration The configuration for the system
160      * @param filter the license filter that specifies which licenses to output.
161      * @throws IOException if PrintWriter can not be retrieved from configuration.
162      */
163     public static void listLicenses(final ReportConfiguration configuration, final LicenseFilter filter) throws IOException {
164         try (PrintWriter pw = configuration.getWriter().get()) {
165             pw.format("Licenses (%s):%n", filter);
166             configuration.getLicenses(filter)
167                     .forEach(lic -> pw.format(LICENSE_FORMAT, lic.getLicenseFamily().getFamilyCategory(),
168                             lic.getLicenseFamily().getFamilyName(), lic.getNote()));
169             pw.println();
170         }
171     }
172 
173     /**
174      * Writes a text summary of issues with the run.
175      * @param appendable the appendable to write to.
176      * @throws IOException on error.
177      */
178     public void writeSummary(final Appendable appendable) throws IOException {
179         appendable.append("RAT summary:").append(System.lineSeparator());
180         for (ClaimStatistic.Counter counter : ClaimStatistic.Counter.values()) {
181             appendable.append("  ").append(counter.displayName()).append(":  ")
182                     .append(Integer.toString(getClaimsStatistic().getCounter(counter)))
183                     .append(System.lineSeparator());
184         }
185     }
186 }