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.report.xml;
20  
21  import java.io.IOException;
22  import java.util.Calendar;
23  import java.util.Locale;
24  
25  import org.apache.commons.lang3.StringUtils;
26  import org.apache.commons.lang3.time.DateFormatUtils;
27  import org.apache.rat.VersionInfo;
28  import org.apache.rat.api.Document;
29  import org.apache.rat.api.MetaData;
30  import org.apache.rat.api.RatException;
31  import org.apache.rat.config.results.ClaimValidator;
32  import org.apache.rat.license.ILicense;
33  import org.apache.rat.report.claim.ClaimStatistic;
34  import org.apache.rat.report.xml.writer.XmlWriter;
35  import org.apache.rat.utils.CasedString;
36  
37  /**
38   * Creates the elements in the XML report.
39   */
40  public final class XmlElements {
41      private XmlElements() {
42          // do not instantiate
43      }
44  
45      /**
46       * Converts an enum name to pascal case.
47       *
48       * @param name the attribute to normalize
49       * @return a pascal cased name.
50       */
51      private static String normalizeName(final String name) {
52          CasedString casedName = new CasedString(CasedString.StringCase.SNAKE, name.toLowerCase(Locale.ROOT));
53          return casedName.toCase(CasedString.StringCase.PASCAL);
54      }
55  
56      /**
57       * Create the RAT report element. Includes the timestamp and the version element.
58       * Does not close the report.
59       *
60       * @throws RatException on error
61       */
62      public static void ratReport(final XmlWriter writer) throws RatException {
63          try {
64              writer.startElement(Elements.RAT_REPORT.elementName)
65                      .attribute(Attributes.TIMESTAMP.attributeName(),
66                              DateFormatUtils.ISO_8601_EXTENDED_DATETIME_TIME_ZONE_FORMAT.format(Calendar.getInstance()));
67              version(writer);
68          } catch (IOException e) {
69              throw new RatException(e);
70          }
71      }
72  
73      /**
74       * Creates the version element with all version attributes populated. Closes the version element.
75       *
76       * @throws RatException on error
77       */
78      public static void version(final XmlWriter writer) throws RatException {
79          VersionInfo versionInfo = new VersionInfo();
80          try {
81              writer.startElement(Elements.VERSION.elementName)
82                      .attribute(Attributes.PRODUCT.attributeName(), versionInfo.getTitle())
83                      .attribute(Attributes.VENDOR.attributeName(), versionInfo.getVendor())
84                      .attribute(Attributes.VERSION.attributeName(), versionInfo.getVersion())
85                      .closeElement();
86          } catch (IOException e) {
87              throw new RatException(e);
88          }
89      }
90  
91      /**
92       * Creates a license element. Closes the element before exit.
93       *
94       * @param license  the license for the element.
95       * @param approved {@code true} if the license is approved.
96       * @throws RatException on error.
97       */
98      public static void license(final XmlWriter writer, final ILicense license, final boolean approved) throws RatException {
99          try {
100             writer.startElement(Elements.LICENSE.elementName)
101                     .attribute(Attributes.ID.attributeName(), license.getId())
102                     .attribute(Attributes.NAME.attributeName(), license.getName())
103                     .attribute(Attributes.APPROVAL.attributeName(), Boolean.toString(approved))
104                     .attribute(Attributes.FAMILY.attributeName(), license.getLicenseFamily().getFamilyCategory());
105 
106             if (StringUtils.isNotBlank(license.getNote())) {
107                 writer.startElement(Elements.NOTES.elementName).cdata(license.getNote()).closeElement();
108             }
109             writer.closeElement();
110         } catch (IOException e) {
111             throw new RatException(e);
112         }
113     }
114 
115     /**
116      * Creates a document element with attributes. Does <strong>NOT</strong> close the document element.
117      *
118      * @param document the document to write.
119      * @throws RatException on error.
120      */
121     public static void document(final XmlWriter writer, final Document document) throws RatException {
122         final MetaData metaData = document.getMetaData();
123         try {
124             writer.startElement(Elements.RESOURCE.elementName)
125                     .attribute(Attributes.NAME.attributeName(), document.getName().localized("/"))
126                     .attribute(Attributes.TYPE.attributeName(), metaData.getDocumentType().toString())
127                     .attribute(Attributes.MEDIA_TYPE.attributeName(), metaData.getMediaType().toString());
128             if (Document.Type.STANDARD == metaData.getDocumentType() || metaData.hasCharset()) {
129                 writer.attribute(Attributes.ENCODING.attributeName(), metaData.getCharset().displayName());
130             }
131             if (document.isIgnored()) {
132                 writer.attribute(Attributes.IS_DIRECTORY.attributeName(), Boolean.toString(document.isDirectory()));
133             }
134         } catch (IOException e) {
135             throw new RatException(e);
136         }
137     }
138 
139     /**
140      * Creates a statistics element.
141      *
142      * @throws RatException on error.
143      */
144     public static void statistics(final XmlWriter writer, final ClaimStatistic statistic, final ClaimValidator validator) throws RatException {
145         try {
146             writer.startElement(Elements.STATISTICS.elementName);
147             for (ClaimStatistic.Counter counter : ClaimStatistic.Counter.values()) {
148                 int count = statistic.getCounter(counter);
149                 XmlElements.statistic(writer, counter.displayName(), count, counter.getDescription(), validator.isValid(counter, count));
150             }
151             for (String category : statistic.getLicenseFamilyCategories()) {
152                 XmlElements.licenseCategory(writer, category, statistic.getLicenseCategoryCount(category));
153             }
154             for (String category : statistic.getLicenseNames()) {
155                 XmlElements.licenseName(writer, category, statistic.getLicenseNameCount(category));
156             }
157             for (Document.Type type : statistic.getDocumentTypes()) {
158                 XmlElements.documentType(writer, type.name(), statistic.getCounter(type));
159             }
160 
161             writer.closeElement();
162         } catch (IOException e) {
163             throw new RatException(e);
164         }
165     }
166 
167     /**
168      * Creates a statistic element. Closes the element before returning.
169      *
170      * @param name        the name of the statistics element.
171      * @param count       the count for the element.
172      * @param description description of this statistic.
173      * @param isOk        if {@code true} the count is within limits.
174      * @throws RatException on error.
175      */
176     public static void statistic(final XmlWriter writer, final String name, final int count, final String description, final boolean isOk) throws RatException {
177         try {
178             writer.startElement(Elements.STATISTIC.elementName)
179                     .attribute(Attributes.NAME.attributeName(), name)
180                     .attribute(Attributes.COUNT.attributeName(), Integer.toString(count))
181                     .attribute(Attributes.APPROVAL.attributeName(), Boolean.toString(isOk))
182                     .attribute(Attributes.DESCRIPTION.attributeName(), description)
183                     .closeElement();
184         } catch (IOException e) {
185             throw new RatException(e);
186         }
187     }
188 
189     /**
190      * Creates a statistic element. Closes the element before returning.
191      *
192      * @param name  the name of the statistics element.
193      * @param count the count for the element.
194      * @throws RatException on error.
195      */
196     public static void licenseCategory(final XmlWriter writer, final String name, final int count) throws RatException {
197         try {
198             writer.startElement(Elements.LICENSE_CATEGORY.elementName)
199                     .attribute(Attributes.NAME.attributeName(), name)
200                     .attribute(Attributes.COUNT.attributeName(), Integer.toString(count))
201                     .closeElement();
202         } catch (IOException e) {
203             throw new RatException(e);
204         }
205     }
206 
207     /**
208      * Creates a statistic element. Closes the element before returning.
209      *
210      * @param name  the name of the statistics element.
211      * @param count the count for the element.
212      * @throws RatException on error.
213      */
214     public static void licenseName(final XmlWriter writer, final String name, final int count) throws RatException {
215         try {
216             writer.startElement(Elements.LICENSE_NAME.elementName)
217                     .attribute(Attributes.NAME.attributeName(), name)
218                     .attribute(Attributes.COUNT.attributeName(), Integer.toString(count))
219                     .closeElement();
220         } catch (IOException e) {
221             throw new RatException(e);
222         }
223     }
224 
225     /**
226      * Creates a document type element. Closes the element before returning.
227      *
228      * @param name  the name of the document type element.
229      * @param count the count for the element.
230      * @throws RatException on error.
231      */
232     public static void documentType(final XmlWriter writer, final String name, final int count) throws RatException {
233         try {
234             writer.startElement(Elements.DOCUMENT_TYPE.elementName)
235                     .attribute(Attributes.NAME.attributeName(), name)
236                     .attribute(Attributes.COUNT.attributeName(), Integer.toString(count))
237                     .closeElement();
238         } catch (IOException e) {
239             throw new RatException(e);
240         }
241     }
242 
243     /**
244      * The elements in the report.
245      */
246     public enum Elements {
247         /**
248          * The start of the RAT report.
249          */
250         RAT_REPORT("rat-report"),
251         /**
252          * The version of RAT being run.
253          */
254         VERSION(),
255         /**
256          * A resource element.
257          */
258         RESOURCE(),
259         /**
260          * A license element.
261          */
262         LICENSE(),
263         /**
264          * A notes element.
265          */
266         NOTES(),
267         /**
268          * A statistics element.
269          */
270         STATISTICS(),
271         /**
272          * A statistic entry.
273          */
274         STATISTIC(),
275         /**
276          * A license name entry.
277          */
278         LICENSE_NAME(),
279         /**
280          * A license category entry.
281          */
282         LICENSE_CATEGORY(),
283         /**
284          * A document type entry.
285          */
286         DOCUMENT_TYPE();
287 
288         /**
289          * The XML name for the element
290          */
291         private final String elementName;
292 
293         /**
294          * Constructor.
295          *
296          * @param elementName the XML name for the element.
297          */
298         Elements(final String elementName) {
299             this.elementName = elementName;
300         }
301 
302         Elements() {
303             this.elementName = normalizeName(name());
304         }
305     }
306 
307     /**
308      * The attributes of elements in the report.
309      */
310     public enum Attributes {
311         /**
312          * A timestamp.
313          */
314         TIMESTAMP,
315         /**
316          * A version string.
317          */
318         VERSION,
319         /**
320          * The product identifier.
321          */
322         PRODUCT,
323         /**
324          * The vendor identifier.
325          */
326         VENDOR,
327         /**
328          * The approval flag.
329          */
330         APPROVAL,
331         /**
332          * The family category.
333          */
334         FAMILY,
335         /**
336          * The document type.
337          */
338         TYPE,
339         /**
340          * The id.
341          */
342         ID,
343         /**
344          * The name.
345          */
346         NAME,
347         /**
348          * A counter.
349          */
350         COUNT,
351         /**
352          * A description.
353          */
354         DESCRIPTION,
355         /**
356          * The media type for a document.
357          */
358         MEDIA_TYPE,
359         /**
360          * The encoding for a text document.
361          */
362         ENCODING,
363         /**
364          * Denotes a skipped directory.
365          */
366         IS_DIRECTORY;
367 
368         String attributeName() {
369             return normalizeName(this.name());
370         }
371     }
372 }